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;
21303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport android.content.Context;
22303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport android.content.pm.ActivityInfo;
2337c8d8ef855aacb074ee0b702a46dbc62b7551a2Winson Chungimport android.content.res.Resources;
24303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport android.graphics.Bitmap;
25303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport android.graphics.drawable.BitmapDrawable;
26303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport android.graphics.drawable.Drawable;
27303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport android.os.Handler;
28303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport android.os.HandlerThread;
29303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport android.os.UserHandle;
30a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guyimport android.util.Log;
31a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy
3281e0c8491f22c64300182c652ac2add96888dd2eJorim Jaggiimport com.android.systemui.R;
33f1fbd77cf057e43926f9a0347692611386d09f40Winson Chungimport com.android.systemui.recents.Constants;
348eaeb7dc93ed71b768a2ea8d45021cca010e8263Winson Chungimport com.android.systemui.recents.RecentsConfiguration;
35ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport com.android.systemui.recents.misc.SystemServicesProxy;
36303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
37a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chungimport java.util.ArrayList;
38ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chungimport java.util.Collection;
39303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport java.util.Collections;
40ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chungimport java.util.HashMap;
41303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport java.util.List;
42303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport java.util.concurrent.ConcurrentLinkedQueue;
43303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
44303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
45ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung/** Handle to an ActivityInfo */
46ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chungclass ActivityInfoHandle {
47ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung    ActivityInfo info;
48ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung}
49ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung
50303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung/** A bitmap load queue */
51303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungclass TaskResourceLoadQueue {
52303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    ConcurrentLinkedQueue<Task> mQueue = new ConcurrentLinkedQueue<Task>();
53303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
544c71aefcbd7f7bef5dab1d05d5f7001aaea1b067Winson Chung    /** Adds a new task to the load queue */
55ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung    void addTasks(Collection<Task> tasks) {
56ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung        for (Task t : tasks) {
57ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung            if (!mQueue.contains(t)) {
58ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung                mQueue.add(t);
59ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung            }
60ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung        }
61ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung        synchronized(this) {
62ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung            notifyAll();
63ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung        }
64ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung    }
65ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung
66ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung    /** Adds a new task to the load queue */
6793748a11cba1b44edbc2e888c997533461355594Winson Chung    void addTask(Task t) {
68303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        if (!mQueue.contains(t)) {
69303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            mQueue.add(t);
70303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
71303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        synchronized(this) {
72303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            notifyAll();
73303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
74303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
75303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
764c71aefcbd7f7bef5dab1d05d5f7001aaea1b067Winson Chung    /**
774c71aefcbd7f7bef5dab1d05d5f7001aaea1b067Winson Chung     * Retrieves the next task from the load queue, as well as whether we want that task to be
784c71aefcbd7f7bef5dab1d05d5f7001aaea1b067Winson Chung     * force reloaded.
794c71aefcbd7f7bef5dab1d05d5f7001aaea1b067Winson Chung     */
8093748a11cba1b44edbc2e888c997533461355594Winson Chung    Task nextTask() {
8193748a11cba1b44edbc2e888c997533461355594Winson Chung        return mQueue.poll();
824c71aefcbd7f7bef5dab1d05d5f7001aaea1b067Winson Chung    }
834c71aefcbd7f7bef5dab1d05d5f7001aaea1b067Winson Chung
844c71aefcbd7f7bef5dab1d05d5f7001aaea1b067Winson Chung    /** Removes a task from the load queue */
85303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    void removeTask(Task t) {
86303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mQueue.remove(t);
87303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
88303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
894c71aefcbd7f7bef5dab1d05d5f7001aaea1b067Winson Chung    /** Clears all the tasks from the load queue */
90303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    void clearTasks() {
91303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mQueue.clear();
92303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
93303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
944c71aefcbd7f7bef5dab1d05d5f7001aaea1b067Winson Chung    /** Returns whether the load queue is empty */
95303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    boolean isEmpty() {
96303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mQueue.isEmpty();
97303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
98303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung}
99303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
100303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung/* Task resource loader */
101303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungclass TaskResourceLoader implements Runnable {
102303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    Context mContext;
103303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    HandlerThread mLoadThread;
104303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    Handler mLoadThreadHandler;
105303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    Handler mMainThreadHandler;
106303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
107a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung    SystemServicesProxy mSystemServicesProxy;
108303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    TaskResourceLoadQueue mLoadQueue;
1095e3e5d8945249cfeb8bd59de112be88954ba62bfWinson Chung    DrawableLruCache mApplicationIconCache;
110303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    BitmapLruCache mThumbnailCache;
111c9567c07dd4953f5c5e3821d30525e50ed8b9b29Winson Chung    Bitmap mDefaultThumbnail;
11293748a11cba1b44edbc2e888c997533461355594Winson Chung    BitmapDrawable mDefaultApplicationIcon;
11304dfe0d26b944324ee920001f40d74cff47281d6Winson Chung
114303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    boolean mCancelled;
11504dfe0d26b944324ee920001f40d74cff47281d6Winson Chung    boolean mWaitingOnLoadQueue;
116303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
117303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Constructor, creates a new loading thread that loads task resources in the background */
11893748a11cba1b44edbc2e888c997533461355594Winson Chung    public TaskResourceLoader(TaskResourceLoadQueue loadQueue, DrawableLruCache applicationIconCache,
11993748a11cba1b44edbc2e888c997533461355594Winson Chung                              BitmapLruCache thumbnailCache, Bitmap defaultThumbnail,
12093748a11cba1b44edbc2e888c997533461355594Winson Chung                              BitmapDrawable defaultApplicationIcon) {
121303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mLoadQueue = loadQueue;
1225e3e5d8945249cfeb8bd59de112be88954ba62bfWinson Chung        mApplicationIconCache = applicationIconCache;
123303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mThumbnailCache = thumbnailCache;
124c9567c07dd4953f5c5e3821d30525e50ed8b9b29Winson Chung        mDefaultThumbnail = defaultThumbnail;
12593748a11cba1b44edbc2e888c997533461355594Winson Chung        mDefaultApplicationIcon = defaultApplicationIcon;
126303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mMainThreadHandler = new Handler();
12781e0c8491f22c64300182c652ac2add96888dd2eJorim Jaggi        mLoadThread = new HandlerThread("Recents-TaskResourceLoader",
12850949eaff714a8ad1417b9fd4192e258f552dcc3Jorim Jaggi                android.os.Process.THREAD_PRIORITY_BACKGROUND);
129303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mLoadThread.start();
130303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mLoadThreadHandler = new Handler(mLoadThread.getLooper());
131303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mLoadThreadHandler.post(this);
132303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
133303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
134303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Restarts the loader thread */
135303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    void start(Context context) {
136303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mContext = context;
137303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mCancelled = false;
138a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung        mSystemServicesProxy = new SystemServicesProxy(context);
139303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        // Notify the load thread to start loading
140303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        synchronized(mLoadThread) {
141303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            mLoadThread.notifyAll();
142303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
143303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
144303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
145303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Requests the loader thread to stop after the current iteration */
146303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    void stop() {
147303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        // Mark as cancelled for the thread to pick up
148303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mCancelled = true;
149a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung        mSystemServicesProxy = null;
15004dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        // If we are waiting for the load queue for more tasks, then we can just reset the
15104dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        // Context now, since nothing is using it
15204dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        if (mWaitingOnLoadQueue) {
15304dfe0d26b944324ee920001f40d74cff47281d6Winson Chung            mContext = null;
15404dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        }
155303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
156303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
157303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    @Override
158303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public void run() {
159303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        while (true) {
16010f8139d3b8dd7cd08a2fc688285b3b74a34f0dbWinson Chung            if (mCancelled) {
161303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                // We have to unset the context here, since the background thread may be using it
162303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                // when we call stop()
163303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                mContext = null;
164303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                // If we are cancelled, then wait until we are started again
165303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                synchronized(mLoadThread) {
166303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                    try {
167303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                        mLoadThread.wait();
168303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                    } catch (InterruptedException ie) {
169303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                        ie.printStackTrace();
170303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                    }
171303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                }
172303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            } else {
173a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung                SystemServicesProxy ssp = mSystemServicesProxy;
174a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung
175303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                // Load the next item from the queue
17693748a11cba1b44edbc2e888c997533461355594Winson Chung                final Task t = mLoadQueue.nextTask();
177303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                if (t != null) {
178ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung                    Drawable cachedIcon = mApplicationIconCache.get(t.key);
179ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung                    Bitmap cachedThumbnail = mThumbnailCache.get(t.key);
180bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi
18193748a11cba1b44edbc2e888c997533461355594Winson Chung                    // Load the application icon if it is stale or we haven't cached one yet
18293748a11cba1b44edbc2e888c997533461355594Winson Chung                    if (cachedIcon == null) {
183bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi                        cachedIcon = getTaskDescriptionIcon(t.key, t.icon, t.iconFilename, ssp,
184bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi                                mContext.getResources());
185bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi
186bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi                        if (cachedIcon == null) {
187bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi                            ActivityInfo info = ssp.getActivityInfo(t.key.baseIntent.getComponent(),
188bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi                                    t.key.userId);
189bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi                            if (info != null) {
190bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi                                cachedIcon = ssp.getActivityIcon(info, t.key.userId);
191bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi                            }
192ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung                        }
193bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi
194ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung                        if (cachedIcon == null) {
195ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung                            cachedIcon = mDefaultApplicationIcon;
196303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                        }
197bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi
198ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung                        // At this point, even if we can't load the icon, we will set the default
199ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung                        // icon.
20093748a11cba1b44edbc2e888c997533461355594Winson Chung                        mApplicationIconCache.put(t.key, cachedIcon);
201a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung                    }
20293748a11cba1b44edbc2e888c997533461355594Winson Chung                    // Load the thumbnail if it is stale or we haven't cached one yet
20393748a11cba1b44edbc2e888c997533461355594Winson Chung                    if (cachedThumbnail == null) {
204ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung                        cachedThumbnail = ssp.getTaskThumbnail(t.key.id);
205ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung                        if (cachedThumbnail != null) {
206ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung                            cachedThumbnail.setHasAlpha(false);
207ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung                        } else {
208ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung                            cachedThumbnail = mDefaultThumbnail;
209303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                        }
21093748a11cba1b44edbc2e888c997533461355594Winson Chung                        mThumbnailCache.put(t.key, cachedThumbnail);
211a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung                    }
212a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung                    if (!mCancelled) {
213a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung                        // Notify that the task data has changed
21493748a11cba1b44edbc2e888c997533461355594Winson Chung                        final Drawable newIcon = cachedIcon;
215e8199c582d826a39e6e47b0d8418834c15242fecSelim Cinek                        final Bitmap newThumbnail = cachedThumbnail == mDefaultThumbnail
216e8199c582d826a39e6e47b0d8418834c15242fecSelim Cinek                                ? null : cachedThumbnail;
217a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung                        mMainThreadHandler.post(new Runnable() {
218a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung                            @Override
219a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung                            public void run() {
2208eaeb7dc93ed71b768a2ea8d45021cca010e8263Winson Chung                                t.notifyTaskDataLoaded(newThumbnail, newIcon);
221a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung                            }
222a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung                        });
223303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                    }
224303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                }
225303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
226303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                // If there are no other items in the list, then just wait until something is added
227303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                if (!mCancelled && mLoadQueue.isEmpty()) {
228303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                    synchronized(mLoadQueue) {
229303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                        try {
23004dfe0d26b944324ee920001f40d74cff47281d6Winson Chung                            mWaitingOnLoadQueue = true;
231303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                            mLoadQueue.wait();
23204dfe0d26b944324ee920001f40d74cff47281d6Winson Chung                            mWaitingOnLoadQueue = false;
233303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                        } catch (InterruptedException ie) {
234303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                            ie.printStackTrace();
235303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                        }
236303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                    }
237303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                }
238303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
239303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
240303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
241bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi
242bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi    Drawable getTaskDescriptionIcon(Task.TaskKey taskKey, Bitmap iconBitmap, String iconFilename,
243bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi            SystemServicesProxy ssp, Resources res) {
244bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi        Bitmap tdIcon = iconBitmap != null
245bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi                ? iconBitmap
246bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi                : ActivityManager.TaskDescription.loadTaskDescriptionIcon(iconFilename);
247bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi        if (tdIcon != null) {
248bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi            return ssp.getBadgedIcon(new BitmapDrawable(res, tdIcon), taskKey.userId);
249bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi        }
250bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi        return null;
251bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi    }
252303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung}
253303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
254303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung/* Recents task loader
255303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * NOTE: We should not hold any references to a Context from a static instance */
256303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungpublic class RecentsTaskLoader {
257a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy    private static final String TAG = "RecentsTaskLoader";
258a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy
259303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    static RecentsTaskLoader sInstance;
260303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
261a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung    SystemServicesProxy mSystemServicesProxy;
2625e3e5d8945249cfeb8bd59de112be88954ba62bfWinson Chung    DrawableLruCache mApplicationIconCache;
263303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    BitmapLruCache mThumbnailCache;
264a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung    StringLruCache mActivityLabelCache;
265303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    TaskResourceLoadQueue mLoadQueue;
266303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    TaskResourceLoader mLoader;
267303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
2689f49df933f01a32d04bdf92d53c943065aa8ddf7Winson Chung    RecentsPackageMonitor mPackageMonitor;
2699f49df933f01a32d04bdf92d53c943065aa8ddf7Winson Chung
2704d7b092a866d2fce3e11b5a12cda2b87a83af52dWinson Chung    int mMaxThumbnailCacheSize;
2714d7b092a866d2fce3e11b5a12cda2b87a83af52dWinson Chung    int mMaxIconCacheSize;
2724d7b092a866d2fce3e11b5a12cda2b87a83af52dWinson Chung
2735e3e5d8945249cfeb8bd59de112be88954ba62bfWinson Chung    BitmapDrawable mDefaultApplicationIcon;
274303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    Bitmap mDefaultThumbnail;
275303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
276303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Private Constructor */
277303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    private RecentsTaskLoader(Context context) {
27881e0c8491f22c64300182c652ac2add96888dd2eJorim Jaggi        mMaxThumbnailCacheSize = context.getResources().getInteger(
27981e0c8491f22c64300182c652ac2add96888dd2eJorim Jaggi                R.integer.config_recents_max_thumbnail_count);
28081e0c8491f22c64300182c652ac2add96888dd2eJorim Jaggi        mMaxIconCacheSize = context.getResources().getInteger(
28181e0c8491f22c64300182c652ac2add96888dd2eJorim Jaggi                R.integer.config_recents_max_icon_count);
28204dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        int iconCacheSize = Constants.DebugFlags.App.DisableBackgroundCache ? 1 :
2834d7b092a866d2fce3e11b5a12cda2b87a83af52dWinson Chung                mMaxIconCacheSize;
28404dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        int thumbnailCacheSize = Constants.DebugFlags.App.DisableBackgroundCache ? 1 :
2854d7b092a866d2fce3e11b5a12cda2b87a83af52dWinson Chung                mMaxThumbnailCacheSize;
2864d7b092a866d2fce3e11b5a12cda2b87a83af52dWinson Chung
2877aceb9a07fd3883c8f301ba93726d55494b0446eWinson Chung        // Create the default assets
2887aceb9a07fd3883c8f301ba93726d55494b0446eWinson Chung        Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
2897aceb9a07fd3883c8f301ba93726d55494b0446eWinson Chung        icon.eraseColor(0x00000000);
2907aceb9a07fd3883c8f301ba93726d55494b0446eWinson Chung        mDefaultThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
2917aceb9a07fd3883c8f301ba93726d55494b0446eWinson Chung        mDefaultThumbnail.setHasAlpha(false);
2927aceb9a07fd3883c8f301ba93726d55494b0446eWinson Chung        mDefaultThumbnail.eraseColor(0xFFffffff);
2937aceb9a07fd3883c8f301ba93726d55494b0446eWinson Chung        mDefaultApplicationIcon = new BitmapDrawable(context.getResources(), icon);
2947aceb9a07fd3883c8f301ba93726d55494b0446eWinson Chung
295a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung        // Initialize the proxy, cache and loaders
296a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung        mSystemServicesProxy = new SystemServicesProxy(context);
297d543c1bea4d227470f5b6d6535b70e5090064c9aWinson Chung        mPackageMonitor = new RecentsPackageMonitor();
298303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mLoadQueue = new TaskResourceLoadQueue();
2995e3e5d8945249cfeb8bd59de112be88954ba62bfWinson Chung        mApplicationIconCache = new DrawableLruCache(iconCacheSize);
300303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mThumbnailCache = new BitmapLruCache(thumbnailCacheSize);
301a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung        mActivityLabelCache = new StringLruCache(100);
302c9567c07dd4953f5c5e3821d30525e50ed8b9b29Winson Chung        mLoader = new TaskResourceLoader(mLoadQueue, mApplicationIconCache, mThumbnailCache,
30393748a11cba1b44edbc2e888c997533461355594Winson Chung                mDefaultThumbnail, mDefaultApplicationIcon);
304303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
305303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
306303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Initializes the recents task loader */
307303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public static RecentsTaskLoader initialize(Context context) {
308303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        if (sInstance == null) {
309303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            sInstance = new RecentsTaskLoader(context);
310303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
311303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return sInstance;
312303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
313303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
314303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns the current recents task loader */
315303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public static RecentsTaskLoader getInstance() {
316303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return sInstance;
317303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
318303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
319a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung    /** Returns the system services proxy */
320a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung    public SystemServicesProxy getSystemServicesProxy() {
321a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung        return mSystemServicesProxy;
322a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung    }
323a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung
324ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung    /** Gets the list of recent tasks, ordered from back to front. */
3259cb5c4e3854aa7f2ddab707920b688c3108cbc85Winson Chung    private static List<ActivityManager.RecentTaskInfo> getRecentTasks(SystemServicesProxy ssp,
3269cb5c4e3854aa7f2ddab707920b688c3108cbc85Winson Chung            boolean isTopTaskHome) {
327ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        RecentsConfiguration config = RecentsConfiguration.getInstance();
328a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung        List<ActivityManager.RecentTaskInfo> tasks =
3299cb5c4e3854aa7f2ddab707920b688c3108cbc85Winson Chung                ssp.getRecentTasks(config.maxNumTasksToLoad, UserHandle.CURRENT.getIdentifier(),
3309cb5c4e3854aa7f2ddab707920b688c3108cbc85Winson Chung                        isTopTaskHome);
331a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung        Collections.reverse(tasks);
3320d767551c55d9e594a0b944bd1926c21a344b5aeWinson Chung        return tasks;
3330d767551c55d9e594a0b944bd1926c21a344b5aeWinson Chung    }
3340d767551c55d9e594a0b944bd1926c21a344b5aeWinson Chung
335ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung    /** Returns the activity icon using as many cached values as we can. */
336ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung    public Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey,
337ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung             ActivityManager.TaskDescription td, SystemServicesProxy ssp,
338ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung             Resources res, ActivityInfoHandle infoHandle, boolean preloadTask) {
339ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        // Return the cached activity icon if it exists
340ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        Drawable icon = mApplicationIconCache.getAndInvalidateIfModified(taskKey);
341ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        if (icon != null) {
342ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            return icon;
343ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        }
344bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi
345bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi        // If we are preloading this task, continue to load the task description icon or the
346bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi        // activity icon
347ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        if (preloadTask) {
348bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi
349bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi            // Return and cache the task description icon if it exists
350bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi            Drawable tdDrawable = mLoader.getTaskDescriptionIcon(taskKey, td.getInMemoryIcon(),
351bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi                    td.getIconFilename(), ssp, res);
352bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi            if (tdDrawable != null) {
353bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi                mApplicationIconCache.put(taskKey, tdDrawable);
354bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi                return tdDrawable;
355bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi            }
356bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi
357bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi            // Load the icon from the activity info and cache it
358ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            if (infoHandle.info == null) {
359ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung                infoHandle.info = ssp.getActivityInfo(taskKey.baseIntent.getComponent(),
360ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung                        taskKey.userId);
361ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            }
362a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy            if (infoHandle.info != null) {
363a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy                icon = ssp.getActivityIcon(infoHandle.info, taskKey.userId);
364a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy                if (icon != null) {
365a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy                    mApplicationIconCache.put(taskKey, icon);
366a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy                    return icon;
367a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy                }
368a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy            }
369ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        }
370a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy        // If we couldn't load any icon, return null
371ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        return null;
372ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung    }
373ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung
374ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung    /** Returns the activity label using as many cached values as we can. */
375ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung    public String getAndUpdateActivityLabel(Task.TaskKey taskKey,
376ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            ActivityManager.TaskDescription td, SystemServicesProxy ssp,
377ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            ActivityInfoHandle infoHandle) {
378ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        // Return the task description label if it exists
379ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        if (td != null && td.getLabel() != null) {
380ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            return td.getLabel();
381ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        }
382ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        // Return the cached activity label if it exists
383ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        String label = mActivityLabelCache.getAndInvalidateIfModified(taskKey);
384ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        if (label != null) {
385ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            return label;
386ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        }
387ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        // All short paths failed, load the label from the activity info and cache it
388ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        if (infoHandle.info == null) {
389ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            infoHandle.info = ssp.getActivityInfo(taskKey.baseIntent.getComponent(),
390ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung                    taskKey.userId);
391ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        }
392a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy        if (infoHandle.info != null) {
393a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy            label = ssp.getActivityLabel(infoHandle.info);
394a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy            mActivityLabelCache.put(taskKey, label);
395a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy        } else {
396a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy            Log.w(TAG, "Missing ActivityInfo for " + taskKey.baseIntent.getComponent()
397a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy                    + " u=" + taskKey.userId);
398a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy        }
399ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        return label;
400ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung    }
401ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung
402ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung    /** Returns the activity's primary color. */
403ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung    public int getActivityPrimaryColor(ActivityManager.TaskDescription td,
404ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            RecentsConfiguration config) {
405ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        if (td != null && td.getPrimaryColor() != 0) {
406ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            return td.getPrimaryColor();
407ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        }
408ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        return config.taskBarViewDefaultBackgroundColor;
409ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung    }
410ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung
4110d767551c55d9e594a0b944bd1926c21a344b5aeWinson Chung    /** Reload the set of recent tasks */
4129cb5c4e3854aa7f2ddab707920b688c3108cbc85Winson Chung    public SpaceNode reload(Context context, int preloadCount, boolean isTopTaskHome) {
413ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        ArrayList<Task.TaskKey> taskKeys = new ArrayList<Task.TaskKey>();
414ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        ArrayList<Task> tasksToLoad = new ArrayList<Task>();
415ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        TaskStack stack = getTaskStack(mSystemServicesProxy, context.getResources(),
4169cb5c4e3854aa7f2ddab707920b688c3108cbc85Winson Chung                -1, preloadCount, true, isTopTaskHome, taskKeys, tasksToLoad);
417083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung        SpaceNode root = new SpaceNode();
4180d767551c55d9e594a0b944bd1926c21a344b5aeWinson Chung        root.setStack(stack);
4190d767551c55d9e594a0b944bd1926c21a344b5aeWinson Chung
420ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        // Start the task loader and add all the tasks we need to load
421ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        mLoader.start(context);
422ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        mLoadQueue.addTasks(tasksToLoad);
423ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung
424ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        // Update the package monitor with the list of packages to listen for
425ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        mPackageMonitor.setTasks(taskKeys);
426ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung
427ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        return root;
428ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung    }
429ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung
430ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung    /** Creates a lightweight stack of the current recent tasks, without thumbnails and icons. */
431ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung    public TaskStack getTaskStack(SystemServicesProxy ssp, Resources res,
432ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            int preloadTaskId, int preloadTaskCount,
4339cb5c4e3854aa7f2ddab707920b688c3108cbc85Winson Chung            boolean loadTaskThumbnails, boolean isTopTaskHome,
4349cb5c4e3854aa7f2ddab707920b688c3108cbc85Winson Chung            List<Task.TaskKey> taskKeysOut, List<Task> tasksToLoadOut) {
435ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        RecentsConfiguration config = RecentsConfiguration.getInstance();
4369cb5c4e3854aa7f2ddab707920b688c3108cbc85Winson Chung        List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks(ssp, isTopTaskHome);
437a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy        HashMap<Task.ComponentNameKey, ActivityInfoHandle> activityInfoCache =
438a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy                new HashMap<Task.ComponentNameKey, ActivityInfoHandle>();
439ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        ArrayList<Task> tasksToAdd = new ArrayList<Task>();
440ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung        TaskStack stack = new TaskStack();
4410d767551c55d9e594a0b944bd1926c21a344b5aeWinson Chung
442a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung        int taskCount = tasks.size();
443a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung        for (int i = 0; i < taskCount; i++) {
444a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung            ActivityManager.RecentTaskInfo t = tasks.get(i);
445ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung
446a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy            // Compose the task key
447a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy            Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, t.baseIntent, t.userId,
448a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy                    t.firstActiveTime, t.lastActiveTime);
449a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy
450ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            // Get an existing activity info handle if possible
451a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy            Task.ComponentNameKey cnKey = taskKey.getComponentNameKey();
452a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy            ActivityInfoHandle infoHandle;
453ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            boolean hasCachedActivityInfo = false;
454a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy            if (activityInfoCache.containsKey(cnKey)) {
455a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy                infoHandle = activityInfoCache.get(cnKey);
456ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung                hasCachedActivityInfo = true;
457a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy            } else {
458a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy                infoHandle = new ActivityInfoHandle();
459ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            }
460ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung
461ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            // Determine whether to preload this task
462ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            boolean preloadTask = false;
463ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            if (preloadTaskId > 0) {
464ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung                preloadTask = (t.id == preloadTaskId);
465ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            } else if (preloadTaskCount > 0) {
466ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung                preloadTask = (i >= (taskCount - preloadTaskCount));
467a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung            }
468ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung
469ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            // Load the label, icon, and color
470ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            String activityLabel  = getAndUpdateActivityLabel(taskKey, t.taskDescription,
471ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung                    ssp, infoHandle);
472ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            Drawable activityIcon = getAndUpdateActivityIcon(taskKey, t.taskDescription,
473ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung                    ssp, res, infoHandle, preloadTask);
474ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            int activityColor = getActivityPrimaryColor(t.taskDescription, config);
475ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung
476ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            // Update the activity info cache
477ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            if (!hasCachedActivityInfo && infoHandle.info != null) {
478a734fc1ecedb316fdf6deddc169b8b0bddab76bfKenny Guy                activityInfoCache.put(cnKey, infoHandle);
47911e41baac63a42d7ddb7ba2cab40ee55443d262fWinson Chung            }
480a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung
481bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi            Bitmap icon = t.taskDescription != null
482bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi                    ? t.taskDescription.getInMemoryIcon()
483bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi                    : null;
484bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi            String iconFilename = t.taskDescription != null
485bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi                    ? t.taskDescription.getIconFilename()
486bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi                    : null;
487bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi
488ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            // Add the task to the stack
489a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung            Task task = new Task(taskKey, (t.id > -1), t.affiliatedTaskId, t.affiliatedTaskColor,
490a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung                    activityLabel, activityIcon, activityColor, (i == (taskCount - 1)),
491bdd4b201e45ffa82dcd3b09fb9724d243c86c8d8Jorim Jaggi                    config.lockToAppEnabled, icon, iconFilename);
4925e3e5d8945249cfeb8bd59de112be88954ba62bfWinson Chung
493ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            if (preloadTask && loadTaskThumbnails) {
494ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung                // Load the thumbnail from the cache if possible
495a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung                task.thumbnail = mThumbnailCache.getAndInvalidateIfModified(taskKey);
496a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung                if (task.thumbnail == null) {
497ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung                    // Load the thumbnail from the system
498a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung                    task.thumbnail = ssp.getTaskThumbnail(taskKey.id);
499ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung                    if (task.thumbnail != null) {
500ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung                        task.thumbnail.setHasAlpha(false);
501a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung                        mThumbnailCache.put(taskKey, task.thumbnail);
502303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                    }
503303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                }
504ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung                if (task.thumbnail == null && tasksToLoadOut != null) {
505ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung                    // Either the task has changed since the last active time, or it was not
506ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung                    // previously cached, so try and load the task anew.
507ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung                    tasksToLoadOut.add(task);
508ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung                }
509303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
5105e3e5d8945249cfeb8bd59de112be88954ba62bfWinson Chung
511ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            // Add to the list of task keys
512ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            if (taskKeysOut != null) {
513ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung                taskKeysOut.add(taskKey);
514ebfc6981828b0699eef85c58b23a61f2cac41af3Winson Chung            }
5155e3e5d8945249cfeb8bd59de112be88954ba62bfWinson Chung            // Add the task to the stack
516a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung            tasksToAdd.add(task);
517a10370fc2eb8eb95631592160c5f6281b9d75722Winson Chung        }
518a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung        stack.setTasks(tasksToAdd);
519ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung        stack.createAffiliatedGroupings(config);
520ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        return stack;
521ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
522ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
5238eaeb7dc93ed71b768a2ea8d45021cca010e8263Winson Chung    /** Acquires the task resource data directly from the pool. */
524303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public void loadTaskData(Task t) {
525ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung        Drawable applicationIcon = mApplicationIconCache.getAndInvalidateIfModified(t.key);
526ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung        Bitmap thumbnail = mThumbnailCache.getAndInvalidateIfModified(t.key);
527ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung
528ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung        // Grab the thumbnail/icon from the cache, if either don't exist, then trigger a reload and
529ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung        // use the default assets in their place until they load
530ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung        boolean requiresLoad = (applicationIcon == null) || (thumbnail == null);
531ff88d7b39ebe3a0453977092a30c3b2a53a19a00Winson Chung        applicationIcon = applicationIcon != null ? applicationIcon : mDefaultApplicationIcon;
53204dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        if (requiresLoad) {
53393748a11cba1b44edbc2e888c997533461355594Winson Chung            mLoadQueue.addTask(t);
53404dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        }
535e8199c582d826a39e6e47b0d8418834c15242fecSelim Cinek        t.notifyTaskDataLoaded(thumbnail == mDefaultThumbnail ? null : thumbnail, applicationIcon);
536303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
537303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
5384d7b092a866d2fce3e11b5a12cda2b87a83af52dWinson Chung    /** Releases the task resource data back into the pool. */
539303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public void unloadTaskData(Task t) {
54004dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        mLoadQueue.removeTask(t);
541e8199c582d826a39e6e47b0d8418834c15242fecSelim Cinek        t.notifyTaskDataUnloaded(null, mDefaultApplicationIcon);
542303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
543303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
5444d7b092a866d2fce3e11b5a12cda2b87a83af52dWinson Chung    /** Completely removes the resource data from the pool. */
5455393dff555641f5666573952498e27c90fd3edcaWinson Chung    public void deleteTaskData(Task t, boolean notifyTaskDataUnloaded) {
54604dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        mLoadQueue.removeTask(t);
54704dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        mThumbnailCache.remove(t.key);
5485e3e5d8945249cfeb8bd59de112be88954ba62bfWinson Chung        mApplicationIconCache.remove(t.key);
5495393dff555641f5666573952498e27c90fd3edcaWinson Chung        if (notifyTaskDataUnloaded) {
550e8199c582d826a39e6e47b0d8418834c15242fecSelim Cinek            t.notifyTaskDataUnloaded(null, mDefaultApplicationIcon);
5515393dff555641f5666573952498e27c90fd3edcaWinson Chung        }
552303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
553303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
55404dfe0d26b944324ee920001f40d74cff47281d6Winson Chung    /** Stops the task loader and clears all pending tasks */
555303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    void stopLoader() {
556303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mLoader.stop();
557303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mLoadQueue.clearTasks();
558303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
5594d7b092a866d2fce3e11b5a12cda2b87a83af52dWinson Chung
5609f49df933f01a32d04bdf92d53c943065aa8ddf7Winson Chung    /** Registers any broadcast receivers. */
5619f49df933f01a32d04bdf92d53c943065aa8ddf7Winson Chung    public void registerReceivers(Context context, RecentsPackageMonitor.PackageCallbacks cb) {
5629f49df933f01a32d04bdf92d53c943065aa8ddf7Winson Chung        // Register the broadcast receiver to handle messages related to packages being added/removed
5639f49df933f01a32d04bdf92d53c943065aa8ddf7Winson Chung        mPackageMonitor.register(context, cb);
5649f49df933f01a32d04bdf92d53c943065aa8ddf7Winson Chung    }
5659f49df933f01a32d04bdf92d53c943065aa8ddf7Winson Chung
5669f49df933f01a32d04bdf92d53c943065aa8ddf7Winson Chung    /** Unregisters any broadcast receivers. */
5679f49df933f01a32d04bdf92d53c943065aa8ddf7Winson Chung    public void unregisterReceivers() {
5689f49df933f01a32d04bdf92d53c943065aa8ddf7Winson Chung        mPackageMonitor.unregister();
5699f49df933f01a32d04bdf92d53c943065aa8ddf7Winson Chung    }
5709f49df933f01a32d04bdf92d53c943065aa8ddf7Winson Chung
5719f49df933f01a32d04bdf92d53c943065aa8ddf7Winson Chung    /**
5729f49df933f01a32d04bdf92d53c943065aa8ddf7Winson Chung     * Handles signals from the system, trimming memory when requested to prevent us from running
5739f49df933f01a32d04bdf92d53c943065aa8ddf7Winson Chung     * out of memory.
5749f49df933f01a32d04bdf92d53c943065aa8ddf7Winson Chung     */
575f1fbd77cf057e43926f9a0347692611386d09f40Winson Chung    public void onTrimMemory(int level) {
57604dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        switch (level) {
57704dfe0d26b944324ee920001f40d74cff47281d6Winson Chung            case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
57847c4c69575e94635a9356e8a1faf4b56a0120452Winson Chung                // Stop the loader immediately when the UI is no longer visible
57947c4c69575e94635a9356e8a1faf4b56a0120452Winson Chung                stopLoader();
58081e0c8491f22c64300182c652ac2add96888dd2eJorim Jaggi                mThumbnailCache.trimToSize(Math.max(
58181e0c8491f22c64300182c652ac2add96888dd2eJorim Jaggi                        Constants.Values.RecentsTaskLoader.PreloadFirstTasksCount,
58281e0c8491f22c64300182c652ac2add96888dd2eJorim Jaggi                        mMaxThumbnailCacheSize / 2));
58381e0c8491f22c64300182c652ac2add96888dd2eJorim Jaggi                mApplicationIconCache.trimToSize(Math.max(
58481e0c8491f22c64300182c652ac2add96888dd2eJorim Jaggi                        Constants.Values.RecentsTaskLoader.PreloadFirstTasksCount,
58581e0c8491f22c64300182c652ac2add96888dd2eJorim Jaggi                        mMaxIconCacheSize / 2));
58604dfe0d26b944324ee920001f40d74cff47281d6Winson Chung                break;
58704dfe0d26b944324ee920001f40d74cff47281d6Winson Chung            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
58804dfe0d26b944324ee920001f40d74cff47281d6Winson Chung            case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
58904dfe0d26b944324ee920001f40d74cff47281d6Winson Chung                // We are leaving recents, so trim the data a bit
59004dfe0d26b944324ee920001f40d74cff47281d6Winson Chung                mThumbnailCache.trimToSize(mMaxThumbnailCacheSize / 2);
5915e3e5d8945249cfeb8bd59de112be88954ba62bfWinson Chung                mApplicationIconCache.trimToSize(mMaxIconCacheSize / 2);
59204dfe0d26b944324ee920001f40d74cff47281d6Winson Chung                break;
59304dfe0d26b944324ee920001f40d74cff47281d6Winson Chung            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
59404dfe0d26b944324ee920001f40d74cff47281d6Winson Chung            case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
59504dfe0d26b944324ee920001f40d74cff47281d6Winson Chung                // We are going to be low on memory
59604dfe0d26b944324ee920001f40d74cff47281d6Winson Chung                mThumbnailCache.trimToSize(mMaxThumbnailCacheSize / 4);
5975e3e5d8945249cfeb8bd59de112be88954ba62bfWinson Chung                mApplicationIconCache.trimToSize(mMaxIconCacheSize / 4);
59804dfe0d26b944324ee920001f40d74cff47281d6Winson Chung                break;
59904dfe0d26b944324ee920001f40d74cff47281d6Winson Chung            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
60004dfe0d26b944324ee920001f40d74cff47281d6Winson Chung            case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
60104dfe0d26b944324ee920001f40d74cff47281d6Winson Chung                // We are low on memory, so release everything
60204dfe0d26b944324ee920001f40d74cff47281d6Winson Chung                mThumbnailCache.evictAll();
6035e3e5d8945249cfeb8bd59de112be88954ba62bfWinson Chung                mApplicationIconCache.evictAll();
604a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung                // The cache is small, only clear the label cache when we are critical
605a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung                mActivityLabelCache.evictAll();
60604dfe0d26b944324ee920001f40d74cff47281d6Winson Chung                break;
60704dfe0d26b944324ee920001f40d74cff47281d6Winson Chung            default:
60804dfe0d26b944324ee920001f40d74cff47281d6Winson Chung                break;
6094d7b092a866d2fce3e11b5a12cda2b87a83af52dWinson Chung        }
6104d7b092a866d2fce3e11b5a12cda2b87a83af52dWinson Chung    }
611303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung}
612