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