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 17package com.android.systemui.recents.model; 18 19import android.util.Log; 20import android.util.LruCache; 21import android.util.SparseArray; 22 23import java.io.PrintWriter; 24import 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 */ 34public class TaskKeyLruCache<V> { 35 36 public interface EvictionCallback { 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 46 public TaskKeyLruCache(int cacheSize) { 47 this(cacheSize, null); 48 } 49 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 */ 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 */ 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. */ 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. */ 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. */ 110 final void evictAll() { 111 mCache.evictAll(); 112 mKeys.clear(); 113 } 114 115 /** Trims the cache to a specific size */ 116 final void trimToSize(int cacheSize) { 117 mCache.trimToSize(cacheSize); 118 } 119 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