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 android.compat.annotation.UnsupportedAppUsage;
20 import android.content.Context;
21 import android.content.res.TypedArray;
22 import android.graphics.drawable.Drawable;
23 import android.os.Build;
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 com.android.internal.R;
36 
37 import java.text.NumberFormat;
38 
39 /**
40  * A dialog showing a progress indicator and an optional text message or view.
41  * Only a text message or a view can be used at the same time.
42  *
43  * <p>The dialog can be made cancelable on back key press.</p>
44  *
45  * <p>The progress range is 0 to {@link #getMax() max}.</p>
46  *
47  * @deprecated <code>ProgressDialog</code> is a modal dialog, which prevents the
48  * user from interacting with the app. Instead of using this class, you should
49  * use a progress indicator like {@link android.widget.ProgressBar}, which can
50  * be embedded in your app's UI. Alternatively, you can use a
51  * <a href="/guide/topics/ui/notifiers/notifications.html">notification</a>
52  * to inform the user of the task's progress.
53  */
54 @Deprecated
55 public class ProgressDialog extends AlertDialog {
56 
57     /**
58      * Creates a ProgressDialog with a circular, spinning progress
59      * bar. This is the default.
60      */
61     public static final int STYLE_SPINNER = 0;
62 
63     /**
64      * Creates a ProgressDialog with a horizontal progress bar.
65      */
66     public static final int STYLE_HORIZONTAL = 1;
67 
68     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
69     private ProgressBar mProgress;
70     @UnsupportedAppUsage
71     private TextView mMessageView;
72 
73     private int mProgressStyle = STYLE_SPINNER;
74     @UnsupportedAppUsage
75     private TextView mProgressNumber;
76     private String mProgressNumberFormat;
77     private TextView mProgressPercent;
78     private NumberFormat mProgressPercentFormat;
79 
80     private int mMax;
81     private int mProgressVal;
82     private int mSecondaryProgressVal;
83     private int mIncrementBy;
84     private int mIncrementSecondaryBy;
85     private Drawable mProgressDrawable;
86     private Drawable mIndeterminateDrawable;
87     private CharSequence mMessage;
88     private boolean mIndeterminate;
89 
90     private boolean mHasStarted;
91     private Handler mViewUpdateHandler;
92 
93     /**
94      * Creates a Progress dialog.
95      *
96      * @param context the parent context
97      */
ProgressDialog(Context context)98     public ProgressDialog(Context context) {
99         super(context);
100         initFormats();
101     }
102 
103     /**
104      * Creates a Progress dialog.
105      *
106      * @param context the parent context
107      * @param theme the resource ID of the theme against which to inflate
108      *              this dialog, or {@code 0} to use the parent
109      *              {@code context}'s default alert dialog theme
110      */
ProgressDialog(Context context, int theme)111     public ProgressDialog(Context context, int theme) {
112         super(context, theme);
113         initFormats();
114     }
115 
initFormats()116     private void initFormats() {
117         mProgressNumberFormat = "%1d/%2d";
118         mProgressPercentFormat = NumberFormat.getPercentInstance();
119         mProgressPercentFormat.setMaximumFractionDigits(0);
120     }
121 
122     /**
123      * Creates and shows a ProgressDialog.
124      *
125      * @param context the parent context
126      * @param title the title text for the dialog's window
127      * @param message the text to be displayed in the dialog
128      * @return the ProgressDialog
129      */
show(Context context, CharSequence title, CharSequence message)130     public static ProgressDialog show(Context context, CharSequence title,
131             CharSequence message) {
132         return show(context, title, message, false);
133     }
134 
135     /**
136      * Creates and shows a ProgressDialog.
137      *
138      * @param context the parent context
139      * @param title the title text for the dialog's window
140      * @param message the text to be displayed in the dialog
141      * @param indeterminate true if the dialog should be {@link #setIndeterminate(boolean)
142      *        indeterminate}, false otherwise
143      * @return the ProgressDialog
144      */
show(Context context, CharSequence title, CharSequence message, boolean indeterminate)145     public static ProgressDialog show(Context context, CharSequence title,
146             CharSequence message, boolean indeterminate) {
147         return show(context, title, message, indeterminate, false, null);
148     }
149 
150     /**
151      * Creates and shows a ProgressDialog.
152      *
153      * @param context the parent context
154      * @param title the title text for the dialog's window
155      * @param message the text to be displayed in the dialog
156      * @param indeterminate true if the dialog should be {@link #setIndeterminate(boolean)
157      *        indeterminate}, false otherwise
158      * @param cancelable true if the dialog is {@link #setCancelable(boolean) cancelable},
159      *        false otherwise
160      * @return the ProgressDialog
161      */
show(Context context, CharSequence title, CharSequence message, boolean indeterminate, boolean cancelable)162     public static ProgressDialog show(Context context, CharSequence title,
163             CharSequence message, boolean indeterminate, boolean cancelable) {
164         return show(context, title, message, indeterminate, cancelable, null);
165     }
166 
167     /**
168      * Creates and shows a ProgressDialog.
169      *
170      * @param context the parent context
171      * @param title the title text for the dialog's window
172      * @param message the text to be displayed in the dialog
173      * @param indeterminate true if the dialog should be {@link #setIndeterminate(boolean)
174      *        indeterminate}, false otherwise
175      * @param cancelable true if the dialog is {@link #setCancelable(boolean) cancelable},
176      *        false otherwise
177      * @param cancelListener the {@link #setOnCancelListener(OnCancelListener) listener}
178      *        to be invoked when the dialog is canceled
179      * @return the ProgressDialog
180      */
show(Context context, CharSequence title, CharSequence message, boolean indeterminate, boolean cancelable, OnCancelListener cancelListener)181     public static ProgressDialog show(Context context, CharSequence title,
182             CharSequence message, boolean indeterminate,
183             boolean cancelable, OnCancelListener cancelListener) {
184         ProgressDialog dialog = new ProgressDialog(context);
185         dialog.setTitle(title);
186         dialog.setMessage(message);
187         dialog.setIndeterminate(indeterminate);
188         dialog.setCancelable(cancelable);
189         dialog.setOnCancelListener(cancelListener);
190         dialog.show();
191         return dialog;
192     }
193 
194     @Override
onCreate(Bundle savedInstanceState)195     protected void onCreate(Bundle savedInstanceState) {
196         LayoutInflater inflater = LayoutInflater.from(mContext);
197         TypedArray a = mContext.obtainStyledAttributes(null,
198                 com.android.internal.R.styleable.AlertDialog,
199                 com.android.internal.R.attr.alertDialogStyle, 0);
200         if (mProgressStyle == STYLE_HORIZONTAL) {
201 
202             /* Use a separate handler to update the text views as they
203              * must be updated on the same thread that created them.
204              */
205             mViewUpdateHandler = new Handler() {
206                 @Override
207                 public void handleMessage(Message msg) {
208                     super.handleMessage(msg);
209 
210                     /* Update the number and percent */
211                     int progress = mProgress.getProgress();
212                     int max = mProgress.getMax();
213                     if (mProgressNumberFormat != null) {
214                         String format = mProgressNumberFormat;
215                         mProgressNumber.setText(String.format(format, progress, max));
216                     } else {
217                         mProgressNumber.setText("");
218                     }
219                     if (mProgressPercentFormat != null) {
220                         double percent = (double) progress / (double) max;
221                         SpannableString tmp = new SpannableString(mProgressPercentFormat.format(percent));
222                         tmp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD),
223                                 0, tmp.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
224                         mProgressPercent.setText(tmp);
225                     } else {
226                         mProgressPercent.setText("");
227                     }
228                 }
229             };
230             View view = inflater.inflate(a.getResourceId(
231                     com.android.internal.R.styleable.AlertDialog_horizontalProgressLayout,
232                     R.layout.alert_dialog_progress), null);
233             mProgress = (ProgressBar) view.findViewById(R.id.progress);
234             mProgressNumber = (TextView) view.findViewById(R.id.progress_number);
235             mProgressPercent = (TextView) view.findViewById(R.id.progress_percent);
236             setView(view);
237         } else {
238             View view = inflater.inflate(a.getResourceId(
239                     com.android.internal.R.styleable.AlertDialog_progressLayout,
240                     R.layout.progress_dialog), null);
241             mProgress = (ProgressBar) view.findViewById(R.id.progress);
242             mMessageView = (TextView) view.findViewById(R.id.message);
243             setView(view);
244         }
245         a.recycle();
246         if (mMax > 0) {
247             setMax(mMax);
248         }
249         if (mProgressVal > 0) {
250             setProgress(mProgressVal);
251         }
252         if (mSecondaryProgressVal > 0) {
253             setSecondaryProgress(mSecondaryProgressVal);
254         }
255         if (mIncrementBy > 0) {
256             incrementProgressBy(mIncrementBy);
257         }
258         if (mIncrementSecondaryBy > 0) {
259             incrementSecondaryProgressBy(mIncrementSecondaryBy);
260         }
261         if (mProgressDrawable != null) {
262             setProgressDrawable(mProgressDrawable);
263         }
264         if (mIndeterminateDrawable != null) {
265             setIndeterminateDrawable(mIndeterminateDrawable);
266         }
267         if (mMessage != null) {
268             setMessage(mMessage);
269         }
270         setIndeterminate(mIndeterminate);
271         onProgressChanged();
272         super.onCreate(savedInstanceState);
273     }
274 
275     @Override
onStart()276     public void onStart() {
277         super.onStart();
278         mHasStarted = true;
279     }
280 
281     @Override
onStop()282     protected void onStop() {
283         super.onStop();
284         mHasStarted = false;
285     }
286 
287     /**
288      * Sets the current progress.
289      *
290      * @param value the current progress, a value between 0 and {@link #getMax()}
291      *
292      * @see ProgressBar#setProgress(int)
293      */
setProgress(int value)294     public void setProgress(int value) {
295         if (mHasStarted) {
296             mProgress.setProgress(value);
297             onProgressChanged();
298         } else {
299             mProgressVal = value;
300         }
301     }
302 
303     /**
304      * Sets the secondary progress.
305      *
306      * @param secondaryProgress the current secondary progress, a value between 0 and
307      * {@link #getMax()}
308      *
309      * @see ProgressBar#setSecondaryProgress(int)
310      */
setSecondaryProgress(int secondaryProgress)311     public void setSecondaryProgress(int secondaryProgress) {
312         if (mProgress != null) {
313             mProgress.setSecondaryProgress(secondaryProgress);
314             onProgressChanged();
315         } else {
316             mSecondaryProgressVal = secondaryProgress;
317         }
318     }
319 
320     /**
321      * Gets the current progress.
322      *
323      * @return the current progress, a value between 0 and {@link #getMax()}
324      */
getProgress()325     public int getProgress() {
326         if (mProgress != null) {
327             return mProgress.getProgress();
328         }
329         return mProgressVal;
330     }
331 
332     /**
333      * Gets the current secondary progress.
334      *
335      * @return the current secondary progress, a value between 0 and {@link #getMax()}
336      */
getSecondaryProgress()337     public int getSecondaryProgress() {
338         if (mProgress != null) {
339             return mProgress.getSecondaryProgress();
340         }
341         return mSecondaryProgressVal;
342     }
343 
344     /**
345      * Gets the maximum allowed progress value. The default value is 100.
346      *
347      * @return the maximum value
348      */
getMax()349     public int getMax() {
350         if (mProgress != null) {
351             return mProgress.getMax();
352         }
353         return mMax;
354     }
355 
356     /**
357      * Sets the maximum allowed progress value.
358      */
setMax(int max)359     public void setMax(int max) {
360         if (mProgress != null) {
361             mProgress.setMax(max);
362             onProgressChanged();
363         } else {
364             mMax = max;
365         }
366     }
367 
368     /**
369      * Increments the current progress value.
370      *
371      * @param diff the amount by which the current progress will be incremented,
372      * up to {@link #getMax()}
373      */
incrementProgressBy(int diff)374     public void incrementProgressBy(int diff) {
375         if (mProgress != null) {
376             mProgress.incrementProgressBy(diff);
377             onProgressChanged();
378         } else {
379             mIncrementBy += diff;
380         }
381     }
382 
383     /**
384      * Increments the current secondary progress value.
385      *
386      * @param diff the amount by which the current secondary progress will be incremented,
387      * up to {@link #getMax()}
388      */
incrementSecondaryProgressBy(int diff)389     public void incrementSecondaryProgressBy(int diff) {
390         if (mProgress != null) {
391             mProgress.incrementSecondaryProgressBy(diff);
392             onProgressChanged();
393         } else {
394             mIncrementSecondaryBy += diff;
395         }
396     }
397 
398     /**
399      * Sets the drawable to be used to display the progress value.
400      *
401      * @param d the drawable to be used
402      *
403      * @see ProgressBar#setProgressDrawable(Drawable)
404      */
setProgressDrawable(Drawable d)405     public void setProgressDrawable(Drawable d) {
406         if (mProgress != null) {
407             mProgress.setProgressDrawable(d);
408         } else {
409             mProgressDrawable = d;
410         }
411     }
412 
413     /**
414      * Sets the drawable to be used to display the indeterminate progress value.
415      *
416      * @param d the drawable to be used
417      *
418      * @see ProgressBar#setProgressDrawable(Drawable)
419      * @see #setIndeterminate(boolean)
420      */
setIndeterminateDrawable(Drawable d)421     public void setIndeterminateDrawable(Drawable d) {
422         if (mProgress != null) {
423             mProgress.setIndeterminateDrawable(d);
424         } else {
425             mIndeterminateDrawable = d;
426         }
427     }
428 
429     /**
430      * Change the indeterminate mode for this ProgressDialog. In indeterminate
431      * mode, the progress is ignored and the dialog shows an infinite
432      * animation instead.
433      *
434      * <p><strong>Note:</strong> A ProgressDialog with style {@link #STYLE_SPINNER}
435      * is always indeterminate and will ignore this setting.</p>
436      *
437      * @param indeterminate true to enable indeterminate mode, false otherwise
438      *
439      * @see #setProgressStyle(int)
440      */
setIndeterminate(boolean indeterminate)441     public void setIndeterminate(boolean indeterminate) {
442         if (mProgress != null) {
443             mProgress.setIndeterminate(indeterminate);
444         } else {
445             mIndeterminate = indeterminate;
446         }
447     }
448 
449     /**
450      * Whether this ProgressDialog is in indeterminate mode.
451      *
452      * @return true if the dialog is in indeterminate mode, false otherwise
453      */
isIndeterminate()454     public boolean isIndeterminate() {
455         if (mProgress != null) {
456             return mProgress.isIndeterminate();
457         }
458         return mIndeterminate;
459     }
460 
461     @Override
setMessage(CharSequence message)462     public void setMessage(CharSequence message) {
463         if (mProgress != null) {
464             if (mProgressStyle == STYLE_HORIZONTAL) {
465                 super.setMessage(message);
466             } else {
467                 mMessageView.setText(message);
468             }
469         } else {
470             mMessage = message;
471         }
472     }
473 
474     /**
475      * Sets the style of this ProgressDialog, either {@link #STYLE_SPINNER} or
476      * {@link #STYLE_HORIZONTAL}. The default is {@link #STYLE_SPINNER}.
477      *
478      * <p><strong>Note:</strong> A ProgressDialog with style {@link #STYLE_SPINNER}
479      * is always indeterminate and will ignore the {@link #setIndeterminate(boolean)
480      * indeterminate} setting.</p>
481      *
482      * @param style the style of this ProgressDialog, either {@link #STYLE_SPINNER} or
483      * {@link #STYLE_HORIZONTAL}
484      */
setProgressStyle(int style)485     public void setProgressStyle(int style) {
486         mProgressStyle = style;
487     }
488 
489     /**
490      * Change the format of the small text showing current and maximum units
491      * of progress.  The default is "%1d/%2d".
492      * Should not be called during the number is progressing.
493      * @param format A string passed to {@link String#format String.format()};
494      * use "%1d" for the current number and "%2d" for the maximum.  If null,
495      * nothing will be shown.
496      */
setProgressNumberFormat(String format)497     public void setProgressNumberFormat(String format) {
498         mProgressNumberFormat = format;
499         onProgressChanged();
500     }
501 
502     /**
503      * Change the format of the small text showing the percentage of progress.
504      * The default is
505      * {@link NumberFormat#getPercentInstance() NumberFormat.getPercentageInstnace().}
506      * Should not be called during the number is progressing.
507      * @param format An instance of a {@link NumberFormat} to generate the
508      * percentage text.  If null, nothing will be shown.
509      */
setProgressPercentFormat(NumberFormat format)510     public void setProgressPercentFormat(NumberFormat format) {
511         mProgressPercentFormat = format;
512         onProgressChanged();
513     }
514 
onProgressChanged()515     private void onProgressChanged() {
516         if (mProgressStyle == STYLE_HORIZONTAL) {
517             if (mViewUpdateHandler != null && !mViewUpdateHandler.hasMessages(0)) {
518                 mViewUpdateHandler.sendEmptyMessage(0);
519             }
520         }
521     }
522 }
523