Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2011 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 com.android.gallery3d.util;
     18 
     19 import android.app.Activity;
     20 import android.os.Handler;
     21 import android.os.Message;
     22 import android.os.SystemClock;
     23 
     24 import java.util.HashMap;
     25 import java.util.Map;
     26 
     27 /**
     28  * This class manages the visibility of the progress spinner in the action bar for an
     29  * Activity. It filters out short-lived appearances of the progress spinner by only
     30  * showing the spinner if it hasn't been hidden again before the end of a specified
     31  * delay period. It also enforces a minimum display time once the spinner is made visible.
     32  * This meant to cut down on the frequent "flashes" of the progress spinner.
     33  */
     34 public class SpinnerVisibilitySetter {
     35 
     36     private static final int SHOW_SPINNER_REQUESTED = 0;
     37     private static final int HIDE_SPINNER_REQUESTED = 1;
     38     private static final int SHOW_SPINNER_DELAY_REACHED = 2;
     39     private static final int HIDE_SPINNER_DELAY_REACHED = 3;
     40 
     41     // Amount of time after a show request that the progress spinner is actually made visible.
     42     // This means that any show/hide requests that happen subsequently within this period
     43     // of time will be ignored.
     44     private static final long SPINNER_DISPLAY_DELAY = 1000;
     45 
     46     // The minimum amount of time the progress spinner must be visible before it can be hidden.
     47     private static final long MIN_SPINNER_DISPLAY_TIME = 2000;
     48 
     49     private boolean mPendingVisibilityRequest = false;
     50     private boolean mActiveVisibilityRequest = false;
     51     private long mSpinnerVisibilityStartTime;
     52 
     53     Handler mHandler = new Handler() {
     54 
     55         @Override
     56         public void handleMessage(Message msg) {
     57             switch(msg.what) {
     58                 case SHOW_SPINNER_REQUESTED:
     59                     mPendingVisibilityRequest = true;
     60                     sendEmptyMessageDelayed(SHOW_SPINNER_DELAY_REACHED, SPINNER_DISPLAY_DELAY);
     61                     break;
     62                 case HIDE_SPINNER_REQUESTED:
     63                     mPendingVisibilityRequest = false;
     64                     if (!mActiveVisibilityRequest) {
     65                         // We haven't requested to show the spinner so no need to decide
     66                         // when to hide it.
     67                         break;
     68                     }
     69 
     70                     long currTime = SystemClock.uptimeMillis();
     71                     if (currTime - mSpinnerVisibilityStartTime > MIN_SPINNER_DISPLAY_TIME) {
     72                         // The spinner has already been visible longer than the requisite min
     73                         // display time. Send the hide message immediately.
     74                         sendEmptyMessage(HIDE_SPINNER_DELAY_REACHED);
     75                     } else {
     76                         // The spinner is visible but hasn't been visible for long enough yet.
     77                         // Send a delayed hide message.
     78                         sendEmptyMessageAtTime(HIDE_SPINNER_DELAY_REACHED,
     79                                 mSpinnerVisibilityStartTime + MIN_SPINNER_DISPLAY_TIME);
     80                     }
     81                     break;
     82                 case SHOW_SPINNER_DELAY_REACHED:
     83                     if (mPendingVisibilityRequest) {
     84                         mPendingVisibilityRequest = false;
     85                         mActiveVisibilityRequest = true;
     86 
     87                         // Even though the spinner isn't visible quite yet, lets set this
     88                         // here to avoid possible cross-thread synchronization issues.
     89                         mSpinnerVisibilityStartTime = SystemClock.uptimeMillis();
     90                         mActivity.runOnUiThread(new SetProgressVisibilityRunnable(true));
     91                     }
     92                     break;
     93                 case HIDE_SPINNER_DELAY_REACHED:
     94                     mActiveVisibilityRequest = false;
     95                     mActivity.runOnUiThread(new SetProgressVisibilityRunnable(false));
     96                     break;
     97             }
     98         }
     99     };
    100     static final Map<Activity, SpinnerVisibilitySetter> sInstanceMap =
    101             new HashMap<Activity, SpinnerVisibilitySetter>();
    102     private Activity mActivity;
    103 
    104     private SpinnerVisibilitySetter(Activity activity) {
    105         mActivity = activity;
    106     }
    107 
    108     public static SpinnerVisibilitySetter getInstance(Activity activity) {
    109         synchronized(sInstanceMap) {
    110             if (sInstanceMap.get(activity) == null) {
    111                 sInstanceMap.put(activity, new SpinnerVisibilitySetter(activity));
    112             }
    113             return sInstanceMap.get(activity);
    114         }
    115     }
    116 
    117     public void setSpinnerVisibility(boolean visible) {
    118         mHandler.sendEmptyMessage(visible ? SHOW_SPINNER_REQUESTED : HIDE_SPINNER_REQUESTED);
    119     }
    120 
    121     private class SetProgressVisibilityRunnable implements Runnable {
    122         boolean mVisible;
    123 
    124         public SetProgressVisibilityRunnable(boolean visible) {
    125             mVisible = visible;
    126         }
    127 
    128         @Override
    129         public void run() {
    130             mActivity.setProgressBarIndeterminateVisibility(mVisible);
    131         }
    132     }
    133 }
    134