blob: 796f8acccdcb617eda3a1f57b865106fe8252ebf [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.util;
import android.annotation.Nullable;
import android.content.Intent;
import android.os.Bundle;
import android.os.IProgressListener;
import android.os.RemoteException;
import android.util.MathUtils;
/**
* 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
* segmented into smaller pieces using {@link #startSegment(int)} and
* {@link #endSegment(int[])}, and segments can be nested.
* <p>
* Here's an example in action; when finished the overall task progress will be
* at 60.
*
* <pre>
* prog.setProgress(20);
* {
* final int restore = prog.startSegment(40);
* for (int i = 0; i < N; i++) {
* prog.setProgress(i, N);
* ...
* }
* prog.endSegment(restore);
* }
* </pre>
*
* This class is not thread safe.
*
* @hide
*/
public class ProgressReporter {
public static final ProgressReporter NO_OP = new ProgressReporter(0, null);
private final int mId;
private final IProgressListener mListener;
private Bundle mExtras = new Bundle();
private int mProgress = 0;
/**
* Current segment range: first element is starting progress of this
* segment, second element is length of segment.
*/
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) {
mId = id;
mListener = listener;
}
/**
* Set the progress of the currently active segment.
*
* @param progress Segment progress between 0-100.
*/
public void setProgress(int progress) {
setProgress(progress, 100, null);
}
/**
* Set the progress of the currently active segment.
*
* @param progress Segment progress between 0-100.
*/
public void setProgress(int progress, @Nullable CharSequence title) {
setProgress(progress, 100, title);
}
/**
* Set the fractional progress of the currently active segment.
*/
public void setProgress(int n, int m) {
setProgress(n, m, null);
}
/**
* 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);
}
notifyProgress(mId, mProgress, mExtras);
}
/**
* Start a new inner segment that will contribute the given range towards
* the currently active segment. You must pass the returned value to
* {@link #endSegment(int[])} when finished.
*/
public int[] startSegment(int size) {
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;
}
int getProgress() {
return mProgress;
}
int[] getSegmentRange() {
return mSegmentRange;
}
/**
* Report this entire task as being finished.
*/
public void finish() {
notifyFinished(mId, null);
}
private void notifyProgress(int id, int progress, Bundle extras) {
if (mListener != null) {
try {
mListener.onProgress(id, progress, extras);
} catch (RemoteException ignored) {
}
}
}
public void notifyFinished(int id, Bundle extras) {
if (mListener != null) {
try {
mListener.onFinished(id, extras);
} catch (RemoteException ignored) {
}
}
}
}