• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.layoutlib.bridge.util;
18 
19 import com.android.tools.layoutlib.annotations.NotNull;
20 import com.android.tools.layoutlib.annotations.Nullable;
21 
22 import android.os.Handler;
23 import android.util.Pair;
24 
25 import java.util.LinkedList;
26 import java.util.WeakHashMap;
27 
28 /**
29  * A queue that stores {@link Runnable}s associated with the corresponding {@link Handler}s.
30  * {@link Runnable}s get automatically released when the corresponding {@link Handler} gets
31  * collected by the garbage collector. All {@link Runnable}s are queued in a single virtual queue
32  * with respect to their corresponding uptime (the time when they should be executed).
33  */
34 public class HandlerMessageQueue {
35     private final WeakHashMap<Handler, LinkedList<Pair<Long, Runnable>>> runnablesMap =
36             new WeakHashMap<>();
37 
38     /**
39      * Adds a {@link Runnable} associated with the {@link Handler} to be executed at
40      * particular time
41      * @param h handler associated with the {@link Runnable}
42      * @param uptimeMillis time in milliseconds the {@link Runnable} to be executed
43      * @param r {@link Runnable} to be added
44      */
add(@otNull Handler h, long uptimeMillis, @NotNull Runnable r)45     public void add(@NotNull Handler h, long uptimeMillis, @NotNull Runnable r) {
46         LinkedList<Pair<Long, Runnable>> runnables = runnablesMap.computeIfAbsent(h,
47                 k -> new LinkedList<>());
48 
49         int idx = 0;
50         while (idx < runnables.size()) {
51             if (runnables.get(idx).first <= uptimeMillis) {
52                 idx++;
53             } else {
54                 break;
55             }
56         }
57         runnables.add(idx, Pair.create(uptimeMillis, r));
58     }
59 
60     private static class HandlerWrapper {
61         public Handler handler;
62     }
63 
64     /**
65      * Removes from the queue and returns the {@link Runnable} with the smallest uptime if it
66      * is less than the one passed as a parameter or null if such runnable does not exist.
67      * @param uptimeMillis
68      * @return the {@link Runnable} from the queue
69      */
70     @Nullable
extractFirst(long uptimeMillis)71     public Runnable extractFirst(long uptimeMillis) {
72         final HandlerWrapper w = new HandlerWrapper();
73         runnablesMap.forEach((h, l) -> {
74             if (!l.isEmpty()) {
75                 long currentUptime = l.getFirst().first;
76                 if (currentUptime <= uptimeMillis) {
77                     if (w.handler == null || currentUptime <
78                             runnablesMap.get(w.handler).getFirst().first) {
79                         w.handler = h;
80                     }
81                 }
82             }
83         });
84         if (w.handler != null) {
85             return runnablesMap.get(w.handler).pollFirst().second;
86         }
87         return null;
88     }
89 
90     /**
91      * @return true is queue has no runnables left
92      */
isNotEmpty()93     public boolean isNotEmpty() {
94         return runnablesMap.values().stream().anyMatch(l -> !l.isEmpty());
95     }
96 
97     /**
98      * @return number of runnables in the queue
99      */
size()100     public int size() {
101         return runnablesMap.values().stream().mapToInt(LinkedList::size).sum();
102     }
103 
104     /**
105      * Completely clears the entire queue
106      */
clear()107     public void clear() {
108         runnablesMap.clear();
109     }
110 }
111