[go: nahoru, domu]

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