• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.systemui.recents.model;
18 
19 import android.util.Log;
20 import android.util.LruCache;
21 import android.util.SparseArray;
22 
23 import java.io.PrintWriter;
24 import java.util.ArrayList;
25 
26 /**
27  * A mapping of {@link Task.TaskKey} to value, with additional LRU functionality where the least
28  * recently referenced key/values will be evicted as more values than the given cache size are
29  * inserted.
30  *
31  * In addition, this also allows the caller to invalidate cached values for keys that have since
32  * changed.
33  */
34 public class TaskKeyLruCache<V> {
35 
36     public interface EvictionCallback {
onEntryEvicted(Task.TaskKey key)37         public void onEntryEvicted(Task.TaskKey key);
38     }
39 
40     private static final String TAG = "TaskKeyLruCache";
41 
42     private final SparseArray<Task.TaskKey> mKeys = new SparseArray<>();
43     private final LruCache<Integer, V> mCache;
44     private final EvictionCallback mEvictionCallback;
45 
TaskKeyLruCache(int cacheSize)46     public TaskKeyLruCache(int cacheSize) {
47         this(cacheSize, null);
48     }
49 
TaskKeyLruCache(int cacheSize, EvictionCallback evictionCallback)50     public TaskKeyLruCache(int cacheSize, EvictionCallback evictionCallback) {
51         mEvictionCallback = evictionCallback;
52         mCache = new LruCache<Integer, V>(cacheSize) {
53 
54             @Override
55             protected void entryRemoved(boolean evicted, Integer taskId, V oldV, V newV) {
56                 if (mEvictionCallback != null) {
57                     mEvictionCallback.onEntryEvicted(mKeys.get(taskId));
58                 }
59                 mKeys.remove(taskId);
60             }
61         };
62     }
63 
64     /**
65      * Gets a specific entry in the cache with the specified key, regardless of whether the cached
66      * value is valid or not.
67      */
get(Task.TaskKey key)68     final V get(Task.TaskKey key) {
69         return mCache.get(key.id);
70     }
71 
72     /**
73      * Returns the value only if the key is valid (has not been updated since the last time it was
74      * in the cache)
75      */
getAndInvalidateIfModified(Task.TaskKey key)76     final V getAndInvalidateIfModified(Task.TaskKey key) {
77         Task.TaskKey lastKey = mKeys.get(key.id);
78         if (lastKey != null) {
79             if ((lastKey.stackId != key.stackId) ||
80                     (lastKey.lastActiveTime != key.lastActiveTime)) {
81                 // The task has updated (been made active since the last time it was put into the
82                 // LRU cache) or the stack id for the task has changed, invalidate that cache item
83                 remove(key);
84                 return null;
85             }
86         }
87         // Either the task does not exist in the cache, or the last active time is the same as
88         // the key specified, so return what is in the cache
89         return mCache.get(key.id);
90     }
91 
92     /** Puts an entry in the cache for a specific key. */
put(Task.TaskKey key, V value)93     final void put(Task.TaskKey key, V value) {
94         if (key == null || value == null) {
95             Log.e(TAG, "Unexpected null key or value: " + key + ", " + value);
96             return;
97         }
98         mKeys.put(key.id, key);
99         mCache.put(key.id, value);
100     }
101 
102     /** Removes a cache entry for a specific key. */
remove(Task.TaskKey key)103     final void remove(Task.TaskKey key) {
104         // Remove the key after the cache value because we need it to make the callback
105         mCache.remove(key.id);
106         mKeys.remove(key.id);
107     }
108 
109     /** Removes all the entries in the cache. */
evictAll()110     final void evictAll() {
111         mCache.evictAll();
112         mKeys.clear();
113     }
114 
115     /** Trims the cache to a specific size */
trimToSize(int cacheSize)116     final void trimToSize(int cacheSize) {
117         mCache.trimToSize(cacheSize);
118     }
119 
dump(String prefix, PrintWriter writer)120     public void dump(String prefix, PrintWriter writer) {
121         String innerPrefix = prefix + "  ";
122 
123         writer.print(prefix); writer.print(TAG);
124         writer.print(" numEntries="); writer.print(mKeys.size());
125         writer.println();
126         int keyCount = mKeys.size();
127         for (int i = 0; i < keyCount; i++) {
128             writer.print(innerPrefix); writer.println(mKeys.get(mKeys.keyAt(i)));
129         }
130     }
131 }
132