1ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka/* 2ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka * Copyright (C) 2011 The Android Open Source Project 3ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka * 4ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka * Licensed under the Apache License, Version 2.0 (the "License"); 5ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka * you may not use this file except in compliance with the License. 6ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka * You may obtain a copy of the License at 7ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka * 8ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka * http://www.apache.org/licenses/LICENSE-2.0 9ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka * 10ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka * Unless required by applicable law or agreed to in writing, software 11ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka * distributed under the License is distributed on an "AS IS" BASIS, 12ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka * See the License for the specific language governing permissions and 14ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka * limitations under the License. 15ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka */ 16ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 17ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkapackage com.android.systemui.recent; 18ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 19ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.app.ActivityManager; 204f0a49e6b9ad1b00972dbe8a751263aa6c482538Amith Yamasaniimport android.app.AppGlobals; 21ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.content.ComponentName; 22ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.content.Context; 23ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.content.Intent; 24ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.content.pm.ActivityInfo; 254f0a49e6b9ad1b00972dbe8a751263aa6c482538Amith Yamasaniimport android.content.pm.IPackageManager; 26ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.content.pm.PackageManager; 27ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.content.pm.ResolveInfo; 28ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.content.res.Resources; 29ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.graphics.Bitmap; 309926272f32868c858b24b45e048210cf3515741eMichael Jurkaimport android.graphics.drawable.BitmapDrawable; 31ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.graphics.drawable.Drawable; 32ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.os.AsyncTask; 33ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.os.Handler; 34ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.os.Process; 354f0a49e6b9ad1b00972dbe8a751263aa6c482538Amith Yamasaniimport android.os.RemoteException; 3680343f646f9686528212f82163a77ef48e30f4c3Michael Jurkaimport android.os.UserHandle; 37ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.util.Log; 38cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurkaimport android.view.MotionEvent; 39cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurkaimport android.view.View; 40ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 41ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport com.android.systemui.R; 42ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport com.android.systemui.recents.misc.SystemServicesProxy; 43ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport com.android.systemui.statusbar.phone.PhoneStatusBar; 44ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 4599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurkaimport java.util.ArrayList; 4699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurkaimport java.util.List; 4799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurkaimport java.util.concurrent.BlockingQueue; 4899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurkaimport java.util.concurrent.LinkedBlockingQueue; 4999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka 50cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurkapublic class RecentTasksLoader implements View.OnTouchListener { 51ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka static final String TAG = "RecentTasksLoader"; 52b0e49fc93c146d7ddc8e1f27ec67306a71168510John Spurlock static final boolean DEBUG = PhoneStatusBar.DEBUG || false; 53ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 54ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka private static final int DISPLAY_TASKS = 20; 55ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka private static final int MAX_TASKS = DISPLAY_TASKS + 1; // allow extra for non-apps 56ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 57ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka private Context mContext; 58ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka private RecentsPanelView mRecentsPanel; 5980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka 6080343f646f9686528212f82163a77ef48e30f4c3Michael Jurka private Object mFirstTaskLock = new Object(); 61cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka private TaskDescription mFirstTask; 62cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka private boolean mFirstTaskLoaded; 63ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 6499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka private AsyncTask<Void, ArrayList<TaskDescription>, Void> mTaskLoader; 6599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka private AsyncTask<Void, TaskDescription, Void> mThumbnailLoader; 66cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka private Handler mHandler; 67ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 68ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka private int mIconDpi; 699926272f32868c858b24b45e048210cf3515741eMichael Jurka private ColorDrawableWithDimensions mDefaultThumbnailBackground; 709926272f32868c858b24b45e048210cf3515741eMichael Jurka private ColorDrawableWithDimensions mDefaultIconBackground; 71cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka private int mNumTasksInFirstScreenful = Integer.MAX_VALUE; 72cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 73cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka private boolean mFirstScreenful; 74cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka private ArrayList<TaskDescription> mLoadedTasks; 75cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 76cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka private enum State { LOADING, LOADED, CANCELLED }; 77cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka private State mState = State.CANCELLED; 78cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 7980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka 8080343f646f9686528212f82163a77ef48e30f4c3Michael Jurka private static RecentTasksLoader sInstance; 8180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka public static RecentTasksLoader getInstance(Context context) { 8280343f646f9686528212f82163a77ef48e30f4c3Michael Jurka if (sInstance == null) { 8380343f646f9686528212f82163a77ef48e30f4c3Michael Jurka sInstance = new RecentTasksLoader(context); 84cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 8580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka return sInstance; 86cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 87ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 8880343f646f9686528212f82163a77ef48e30f4c3Michael Jurka private RecentTasksLoader(Context context) { 89ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka mContext = context; 90cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mHandler = new Handler(); 91ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 92ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka final Resources res = context.getResources(); 93ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 94ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka // get the icon size we want -- on tablets, we use bigger icons 95ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka boolean isTablet = res.getBoolean(R.bool.config_recents_interface_for_tablets); 96ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka if (isTablet) { 9743e34f61f0014400583895525fa08274615a21d2Winson Chung ActivityManager activityManager = 9843e34f61f0014400583895525fa08274615a21d2Winson Chung (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 9943e34f61f0014400583895525fa08274615a21d2Winson Chung mIconDpi = activityManager.getLauncherLargeIconDensity(); 100ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } else { 101ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka mIconDpi = res.getDisplayMetrics().densityDpi; 102ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 103ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 10499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka // Render default icon (just a blank image) 10599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka int defaultIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.app_icon_size); 10699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka int iconSize = (int) (defaultIconSize * mIconDpi / res.getDisplayMetrics().densityDpi); 1079926272f32868c858b24b45e048210cf3515741eMichael Jurka mDefaultIconBackground = new ColorDrawableWithDimensions(0x00000000, iconSize, iconSize); 10899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka 109ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka // Render the default thumbnail background 11099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka int thumbnailWidth = 11199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width); 11299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka int thumbnailHeight = 11399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height); 114ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka int color = res.getColor(R.drawable.status_bar_recents_app_thumbnail_background); 115ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 11699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka mDefaultThumbnailBackground = 1179926272f32868c858b24b45e048210cf3515741eMichael Jurka new ColorDrawableWithDimensions(color, thumbnailWidth, thumbnailHeight); 118ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 119ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 120cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka public void setRecentsPanel(RecentsPanelView newRecentsPanel, RecentsPanelView caller) { 121cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka // Only allow clearing mRecentsPanel if the caller is the current recentsPanel 122cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (newRecentsPanel != null || mRecentsPanel == caller) { 123cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mRecentsPanel = newRecentsPanel; 124cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (mRecentsPanel != null) { 125cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mNumTasksInFirstScreenful = mRecentsPanel.numItemsInOneScreenful(); 126cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 127cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 128ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 129ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 1309926272f32868c858b24b45e048210cf3515741eMichael Jurka public Drawable getDefaultThumbnail() { 131412cba8aa10231cdf515d9400a754e8a16a8eb3dMichael Jurka return mDefaultThumbnailBackground; 132412cba8aa10231cdf515d9400a754e8a16a8eb3dMichael Jurka } 133412cba8aa10231cdf515d9400a754e8a16a8eb3dMichael Jurka 1349926272f32868c858b24b45e048210cf3515741eMichael Jurka public Drawable getDefaultIcon() { 13599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka return mDefaultIconBackground; 13699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 13799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka 138cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka public ArrayList<TaskDescription> getLoadedTasks() { 139cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka return mLoadedTasks; 140cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 141cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 142e57922cc7d96620cab0c296e93b2b9b3a471c331Michael Jurka public void remove(TaskDescription td) { 143e57922cc7d96620cab0c296e93b2b9b3a471c331Michael Jurka mLoadedTasks.remove(td); 144e57922cc7d96620cab0c296e93b2b9b3a471c331Michael Jurka } 145e57922cc7d96620cab0c296e93b2b9b3a471c331Michael Jurka 146cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka public boolean isFirstScreenful() { 147cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka return mFirstScreenful; 148cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 149cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 150cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka private boolean isCurrentHomeActivity(ComponentName component, ActivityInfo homeInfo) { 151cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (homeInfo == null) { 152cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka final PackageManager pm = mContext.getPackageManager(); 153cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME) 154cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka .resolveActivityInfo(pm, 0); 155cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 156cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka return homeInfo != null 157cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka && homeInfo.packageName.equals(component.getPackageName()) 158cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka && homeInfo.name.equals(component.getClassName()); 159cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 160cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 161cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka // Create an TaskDescription, returning null if the title or icon is null 162ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka TaskDescription createTaskDescription(int taskId, int persistentTaskId, Intent baseIntent, 1631f1cce1725a2fceee4162aec23518d42c78d6669Kenny Guy ComponentName origActivity, CharSequence description, int userId) { 164ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka Intent intent = new Intent(baseIntent); 165ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka if (origActivity != null) { 166ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka intent.setComponent(origActivity); 167ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 168ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka final PackageManager pm = mContext.getPackageManager(); 1694f0a49e6b9ad1b00972dbe8a751263aa6c482538Amith Yamasani final IPackageManager ipm = AppGlobals.getPackageManager(); 170ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) 171ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka | Intent.FLAG_ACTIVITY_NEW_TASK); 1724f0a49e6b9ad1b00972dbe8a751263aa6c482538Amith Yamasani ResolveInfo resolveInfo = null; 1734f0a49e6b9ad1b00972dbe8a751263aa6c482538Amith Yamasani try { 1744f0a49e6b9ad1b00972dbe8a751263aa6c482538Amith Yamasani resolveInfo = ipm.resolveIntent(intent, null, 0, userId); 1754f0a49e6b9ad1b00972dbe8a751263aa6c482538Amith Yamasani } catch (RemoteException re) { 1764f0a49e6b9ad1b00972dbe8a751263aa6c482538Amith Yamasani } 177ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka if (resolveInfo != null) { 178ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka final ActivityInfo info = resolveInfo.activityInfo; 179ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka final String title = info.loadLabel(pm).toString(); 180ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 18199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (title != null && title.length() > 0) { 182ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka if (DEBUG) Log.v(TAG, "creating activity desc for id=" 183ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka + persistentTaskId + ", label=" + title); 184ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 185ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka TaskDescription item = new TaskDescription(taskId, 186ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka persistentTaskId, resolveInfo, baseIntent, info.packageName, 1871f1cce1725a2fceee4162aec23518d42c78d6669Kenny Guy description, userId); 188ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka item.setLabel(title); 189ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 190ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka return item; 191ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } else { 192ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka if (DEBUG) Log.v(TAG, "SKIPPING item " + persistentTaskId); 193ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 194ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 195ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka return null; 196ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 197ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 19899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka void loadThumbnailAndIcon(TaskDescription td) { 199ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka final ActivityManager am = (ActivityManager) 200ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka mContext.getSystemService(Context.ACTIVITY_SERVICE); 20199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka final PackageManager pm = mContext.getPackageManager(); 202ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung final Bitmap thumbnail = SystemServicesProxy.getThumbnail(am, td.persistentTaskId); 20399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka Drawable icon = getFullResIcon(td.resolveInfo, pm); 2044f0a49e6b9ad1b00972dbe8a751263aa6c482538Amith Yamasani if (td.userId != UserHandle.myUserId()) { 2054f0a49e6b9ad1b00972dbe8a751263aa6c482538Amith Yamasani // Need to badge the icon 206fdf169cbea5c59c6f74c25c6c529d8a19c6cb78cAmith Yamasani icon = mContext.getPackageManager().getUserBadgedIcon(icon, new UserHandle(td.userId)); 2074f0a49e6b9ad1b00972dbe8a751263aa6c482538Amith Yamasani } 208ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka if (DEBUG) Log.v(TAG, "Loaded bitmap for task " 20915491c6a728131e322c45bc440500a8a78e4a410Dianne Hackborn + td + ": " + thumbnail); 210ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka synchronized (td) { 21115491c6a728131e322c45bc440500a8a78e4a410Dianne Hackborn if (thumbnail != null) { 2129926272f32868c858b24b45e048210cf3515741eMichael Jurka td.setThumbnail(new BitmapDrawable(mContext.getResources(), thumbnail)); 213ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } else { 214ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka td.setThumbnail(mDefaultThumbnailBackground); 215ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 21699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (icon != null) { 21799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka td.setIcon(icon); 21899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 21999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka td.setLoaded(true); 220ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 221ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 222ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 223ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka Drawable getFullResDefaultActivityIcon() { 224ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka return getFullResIcon(Resources.getSystem(), 225ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka com.android.internal.R.mipmap.sym_def_app_icon); 226ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 227ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 228ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka Drawable getFullResIcon(Resources resources, int iconId) { 229ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka try { 230ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka return resources.getDrawableForDensity(iconId, mIconDpi); 231ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } catch (Resources.NotFoundException e) { 232ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka return getFullResDefaultActivityIcon(); 233ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 234ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 235ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 236ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka private Drawable getFullResIcon(ResolveInfo info, PackageManager packageManager) { 237ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka Resources resources; 238ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka try { 239ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka resources = packageManager.getResourcesForApplication( 240ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka info.activityInfo.applicationInfo); 241ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } catch (PackageManager.NameNotFoundException e) { 242ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka resources = null; 243ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 244ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka if (resources != null) { 245ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka int iconId = info.activityInfo.getIconResource(); 246ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka if (iconId != 0) { 247ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka return getFullResIcon(resources, iconId); 248ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 249ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 250ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka return getFullResDefaultActivityIcon(); 251ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 252ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 253cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka Runnable mPreloadTasksRunnable = new Runnable() { 254cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka public void run() { 255cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka loadTasksInBackground(); 256cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 257cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka }; 258cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 259cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka // additional optimization when we have software system buttons - start loading the recent 260cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka // tasks on touch down 261cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka @Override 262cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka public boolean onTouch(View v, MotionEvent ev) { 263cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka int action = ev.getAction() & MotionEvent.ACTION_MASK; 264cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (action == MotionEvent.ACTION_DOWN) { 265d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka preloadRecentTasksList(); 266cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } else if (action == MotionEvent.ACTION_CANCEL) { 267d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka cancelPreloadingRecentTasksList(); 268cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } else if (action == MotionEvent.ACTION_UP) { 269cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka // Remove the preloader if we haven't called it yet 270cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mHandler.removeCallbacks(mPreloadTasksRunnable); 271cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (!v.isPressed()) { 272cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka cancelLoadingThumbnailsAndIcons(); 273cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 274cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 275cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 276cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka return false; 277cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 278cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 279d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka public void preloadRecentTasksList() { 280d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka mHandler.post(mPreloadTasksRunnable); 281d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka } 282d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka 283d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka public void cancelPreloadingRecentTasksList() { 284d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka cancelLoadingThumbnailsAndIcons(); 285d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka mHandler.removeCallbacks(mPreloadTasksRunnable); 286d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka } 287d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka 288cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka public void cancelLoadingThumbnailsAndIcons(RecentsPanelView caller) { 289cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka // Only oblige this request if it comes from the current RecentsPanel 290cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka // (eg when you rotate, the old RecentsPanel request should be ignored) 291cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (mRecentsPanel == caller) { 292cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka cancelLoadingThumbnailsAndIcons(); 293cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 294cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 295cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 296cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 297cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka private void cancelLoadingThumbnailsAndIcons() { 29845eed3c69b718fe5dedaff0322e2ed4c2f55b9d3Michael Jurka if (mRecentsPanel != null && mRecentsPanel.isShowing()) { 29945eed3c69b718fe5dedaff0322e2ed4c2f55b9d3Michael Jurka return; 30045eed3c69b718fe5dedaff0322e2ed4c2f55b9d3Michael Jurka } 30145eed3c69b718fe5dedaff0322e2ed4c2f55b9d3Michael Jurka 30299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (mTaskLoader != null) { 30399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka mTaskLoader.cancel(false); 30499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka mTaskLoader = null; 30599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 306ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka if (mThumbnailLoader != null) { 307ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka mThumbnailLoader.cancel(false); 308ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka mThumbnailLoader = null; 309ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 310cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mLoadedTasks = null; 311cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (mRecentsPanel != null) { 312cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mRecentsPanel.onTaskLoadingCancelled(); 313cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 314cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mFirstScreenful = false; 315cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mState = State.CANCELLED; 316ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 317ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 31880343f646f9686528212f82163a77ef48e30f4c3Michael Jurka private void clearFirstTask() { 31980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka synchronized (mFirstTaskLock) { 32080343f646f9686528212f82163a77ef48e30f4c3Michael Jurka mFirstTask = null; 32180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka mFirstTaskLoaded = false; 32280343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } 32380343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } 32480343f646f9686528212f82163a77ef48e30f4c3Michael Jurka 32580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka public void preloadFirstTask() { 32680343f646f9686528212f82163a77ef48e30f4c3Michael Jurka Thread bgLoad = new Thread() { 32780343f646f9686528212f82163a77ef48e30f4c3Michael Jurka public void run() { 32880343f646f9686528212f82163a77ef48e30f4c3Michael Jurka TaskDescription first = loadFirstTask(); 32980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka synchronized(mFirstTaskLock) { 33080343f646f9686528212f82163a77ef48e30f4c3Michael Jurka if (mCancelPreloadingFirstTask) { 33180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka clearFirstTask(); 33280343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } else { 33380343f646f9686528212f82163a77ef48e30f4c3Michael Jurka mFirstTask = first; 33480343f646f9686528212f82163a77ef48e30f4c3Michael Jurka mFirstTaskLoaded = true; 33580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } 33680343f646f9686528212f82163a77ef48e30f4c3Michael Jurka mPreloadingFirstTask = false; 33780343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } 33880343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } 33980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka }; 34080343f646f9686528212f82163a77ef48e30f4c3Michael Jurka synchronized(mFirstTaskLock) { 34180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka if (!mPreloadingFirstTask) { 34280343f646f9686528212f82163a77ef48e30f4c3Michael Jurka clearFirstTask(); 34380343f646f9686528212f82163a77ef48e30f4c3Michael Jurka mPreloadingFirstTask = true; 34480343f646f9686528212f82163a77ef48e30f4c3Michael Jurka bgLoad.start(); 34580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } 34680343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } 34780343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } 34880343f646f9686528212f82163a77ef48e30f4c3Michael Jurka 34980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka public void cancelPreloadingFirstTask() { 35080343f646f9686528212f82163a77ef48e30f4c3Michael Jurka synchronized(mFirstTaskLock) { 35180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka if (mPreloadingFirstTask) { 35280343f646f9686528212f82163a77ef48e30f4c3Michael Jurka mCancelPreloadingFirstTask = true; 35380343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } else { 35480343f646f9686528212f82163a77ef48e30f4c3Michael Jurka clearFirstTask(); 35580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } 35680343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } 35780343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } 35880343f646f9686528212f82163a77ef48e30f4c3Michael Jurka 35980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka boolean mPreloadingFirstTask; 36080343f646f9686528212f82163a77ef48e30f4c3Michael Jurka boolean mCancelPreloadingFirstTask; 36180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka public TaskDescription getFirstTask() { 36280343f646f9686528212f82163a77ef48e30f4c3Michael Jurka while(true) { 36380343f646f9686528212f82163a77ef48e30f4c3Michael Jurka synchronized(mFirstTaskLock) { 36480343f646f9686528212f82163a77ef48e30f4c3Michael Jurka if (mFirstTaskLoaded) { 36580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka return mFirstTask; 36680343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } else if (!mFirstTaskLoaded && !mPreloadingFirstTask) { 36780343f646f9686528212f82163a77ef48e30f4c3Michael Jurka mFirstTask = loadFirstTask(); 36880343f646f9686528212f82163a77ef48e30f4c3Michael Jurka mFirstTaskLoaded = true; 36980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka return mFirstTask; 37080343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } 37180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } 37280343f646f9686528212f82163a77ef48e30f4c3Michael Jurka try { 37380343f646f9686528212f82163a77ef48e30f4c3Michael Jurka Thread.sleep(3); 37480343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } catch (InterruptedException e) { 37580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } 37680343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } 37780343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } 37880343f646f9686528212f82163a77ef48e30f4c3Michael Jurka 37980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka public TaskDescription loadFirstTask() { 38080343f646f9686528212f82163a77ef48e30f4c3Michael Jurka final ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); 38180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka 38282326a98a4507deee89a90654dd0953c459811afKenny Guy final List<ActivityManager.RecentTaskInfo> recentTasks = am.getRecentTasksForUser(1, 3832a764949c943681a4d25a17a0b203a0127a4a486Kenny Guy ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_PROFILES, 38482326a98a4507deee89a90654dd0953c459811afKenny Guy UserHandle.CURRENT.getIdentifier()); 38580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka TaskDescription item = null; 38680343f646f9686528212f82163a77ef48e30f4c3Michael Jurka if (recentTasks.size() > 0) { 38780343f646f9686528212f82163a77ef48e30f4c3Michael Jurka ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(0); 38880343f646f9686528212f82163a77ef48e30f4c3Michael Jurka 38980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka Intent intent = new Intent(recentInfo.baseIntent); 39080343f646f9686528212f82163a77ef48e30f4c3Michael Jurka if (recentInfo.origActivity != null) { 39180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka intent.setComponent(recentInfo.origActivity); 39280343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } 39380343f646f9686528212f82163a77ef48e30f4c3Michael Jurka 39480343f646f9686528212f82163a77ef48e30f4c3Michael Jurka // Don't load the current home activity. 39580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka if (isCurrentHomeActivity(intent.getComponent(), null)) { 39680343f646f9686528212f82163a77ef48e30f4c3Michael Jurka return null; 39780343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } 39880343f646f9686528212f82163a77ef48e30f4c3Michael Jurka 39980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka // Don't load ourselves 40080343f646f9686528212f82163a77ef48e30f4c3Michael Jurka if (intent.getComponent().getPackageName().equals(mContext.getPackageName())) { 40180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka return null; 40280343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } 40380343f646f9686528212f82163a77ef48e30f4c3Michael Jurka 40480343f646f9686528212f82163a77ef48e30f4c3Michael Jurka item = createTaskDescription(recentInfo.id, 40580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka recentInfo.persistentId, recentInfo.baseIntent, 4061f1cce1725a2fceee4162aec23518d42c78d6669Kenny Guy recentInfo.origActivity, recentInfo.description, 4071f1cce1725a2fceee4162aec23518d42c78d6669Kenny Guy recentInfo.userId); 4082a430cccc2a801da72e212d5c5b6a63676e4860cMichael Jurka if (item != null) { 4092a430cccc2a801da72e212d5c5b6a63676e4860cMichael Jurka loadThumbnailAndIcon(item); 4102a430cccc2a801da72e212d5c5b6a63676e4860cMichael Jurka } 41180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka return item; 41280343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } 41380343f646f9686528212f82163a77ef48e30f4c3Michael Jurka return null; 41480343f646f9686528212f82163a77ef48e30f4c3Michael Jurka } 41580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka 41699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka public void loadTasksInBackground() { 417cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka loadTasksInBackground(false); 418cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 419cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka public void loadTasksInBackground(final boolean zeroeth) { 420cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (mState != State.CANCELLED) { 421cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka return; 422cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 423cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mState = State.LOADING; 424cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mFirstScreenful = true; 425cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 42699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka final LinkedBlockingQueue<TaskDescription> tasksWaitingForThumbnails = 42799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka new LinkedBlockingQueue<TaskDescription>(); 42899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka mTaskLoader = new AsyncTask<Void, ArrayList<TaskDescription>, Void>() { 42999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka @Override 43099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka protected void onProgressUpdate(ArrayList<TaskDescription>... values) { 43199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (!isCancelled()) { 43299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka ArrayList<TaskDescription> newTasks = values[0]; 43399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka // do a callback to RecentsPanelView to let it know we have more values 43499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka // how do we let it know we're all done? just always call back twice 435cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (mRecentsPanel != null) { 436cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mRecentsPanel.onTasksLoaded(newTasks, mFirstScreenful); 437cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 438cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (mLoadedTasks == null) { 439cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mLoadedTasks = new ArrayList<TaskDescription>(); 440cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 441cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mLoadedTasks.addAll(newTasks); 442cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mFirstScreenful = false; 44399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 44499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 44599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka @Override 44699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka protected Void doInBackground(Void... params) { 44799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka // We load in two stages: first, we update progress with just the first screenful 44899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka // of items. Then, we update with the rest of the items 44999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka final int origPri = Process.getThreadPriority(Process.myTid()); 450252030b79ce10d926f8ed4f752c7ddfa714dc100Glenn Kasten Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 45199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka final PackageManager pm = mContext.getPackageManager(); 45299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka final ActivityManager am = (ActivityManager) 453ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka mContext.getSystemService(Context.ACTIVITY_SERVICE); 454ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 45599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka final List<ActivityManager.RecentTaskInfo> recentTasks = 45682326a98a4507deee89a90654dd0953c459811afKenny Guy am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE 4572a764949c943681a4d25a17a0b203a0127a4a486Kenny Guy | ActivityManager.RECENT_INCLUDE_PROFILES); 45899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka int numTasks = recentTasks.size(); 45999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN) 46099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka .addCategory(Intent.CATEGORY_HOME).resolveActivityInfo(pm, 0); 461ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 46299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka boolean firstScreenful = true; 46399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka ArrayList<TaskDescription> tasks = new ArrayList<TaskDescription>(); 464ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 46599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka // skip the first task - assume it's either the home screen or the current activity. 466cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka final int first = 0; 46799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka for (int i = first, index = 0; i < numTasks && (index < MAX_TASKS); ++i) { 46899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (isCancelled()) { 46999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka break; 47099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 47199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i); 472cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 473cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka Intent intent = new Intent(recentInfo.baseIntent); 474cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (recentInfo.origActivity != null) { 475cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka intent.setComponent(recentInfo.origActivity); 476cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 477cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 478cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka // Don't load the current home activity. 479cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (isCurrentHomeActivity(intent.getComponent(), homeInfo)) { 480cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka continue; 481cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 482cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 483cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka // Don't load ourselves 484cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (intent.getComponent().getPackageName().equals(mContext.getPackageName())) { 485cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka continue; 486cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 487cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 48899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka TaskDescription item = createTaskDescription(recentInfo.id, 48999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka recentInfo.persistentId, recentInfo.baseIntent, 4901f1cce1725a2fceee4162aec23518d42c78d6669Kenny Guy recentInfo.origActivity, recentInfo.description, 4911f1cce1725a2fceee4162aec23518d42c78d6669Kenny Guy recentInfo.userId); 49299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka 49399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (item != null) { 49499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka while (true) { 49599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka try { 49699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka tasksWaitingForThumbnails.put(item); 49799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka break; 49899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } catch (InterruptedException e) { 49999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 50099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 50199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka tasks.add(item); 50299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (firstScreenful && tasks.size() == mNumTasksInFirstScreenful) { 50399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka publishProgress(tasks); 50499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka tasks = new ArrayList<TaskDescription>(); 50599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka firstScreenful = false; 50699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka //break; 50799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 50899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka ++index; 50999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 51099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 511ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 51299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (!isCancelled()) { 51399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka publishProgress(tasks); 51499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (firstScreenful) { 51599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka // always should publish two updates 51699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka publishProgress(new ArrayList<TaskDescription>()); 51799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 51899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 519ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 52099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka while (true) { 52199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka try { 52299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka tasksWaitingForThumbnails.put(new TaskDescription()); 52399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka break; 52499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } catch (InterruptedException e) { 52599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 52699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 527ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 52899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka Process.setThreadPriority(origPri); 52999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka return null; 530ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 53199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka }; 53299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka mTaskLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 53399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka loadThumbnailsAndIconsInBackground(tasksWaitingForThumbnails); 534ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 535ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 53699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka private void loadThumbnailsAndIconsInBackground( 53799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka final BlockingQueue<TaskDescription> tasksWaitingForThumbnails) { 53899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka // continually read items from tasksWaitingForThumbnails and load 53999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka // thumbnails and icons for them. finish thread when cancelled or there 54099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka // is a null item in tasksWaitingForThumbnails 54199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka mThumbnailLoader = new AsyncTask<Void, TaskDescription, Void>() { 54299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka @Override 54399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka protected void onProgressUpdate(TaskDescription... values) { 54499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (!isCancelled()) { 54599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka TaskDescription td = values[0]; 546cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (td.isNull()) { // end sentinel 547cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mState = State.LOADED; 548cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } else { 549cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (mRecentsPanel != null) { 550cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mRecentsPanel.onTaskThumbnailLoaded(td); 551cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 552cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 55399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 55499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 55599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka @Override 55699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka protected Void doInBackground(Void... params) { 55799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka final int origPri = Process.getThreadPriority(Process.myTid()); 558252030b79ce10d926f8ed4f752c7ddfa714dc100Glenn Kasten Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 55999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka 56099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka while (true) { 56199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (isCancelled()) { 56299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka break; 563ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 56499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka TaskDescription td = null; 56599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka while (td == null) { 56699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka try { 56799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka td = tasksWaitingForThumbnails.take(); 56899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } catch (InterruptedException e) { 569ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 570ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 571cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (td.isNull()) { // end sentinel 572cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka publishProgress(td); 57399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka break; 57499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 57599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka loadThumbnailAndIcon(td); 576cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 577cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka publishProgress(td); 57899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 57999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka 58099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka Process.setThreadPriority(origPri); 58199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka return null; 582ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 58399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka }; 58499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka mThumbnailLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 585ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 586ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka} 587