1 package com.android.mail.utils;
2 
3 import android.os.Handler;
4 import android.view.View;
5 import android.view.ViewTreeObserver;
6 
7 /**
8  * Given a View to monitor draws on, an instance of this class will notify a listener of state
9  * changes between {@link #STATE_ACTIVE} and {@link #STATE_IDLE}.
10  * <p>
11  * Any drawing will instantly trigger {@link #STATE_ACTIVE}. {@link #STATE_IDLE} is only
12  * subsequently triggered if {@link #IDLE_WINDOW_MS} continuous milliseconds elapse with zero draws.
13  */
14 public class DrawIdler {
15 
16     public static final int STATE_IDLE = 0;
17     public static final int STATE_ACTIVE = 1;
18 
19     private static final int IDLE_WINDOW_MS = 100;
20 
21     private int mState = STATE_IDLE;
22 
23     private View mRoot;
24     private IdleListener mListener;
25     private final IdleReader mIdleReader = new IdleReader();
26     private final Handler mHandler = new Handler();
27 
28     public interface IdleListener {
onStateChanged(DrawIdler idler, int newState)29         void onStateChanged(DrawIdler idler, int newState);
30     }
31 
setListener(IdleListener listener)32     public void setListener(IdleListener listener) {
33         mListener = listener;
34         if (mListener != null) {
35             mListener.onStateChanged(this, mState);
36         }
37     }
38 
setRootView(View rootView)39     public void setRootView(View rootView) {
40         if (mRoot == rootView) {
41             return;
42         } else if (mRoot != null) {
43             mRoot.getViewTreeObserver().removeOnPreDrawListener(mIdleReader);
44         }
45 
46         mRoot = rootView;
47 
48         if (mRoot != null) {
49             mRoot.getViewTreeObserver().addOnPreDrawListener(mIdleReader);
50         }
51     }
52 
getCurrentState()53     public int getCurrentState() {
54         return mState;
55     }
56 
setState(int newState)57     private void setState(int newState) {
58         if (mState == newState) {
59             return;
60         }
61         mState = newState;
62         if (mListener != null) {
63             mListener.onStateChanged(this, newState);
64         }
65     }
66 
67     // this inner class keeps implementation details private
68     // (we use OnPreDrawListener instead of OnDrawListener because the latter is only JB+)
69     private class IdleReader implements Runnable, ViewTreeObserver.OnPreDrawListener {
70 
71         @Override
run()72         public void run() {
73             setState(STATE_IDLE);
74         }
75 
76         @Override
onPreDraw()77         public boolean onPreDraw() {
78             setState(STATE_ACTIVE);
79             mHandler.removeCallbacks(this);
80             mHandler.postDelayed(this, IDLE_WINDOW_MS);
81             return true; // always allow the draw; we're only here to observe
82         }
83 
84     }
85 
86 }
87