diff options
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/com/android/internal/util/ProgressReporter.java | 119 |
1 files changed, 96 insertions, 23 deletions
diff --git a/core/java/com/android/internal/util/ProgressReporter.java b/core/java/com/android/internal/util/ProgressReporter.java index 796f8acccdcb..7a8efba8a637 100644 --- a/core/java/com/android/internal/util/ProgressReporter.java +++ b/core/java/com/android/internal/util/ProgressReporter.java @@ -20,9 +20,12 @@ import android.annotation.Nullable; import android.content.Intent; import android.os.Bundle; import android.os.IProgressListener; +import android.os.RemoteCallbackList; import android.os.RemoteException; import android.util.MathUtils; +import com.android.internal.annotations.GuardedBy; + /** * Tracks and reports progress of a single task to a {@link IProgressListener}. * The reported progress of a task ranges from 0-100, but the task can be @@ -44,33 +47,67 @@ import android.util.MathUtils; * } * </pre> * - * This class is not thread safe. - * * @hide */ public class ProgressReporter { - public static final ProgressReporter NO_OP = new ProgressReporter(0, null); + private static final int STATE_INIT = 0; + private static final int STATE_STARTED = 1; + private static final int STATE_FINISHED = 2; private final int mId; - private final IProgressListener mListener; - private Bundle mExtras = new Bundle(); + @GuardedBy("this") + private final RemoteCallbackList<IProgressListener> mListeners = new RemoteCallbackList<>(); + @GuardedBy("this") + private int mState = STATE_INIT; + @GuardedBy("this") private int mProgress = 0; + @GuardedBy("this") + private Bundle mExtras = new Bundle(); /** * Current segment range: first element is starting progress of this * segment, second element is length of segment. */ + @GuardedBy("this") private int[] mSegmentRange = new int[] { 0, 100 }; /** * Create a new task with the given identifier whose progress will be * reported to the given listener. */ - public ProgressReporter(int id, @Nullable IProgressListener listener) { + public ProgressReporter(int id) { mId = id; - mListener = listener; + } + + /** + * Add given listener to watch for progress events. The current state will + * be immediately dispatched to the given listener. + */ + public void addListener(@Nullable IProgressListener listener) { + if (listener == null) return; + synchronized (this) { + mListeners.register(listener); + switch (mState) { + case STATE_INIT: + // Nothing has happened yet + break; + case STATE_STARTED: + try { + listener.onStarted(mId, null); + listener.onProgress(mId, mProgress, mExtras); + } catch (RemoteException ignored) { + } + break; + case STATE_FINISHED: + try { + listener.onFinished(mId, null); + } catch (RemoteException ignored) { + } + break; + } + } } /** @@ -102,12 +139,17 @@ public class ProgressReporter { * Set the fractional progress of the currently active segment. */ public void setProgress(int n, int m, @Nullable CharSequence title) { - mProgress = mSegmentRange[0] - + MathUtils.constrain((n * mSegmentRange[1]) / m, 0, mSegmentRange[1]); - if (title != null) { - mExtras.putCharSequence(Intent.EXTRA_TITLE, title); + synchronized (this) { + if (mState != STATE_STARTED) { + throw new IllegalStateException("Must be started to change progress"); + } + mProgress = mSegmentRange[0] + + MathUtils.constrain((n * mSegmentRange[1]) / m, 0, mSegmentRange[1]); + if (title != null) { + mExtras.putCharSequence(Intent.EXTRA_TITLE, title); + } + notifyProgress(mId, mProgress, mExtras); } - notifyProgress(mId, mProgress, mExtras); } /** @@ -116,17 +158,21 @@ public class ProgressReporter { * {@link #endSegment(int[])} when finished. */ public int[] startSegment(int size) { - final int[] lastRange = mSegmentRange; - mSegmentRange = new int[] { mProgress, (size * mSegmentRange[1] / 100) }; - return lastRange; + synchronized (this) { + final int[] lastRange = mSegmentRange; + mSegmentRange = new int[] { mProgress, (size * mSegmentRange[1] / 100) }; + return lastRange; + } } /** * End the current segment. */ public void endSegment(int[] lastRange) { - mProgress = mSegmentRange[0] + mSegmentRange[1]; - mSegmentRange = lastRange; + synchronized (this) { + mProgress = mSegmentRange[0] + mSegmentRange[1]; + mSegmentRange = lastRange; + } } int getProgress() { @@ -138,27 +184,54 @@ public class ProgressReporter { } /** + * Report this entire task as being started. + */ + public void start() { + synchronized (this) { + mState = STATE_STARTED; + notifyStarted(mId, null); + notifyProgress(mId, mProgress, mExtras); + } + } + + /** * Report this entire task as being finished. */ public void finish() { - notifyFinished(mId, null); + synchronized (this) { + mState = STATE_FINISHED; + notifyFinished(mId, null); + mListeners.kill(); + } + } + + private void notifyStarted(int id, Bundle extras) { + for (int i = mListeners.beginBroadcast() - 1; i >= 0; i--) { + try { + mListeners.getBroadcastItem(i).onStarted(id, extras); + } catch (RemoteException ignored) { + } + } + mListeners.finishBroadcast(); } private void notifyProgress(int id, int progress, Bundle extras) { - if (mListener != null) { + for (int i = mListeners.beginBroadcast() - 1; i >= 0; i--) { try { - mListener.onProgress(id, progress, extras); + mListeners.getBroadcastItem(i).onProgress(id, progress, extras); } catch (RemoteException ignored) { } } + mListeners.finishBroadcast(); } - public void notifyFinished(int id, Bundle extras) { - if (mListener != null) { + private void notifyFinished(int id, Bundle extras) { + for (int i = mListeners.beginBroadcast() - 1; i >= 0; i--) { try { - mListener.onFinished(id, extras); + mListeners.getBroadcastItem(i).onFinished(id, extras); } catch (RemoteException ignored) { } } + mListeners.finishBroadcast(); } } |
