1303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung/* 2303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * Copyright (C) 2014 The Android Open Source Project 3303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * 4303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * Licensed under the Apache License, Version 2.0 (the "License"); 5303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * you may not use this file except in compliance with the License. 6303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * You may obtain a copy of the License at 7303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * 8303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * http://www.apache.org/licenses/LICENSE-2.0 9303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * 10303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * Unless required by applicable law or agreed to in writing, software 11303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * distributed under the License is distributed on an "AS IS" BASIS, 12303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * See the License for the specific language governing permissions and 14303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * limitations under the License. 15303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung */ 16303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 17f1fbd77cf057e43926f9a0347692611386d09f40Winson Chungpackage com.android.systemui.recents.model; 18303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 19303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport android.app.ActivityManager; 204d7b092a866d2fce3e11b5a12cda2b87a83af52dWinson Chungimport android.content.ComponentCallbacks2; 21e7f138c7f0a190c86cec10fb32fa106aacae4093Winsonimport android.content.ComponentName; 22303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport android.content.Context; 23303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport android.content.pm.ActivityInfo; 2437c8d8ef855aacb074ee0b702a46dbc62b7551a2Winson Chungimport android.content.res.Resources; 25303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport android.graphics.Bitmap; 26303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport android.graphics.drawable.BitmapDrawable; 27303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport android.graphics.drawable.Drawable; 28303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport android.os.Handler; 29303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport android.os.HandlerThread; 30a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guyimport android.util.Log; 31e7f138c7f0a190c86cec10fb32fa106aacae4093Winsonimport android.util.LruCache; 32c0d7058b14c24cd07912f5629c26b39b7b4673d5Winson 3381e0c8491f22c64300182c652ac2add96888dd2eJorim Jaggiimport com.android.systemui.R; 34e7f138c7f0a190c86cec10fb32fa106aacae4093Winsonimport com.android.systemui.recents.Recents; 358eaeb7dc93ed71b768a2ea8d45021cca010e8263Winson Chungimport com.android.systemui.recents.RecentsConfiguration; 36c742f973b1e506732911c156c5869fd377afc5bfWinsonimport com.android.systemui.recents.RecentsDebugFlags; 37e7f138c7f0a190c86cec10fb32fa106aacae4093Winsonimport com.android.systemui.recents.events.activity.PackagesChangedEvent; 38ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport com.android.systemui.recents.misc.SystemServicesProxy; 3929a763b83c3a5cb65b2eb682e8404efc47e4dc19Winsonimport com.android.systemui.recents.misc.Utilities; 40303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 4129a763b83c3a5cb65b2eb682e8404efc47e4dc19Winsonimport java.io.PrintWriter; 42e7f138c7f0a190c86cec10fb32fa106aacae4093Winsonimport java.util.Map; 43303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport java.util.concurrent.ConcurrentLinkedQueue; 44303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 45303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 46e7f138c7f0a190c86cec10fb32fa106aacae4093Winson/** 47e7f138c7f0a190c86cec10fb32fa106aacae4093Winson * A Task load queue 48e7f138c7f0a190c86cec10fb32fa106aacae4093Winson */ 49303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungclass TaskResourceLoadQueue { 50303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung ConcurrentLinkedQueue<Task> mQueue = new ConcurrentLinkedQueue<Task>(); 51303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 524c71aefcbd7f7bef5dab1d05d5f7001aaea1b067Winson Chung /** Adds a new task to the load queue */ 5393748a11cba1b44edbc2e888c997533461355594Winson Chung void addTask(Task t) { 54303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung if (!mQueue.contains(t)) { 55303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung mQueue.add(t); 56303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 57303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung synchronized(this) { 58303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung notifyAll(); 59303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 60303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 61303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 624c71aefcbd7f7bef5dab1d05d5f7001aaea1b067Winson Chung /** 634c71aefcbd7f7bef5dab1d05d5f7001aaea1b067Winson Chung * Retrieves the next task from the load queue, as well as whether we want that task to be 644c71aefcbd7f7bef5dab1d05d5f7001aaea1b067Winson Chung * force reloaded. 654c71aefcbd7f7bef5dab1d05d5f7001aaea1b067Winson Chung */ 6693748a11cba1b44edbc2e888c997533461355594Winson Chung Task nextTask() { 6793748a11cba1b44edbc2e888c997533461355594Winson Chung return mQueue.poll(); 684c71aefcbd7f7bef5dab1d05d5f7001aaea1b067Winson Chung } 694c71aefcbd7f7bef5dab1d05d5f7001aaea1b067Winson Chung 704c71aefcbd7f7bef5dab1d05d5f7001aaea1b067Winson Chung /** Removes a task from the load queue */ 71303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung void removeTask(Task t) { 72303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung mQueue.remove(t); 73303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 74303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 754c71aefcbd7f7bef5dab1d05d5f7001aaea1b067Winson Chung /** Clears all the tasks from the load queue */ 76303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung void clearTasks() { 77303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung mQueue.clear(); 78303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 79303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 804c71aefcbd7f7bef5dab1d05d5f7001aaea1b067Winson Chung /** Returns whether the load queue is empty */ 81303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung boolean isEmpty() { 82303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung return mQueue.isEmpty(); 83303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 84303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung} 85303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 86e7f138c7f0a190c86cec10fb32fa106aacae4093Winson/** 87e7f138c7f0a190c86cec10fb32fa106aacae4093Winson * Task resource loader 88e7f138c7f0a190c86cec10fb32fa106aacae4093Winson */ 89e7f138c7f0a190c86cec10fb32fa106aacae4093Winsonclass BackgroundTaskLoader implements Runnable { 9096d704186621f6310e0e7d39db57caff67baa96cWinson Chung static String TAG = "TaskResourceLoader"; 9196d704186621f6310e0e7d39db57caff67baa96cWinson Chung static boolean DEBUG = false; 9296d704186621f6310e0e7d39db57caff67baa96cWinson Chung 93303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung Context mContext; 94303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung HandlerThread mLoadThread; 95303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung Handler mLoadThreadHandler; 96303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung Handler mMainThreadHandler; 97303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 98303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung TaskResourceLoadQueue mLoadQueue; 99296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung TaskKeyLruCache<Drawable> mIconCache; 100217009356efa2b854ab3981dff8d315a0d679c73Winson TaskKeyLruCache<ThumbnailData> mThumbnailCache; 101c9567c07dd4953f5c5e3821d30525e50ed8b9b29Winson Chung Bitmap mDefaultThumbnail; 102296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung BitmapDrawable mDefaultIcon; 10304dfe0d26b944324ee920001f40d74cff47281d6Winson Chung 104303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung boolean mCancelled; 10504dfe0d26b944324ee920001f40d74cff47281d6Winson Chung boolean mWaitingOnLoadQueue; 106303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 107303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung /** Constructor, creates a new loading thread that loads task resources in the background */ 108e7f138c7f0a190c86cec10fb32fa106aacae4093Winson public BackgroundTaskLoader(TaskResourceLoadQueue loadQueue, 109217009356efa2b854ab3981dff8d315a0d679c73Winson TaskKeyLruCache<Drawable> iconCache, TaskKeyLruCache<ThumbnailData> thumbnailCache, 110296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung Bitmap defaultThumbnail, BitmapDrawable defaultIcon) { 111303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung mLoadQueue = loadQueue; 112296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung mIconCache = iconCache; 113303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung mThumbnailCache = thumbnailCache; 114c9567c07dd4953f5c5e3821d30525e50ed8b9b29Winson Chung mDefaultThumbnail = defaultThumbnail; 115296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung mDefaultIcon = defaultIcon; 116303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung mMainThreadHandler = new Handler(); 11781e0c8491f22c64300182c652ac2add96888dd2eJorim Jaggi mLoadThread = new HandlerThread("Recents-TaskResourceLoader", 11850949eaff714a8ad1417b9fd4192e258f552dcc3Jorim Jaggi android.os.Process.THREAD_PRIORITY_BACKGROUND); 119303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung mLoadThread.start(); 120303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung mLoadThreadHandler = new Handler(mLoadThread.getLooper()); 121303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung mLoadThreadHandler.post(this); 122303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 123303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 124303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung /** Restarts the loader thread */ 125303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung void start(Context context) { 126303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung mContext = context; 127303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung mCancelled = false; 128303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung // Notify the load thread to start loading 129303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung synchronized(mLoadThread) { 130303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung mLoadThread.notifyAll(); 131303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 132303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 133303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 134303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung /** Requests the loader thread to stop after the current iteration */ 135303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung void stop() { 136303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung // Mark as cancelled for the thread to pick up 137303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung mCancelled = true; 13804dfe0d26b944324ee920001f40d74cff47281d6Winson Chung // If we are waiting for the load queue for more tasks, then we can just reset the 13904dfe0d26b944324ee920001f40d74cff47281d6Winson Chung // Context now, since nothing is using it 14004dfe0d26b944324ee920001f40d74cff47281d6Winson Chung if (mWaitingOnLoadQueue) { 14104dfe0d26b944324ee920001f40d74cff47281d6Winson Chung mContext = null; 14204dfe0d26b944324ee920001f40d74cff47281d6Winson Chung } 143303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 144303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 145303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung @Override 146303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung public void run() { 147303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung while (true) { 14810f8139d3b8dd7cd08a2fc688285b3b74a34f0dbWinson Chung if (mCancelled) { 149303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung // We have to unset the context here, since the background thread may be using it 150303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung // when we call stop() 151303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung mContext = null; 152303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung // If we are cancelled, then wait until we are started again 153303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung synchronized(mLoadThread) { 154303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung try { 155303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung mLoadThread.wait(); 156303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } catch (InterruptedException ie) { 157303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung ie.printStackTrace(); 158303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 159303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 160303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } else { 16153ec42cb17693b2d631746e1e5d31021a3359163Winson RecentsConfiguration config = Recents.getConfiguration(); 162e7f138c7f0a190c86cec10fb32fa106aacae4093Winson SystemServicesProxy ssp = Recents.getSystemServices(); 16366e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung // If we've stopped the loader, then fall through to the above logic to wait on 164f14fdda21293d1f4bb4f35932833a9f05be554e2winsonchung // the load thread 16566e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung if (ssp != null) { 16666e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung // Load the next item from the queue 16766e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung final Task t = mLoadQueue.nextTask(); 16866e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung if (t != null) { 169296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung Drawable cachedIcon = mIconCache.get(t.key); 170217009356efa2b854ab3981dff8d315a0d679c73Winson ThumbnailData cachedThumbnailData = mThumbnailCache.get(t.key); 17166e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung 172296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung // Load the icon if it is stale or we haven't cached one yet 173bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi if (cachedIcon == null) { 174296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung cachedIcon = ssp.getBadgedTaskDescriptionIcon(t.taskDescription, 175296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung t.key.userId, mContext.getResources()); 17666e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung 17766e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung if (cachedIcon == null) { 17866e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung ActivityInfo info = ssp.getActivityInfo( 179e7f138c7f0a190c86cec10fb32fa106aacae4093Winson t.key.getComponent(), t.key.userId); 18066e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung if (info != null) { 18166e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung if (DEBUG) Log.d(TAG, "Loading icon: " + t.key); 182296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung cachedIcon = ssp.getBadgedActivityIcon(info, t.key.userId); 18366e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung } 184bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi } 185bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi 18666e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung if (cachedIcon == null) { 187296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung cachedIcon = mDefaultIcon; 18866e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung } 189bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi 19066e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung // At this point, even if we can't load the icon, we will set the 19166e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung // default icon. 192296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung mIconCache.put(t.key, cachedIcon); 19396d704186621f6310e0e7d39db57caff67baa96cWinson Chung } 19466e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung // Load the thumbnail if it is stale or we haven't cached one yet 195217009356efa2b854ab3981dff8d315a0d679c73Winson if (cachedThumbnailData == null) { 19666e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung if (config.svelteLevel < RecentsConfiguration.SVELTE_DISABLE_LOADING) { 19766e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung if (DEBUG) Log.d(TAG, "Loading thumbnail: " + t.key); 198217009356efa2b854ab3981dff8d315a0d679c73Winson cachedThumbnailData = ssp.getTaskThumbnail(t.key.id); 19966e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung } 200217009356efa2b854ab3981dff8d315a0d679c73Winson 201217009356efa2b854ab3981dff8d315a0d679c73Winson if (cachedThumbnailData.thumbnail == null) { 202217009356efa2b854ab3981dff8d315a0d679c73Winson cachedThumbnailData.thumbnail = mDefaultThumbnail; 20366e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung } 204217009356efa2b854ab3981dff8d315a0d679c73Winson 20566e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung // When svelte, we trim the memory to just the visible thumbnails when 20666e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung // leaving, so don't thrash the cache as the user scrolls (just load 20766e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung // them from scratch each time) 20866e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung if (config.svelteLevel < RecentsConfiguration.SVELTE_LIMIT_CACHE) { 209217009356efa2b854ab3981dff8d315a0d679c73Winson mThumbnailCache.put(t.key, cachedThumbnailData); 21066e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung } 211303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 21266e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung if (!mCancelled) { 21366e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung // Notify that the task data has changed 21466e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung final Drawable newIcon = cachedIcon; 215217009356efa2b854ab3981dff8d315a0d679c73Winson final ThumbnailData newThumbnailData = cachedThumbnailData; 21666e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung mMainThreadHandler.post(new Runnable() { 21766e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung @Override 21866e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung public void run() { 219217009356efa2b854ab3981dff8d315a0d679c73Winson t.notifyTaskDataLoaded(newThumbnailData.thumbnail, newIcon, 220217009356efa2b854ab3981dff8d315a0d679c73Winson newThumbnailData.thumbnailInfo); 22166e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung } 22266e86f97747cae9d2ae306a35d9a324c5b3cef68Winson Chung }); 22396d704186621f6310e0e7d39db57caff67baa96cWinson Chung } 224a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung } 225303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 226303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 227303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung // If there are no other items in the list, then just wait until something is added 228303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung if (!mCancelled && mLoadQueue.isEmpty()) { 229303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung synchronized(mLoadQueue) { 230303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung try { 23104dfe0d26b944324ee920001f40d74cff47281d6Winson Chung mWaitingOnLoadQueue = true; 232303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung mLoadQueue.wait(); 23304dfe0d26b944324ee920001f40d74cff47281d6Winson Chung mWaitingOnLoadQueue = false; 234303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } catch (InterruptedException ie) { 235303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung ie.printStackTrace(); 236303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 237303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 238303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 239303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 240303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 241303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 242303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung} 243303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 244e7f138c7f0a190c86cec10fb32fa106aacae4093Winson/** 245e7f138c7f0a190c86cec10fb32fa106aacae4093Winson * Recents task loader 246e7f138c7f0a190c86cec10fb32fa106aacae4093Winson */ 247303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungpublic class RecentsTaskLoader { 2484d7b092a866d2fce3e11b5a12cda2b87a83af52dWinson Chung 249e7f138c7f0a190c86cec10fb32fa106aacae4093Winson private static final String TAG = "RecentsTaskLoader"; 250e7f138c7f0a190c86cec10fb32fa106aacae4093Winson private static final boolean DEBUG = false; 251e7f138c7f0a190c86cec10fb32fa106aacae4093Winson 252e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // This activity info LruCache is useful because it can be expensive to retrieve ActivityInfos 253e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // for many tasks, which we use to get the activity labels and icons. Unlike the other caches 254e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // below, this is per-package so we can't invalidate the items in the cache based on the last 255e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // active time. Instead, we rely on the RecentsPackageMonitor to keep us informed whenever a 256e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // package in the cache has been updated, so that we may remove it. 257e7f138c7f0a190c86cec10fb32fa106aacae4093Winson private final LruCache<ComponentName, ActivityInfo> mActivityInfoCache; 258296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung private final TaskKeyLruCache<Drawable> mIconCache; 259217009356efa2b854ab3981dff8d315a0d679c73Winson private final TaskKeyLruCache<ThumbnailData> mThumbnailCache; 260e7f138c7f0a190c86cec10fb32fa106aacae4093Winson private final TaskKeyLruCache<String> mActivityLabelCache; 261e7f138c7f0a190c86cec10fb32fa106aacae4093Winson private final TaskKeyLruCache<String> mContentDescriptionCache; 262e7f138c7f0a190c86cec10fb32fa106aacae4093Winson private final TaskResourceLoadQueue mLoadQueue; 263e7f138c7f0a190c86cec10fb32fa106aacae4093Winson private final BackgroundTaskLoader mLoader; 264e7f138c7f0a190c86cec10fb32fa106aacae4093Winson 265e7f138c7f0a190c86cec10fb32fa106aacae4093Winson private final int mMaxThumbnailCacheSize; 266e7f138c7f0a190c86cec10fb32fa106aacae4093Winson private final int mMaxIconCacheSize; 267e7f138c7f0a190c86cec10fb32fa106aacae4093Winson private int mNumVisibleTasksLoaded; 268e7f138c7f0a190c86cec10fb32fa106aacae4093Winson private int mNumVisibleThumbnailsLoaded; 269e7f138c7f0a190c86cec10fb32fa106aacae4093Winson 270e7f138c7f0a190c86cec10fb32fa106aacae4093Winson int mDefaultTaskBarBackgroundColor; 2711af8eda6ea1c89d44123b2bfd5fa0293bb9d68cbWinson Chung int mDefaultTaskViewBackgroundColor; 272296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung BitmapDrawable mDefaultIcon; 273303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung Bitmap mDefaultThumbnail; 274303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 275a1b96b5d58e3d0e938b8fc3a6d3e8bf8b115f568Winson private TaskKeyLruCache.EvictionCallback mClearActivityInfoOnEviction = 276a1b96b5d58e3d0e938b8fc3a6d3e8bf8b115f568Winson new TaskKeyLruCache.EvictionCallback() { 277a1b96b5d58e3d0e938b8fc3a6d3e8bf8b115f568Winson @Override 278a1b96b5d58e3d0e938b8fc3a6d3e8bf8b115f568Winson public void onEntryEvicted(Task.TaskKey key) { 279a1ededd056d51532ab18354f17f8065ec1134535Winson if (key != null) { 280a1ededd056d51532ab18354f17f8065ec1134535Winson mActivityInfoCache.remove(key.getComponent()); 281a1ededd056d51532ab18354f17f8065ec1134535Winson } 282a1b96b5d58e3d0e938b8fc3a6d3e8bf8b115f568Winson } 283a1b96b5d58e3d0e938b8fc3a6d3e8bf8b115f568Winson }; 284a1b96b5d58e3d0e938b8fc3a6d3e8bf8b115f568Winson 285e7f138c7f0a190c86cec10fb32fa106aacae4093Winson public RecentsTaskLoader(Context context) { 286e7f138c7f0a190c86cec10fb32fa106aacae4093Winson Resources res = context.getResources(); 287e7f138c7f0a190c86cec10fb32fa106aacae4093Winson mDefaultTaskBarBackgroundColor = 2881af8eda6ea1c89d44123b2bfd5fa0293bb9d68cbWinson Chung context.getColor(R.color.recents_task_bar_default_background_color); 2891af8eda6ea1c89d44123b2bfd5fa0293bb9d68cbWinson Chung mDefaultTaskViewBackgroundColor = 2901af8eda6ea1c89d44123b2bfd5fa0293bb9d68cbWinson Chung context.getColor(R.color.recents_task_view_default_background_color); 291e7f138c7f0a190c86cec10fb32fa106aacae4093Winson mMaxThumbnailCacheSize = res.getInteger(R.integer.config_recents_max_thumbnail_count); 292e7f138c7f0a190c86cec10fb32fa106aacae4093Winson mMaxIconCacheSize = res.getInteger(R.integer.config_recents_max_icon_count); 293c742f973b1e506732911c156c5869fd377afc5bfWinson int iconCacheSize = RecentsDebugFlags.Static.DisableBackgroundCache ? 1 : 2944d7b092a866d2fce3e11b5a12cda2b87a83af52dWinson Chung mMaxIconCacheSize; 295c742f973b1e506732911c156c5869fd377afc5bfWinson int thumbnailCacheSize = RecentsDebugFlags.Static.DisableBackgroundCache ? 1 : 2964d7b092a866d2fce3e11b5a12cda2b87a83af52dWinson Chung mMaxThumbnailCacheSize; 2974d7b092a866d2fce3e11b5a12cda2b87a83af52dWinson Chung 2987aceb9a07fd3883c8f301ba93726d55494b0446eWinson Chung // Create the default assets 299e7f138c7f0a190c86cec10fb32fa106aacae4093Winson Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8); 300e7f138c7f0a190c86cec10fb32fa106aacae4093Winson icon.eraseColor(0); 3017aceb9a07fd3883c8f301ba93726d55494b0446eWinson Chung mDefaultThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); 3027aceb9a07fd3883c8f301ba93726d55494b0446eWinson Chung mDefaultThumbnail.setHasAlpha(false); 3037aceb9a07fd3883c8f301ba93726d55494b0446eWinson Chung mDefaultThumbnail.eraseColor(0xFFffffff); 304296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung mDefaultIcon = new BitmapDrawable(context.getResources(), icon); 3057aceb9a07fd3883c8f301ba93726d55494b0446eWinson Chung 306a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung // Initialize the proxy, cache and loaders 307e7f138c7f0a190c86cec10fb32fa106aacae4093Winson int numRecentTasks = ActivityManager.getMaxRecentTasksStatic(); 308303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung mLoadQueue = new TaskResourceLoadQueue(); 309a1b96b5d58e3d0e938b8fc3a6d3e8bf8b115f568Winson mIconCache = new TaskKeyLruCache<>(iconCacheSize, mClearActivityInfoOnEviction); 310e7f138c7f0a190c86cec10fb32fa106aacae4093Winson mThumbnailCache = new TaskKeyLruCache<>(thumbnailCacheSize); 311a1b96b5d58e3d0e938b8fc3a6d3e8bf8b115f568Winson mActivityLabelCache = new TaskKeyLruCache<>(numRecentTasks, mClearActivityInfoOnEviction); 312a1b96b5d58e3d0e938b8fc3a6d3e8bf8b115f568Winson mContentDescriptionCache = new TaskKeyLruCache<>(numRecentTasks, 313a1b96b5d58e3d0e938b8fc3a6d3e8bf8b115f568Winson mClearActivityInfoOnEviction); 314e7f138c7f0a190c86cec10fb32fa106aacae4093Winson mActivityInfoCache = new LruCache(numRecentTasks); 315296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung mLoader = new BackgroundTaskLoader(mLoadQueue, mIconCache, mThumbnailCache, 316296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung mDefaultThumbnail, mDefaultIcon); 317303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 318303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 319a91c293be26b2deb5434eb827a800fa0c80dc92cWinson Chung /** Returns the size of the app icon cache. */ 320296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung public int getIconCacheSize() { 321a91c293be26b2deb5434eb827a800fa0c80dc92cWinson Chung return mMaxIconCacheSize; 322ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung } 323ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung 32490d5136ebd59c9aff9543ea5750d4c5d57ac99dcWinson Chung /** Returns the size of the thumbnail cache. */ 32590d5136ebd59c9aff9543ea5750d4c5d57ac99dcWinson Chung public int getThumbnailCacheSize() { 32690d5136ebd59c9aff9543ea5750d4c5d57ac99dcWinson Chung return mMaxThumbnailCacheSize; 32790d5136ebd59c9aff9543ea5750d4c5d57ac99dcWinson Chung } 32890d5136ebd59c9aff9543ea5750d4c5d57ac99dcWinson Chung 32990d5136ebd59c9aff9543ea5750d4c5d57ac99dcWinson Chung /** Creates a new plan for loading the recent tasks. */ 330a91c293be26b2deb5434eb827a800fa0c80dc92cWinson Chung public RecentsTaskLoadPlan createLoadPlan(Context context) { 33153ec42cb17693b2d631746e1e5d31021a3359163Winson RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(context); 332a91c293be26b2deb5434eb827a800fa0c80dc92cWinson Chung return plan; 333a91c293be26b2deb5434eb827a800fa0c80dc92cWinson Chung } 334a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung 33590d5136ebd59c9aff9543ea5750d4c5d57ac99dcWinson Chung /** Preloads recents tasks using the specified plan to store the output. */ 336d46b72788e8811d2e423ea1e5b2ff104ecb7f721Winson public void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId, 337dfd7be012b889f92d3e7e6d80ff7fe6b55c75901Winson boolean includeFrontMostExcludedTask) { 338dfd7be012b889f92d3e7e6d80ff7fe6b55c75901Winson plan.preloadPlan(this, runningTaskId, includeFrontMostExcludedTask); 339a91c293be26b2deb5434eb827a800fa0c80dc92cWinson Chung } 3405e3e5d8945249cfeb8bd59de112be88954ba62bfWinson Chung 34190d5136ebd59c9aff9543ea5750d4c5d57ac99dcWinson Chung /** Begins loading the heavy task data according to the specified options. */ 342a91c293be26b2deb5434eb827a800fa0c80dc92cWinson Chung public void loadTasks(Context context, RecentsTaskLoadPlan plan, 343a91c293be26b2deb5434eb827a800fa0c80dc92cWinson Chung RecentsTaskLoadPlan.Options opts) { 344a91c293be26b2deb5434eb827a800fa0c80dc92cWinson Chung if (opts == null) { 345a91c293be26b2deb5434eb827a800fa0c80dc92cWinson Chung throw new RuntimeException("Requires load options"); 346a91c293be26b2deb5434eb827a800fa0c80dc92cWinson Chung } 34796d704186621f6310e0e7d39db57caff67baa96cWinson Chung plan.executePlan(opts, this, mLoadQueue); 34890d5136ebd59c9aff9543ea5750d4c5d57ac99dcWinson Chung if (!opts.onlyLoadForCache) { 349a91c293be26b2deb5434eb827a800fa0c80dc92cWinson Chung mNumVisibleTasksLoaded = opts.numVisibleTasks; 35096d704186621f6310e0e7d39db57caff67baa96cWinson Chung mNumVisibleThumbnailsLoaded = opts.numVisibleTaskThumbnails; 351a91c293be26b2deb5434eb827a800fa0c80dc92cWinson Chung 35290d5136ebd59c9aff9543ea5750d4c5d57ac99dcWinson Chung // Start the loader 35390d5136ebd59c9aff9543ea5750d4c5d57ac99dcWinson Chung mLoader.start(context); 35490d5136ebd59c9aff9543ea5750d4c5d57ac99dcWinson Chung } 355ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung } 356ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung 3576d5b8b8e4473cc5d3ad2ace3376207c53d48ada3Winson /** 3586d5b8b8e4473cc5d3ad2ace3376207c53d48ada3Winson * Acquires the task resource data directly from the cache, loading if necessary. 3596d5b8b8e4473cc5d3ad2ace3376207c53d48ada3Winson */ 360d2a030613154e2007d9816e090c39e9726e7adbaWinson public void loadTaskData(Task t) { 361296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung Drawable icon = mIconCache.getAndInvalidateIfModified(t.key); 362217009356efa2b854ab3981dff8d315a0d679c73Winson Bitmap thumbnail = null; 363217009356efa2b854ab3981dff8d315a0d679c73Winson ActivityManager.TaskThumbnailInfo thumbnailInfo = null; 364d2a030613154e2007d9816e090c39e9726e7adbaWinson ThumbnailData thumbnailData = mThumbnailCache.getAndInvalidateIfModified(t.key); 365d2a030613154e2007d9816e090c39e9726e7adbaWinson if (thumbnailData != null) { 366d2a030613154e2007d9816e090c39e9726e7adbaWinson thumbnail = thumbnailData.thumbnail; 367d2a030613154e2007d9816e090c39e9726e7adbaWinson thumbnailInfo = thumbnailData.thumbnailInfo; 3686d5b8b8e4473cc5d3ad2ace3376207c53d48ada3Winson } 369ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung 370ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung // Grab the thumbnail/icon from the cache, if either don't exist, then trigger a reload and 371ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung // use the default assets in their place until they load 372296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung boolean requiresLoad = (icon == null) || (thumbnail == null); 373296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung icon = icon != null ? icon : mDefaultIcon; 37404dfe0d26b944324ee920001f40d74cff47281d6Winson Chung if (requiresLoad) { 37593748a11cba1b44edbc2e888c997533461355594Winson Chung mLoadQueue.addTask(t); 37604dfe0d26b944324ee920001f40d74cff47281d6Winson Chung } 377217009356efa2b854ab3981dff8d315a0d679c73Winson t.notifyTaskDataLoaded(thumbnail == mDefaultThumbnail ? null : thumbnail, icon, 378217009356efa2b854ab3981dff8d315a0d679c73Winson thumbnailInfo); 379303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 380303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 3814d7b092a866d2fce3e11b5a12cda2b87a83af52dWinson Chung /** Releases the task resource data back into the pool. */ 382303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung public void unloadTaskData(Task t) { 38304dfe0d26b944324ee920001f40d74cff47281d6Winson Chung mLoadQueue.removeTask(t); 384296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung t.notifyTaskDataUnloaded(null, mDefaultIcon); 385303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 386303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 3874d7b092a866d2fce3e11b5a12cda2b87a83af52dWinson Chung /** Completely removes the resource data from the pool. */ 3885393dff555641f5666573952498e27c90fd3edcaWinson Chung public void deleteTaskData(Task t, boolean notifyTaskDataUnloaded) { 38904dfe0d26b944324ee920001f40d74cff47281d6Winson Chung mLoadQueue.removeTask(t); 39004dfe0d26b944324ee920001f40d74cff47281d6Winson Chung mThumbnailCache.remove(t.key); 391296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung mIconCache.remove(t.key); 3926d5b8b8e4473cc5d3ad2ace3376207c53d48ada3Winson mActivityLabelCache.remove(t.key); 3936d5b8b8e4473cc5d3ad2ace3376207c53d48ada3Winson mContentDescriptionCache.remove(t.key); 3945393dff555641f5666573952498e27c90fd3edcaWinson Chung if (notifyTaskDataUnloaded) { 395296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung t.notifyTaskDataUnloaded(null, mDefaultIcon); 3965393dff555641f5666573952498e27c90fd3edcaWinson Chung } 397303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung } 398303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung 3999f49df933f01a32d04bdf92d53c943065aa8ddf7Winson Chung /** 4009f49df933f01a32d04bdf92d53c943065aa8ddf7Winson Chung * Handles signals from the system, trimming memory when requested to prevent us from running 4019f49df933f01a32d04bdf92d53c943065aa8ddf7Winson Chung * out of memory. 4029f49df933f01a32d04bdf92d53c943065aa8ddf7Winson Chung */ 403f1fbd77cf057e43926f9a0347692611386d09f40Winson Chung public void onTrimMemory(int level) { 40453ec42cb17693b2d631746e1e5d31021a3359163Winson RecentsConfiguration config = Recents.getConfiguration(); 40504dfe0d26b944324ee920001f40d74cff47281d6Winson Chung switch (level) { 40604dfe0d26b944324ee920001f40d74cff47281d6Winson Chung case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN: 40747c4c69575e94635a9356e8a1faf4b56a0120452Winson Chung // Stop the loader immediately when the UI is no longer visible 40847c4c69575e94635a9356e8a1faf4b56a0120452Winson Chung stopLoader(); 40996d704186621f6310e0e7d39db57caff67baa96cWinson Chung if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) { 41096d704186621f6310e0e7d39db57caff67baa96cWinson Chung mThumbnailCache.trimToSize(Math.max(mNumVisibleTasksLoaded, 41196d704186621f6310e0e7d39db57caff67baa96cWinson Chung mMaxThumbnailCacheSize / 2)); 41296d704186621f6310e0e7d39db57caff67baa96cWinson Chung } else if (config.svelteLevel == RecentsConfiguration.SVELTE_LIMIT_CACHE) { 41396d704186621f6310e0e7d39db57caff67baa96cWinson Chung mThumbnailCache.trimToSize(mNumVisibleThumbnailsLoaded); 41496d704186621f6310e0e7d39db57caff67baa96cWinson Chung } else if (config.svelteLevel >= RecentsConfiguration.SVELTE_DISABLE_CACHE) { 41596d704186621f6310e0e7d39db57caff67baa96cWinson Chung mThumbnailCache.evictAll(); 41696d704186621f6310e0e7d39db57caff67baa96cWinson Chung } 417296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung mIconCache.trimToSize(Math.max(mNumVisibleTasksLoaded, 41881e0c8491f22c64300182c652ac2add96888dd2eJorim Jaggi mMaxIconCacheSize / 2)); 41904dfe0d26b944324ee920001f40d74cff47281d6Winson Chung break; 42004dfe0d26b944324ee920001f40d74cff47281d6Winson Chung case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE: 42104dfe0d26b944324ee920001f40d74cff47281d6Winson Chung case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND: 42204dfe0d26b944324ee920001f40d74cff47281d6Winson Chung // We are leaving recents, so trim the data a bit 423a91c293be26b2deb5434eb827a800fa0c80dc92cWinson Chung mThumbnailCache.trimToSize(Math.max(1, mMaxThumbnailCacheSize / 2)); 424296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung mIconCache.trimToSize(Math.max(1, mMaxIconCacheSize / 2)); 425e7f138c7f0a190c86cec10fb32fa106aacae4093Winson mActivityInfoCache.trimToSize(Math.max(1, 426e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ActivityManager.getMaxRecentTasksStatic() / 2)); 42704dfe0d26b944324ee920001f40d74cff47281d6Winson Chung break; 42804dfe0d26b944324ee920001f40d74cff47281d6Winson Chung case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW: 42904dfe0d26b944324ee920001f40d74cff47281d6Winson Chung case ComponentCallbacks2.TRIM_MEMORY_MODERATE: 43004dfe0d26b944324ee920001f40d74cff47281d6Winson Chung // We are going to be low on memory 431a91c293be26b2deb5434eb827a800fa0c80dc92cWinson Chung mThumbnailCache.trimToSize(Math.max(1, mMaxThumbnailCacheSize / 4)); 432296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung mIconCache.trimToSize(Math.max(1, mMaxIconCacheSize / 4)); 433e7f138c7f0a190c86cec10fb32fa106aacae4093Winson mActivityInfoCache.trimToSize(Math.max(1, 434e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ActivityManager.getMaxRecentTasksStatic() / 4)); 43504dfe0d26b944324ee920001f40d74cff47281d6Winson Chung break; 43604dfe0d26b944324ee920001f40d74cff47281d6Winson Chung case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL: 43704dfe0d26b944324ee920001f40d74cff47281d6Winson Chung case ComponentCallbacks2.TRIM_MEMORY_COMPLETE: 43804dfe0d26b944324ee920001f40d74cff47281d6Winson Chung // We are low on memory, so release everything 43904dfe0d26b944324ee920001f40d74cff47281d6Winson Chung mThumbnailCache.evictAll(); 440296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung mIconCache.evictAll(); 441e7f138c7f0a190c86cec10fb32fa106aacae4093Winson mActivityInfoCache.evictAll(); 442a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung // The cache is small, only clear the label cache when we are critical 443a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung mActivityLabelCache.evictAll(); 444b7a42fda313b6e5d5e82591ea9fb5d1b30acfc55Benjamin Franz mContentDescriptionCache.evictAll(); 44504dfe0d26b944324ee920001f40d74cff47281d6Winson Chung break; 44604dfe0d26b944324ee920001f40d74cff47281d6Winson Chung default: 44704dfe0d26b944324ee920001f40d74cff47281d6Winson Chung break; 4484d7b092a866d2fce3e11b5a12cda2b87a83af52dWinson Chung } 4494d7b092a866d2fce3e11b5a12cda2b87a83af52dWinson Chung } 450e7f138c7f0a190c86cec10fb32fa106aacae4093Winson 451e7f138c7f0a190c86cec10fb32fa106aacae4093Winson /** 452e7f138c7f0a190c86cec10fb32fa106aacae4093Winson * Returns the cached task label if the task key is not expired, updating the cache if it is. 453e7f138c7f0a190c86cec10fb32fa106aacae4093Winson */ 454296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung String getAndUpdateActivityTitle(Task.TaskKey taskKey, ActivityManager.TaskDescription td) { 455296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung SystemServicesProxy ssp = Recents.getSystemServices(); 456296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung 457e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // Return the task description label if it exists 458e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (td != null && td.getLabel() != null) { 459e7f138c7f0a190c86cec10fb32fa106aacae4093Winson return td.getLabel(); 460e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 461e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // Return the cached activity label if it exists 462e7f138c7f0a190c86cec10fb32fa106aacae4093Winson String label = mActivityLabelCache.getAndInvalidateIfModified(taskKey); 463e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (label != null) { 464e7f138c7f0a190c86cec10fb32fa106aacae4093Winson return label; 465e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 466e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // All short paths failed, load the label from the activity info and cache it 467296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey); 468e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (activityInfo != null) { 469c5ef63f4e95329158d88a6cbb05789b57098222dWinson label = ssp.getBadgedActivityLabel(activityInfo, taskKey.userId); 470e7f138c7f0a190c86cec10fb32fa106aacae4093Winson mActivityLabelCache.put(taskKey, label); 471e7f138c7f0a190c86cec10fb32fa106aacae4093Winson return label; 472e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 473e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // If the activity info does not exist or fails to load, return an empty label for now, 474e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // but do not cache it 475e7f138c7f0a190c86cec10fb32fa106aacae4093Winson return ""; 476e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 477e7f138c7f0a190c86cec10fb32fa106aacae4093Winson 478e7f138c7f0a190c86cec10fb32fa106aacae4093Winson /** 479e7f138c7f0a190c86cec10fb32fa106aacae4093Winson * Returns the cached task content description if the task key is not expired, updating the 480e7f138c7f0a190c86cec10fb32fa106aacae4093Winson * cache if it is. 481e7f138c7f0a190c86cec10fb32fa106aacae4093Winson */ 482c5ef63f4e95329158d88a6cbb05789b57098222dWinson String getAndUpdateContentDescription(Task.TaskKey taskKey, Resources res) { 483296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung SystemServicesProxy ssp = Recents.getSystemServices(); 484296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung 485e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // Return the cached content description if it exists 486e7f138c7f0a190c86cec10fb32fa106aacae4093Winson String label = mContentDescriptionCache.getAndInvalidateIfModified(taskKey); 487e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (label != null) { 488e7f138c7f0a190c86cec10fb32fa106aacae4093Winson return label; 489e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 490e7f138c7f0a190c86cec10fb32fa106aacae4093Winson 491c5ef63f4e95329158d88a6cbb05789b57098222dWinson // All short paths failed, load the label from the activity info and cache it 492c5ef63f4e95329158d88a6cbb05789b57098222dWinson ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey); 493c5ef63f4e95329158d88a6cbb05789b57098222dWinson if (activityInfo != null) { 494c5ef63f4e95329158d88a6cbb05789b57098222dWinson label = ssp.getBadgedContentDescription(activityInfo, taskKey.userId, res); 495e7f138c7f0a190c86cec10fb32fa106aacae4093Winson mContentDescriptionCache.put(taskKey, label); 496e7f138c7f0a190c86cec10fb32fa106aacae4093Winson return label; 497e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 498e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // If the content description does not exist, return an empty label for now, but do not 499e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // cache it 500e7f138c7f0a190c86cec10fb32fa106aacae4093Winson return ""; 501e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 502e7f138c7f0a190c86cec10fb32fa106aacae4093Winson 503e7f138c7f0a190c86cec10fb32fa106aacae4093Winson /** 504e7f138c7f0a190c86cec10fb32fa106aacae4093Winson * Returns the cached task icon if the task key is not expired, updating the cache if it is. 505e7f138c7f0a190c86cec10fb32fa106aacae4093Winson */ 506e7f138c7f0a190c86cec10fb32fa106aacae4093Winson Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey, ActivityManager.TaskDescription td, 507296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung Resources res, boolean loadIfNotCached) { 508296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung SystemServicesProxy ssp = Recents.getSystemServices(); 509296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung 510e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // Return the cached activity icon if it exists 511296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung Drawable icon = mIconCache.getAndInvalidateIfModified(taskKey); 512e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (icon != null) { 513e7f138c7f0a190c86cec10fb32fa106aacae4093Winson return icon; 514e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 515e7f138c7f0a190c86cec10fb32fa106aacae4093Winson 516e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (loadIfNotCached) { 517e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // Return and cache the task description icon if it exists 518296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung icon = ssp.getBadgedTaskDescriptionIcon(td, taskKey.userId, res); 519e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (icon != null) { 520296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung mIconCache.put(taskKey, icon); 521e7f138c7f0a190c86cec10fb32fa106aacae4093Winson return icon; 522e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 523e7f138c7f0a190c86cec10fb32fa106aacae4093Winson 524e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // Load the icon from the activity info and cache it 525296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey); 526e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (activityInfo != null) { 527296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung icon = ssp.getBadgedActivityIcon(activityInfo, taskKey.userId); 528e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (icon != null) { 529296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung mIconCache.put(taskKey, icon); 530e7f138c7f0a190c86cec10fb32fa106aacae4093Winson return icon; 531e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 532e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 533e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 534e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // We couldn't load any icon 535e7f138c7f0a190c86cec10fb32fa106aacae4093Winson return null; 536e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 537e7f138c7f0a190c86cec10fb32fa106aacae4093Winson 538e7f138c7f0a190c86cec10fb32fa106aacae4093Winson /** 539e7f138c7f0a190c86cec10fb32fa106aacae4093Winson * Returns the cached thumbnail if the task key is not expired, updating the cache if it is. 540e7f138c7f0a190c86cec10fb32fa106aacae4093Winson */ 541296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung Bitmap getAndUpdateThumbnail(Task.TaskKey taskKey, boolean loadIfNotCached) { 542296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung SystemServicesProxy ssp = Recents.getSystemServices(); 543296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung 544e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // Return the cached thumbnail if it exists 545217009356efa2b854ab3981dff8d315a0d679c73Winson ThumbnailData thumbnailData = mThumbnailCache.getAndInvalidateIfModified(taskKey); 546217009356efa2b854ab3981dff8d315a0d679c73Winson if (thumbnailData != null) { 547217009356efa2b854ab3981dff8d315a0d679c73Winson return thumbnailData.thumbnail; 548e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 549e7f138c7f0a190c86cec10fb32fa106aacae4093Winson 550e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (loadIfNotCached) { 55153ec42cb17693b2d631746e1e5d31021a3359163Winson RecentsConfiguration config = Recents.getConfiguration(); 552e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (config.svelteLevel < RecentsConfiguration.SVELTE_DISABLE_LOADING) { 553e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // Load the thumbnail from the system 554217009356efa2b854ab3981dff8d315a0d679c73Winson thumbnailData = ssp.getTaskThumbnail(taskKey.id); 555217009356efa2b854ab3981dff8d315a0d679c73Winson if (thumbnailData.thumbnail != null) { 556217009356efa2b854ab3981dff8d315a0d679c73Winson mThumbnailCache.put(taskKey, thumbnailData); 557217009356efa2b854ab3981dff8d315a0d679c73Winson return thumbnailData.thumbnail; 558e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 559e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 560e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 561e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // We couldn't load any thumbnail 562e7f138c7f0a190c86cec10fb32fa106aacae4093Winson return null; 563e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 564e7f138c7f0a190c86cec10fb32fa106aacae4093Winson 565e7f138c7f0a190c86cec10fb32fa106aacae4093Winson /** 566296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung * Returns the task's primary color if possible, defaulting to the default color if there is 567296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung * no specified primary color. 568e7f138c7f0a190c86cec10fb32fa106aacae4093Winson */ 569e7f138c7f0a190c86cec10fb32fa106aacae4093Winson int getActivityPrimaryColor(ActivityManager.TaskDescription td) { 570e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (td != null && td.getPrimaryColor() != 0) { 571e7f138c7f0a190c86cec10fb32fa106aacae4093Winson return td.getPrimaryColor(); 572e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 573e7f138c7f0a190c86cec10fb32fa106aacae4093Winson return mDefaultTaskBarBackgroundColor; 574e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 575e7f138c7f0a190c86cec10fb32fa106aacae4093Winson 576e7f138c7f0a190c86cec10fb32fa106aacae4093Winson /** 5771af8eda6ea1c89d44123b2bfd5fa0293bb9d68cbWinson Chung * Returns the task's background color if possible. 5781af8eda6ea1c89d44123b2bfd5fa0293bb9d68cbWinson Chung */ 5791af8eda6ea1c89d44123b2bfd5fa0293bb9d68cbWinson Chung int getActivityBackgroundColor(ActivityManager.TaskDescription td) { 5801af8eda6ea1c89d44123b2bfd5fa0293bb9d68cbWinson Chung if (td != null && td.getBackgroundColor() != 0) { 5811af8eda6ea1c89d44123b2bfd5fa0293bb9d68cbWinson Chung return td.getBackgroundColor(); 5821af8eda6ea1c89d44123b2bfd5fa0293bb9d68cbWinson Chung } 5831af8eda6ea1c89d44123b2bfd5fa0293bb9d68cbWinson Chung return mDefaultTaskViewBackgroundColor; 5841af8eda6ea1c89d44123b2bfd5fa0293bb9d68cbWinson Chung } 5851af8eda6ea1c89d44123b2bfd5fa0293bb9d68cbWinson Chung 5861af8eda6ea1c89d44123b2bfd5fa0293bb9d68cbWinson Chung /** 587e7f138c7f0a190c86cec10fb32fa106aacae4093Winson * Returns the activity info for the given task key, retrieving one from the system if the 588e7f138c7f0a190c86cec10fb32fa106aacae4093Winson * task key is expired. 589e7f138c7f0a190c86cec10fb32fa106aacae4093Winson */ 5908be1634a543022bd6ee0c1e974d3201d452981e8Winson ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) { 591296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung SystemServicesProxy ssp = Recents.getSystemServices(); 592e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ComponentName cn = taskKey.getComponent(); 593e7f138c7f0a190c86cec10fb32fa106aacae4093Winson ActivityInfo activityInfo = mActivityInfoCache.get(cn); 594e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (activityInfo == null) { 595e7f138c7f0a190c86cec10fb32fa106aacae4093Winson activityInfo = ssp.getActivityInfo(cn, taskKey.userId); 596eb1b65a976d143810acab199aecd17b987661973Winson if (cn == null || activityInfo == null) { 597eb1b65a976d143810acab199aecd17b987661973Winson Log.e(TAG, "Unexpected null component name or activity info: " + cn + ", " + 598eb1b65a976d143810acab199aecd17b987661973Winson activityInfo); 599eb1b65a976d143810acab199aecd17b987661973Winson return null; 600eb1b65a976d143810acab199aecd17b987661973Winson } 601e7f138c7f0a190c86cec10fb32fa106aacae4093Winson mActivityInfoCache.put(cn, activityInfo); 602e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 603e7f138c7f0a190c86cec10fb32fa106aacae4093Winson return activityInfo; 604e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 605e7f138c7f0a190c86cec10fb32fa106aacae4093Winson 606e7f138c7f0a190c86cec10fb32fa106aacae4093Winson /** 607e7f138c7f0a190c86cec10fb32fa106aacae4093Winson * Stops the task loader and clears all queued, pending task loads. 608e7f138c7f0a190c86cec10fb32fa106aacae4093Winson */ 609e7f138c7f0a190c86cec10fb32fa106aacae4093Winson private void stopLoader() { 610e7f138c7f0a190c86cec10fb32fa106aacae4093Winson mLoader.stop(); 611e7f138c7f0a190c86cec10fb32fa106aacae4093Winson mLoadQueue.clearTasks(); 612e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 613e7f138c7f0a190c86cec10fb32fa106aacae4093Winson 614e7f138c7f0a190c86cec10fb32fa106aacae4093Winson /**** Event Bus Events ****/ 615e7f138c7f0a190c86cec10fb32fa106aacae4093Winson 616e7f138c7f0a190c86cec10fb32fa106aacae4093Winson public final void onBusEvent(PackagesChangedEvent event) { 617e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // Remove all the cached activity infos for this package. The other caches do not need to 618e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // be pruned at this time, as the TaskKey expiration checks will flush them next time their 619e7f138c7f0a190c86cec10fb32fa106aacae4093Winson // cached contents are requested 620e7f138c7f0a190c86cec10fb32fa106aacae4093Winson Map<ComponentName, ActivityInfo> activityInfoCache = mActivityInfoCache.snapshot(); 621e7f138c7f0a190c86cec10fb32fa106aacae4093Winson for (ComponentName cn : activityInfoCache.keySet()) { 622e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (cn.getPackageName().equals(event.packageName)) { 623e7f138c7f0a190c86cec10fb32fa106aacae4093Winson if (DEBUG) { 624e7f138c7f0a190c86cec10fb32fa106aacae4093Winson Log.d(TAG, "Removing activity info from cache: " + cn); 625e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 626e7f138c7f0a190c86cec10fb32fa106aacae4093Winson mActivityInfoCache.remove(cn); 627e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 628e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 629e7f138c7f0a190c86cec10fb32fa106aacae4093Winson } 63029a763b83c3a5cb65b2eb682e8404efc47e4dc19Winson 63129a763b83c3a5cb65b2eb682e8404efc47e4dc19Winson public void dump(String prefix, PrintWriter writer) { 63229a763b83c3a5cb65b2eb682e8404efc47e4dc19Winson String innerPrefix = prefix + " "; 63329a763b83c3a5cb65b2eb682e8404efc47e4dc19Winson 63429a763b83c3a5cb65b2eb682e8404efc47e4dc19Winson writer.print(prefix); writer.println(TAG); 63529a763b83c3a5cb65b2eb682e8404efc47e4dc19Winson writer.print(prefix); writer.println("Icon Cache"); 63629a763b83c3a5cb65b2eb682e8404efc47e4dc19Winson mIconCache.dump(innerPrefix, writer); 63729a763b83c3a5cb65b2eb682e8404efc47e4dc19Winson writer.print(prefix); writer.println("Thumbnail Cache"); 63829a763b83c3a5cb65b2eb682e8404efc47e4dc19Winson mThumbnailCache.dump(innerPrefix, writer); 63929a763b83c3a5cb65b2eb682e8404efc47e4dc19Winson } 640303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung} 641