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
17package android.app;
18
19import android.content.Context;
20import android.graphics.drawable.Drawable;
21import android.os.Bundle;
22import android.os.Handler;
23import android.os.Message;
24import android.text.Spannable;
25import android.text.SpannableString;
26import android.text.style.StyleSpan;
27import android.view.LayoutInflater;
28import android.view.View;
29import android.widget.ProgressBar;
30import android.widget.TextView;
31
32import com.android.internal.R;
33
34import java.text.NumberFormat;
35
36/**
37 * <p>A dialog showing a progress indicator and an optional text message or view.
38 * Only a text message or a view can be used at the same time.</p>
39 * <p>The dialog can be made cancelable on back key press.</p>
40 * <p>The progress range is 0..10000.</p>
41 */
42public class ProgressDialog extends AlertDialog {
43
44    /** Creates a ProgressDialog with a ciruclar, spinning progress
45     * bar. This is the default.
46     */
47    public static final int STYLE_SPINNER = 0;
48
49    /** Creates a ProgressDialog with a horizontal progress bar.
50     */
51    public static final int STYLE_HORIZONTAL = 1;
52
53    private ProgressBar mProgress;
54    private TextView mMessageView;
55
56    private int mProgressStyle = STYLE_SPINNER;
57    private TextView mProgressNumber;
58    private String mProgressNumberFormat;
59    private TextView mProgressPercent;
60    private NumberFormat mProgressPercentFormat;
61
62    private int mMax;
63    private int mProgressVal;
64    private int mSecondaryProgressVal;
65    private int mIncrementBy;
66    private int mIncrementSecondaryBy;
67    private Drawable mProgressDrawable;
68    private Drawable mIndeterminateDrawable;
69    private CharSequence mMessage;
70    private boolean mIndeterminate;
71
72    private boolean mHasStarted;
73    private Handler mViewUpdateHandler;
74
75    public ProgressDialog(Context context) {
76        this(context, com.android.internal.R.style.Theme_Dialog_Alert);
77    }
78
79    public ProgressDialog(Context context, int theme) {
80        super(context, theme);
81    }
82
83    public static ProgressDialog show(Context context, CharSequence title,
84            CharSequence message) {
85        return show(context, title, message, false);
86    }
87
88    public static ProgressDialog show(Context context, CharSequence title,
89            CharSequence message, boolean indeterminate) {
90        return show(context, title, message, indeterminate, false, null);
91    }
92
93    public static ProgressDialog show(Context context, CharSequence title,
94            CharSequence message, boolean indeterminate, boolean cancelable) {
95        return show(context, title, message, indeterminate, cancelable, null);
96    }
97
98    public static ProgressDialog show(Context context, CharSequence title,
99            CharSequence message, boolean indeterminate,
100            boolean cancelable, OnCancelListener cancelListener) {
101        ProgressDialog dialog = new ProgressDialog(context);
102        dialog.setTitle(title);
103        dialog.setMessage(message);
104        dialog.setIndeterminate(indeterminate);
105        dialog.setCancelable(cancelable);
106        dialog.setOnCancelListener(cancelListener);
107        dialog.show();
108        return dialog;
109    }
110
111    @Override
112    protected void onCreate(Bundle savedInstanceState) {
113        LayoutInflater inflater = LayoutInflater.from(mContext);
114        if (mProgressStyle == STYLE_HORIZONTAL) {
115
116            /* Use a separate handler to update the text views as they
117             * must be updated on the same thread that created them.
118             */
119            mViewUpdateHandler = new Handler() {
120                @Override
121                public void handleMessage(Message msg) {
122                    super.handleMessage(msg);
123
124                    /* Update the number and percent */
125                    int progress = mProgress.getProgress();
126                    int max = mProgress.getMax();
127                    double percent = (double) progress / (double) max;
128                    String format = mProgressNumberFormat;
129                    mProgressNumber.setText(String.format(format, progress, max));
130                    SpannableString tmp = new SpannableString(mProgressPercentFormat.format(percent));
131                    tmp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD),
132                            0, tmp.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
133                    mProgressPercent.setText(tmp);
134                }
135            };
136            View view = inflater.inflate(R.layout.alert_dialog_progress, null);
137            mProgress = (ProgressBar) view.findViewById(R.id.progress);
138            mProgressNumber = (TextView) view.findViewById(R.id.progress_number);
139            mProgressNumberFormat = "%d/%d";
140            mProgressPercent = (TextView) view.findViewById(R.id.progress_percent);
141            mProgressPercentFormat = NumberFormat.getPercentInstance();
142            mProgressPercentFormat.setMaximumFractionDigits(0);
143            setView(view);
144        } else {
145            View view = inflater.inflate(R.layout.progress_dialog, null);
146            mProgress = (ProgressBar) view.findViewById(R.id.progress);
147            mMessageView = (TextView) view.findViewById(R.id.message);
148            setView(view);
149        }
150        if (mMax > 0) {
151            setMax(mMax);
152        }
153        if (mProgressVal > 0) {
154            setProgress(mProgressVal);
155        }
156        if (mSecondaryProgressVal > 0) {
157            setSecondaryProgress(mSecondaryProgressVal);
158        }
159        if (mIncrementBy > 0) {
160            incrementProgressBy(mIncrementBy);
161        }
162        if (mIncrementSecondaryBy > 0) {
163            incrementSecondaryProgressBy(mIncrementSecondaryBy);
164        }
165        if (mProgressDrawable != null) {
166            setProgressDrawable(mProgressDrawable);
167        }
168        if (mIndeterminateDrawable != null) {
169            setIndeterminateDrawable(mIndeterminateDrawable);
170        }
171        if (mMessage != null) {
172            setMessage(mMessage);
173        }
174        setIndeterminate(mIndeterminate);
175        onProgressChanged();
176        super.onCreate(savedInstanceState);
177    }
178
179    @Override
180    public void onStart() {
181        super.onStart();
182        mHasStarted = true;
183    }
184
185    @Override
186    protected void onStop() {
187        super.onStop();
188        mHasStarted = false;
189    }
190
191    public void setProgress(int value) {
192        if (mHasStarted) {
193            mProgress.setProgress(value);
194            onProgressChanged();
195        } else {
196            mProgressVal = value;
197        }
198    }
199
200    public void setSecondaryProgress(int secondaryProgress) {
201        if (mProgress != null) {
202            mProgress.setSecondaryProgress(secondaryProgress);
203            onProgressChanged();
204        } else {
205            mSecondaryProgressVal = secondaryProgress;
206        }
207    }
208
209    public int getProgress() {
210        if (mProgress != null) {
211            return mProgress.getProgress();
212        }
213        return mProgressVal;
214    }
215
216    public int getSecondaryProgress() {
217        if (mProgress != null) {
218            return mProgress.getSecondaryProgress();
219        }
220        return mSecondaryProgressVal;
221    }
222
223    public int getMax() {
224        if (mProgress != null) {
225            return mProgress.getMax();
226        }
227        return mMax;
228    }
229
230    public void setMax(int max) {
231        if (mProgress != null) {
232            mProgress.setMax(max);
233            onProgressChanged();
234        } else {
235            mMax = max;
236        }
237    }
238
239    public void incrementProgressBy(int diff) {
240        if (mProgress != null) {
241            mProgress.incrementProgressBy(diff);
242            onProgressChanged();
243        } else {
244            mIncrementBy += diff;
245        }
246    }
247
248    public void incrementSecondaryProgressBy(int diff) {
249        if (mProgress != null) {
250            mProgress.incrementSecondaryProgressBy(diff);
251            onProgressChanged();
252        } else {
253            mIncrementSecondaryBy += diff;
254        }
255    }
256
257    public void setProgressDrawable(Drawable d) {
258        if (mProgress != null) {
259            mProgress.setProgressDrawable(d);
260        } else {
261            mProgressDrawable = d;
262        }
263    }
264
265    public void setIndeterminateDrawable(Drawable d) {
266        if (mProgress != null) {
267            mProgress.setIndeterminateDrawable(d);
268        } else {
269            mIndeterminateDrawable = d;
270        }
271    }
272
273    public void setIndeterminate(boolean indeterminate) {
274        if (mProgress != null) {
275            mProgress.setIndeterminate(indeterminate);
276        } else {
277            mIndeterminate = indeterminate;
278        }
279    }
280
281    public boolean isIndeterminate() {
282        if (mProgress != null) {
283            return mProgress.isIndeterminate();
284        }
285        return mIndeterminate;
286    }
287
288    @Override
289    public void setMessage(CharSequence message) {
290        if (mProgress != null) {
291            if (mProgressStyle == STYLE_HORIZONTAL) {
292                super.setMessage(message);
293            } else {
294                mMessageView.setText(message);
295            }
296        } else {
297            mMessage = message;
298        }
299    }
300
301    public void setProgressStyle(int style) {
302        mProgressStyle = style;
303    }
304
305    /**
306     * Change the format of Progress Number. The default is "current/max".
307     * Should not be called during the number is progressing.
308     * @param format Should contain two "%d". The first is used for current number
309     * and the second is used for the maximum.
310     * @hide
311     */
312    public void setProgressNumberFormat(String format) {
313        mProgressNumberFormat = format;
314    }
315
316    private void onProgressChanged() {
317        if (mProgressStyle == STYLE_HORIZONTAL) {
318            mViewUpdateHandler.sendEmptyMessage(0);
319        }
320    }
321}
322