1/*
2 * Copyright (C) 2013 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.support.v4.widget;
18
19import android.content.Context;
20import android.util.AttributeSet;
21import android.view.View;
22import android.widget.ProgressBar;
23
24/**
25 * ContentLoadingProgressBar implements a ProgressBar that waits a minimum time to be
26 * dismissed before showing. Once visible, the progress bar will be visible for
27 * a minimum amount of time to avoid "flashes" in the UI when an event could take
28 * a largely variable time to complete (from none, to a user perceivable amount)
29 */
30public class ContentLoadingProgressBar extends ProgressBar {
31    private static final int MIN_SHOW_TIME = 500; // ms
32    private static final int MIN_DELAY = 500; // ms
33
34    private long mStartTime = -1;
35
36    private boolean mPostedHide = false;
37
38    private boolean mPostedShow = false;
39
40    private boolean mDismissed = false;
41
42    private final Runnable mDelayedHide = new Runnable() {
43
44        @Override
45        public void run() {
46            mPostedHide = false;
47            mStartTime = -1;
48            setVisibility(View.GONE);
49        }
50    };
51
52    private final Runnable mDelayedShow = new Runnable() {
53
54        @Override
55        public void run() {
56            mPostedShow = false;
57            if (!mDismissed) {
58                mStartTime = System.currentTimeMillis();
59                setVisibility(View.VISIBLE);
60            }
61        }
62    };
63
64    public ContentLoadingProgressBar(Context context) {
65        this(context, null);
66    }
67
68    public ContentLoadingProgressBar(Context context, AttributeSet attrs) {
69        super(context, attrs, 0);
70    }
71
72    @Override
73    public void onAttachedToWindow() {
74        super.onAttachedToWindow();
75        removeCallbacks();
76    }
77
78    @Override
79    public void onDetachedFromWindow() {
80        super.onDetachedFromWindow();
81        removeCallbacks();
82    }
83
84    private void removeCallbacks() {
85        removeCallbacks(mDelayedHide);
86        removeCallbacks(mDelayedShow);
87    }
88
89    /**
90     * Hide the progress view if it is visible. The progress view will not be
91     * hidden until it has been shown for at least a minimum show time. If the
92     * progress view was not yet visible, cancels showing the progress view.
93     */
94    public void hide() {
95        mDismissed = true;
96        removeCallbacks(mDelayedShow);
97        long diff = System.currentTimeMillis() - mStartTime;
98        if (diff >= MIN_SHOW_TIME || mStartTime == -1) {
99            // The progress spinner has been shown long enough
100            // OR was not shown yet. If it wasn't shown yet,
101            // it will just never be shown.
102            setVisibility(View.GONE);
103        } else {
104            // The progress spinner is shown, but not long enough,
105            // so put a delayed message in to hide it when its been
106            // shown long enough.
107            if (!mPostedHide) {
108                postDelayed(mDelayedHide, MIN_SHOW_TIME - diff);
109                mPostedHide = true;
110            }
111        }
112    }
113
114    /**
115     * Show the progress view after waiting for a minimum delay. If
116     * during that time, hide() is called, the view is never made visible.
117     */
118    public void show() {
119        // Reset the start time.
120        mStartTime = -1;
121        mDismissed = false;
122        removeCallbacks(mDelayedHide);
123        if (!mPostedShow) {
124            postDelayed(mDelayedShow, MIN_DELAY);
125            mPostedShow = true;
126        }
127    }
128}
129