1befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini/*
2befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini * Copyright (C) 2013 The Android Open Source Project
3befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini *
4befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini * Licensed under the Apache License, Version 2.0 (the "License");
5befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini * you may not use this file except in compliance with the License.
6befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini * You may obtain a copy of the License at
7befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini *
8befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini *      http://www.apache.org/licenses/LICENSE-2.0
9befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini *
10befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini * Unless required by applicable law or agreed to in writing, software
11befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini * distributed under the License is distributed on an "AS IS" BASIS,
12befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini * See the License for the specific language governing permissions and
14befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini * limitations under the License.
15befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini */
16befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini
17befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpinipackage android.support.v4.widget;
18befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini
19befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpiniimport android.content.Context;
20befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpiniimport android.util.AttributeSet;
21befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpiniimport android.view.View;
22befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpiniimport android.widget.ProgressBar;
23befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini
24befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini/**
25befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini * ContentLoadingProgressBar implements a ProgressBar that waits a minimum time to be
26befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini * dismissed before showing. Once visible, the progress bar will be visible for
27befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini * a minimum amount of time to avoid "flashes" in the UI when an event could take
28befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini * a largely variable time to complete (from none, to a user perceivable amount)
29befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini */
30befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpinipublic class ContentLoadingProgressBar extends ProgressBar {
31befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    private static final int MIN_SHOW_TIME = 500; // ms
32befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    private static final int MIN_DELAY = 500; // ms
33befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini
34befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    private long mStartTime = -1;
35befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini
36befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    private boolean mPostedHide = false;
37befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini
38befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    private boolean mPostedShow = false;
39befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini
40befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    private boolean mDismissed = false;
41befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini
42befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    private final Runnable mDelayedHide = new Runnable() {
43befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini
44befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        @Override
45befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        public void run() {
46befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini            mPostedHide = false;
47befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini            mStartTime = -1;
48befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini            setVisibility(View.GONE);
49befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        }
50befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    };
51befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini
52befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    private final Runnable mDelayedShow = new Runnable() {
53befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini
54befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        @Override
55befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        public void run() {
56befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini            mPostedShow = false;
57befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini            if (!mDismissed) {
58befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini                mStartTime = System.currentTimeMillis();
59befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini                setVisibility(View.VISIBLE);
60befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini            }
61befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        }
62befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    };
63befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini
64befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    public ContentLoadingProgressBar(Context context) {
65befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        this(context, null);
66befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    }
67befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini
68befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    public ContentLoadingProgressBar(Context context, AttributeSet attrs) {
69befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        super(context, attrs, 0);
70befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    }
71befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini
72befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    @Override
73befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    public void onAttachedToWindow() {
74befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        super.onAttachedToWindow();
75befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        removeCallbacks();
76befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    }
77befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini
78befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    @Override
79befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    public void onDetachedFromWindow() {
80befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        super.onDetachedFromWindow();
81befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        removeCallbacks();
82befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    }
83befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini
84befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    private void removeCallbacks() {
85befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        removeCallbacks(mDelayedHide);
86befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        removeCallbacks(mDelayedShow);
87befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    }
88befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini
89befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    /**
90befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini     * Hide the progress view if it is visible. The progress view will not be
91befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini     * hidden until it has been shown for at least a minimum show time. If the
92befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini     * progress view was not yet visible, cancels showing the progress view.
93befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini     */
94befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    public void hide() {
95befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        mDismissed = true;
96befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        removeCallbacks(mDelayedShow);
97befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        long diff = System.currentTimeMillis() - mStartTime;
98befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        if (diff >= MIN_SHOW_TIME || mStartTime == -1) {
99befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini            // The progress spinner has been shown long enough
100befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini            // OR was not shown yet. If it wasn't shown yet,
101befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini            // it will just never be shown.
102befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini            setVisibility(View.GONE);
103befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        } else {
104befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini            // The progress spinner is shown, but not long enough,
105befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini            // so put a delayed message in to hide it when its been
106befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini            // shown long enough.
107befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini            if (!mPostedHide) {
108befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini                postDelayed(mDelayedHide, MIN_SHOW_TIME - diff);
109befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini                mPostedHide = true;
110befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini            }
111befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        }
112befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    }
113befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini
114befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    /**
115befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini     * Show the progress view after waiting for a minimum delay. If
116befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini     * during that time, hide() is called, the view is never made visible.
117befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini     */
118befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    public void show() {
119befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        // Reset the start time.
120befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        mStartTime = -1;
121befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        mDismissed = false;
122befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        removeCallbacks(mDelayedHide);
123befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        if (!mPostedShow) {
124befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini            postDelayed(mDelayedShow, MIN_DELAY);
125befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini            mPostedShow = true;
126befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini        }
127befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini    }
128befff92741b1f0629d9a9389a3889cca56d914a2Mindy DelliCarpini}
129