1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.app;
18 
19 import com.android.internal.R;
20 
21 import android.content.Context;
22 import android.content.res.TypedArray;
23 import android.graphics.drawable.Drawable;
24 import android.os.Bundle;
25 import android.os.Handler;
26 import android.os.Message;
27 import android.text.Spannable;
28 import android.text.SpannableString;
29 import android.text.style.StyleSpan;
30 import android.view.LayoutInflater;
31 import android.view.View;
32 import android.widget.ProgressBar;
33 import android.widget.TextView;
34 
35 import java.text.NumberFormat;
36 
37 /**
38  * <p>A dialog showing a progress indicator and an optional text message or view.
39  * Only a text message or a view can be used at the same time.</p>
40  * <p>The dialog can be made cancelable on back key press.</p>
41  * <p>The progress range is 0..10000.</p>
42  */
43 public class ProgressDialog extends AlertDialog {
44 
45     /** Creates a ProgressDialog with a circular, spinning progress
46      * bar. This is the default.
47      */
48     public static final int STYLE_SPINNER = 0;
49 
50     /** Creates a ProgressDialog with a horizontal progress bar.
51      */
52     public static final int STYLE_HORIZONTAL = 1;
53 
54     private ProgressBar mProgress;
55     private TextView mMessageView;
56 
57     private int mProgressStyle = STYLE_SPINNER;
58     private TextView mProgressNumber;
59     private String mProgressNumberFormat;
60     private TextView mProgressPercent;
61     private NumberFormat mProgressPercentFormat;
62 
63     private int mMax;
64     private int mProgressVal;
65     private int mSecondaryProgressVal;
66     private int mIncrementBy;
67     private int mIncrementSecondaryBy;
68     private Drawable mProgressDrawable;
69     private Drawable mIndeterminateDrawable;
70     private CharSequence mMessage;
71     private boolean mIndeterminate;
72 
73     private boolean mHasStarted;
74     private Handler mViewUpdateHandler;
75 
ProgressDialog(Context context)76     public ProgressDialog(Context context) {
77         super(context);
78         initFormats();
79     }
80 
ProgressDialog(Context context, int theme)81     public ProgressDialog(Context context, int theme) {
82         super(context, theme);
83         initFormats();
84     }
85 
initFormats()86     private void initFormats() {
87         mProgressNumberFormat = "%1d/%2d";
88         mProgressPercentFormat = NumberFormat.getPercentInstance();
89         mProgressPercentFormat.setMaximumFractionDigits(0);
90     }
91 
show(Context context, CharSequence title, CharSequence message)92     public static ProgressDialog show(Context context, CharSequence title,
93             CharSequence message) {
94         return show(context, title, message, false);
95     }
96 
show(Context context, CharSequence title, CharSequence message, boolean indeterminate)97     public static ProgressDialog show(Context context, CharSequence title,
98             CharSequence message, boolean indeterminate) {
99         return show(context, title, message, indeterminate, false, null);
100     }
101 
show(Context context, CharSequence title, CharSequence message, boolean indeterminate, boolean cancelable)102     public static ProgressDialog show(Context context, CharSequence title,
103             CharSequence message, boolean indeterminate, boolean cancelable) {
104         return show(context, title, message, indeterminate, cancelable, null);
105     }
106 
show(Context context, CharSequence title, CharSequence message, boolean indeterminate, boolean cancelable, OnCancelListener cancelListener)107     public static ProgressDialog show(Context context, CharSequence title,
108             CharSequence message, boolean indeterminate,
109             boolean cancelable, OnCancelListener cancelListener) {
110         ProgressDialog dialog = new ProgressDialog(context);
111         dialog.setTitle(title);
112         dialog.setMessage(message);
113         dialog.setIndeterminate(indeterminate);
114         dialog.setCancelable(cancelable);
115         dialog.setOnCancelListener(cancelListener);
116         dialog.show();
117         return dialog;
118     }
119 
120     @Override
onCreate(Bundle savedInstanceState)121     protected void onCreate(Bundle savedInstanceState) {
122         LayoutInflater inflater = LayoutInflater.from(mContext);
123         TypedArray a = mContext.obtainStyledAttributes(null,
124                 com.android.internal.R.styleable.AlertDialog,
125                 com.android.internal.R.attr.alertDialogStyle, 0);
126         if (mProgressStyle == STYLE_HORIZONTAL) {
127 
128             /* Use a separate handler to update the text views as they
129              * must be updated on the same thread that created them.
130              */
131             mViewUpdateHandler = new Handler() {
132                 @Override
133                 public void handleMessage(Message msg) {
134                     super.handleMessage(msg);
135 
136                     /* Update the number and percent */
137                     int progress = mProgress.getProgress();
138                     int max = mProgress.getMax();
139                     if (mProgressNumberFormat != null) {
140                         String format = mProgressNumberFormat;
141                         mProgressNumber.setText(String.format(format, progress, max));
142                     } else {
143                         mProgressNumber.setText("");
144                     }
145                     if (mProgressPercentFormat != null) {
146                         double percent = (double) progress / (double) max;
147                         SpannableString tmp = new SpannableString(mProgressPercentFormat.format(percent));
148                         tmp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD),
149                                 0, tmp.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
150                         mProgressPercent.setText(tmp);
151                     } else {
152                         mProgressPercent.setText("");
153                     }
154                 }
155             };
156             View view = inflater.inflate(a.getResourceId(
157                     com.android.internal.R.styleable.AlertDialog_horizontalProgressLayout,
158                     R.layout.alert_dialog_progress), null);
159             mProgress = (ProgressBar) view.findViewById(R.id.progress);
160             mProgressNumber = (TextView) view.findViewById(R.id.progress_number);
161             mProgressPercent = (TextView) view.findViewById(R.id.progress_percent);
162             setView(view);
163         } else {
164             View view = inflater.inflate(a.getResourceId(
165                     com.android.internal.R.styleable.AlertDialog_progressLayout,
166                     R.layout.progress_dialog), null);
167             mProgress = (ProgressBar) view.findViewById(R.id.progress);
168             mMessageView = (TextView) view.findViewById(R.id.message);
169             setView(view);
170         }
171         a.recycle();
172         if (mMax > 0) {
173             setMax(mMax);
174         }
175         if (mProgressVal > 0) {
176             setProgress(mProgressVal);
177         }
178         if (mSecondaryProgressVal > 0) {
179             setSecondaryProgress(mSecondaryProgressVal);
180         }
181         if (mIncrementBy > 0) {
182             incrementProgressBy(mIncrementBy);
183         }
184         if (mIncrementSecondaryBy > 0) {
185             incrementSecondaryProgressBy(mIncrementSecondaryBy);
186         }
187         if (mProgressDrawable != null) {
188             setProgressDrawable(mProgressDrawable);
189         }
190         if (mIndeterminateDrawable != null) {
191             setIndeterminateDrawable(mIndeterminateDrawable);
192         }
193         if (mMessage != null) {
194             setMessage(mMessage);
195         }
196         setIndeterminate(mIndeterminate);
197         onProgressChanged();
198         super.onCreate(savedInstanceState);
199     }
200 
201     @Override
onStart()202     public void onStart() {
203         super.onStart();
204         mHasStarted = true;
205     }
206 
207     @Override
onStop()208     protected void onStop() {
209         super.onStop();
210         mHasStarted = false;
211     }
212 
setProgress(int value)213     public void setProgress(int value) {
214         if (mHasStarted) {
215             mProgress.setProgress(value);
216             onProgressChanged();
217         } else {
218             mProgressVal = value;
219         }
220     }
221 
setSecondaryProgress(int secondaryProgress)222     public void setSecondaryProgress(int secondaryProgress) {
223         if (mProgress != null) {
224             mProgress.setSecondaryProgress(secondaryProgress);
225             onProgressChanged();
226         } else {
227             mSecondaryProgressVal = secondaryProgress;
228         }
229     }
230 
getProgress()231     public int getProgress() {
232         if (mProgress != null) {
233             return mProgress.getProgress();
234         }
235         return mProgressVal;
236     }
237 
getSecondaryProgress()238     public int getSecondaryProgress() {
239         if (mProgress != null) {
240             return mProgress.getSecondaryProgress();
241         }
242         return mSecondaryProgressVal;
243     }
244 
getMax()245     public int getMax() {
246         if (mProgress != null) {
247             return mProgress.getMax();
248         }
249         return mMax;
250     }
251 
setMax(int max)252     public void setMax(int max) {
253         if (mProgress != null) {
254             mProgress.setMax(max);
255             onProgressChanged();
256         } else {
257             mMax = max;
258         }
259     }
260 
incrementProgressBy(int diff)261     public void incrementProgressBy(int diff) {
262         if (mProgress != null) {
263             mProgress.incrementProgressBy(diff);
264             onProgressChanged();
265         } else {
266             mIncrementBy += diff;
267         }
268     }
269 
incrementSecondaryProgressBy(int diff)270     public void incrementSecondaryProgressBy(int diff) {
271         if (mProgress != null) {
272             mProgress.incrementSecondaryProgressBy(diff);
273             onProgressChanged();
274         } else {
275             mIncrementSecondaryBy += diff;
276         }
277     }
278 
setProgressDrawable(Drawable d)279     public void setProgressDrawable(Drawable d) {
280         if (mProgress != null) {
281             mProgress.setProgressDrawable(d);
282         } else {
283             mProgressDrawable = d;
284         }
285     }
286 
setIndeterminateDrawable(Drawable d)287     public void setIndeterminateDrawable(Drawable d) {
288         if (mProgress != null) {
289             mProgress.setIndeterminateDrawable(d);
290         } else {
291             mIndeterminateDrawable = d;
292         }
293     }
294 
setIndeterminate(boolean indeterminate)295     public void setIndeterminate(boolean indeterminate) {
296         if (mProgress != null) {
297             mProgress.setIndeterminate(indeterminate);
298         } else {
299             mIndeterminate = indeterminate;
300         }
301     }
302 
isIndeterminate()303     public boolean isIndeterminate() {
304         if (mProgress != null) {
305             return mProgress.isIndeterminate();
306         }
307         return mIndeterminate;
308     }
309 
310     @Override
setMessage(CharSequence message)311     public void setMessage(CharSequence message) {
312         if (mProgress != null) {
313             if (mProgressStyle == STYLE_HORIZONTAL) {
314                 super.setMessage(message);
315             } else {
316                 mMessageView.setText(message);
317             }
318         } else {
319             mMessage = message;
320         }
321     }
322 
setProgressStyle(int style)323     public void setProgressStyle(int style) {
324         mProgressStyle = style;
325     }
326 
327     /**
328      * Change the format of the small text showing current and maximum units
329      * of progress.  The default is "%1d/%2d".
330      * Should not be called during the number is progressing.
331      * @param format A string passed to {@link String#format String.format()};
332      * use "%1d" for the current number and "%2d" for the maximum.  If null,
333      * nothing will be shown.
334      */
setProgressNumberFormat(String format)335     public void setProgressNumberFormat(String format) {
336         mProgressNumberFormat = format;
337         onProgressChanged();
338     }
339 
340     /**
341      * Change the format of the small text showing the percentage of progress.
342      * The default is
343      * {@link NumberFormat#getPercentInstance() NumberFormat.getPercentageInstnace().}
344      * Should not be called during the number is progressing.
345      * @param format An instance of a {@link NumberFormat} to generate the
346      * percentage text.  If null, nothing will be shown.
347      */
setProgressPercentFormat(NumberFormat format)348     public void setProgressPercentFormat(NumberFormat format) {
349         mProgressPercentFormat = format;
350         onProgressChanged();
351     }
352 
onProgressChanged()353     private void onProgressChanged() {
354         if (mProgressStyle == STYLE_HORIZONTAL) {
355             if (mViewUpdateHandler != null && !mViewUpdateHandler.hasMessages(0)) {
356                 mViewUpdateHandler.sendEmptyMessage(0);
357             }
358         }
359     }
360 }
361