RecentTasksLoader.java revision d0d4bb84595d48116b3751b14efbc39388a78882
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; 20ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.content.ComponentName; 21ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.content.Context; 22ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.content.Intent; 23ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.content.pm.ActivityInfo; 24ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.content.pm.PackageManager; 25ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.content.pm.ResolveInfo; 26ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.content.res.Resources; 27ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.graphics.Bitmap; 28ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.graphics.Canvas; 29ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.graphics.drawable.Drawable; 30ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.os.AsyncTask; 31ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.os.Handler; 32ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.os.Process; 33f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackbornimport android.os.UserHandle; 34ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport android.util.Log; 35cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurkaimport android.view.MotionEvent; 36cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurkaimport android.view.View; 37ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 38ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport com.android.systemui.R; 39ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport com.android.systemui.statusbar.phone.PhoneStatusBar; 40ab48b681401628a191a4a90d4906fa88edde95baMichael Jurkaimport com.android.systemui.statusbar.tablet.TabletStatusBar; 41ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 4299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurkaimport java.util.ArrayList; 4399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurkaimport java.util.List; 4499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurkaimport java.util.concurrent.BlockingQueue; 4599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurkaimport java.util.concurrent.LinkedBlockingQueue; 4699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka 47cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurkapublic class RecentTasksLoader implements View.OnTouchListener { 48ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka static final String TAG = "RecentTasksLoader"; 49ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false; 50ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 51ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka private static final int DISPLAY_TASKS = 20; 52ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka private static final int MAX_TASKS = DISPLAY_TASKS + 1; // allow extra for non-apps 53ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 54ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka private Context mContext; 55ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka private RecentsPanelView mRecentsPanel; 56cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka private TaskDescription mFirstTask; 57cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka private boolean mFirstTaskLoaded; 58ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 5999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka private AsyncTask<Void, ArrayList<TaskDescription>, Void> mTaskLoader; 6099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka private AsyncTask<Void, TaskDescription, Void> mThumbnailLoader; 61cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka private Handler mHandler; 62ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 63ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka private int mIconDpi; 64ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka private Bitmap mDefaultThumbnailBackground; 6599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka private Bitmap mDefaultIconBackground; 66cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka private int mNumTasksInFirstScreenful = Integer.MAX_VALUE; 67cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 68cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka private boolean mFirstScreenful; 69cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka private ArrayList<TaskDescription> mLoadedTasks; 70cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 71cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka private enum State { LOADING, LOADED, CANCELLED }; 72cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka private State mState = State.CANCELLED; 73cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 74cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka public TaskDescription getFirstTask() { 75cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka while (!mFirstTaskLoaded) { 76cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (mState == State.CANCELLED) { 77cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka loadTasksInBackground(); 78cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 79cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka try { 80cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (mState == State.LOADED) { 81cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka break; 82cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 83cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka Thread.sleep(5); 84cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } catch (InterruptedException e) { 85cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 86cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 87cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka return mFirstTask; 88cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 89ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 90ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka public RecentTasksLoader(Context context) { 91ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka mContext = context; 92cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mHandler = new Handler(); 93ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 94ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka final Resources res = context.getResources(); 95ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 96ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka // get the icon size we want -- on tablets, we use bigger icons 97ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka boolean isTablet = res.getBoolean(R.bool.config_recents_interface_for_tablets); 98ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka if (isTablet) { 9943e34f61f0014400583895525fa08274615a21d2Winson Chung ActivityManager activityManager = 10043e34f61f0014400583895525fa08274615a21d2Winson Chung (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 10143e34f61f0014400583895525fa08274615a21d2Winson Chung mIconDpi = activityManager.getLauncherLargeIconDensity(); 102ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } else { 103ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka mIconDpi = res.getDisplayMetrics().densityDpi; 104ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 105ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 10699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka // Render default icon (just a blank image) 10799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka int defaultIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.app_icon_size); 10899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka int iconSize = (int) (defaultIconSize * mIconDpi / res.getDisplayMetrics().densityDpi); 10999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka mDefaultIconBackground = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888); 11099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka 111ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka // Render the default thumbnail background 11299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka int thumbnailWidth = 11399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width); 11499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka int thumbnailHeight = 11599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height); 116ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka int color = res.getColor(R.drawable.status_bar_recents_app_thumbnail_background); 117ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 11899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka mDefaultThumbnailBackground = 11999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka Bitmap.createBitmap(thumbnailWidth, thumbnailHeight, Bitmap.Config.ARGB_8888); 120ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka Canvas c = new Canvas(mDefaultThumbnailBackground); 121ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka c.drawColor(color); 122ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 123ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 124cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka public void setRecentsPanel(RecentsPanelView newRecentsPanel, RecentsPanelView caller) { 125cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka // Only allow clearing mRecentsPanel if the caller is the current recentsPanel 126cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (newRecentsPanel != null || mRecentsPanel == caller) { 127cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mRecentsPanel = newRecentsPanel; 128cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (mRecentsPanel != null) { 129cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mNumTasksInFirstScreenful = mRecentsPanel.numItemsInOneScreenful(); 130cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 131cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 132ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 133ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 134412cba8aa10231cdf515d9400a754e8a16a8eb3dMichael Jurka public Bitmap getDefaultThumbnail() { 135412cba8aa10231cdf515d9400a754e8a16a8eb3dMichael Jurka return mDefaultThumbnailBackground; 136412cba8aa10231cdf515d9400a754e8a16a8eb3dMichael Jurka } 137412cba8aa10231cdf515d9400a754e8a16a8eb3dMichael Jurka 13899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka public Bitmap getDefaultIcon() { 13999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka return mDefaultIconBackground; 14099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 14199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka 142cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka public ArrayList<TaskDescription> getLoadedTasks() { 143cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka return mLoadedTasks; 144cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 145cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael 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, 163cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka ComponentName origActivity, CharSequence description) { 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(); 169ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) 170ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka | Intent.FLAG_ACTIVITY_NEW_TASK); 171ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0); 172ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka if (resolveInfo != null) { 173ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka final ActivityInfo info = resolveInfo.activityInfo; 174ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka final String title = info.loadLabel(pm).toString(); 175ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 17699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (title != null && title.length() > 0) { 177ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka if (DEBUG) Log.v(TAG, "creating activity desc for id=" 178ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka + persistentTaskId + ", label=" + title); 179ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 180ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka TaskDescription item = new TaskDescription(taskId, 181ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka persistentTaskId, resolveInfo, baseIntent, info.packageName, 182ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka description); 183ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka item.setLabel(title); 184ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 185ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka return item; 186ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } else { 187ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka if (DEBUG) Log.v(TAG, "SKIPPING item " + persistentTaskId); 188ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 189ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 190ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka return null; 191ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 192ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 19399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka void loadThumbnailAndIcon(TaskDescription td) { 194ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka final ActivityManager am = (ActivityManager) 195ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka mContext.getSystemService(Context.ACTIVITY_SERVICE); 19699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka final PackageManager pm = mContext.getPackageManager(); 197ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka ActivityManager.TaskThumbnails thumbs = am.getTaskThumbnails(td.persistentTaskId); 19899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka Drawable icon = getFullResIcon(td.resolveInfo, pm); 199ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 200ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka if (DEBUG) Log.v(TAG, "Loaded bitmap for task " 201ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka + td + ": " + thumbs.mainThumbnail); 202ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka synchronized (td) { 203ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka if (thumbs != null && thumbs.mainThumbnail != null) { 204ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka td.setThumbnail(thumbs.mainThumbnail); 205ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } else { 206ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka td.setThumbnail(mDefaultThumbnailBackground); 207ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 20899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (icon != null) { 20999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka td.setIcon(icon); 21099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 21199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka td.setLoaded(true); 212ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 213ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 214ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 215ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka Drawable getFullResDefaultActivityIcon() { 216ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka return getFullResIcon(Resources.getSystem(), 217ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka com.android.internal.R.mipmap.sym_def_app_icon); 218ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 219ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 220ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka Drawable getFullResIcon(Resources resources, int iconId) { 221ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka try { 222ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka return resources.getDrawableForDensity(iconId, mIconDpi); 223ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } catch (Resources.NotFoundException e) { 224ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka return getFullResDefaultActivityIcon(); 225ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 226ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 227ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 228ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka private Drawable getFullResIcon(ResolveInfo info, PackageManager packageManager) { 229ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka Resources resources; 230ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka try { 231ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka resources = packageManager.getResourcesForApplication( 232ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka info.activityInfo.applicationInfo); 233ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } catch (PackageManager.NameNotFoundException e) { 234ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka resources = null; 235ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 236ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka if (resources != null) { 237ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka int iconId = info.activityInfo.getIconResource(); 238ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka if (iconId != 0) { 239ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka return getFullResIcon(resources, iconId); 240ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 241ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 242ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka return getFullResDefaultActivityIcon(); 243ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 244ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 245cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka Runnable mPreloadTasksRunnable = new Runnable() { 246cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka public void run() { 247cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka loadTasksInBackground(); 248cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 249cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka }; 250cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 251cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka // additional optimization when we have software system buttons - start loading the recent 252cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka // tasks on touch down 253cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka @Override 254cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka public boolean onTouch(View v, MotionEvent ev) { 255cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka int action = ev.getAction() & MotionEvent.ACTION_MASK; 256cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (action == MotionEvent.ACTION_DOWN) { 257d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka preloadRecentTasksList(); 258cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } else if (action == MotionEvent.ACTION_CANCEL) { 259d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka cancelPreloadingRecentTasksList(); 260cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } else if (action == MotionEvent.ACTION_UP) { 261cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka // Remove the preloader if we haven't called it yet 262cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mHandler.removeCallbacks(mPreloadTasksRunnable); 263cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (!v.isPressed()) { 264cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka cancelLoadingThumbnailsAndIcons(); 265cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 266cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 267cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 268cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka return false; 269cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 270cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 271d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka public void preloadRecentTasksList() { 272d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka mHandler.post(mPreloadTasksRunnable); 273d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka } 274d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka 275d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka public void cancelPreloadingRecentTasksList() { 276d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka cancelLoadingThumbnailsAndIcons(); 277d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka mHandler.removeCallbacks(mPreloadTasksRunnable); 278d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka } 279d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka 280cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka public void cancelLoadingThumbnailsAndIcons(RecentsPanelView caller) { 281cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka // Only oblige this request if it comes from the current RecentsPanel 282cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka // (eg when you rotate, the old RecentsPanel request should be ignored) 283cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (mRecentsPanel == caller) { 284cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka cancelLoadingThumbnailsAndIcons(); 285cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 286cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 287cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 288cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 289cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka private void cancelLoadingThumbnailsAndIcons() { 29099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (mTaskLoader != null) { 29199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka mTaskLoader.cancel(false); 29299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka mTaskLoader = null; 29399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 294ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka if (mThumbnailLoader != null) { 295ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka mThumbnailLoader.cancel(false); 296ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka mThumbnailLoader = null; 297ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 298cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mLoadedTasks = null; 299cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mFirstTask = null; 300cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mFirstTaskLoaded = false; 301cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (mRecentsPanel != null) { 302cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mRecentsPanel.onTaskLoadingCancelled(); 303cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 304cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mFirstScreenful = false; 305cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mState = State.CANCELLED; 306ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 307ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 30899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka public void loadTasksInBackground() { 309cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka loadTasksInBackground(false); 310cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 311cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka public void loadTasksInBackground(final boolean zeroeth) { 312cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (mState != State.CANCELLED) { 313cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka return; 314cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 315cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mState = State.LOADING; 316cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mFirstScreenful = true; 317cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 31899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka final LinkedBlockingQueue<TaskDescription> tasksWaitingForThumbnails = 31999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka new LinkedBlockingQueue<TaskDescription>(); 32099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka mTaskLoader = new AsyncTask<Void, ArrayList<TaskDescription>, Void>() { 32199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka @Override 32299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka protected void onProgressUpdate(ArrayList<TaskDescription>... values) { 32399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (!isCancelled()) { 32499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka ArrayList<TaskDescription> newTasks = values[0]; 32599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka // do a callback to RecentsPanelView to let it know we have more values 32699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka // how do we let it know we're all done? just always call back twice 327cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (mRecentsPanel != null) { 328cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mRecentsPanel.onTasksLoaded(newTasks, mFirstScreenful); 329cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 330cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (mLoadedTasks == null) { 331cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mLoadedTasks = new ArrayList<TaskDescription>(); 332cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 333cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mLoadedTasks.addAll(newTasks); 334cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mFirstScreenful = false; 33599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 33699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 33799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka @Override 33899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka protected Void doInBackground(Void... params) { 33999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka // We load in two stages: first, we update progress with just the first screenful 34099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka // of items. Then, we update with the rest of the items 34199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka final int origPri = Process.getThreadPriority(Process.myTid()); 342252030b79ce10d926f8ed4f752c7ddfa714dc100Glenn Kasten Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 34399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka final PackageManager pm = mContext.getPackageManager(); 34499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka final ActivityManager am = (ActivityManager) 345ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka mContext.getSystemService(Context.ACTIVITY_SERVICE); 346ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 34799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka final List<ActivityManager.RecentTaskInfo> recentTasks = 348d2e99565f5377a9afa839eab738b10e7b5e0a761Amith Yamasani am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE); 34999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka int numTasks = recentTasks.size(); 35099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN) 35199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka .addCategory(Intent.CATEGORY_HOME).resolveActivityInfo(pm, 0); 352ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 35399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka boolean firstScreenful = true; 35499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka ArrayList<TaskDescription> tasks = new ArrayList<TaskDescription>(); 355ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 35699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka // skip the first task - assume it's either the home screen or the current activity. 357cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka final int first = 0; 35899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka for (int i = first, index = 0; i < numTasks && (index < MAX_TASKS); ++i) { 35999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (isCancelled()) { 36099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka break; 36199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 36299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i); 363cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 364cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka Intent intent = new Intent(recentInfo.baseIntent); 365cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (recentInfo.origActivity != null) { 366cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka intent.setComponent(recentInfo.origActivity); 367cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 368cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 369cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka // Don't load the current home activity. 370cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (isCurrentHomeActivity(intent.getComponent(), homeInfo)) { 371cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (index == 0) { 372cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mFirstTaskLoaded = true; 373cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 374cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka continue; 375cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 376cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 377cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka // Don't load ourselves 378cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (intent.getComponent().getPackageName().equals(mContext.getPackageName())) { 379cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka continue; 380cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 381cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 38299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka TaskDescription item = createTaskDescription(recentInfo.id, 38399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka recentInfo.persistentId, recentInfo.baseIntent, 384cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka recentInfo.origActivity, recentInfo.description); 38599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka 38699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (item != null) { 38799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka while (true) { 38899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka try { 38999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka tasksWaitingForThumbnails.put(item); 39099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka break; 39199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } catch (InterruptedException e) { 39299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 39399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 39499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka tasks.add(item); 39599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (firstScreenful && tasks.size() == mNumTasksInFirstScreenful) { 39699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka publishProgress(tasks); 39799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka tasks = new ArrayList<TaskDescription>(); 39899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka firstScreenful = false; 39999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka //break; 40099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 40199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka ++index; 40299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 40399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 404ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 40599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (!isCancelled()) { 40699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka publishProgress(tasks); 40799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (firstScreenful) { 40899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka // always should publish two updates 40999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka publishProgress(new ArrayList<TaskDescription>()); 41099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 41199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 412ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 41399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka while (true) { 41499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka try { 41599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka tasksWaitingForThumbnails.put(new TaskDescription()); 41699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka break; 41799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } catch (InterruptedException e) { 41899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 41999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 420ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 42199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka Process.setThreadPriority(origPri); 42299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka return null; 423ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 42499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka }; 42599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka mTaskLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 42699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka loadThumbnailsAndIconsInBackground(tasksWaitingForThumbnails); 427ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 428ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka 42999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka private void loadThumbnailsAndIconsInBackground( 43099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka final BlockingQueue<TaskDescription> tasksWaitingForThumbnails) { 43199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka // continually read items from tasksWaitingForThumbnails and load 43299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka // thumbnails and icons for them. finish thread when cancelled or there 43399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka // is a null item in tasksWaitingForThumbnails 43499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka mThumbnailLoader = new AsyncTask<Void, TaskDescription, Void>() { 43599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka @Override 43699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka protected void onProgressUpdate(TaskDescription... values) { 43799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (!isCancelled()) { 43899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka TaskDescription td = values[0]; 439cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (td.isNull()) { // end sentinel 440cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mState = State.LOADED; 441cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } else { 442cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (mRecentsPanel != null) { 443cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mRecentsPanel.onTaskThumbnailLoaded(td); 444cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 445cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka } 44699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 44799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 44899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka @Override 44999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka protected Void doInBackground(Void... params) { 45099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka final int origPri = Process.getThreadPriority(Process.myTid()); 451252030b79ce10d926f8ed4f752c7ddfa714dc100Glenn Kasten Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 45299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka 45399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka while (true) { 45499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka if (isCancelled()) { 45599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka break; 456ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 45799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka TaskDescription td = null; 45899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka while (td == null) { 45999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka try { 46099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka td = tasksWaitingForThumbnails.take(); 46199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } catch (InterruptedException e) { 462ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 463ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 464cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (td.isNull()) { // end sentinel 465cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka publishProgress(td); 46699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka break; 46799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 46899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka loadThumbnailAndIcon(td); 469cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka 470cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka if (!mFirstTaskLoaded) { 471cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mFirstTask = td; 472cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mFirstTaskLoaded = true; 47399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 474cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka publishProgress(td); 47599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka } 47699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka 47799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka Process.setThreadPriority(origPri); 47899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka return null; 479ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 48099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka }; 481cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mFirstTask = null; 482cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka mFirstTaskLoaded = false; 48399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka mThumbnailLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 484ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka } 485ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka} 486