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