1 /*
2  * Copyright (C) 2015 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 android.view;
18 
19 import android.os.Handler;
20 
21 import com.android.internal.util.GrowingArrayUtils;
22 
23 /**
24  * Class used to enqueue pending work from Views when no Handler is attached.
25  *
26  * @hide Exposed for test framework only.
27  */
28 public class HandlerActionQueue {
29     private HandlerAction[] mActions;
30     private int mCount;
31 
post(Runnable action)32     public void post(Runnable action) {
33         postDelayed(action, 0);
34     }
35 
postDelayed(Runnable action, long delayMillis)36     public void postDelayed(Runnable action, long delayMillis) {
37         final HandlerAction handlerAction = new HandlerAction(action, delayMillis);
38 
39         synchronized (this) {
40             if (mActions == null) {
41                 mActions = new HandlerAction[4];
42             }
43             mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction);
44             mCount++;
45         }
46     }
47 
removeCallbacks(Runnable action)48     public void removeCallbacks(Runnable action) {
49         synchronized (this) {
50             final int count = mCount;
51             int j = 0;
52 
53             final HandlerAction[] actions = mActions;
54             for (int i = 0; i < count; i++) {
55                 if (actions[i].matches(action)) {
56                     // Remove this action by overwriting it within
57                     // this loop or nulling it out later.
58                     continue;
59                 }
60 
61                 if (j != i) {
62                     // At least one previous entry was removed, so
63                     // this one needs to move to the "new" list.
64                     actions[j] = actions[i];
65                 }
66 
67                 j++;
68             }
69 
70             // The "new" list only has j entries.
71             mCount = j;
72 
73             // Null out any remaining entries.
74             for (; j < count; j++) {
75                 actions[j] = null;
76             }
77         }
78     }
79 
executeActions(Handler handler)80     public void executeActions(Handler handler) {
81         synchronized (this) {
82             final HandlerAction[] actions = mActions;
83             for (int i = 0, count = mCount; i < count; i++) {
84                 final HandlerAction handlerAction = actions[i];
85                 handler.postDelayed(handlerAction.action, handlerAction.delay);
86             }
87 
88             mActions = null;
89             mCount = 0;
90         }
91     }
92 
size()93     public int size() {
94         return mCount;
95     }
96 
getRunnable(int index)97     public Runnable getRunnable(int index) {
98         if (index >= mCount) {
99             throw new IndexOutOfBoundsException();
100         }
101         return mActions[index].action;
102     }
103 
getDelay(int index)104     public long getDelay(int index) {
105         if (index >= mCount) {
106             throw new IndexOutOfBoundsException();
107         }
108         return mActions[index].delay;
109     }
110 
111     private static class HandlerAction {
112         final Runnable action;
113         final long delay;
114 
HandlerAction(Runnable action, long delay)115         public HandlerAction(Runnable action, long delay) {
116             this.action = action;
117             this.delay = delay;
118         }
119 
matches(Runnable otherAction)120         public boolean matches(Runnable otherAction) {
121             return otherAction == null && action == null
122                     || action != null && action.equals(otherAction);
123         }
124     }
125 }
126