RecentTasksLoader.java revision b0e49fc93c146d7ddc8e1f27ec67306a71168510
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;
3380343f646f9686528212f82163a77ef48e30f4c3Michael Jurkaimport 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 Jurka
4199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurkaimport java.util.ArrayList;
4299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurkaimport java.util.List;
4399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurkaimport java.util.concurrent.BlockingQueue;
4499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurkaimport java.util.concurrent.LinkedBlockingQueue;
4599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka
46cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurkapublic class RecentTasksLoader implements View.OnTouchListener {
47ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    static final String TAG = "RecentTasksLoader";
48b0e49fc93c146d7ddc8e1f27ec67306a71168510John Spurlock    static final boolean DEBUG = PhoneStatusBar.DEBUG || false;
49ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
50ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    private static final int DISPLAY_TASKS = 20;
51ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    private static final int MAX_TASKS = DISPLAY_TASKS + 1; // allow extra for non-apps
52ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
53ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    private Context mContext;
54ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    private RecentsPanelView mRecentsPanel;
5580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka
5680343f646f9686528212f82163a77ef48e30f4c3Michael Jurka    private Object mFirstTaskLock = new Object();
57cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    private TaskDescription mFirstTask;
58cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    private boolean mFirstTaskLoaded;
59ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
6099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka    private AsyncTask<Void, ArrayList<TaskDescription>, Void> mTaskLoader;
6199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka    private AsyncTask<Void, TaskDescription, Void> mThumbnailLoader;
62cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    private Handler mHandler;
63ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
64ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    private int mIconDpi;
65ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    private Bitmap mDefaultThumbnailBackground;
6699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka    private Bitmap mDefaultIconBackground;
67cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    private int mNumTasksInFirstScreenful = Integer.MAX_VALUE;
68cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka
69cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    private boolean mFirstScreenful;
70cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    private ArrayList<TaskDescription> mLoadedTasks;
71cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka
72cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    private enum State { LOADING, LOADED, CANCELLED };
73cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    private State mState = State.CANCELLED;
74cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka
7580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka
7680343f646f9686528212f82163a77ef48e30f4c3Michael Jurka    private static RecentTasksLoader sInstance;
7780343f646f9686528212f82163a77ef48e30f4c3Michael Jurka    public static RecentTasksLoader getInstance(Context context) {
7880343f646f9686528212f82163a77ef48e30f4c3Michael Jurka        if (sInstance == null) {
7980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            sInstance = new RecentTasksLoader(context);
80cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        }
8180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka        return sInstance;
82cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    }
83ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
8480343f646f9686528212f82163a77ef48e30f4c3Michael Jurka    private RecentTasksLoader(Context context) {
85ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        mContext = context;
86cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        mHandler = new Handler();
87ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
88ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        final Resources res = context.getResources();
89ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
90ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        // get the icon size we want -- on tablets, we use bigger icons
91ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        boolean isTablet = res.getBoolean(R.bool.config_recents_interface_for_tablets);
92ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        if (isTablet) {
9343e34f61f0014400583895525fa08274615a21d2Winson Chung            ActivityManager activityManager =
9443e34f61f0014400583895525fa08274615a21d2Winson Chung                    (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
9543e34f61f0014400583895525fa08274615a21d2Winson Chung            mIconDpi = activityManager.getLauncherLargeIconDensity();
96ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        } else {
97ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka            mIconDpi = res.getDisplayMetrics().densityDpi;
98ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        }
99ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
10099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        // Render default icon (just a blank image)
10199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        int defaultIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.app_icon_size);
10299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        int iconSize = (int) (defaultIconSize * mIconDpi / res.getDisplayMetrics().densityDpi);
10399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        mDefaultIconBackground = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
10499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka
105ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        // Render the default thumbnail background
10699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        int thumbnailWidth =
10799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
10899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        int thumbnailHeight =
10999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
110ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        int color = res.getColor(R.drawable.status_bar_recents_app_thumbnail_background);
111ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
11299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        mDefaultThumbnailBackground =
11399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                Bitmap.createBitmap(thumbnailWidth, thumbnailHeight, Bitmap.Config.ARGB_8888);
114ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        Canvas c = new Canvas(mDefaultThumbnailBackground);
115ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        c.drawColor(color);
116ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    }
117ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
118cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    public void setRecentsPanel(RecentsPanelView newRecentsPanel, RecentsPanelView caller) {
119cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        // Only allow clearing mRecentsPanel if the caller is the current recentsPanel
120cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        if (newRecentsPanel != null || mRecentsPanel == caller) {
121cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            mRecentsPanel = newRecentsPanel;
122cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            if (mRecentsPanel != null) {
123cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                mNumTasksInFirstScreenful = mRecentsPanel.numItemsInOneScreenful();
124cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            }
125cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        }
126ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    }
127ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
128412cba8aa10231cdf515d9400a754e8a16a8eb3dMichael Jurka    public Bitmap getDefaultThumbnail() {
129412cba8aa10231cdf515d9400a754e8a16a8eb3dMichael Jurka        return mDefaultThumbnailBackground;
130412cba8aa10231cdf515d9400a754e8a16a8eb3dMichael Jurka    }
131412cba8aa10231cdf515d9400a754e8a16a8eb3dMichael Jurka
13299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka    public Bitmap getDefaultIcon() {
13399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        return mDefaultIconBackground;
13499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka    }
13599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka
136cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    public ArrayList<TaskDescription> getLoadedTasks() {
137cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        return mLoadedTasks;
138cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    }
139cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka
140e57922cc7d96620cab0c296e93b2b9b3a471c331Michael Jurka    public void remove(TaskDescription td) {
141e57922cc7d96620cab0c296e93b2b9b3a471c331Michael Jurka        mLoadedTasks.remove(td);
142e57922cc7d96620cab0c296e93b2b9b3a471c331Michael Jurka    }
143e57922cc7d96620cab0c296e93b2b9b3a471c331Michael Jurka
144cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    public boolean isFirstScreenful() {
145cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        return mFirstScreenful;
146cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    }
147cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka
148cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    private boolean isCurrentHomeActivity(ComponentName component, ActivityInfo homeInfo) {
149cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        if (homeInfo == null) {
150cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            final PackageManager pm = mContext.getPackageManager();
151cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
152cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                .resolveActivityInfo(pm, 0);
153cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        }
154cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        return homeInfo != null
155cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            && homeInfo.packageName.equals(component.getPackageName())
156cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            && homeInfo.name.equals(component.getClassName());
157cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    }
158cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka
159cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    // Create an TaskDescription, returning null if the title or icon is null
160ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    TaskDescription createTaskDescription(int taskId, int persistentTaskId, Intent baseIntent,
161cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            ComponentName origActivity, CharSequence description) {
162ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        Intent intent = new Intent(baseIntent);
163ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        if (origActivity != null) {
164ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka            intent.setComponent(origActivity);
165ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        }
166ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        final PackageManager pm = mContext.getPackageManager();
167ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
168ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka                | Intent.FLAG_ACTIVITY_NEW_TASK);
169ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
170ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        if (resolveInfo != null) {
171ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka            final ActivityInfo info = resolveInfo.activityInfo;
172ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka            final String title = info.loadLabel(pm).toString();
173ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
17499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            if (title != null && title.length() > 0) {
175ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka                if (DEBUG) Log.v(TAG, "creating activity desc for id="
176ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka                        + persistentTaskId + ", label=" + title);
177ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
178ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka                TaskDescription item = new TaskDescription(taskId,
179ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka                        persistentTaskId, resolveInfo, baseIntent, info.packageName,
180ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka                        description);
181ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka                item.setLabel(title);
182ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
183ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka                return item;
184ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka            } else {
185ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka                if (DEBUG) Log.v(TAG, "SKIPPING item " + persistentTaskId);
186ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka            }
187ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        }
188ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        return null;
189ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    }
190ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
19199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka    void loadThumbnailAndIcon(TaskDescription td) {
192ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        final ActivityManager am = (ActivityManager)
193ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka                mContext.getSystemService(Context.ACTIVITY_SERVICE);
19499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        final PackageManager pm = mContext.getPackageManager();
19515491c6a728131e322c45bc440500a8a78e4a410Dianne Hackborn        Bitmap thumbnail = am.getTaskTopThumbnail(td.persistentTaskId);
19699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        Drawable icon = getFullResIcon(td.resolveInfo, pm);
197ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
198ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        if (DEBUG) Log.v(TAG, "Loaded bitmap for task "
19915491c6a728131e322c45bc440500a8a78e4a410Dianne Hackborn                + td + ": " + thumbnail);
200ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        synchronized (td) {
20115491c6a728131e322c45bc440500a8a78e4a410Dianne Hackborn            if (thumbnail != null) {
20215491c6a728131e322c45bc440500a8a78e4a410Dianne Hackborn                td.setThumbnail(thumbnail);
203ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka            } else {
204ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka                td.setThumbnail(mDefaultThumbnailBackground);
205ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka            }
20699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            if (icon != null) {
20799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                td.setIcon(icon);
20899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            }
20999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            td.setLoaded(true);
210ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        }
211ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    }
212ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
213ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    Drawable getFullResDefaultActivityIcon() {
214ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        return getFullResIcon(Resources.getSystem(),
215ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka                com.android.internal.R.mipmap.sym_def_app_icon);
216ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    }
217ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
218ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    Drawable getFullResIcon(Resources resources, int iconId) {
219ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        try {
220ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka            return resources.getDrawableForDensity(iconId, mIconDpi);
221ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        } catch (Resources.NotFoundException e) {
222ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka            return getFullResDefaultActivityIcon();
223ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        }
224ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    }
225ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
226ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    private Drawable getFullResIcon(ResolveInfo info, PackageManager packageManager) {
227ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        Resources resources;
228ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        try {
229ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka            resources = packageManager.getResourcesForApplication(
230ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka                    info.activityInfo.applicationInfo);
231ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        } catch (PackageManager.NameNotFoundException e) {
232ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka            resources = null;
233ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        }
234ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        if (resources != null) {
235ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka            int iconId = info.activityInfo.getIconResource();
236ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka            if (iconId != 0) {
237ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka                return getFullResIcon(resources, iconId);
238ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka            }
239ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        }
240ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        return getFullResDefaultActivityIcon();
241ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    }
242ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
243cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    Runnable mPreloadTasksRunnable = new Runnable() {
244cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            public void run() {
245cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                loadTasksInBackground();
246cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            }
247cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        };
248cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka
249cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    // additional optimization when we have software system buttons - start loading the recent
250cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    // tasks on touch down
251cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    @Override
252cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    public boolean onTouch(View v, MotionEvent ev) {
253cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        int action = ev.getAction() & MotionEvent.ACTION_MASK;
254cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        if (action == MotionEvent.ACTION_DOWN) {
255d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka            preloadRecentTasksList();
256cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        } else if (action == MotionEvent.ACTION_CANCEL) {
257d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka            cancelPreloadingRecentTasksList();
258cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        } else if (action == MotionEvent.ACTION_UP) {
259cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            // Remove the preloader if we haven't called it yet
260cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            mHandler.removeCallbacks(mPreloadTasksRunnable);
261cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            if (!v.isPressed()) {
262cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                cancelLoadingThumbnailsAndIcons();
263cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            }
264cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka
265cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        }
266cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        return false;
267cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    }
268cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka
269d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka    public void preloadRecentTasksList() {
270d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka        mHandler.post(mPreloadTasksRunnable);
271d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka    }
272d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka
273d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka    public void cancelPreloadingRecentTasksList() {
274d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka        cancelLoadingThumbnailsAndIcons();
275d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka        mHandler.removeCallbacks(mPreloadTasksRunnable);
276d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka    }
277d0d4bb84595d48116b3751b14efbc39388a78882Michael Jurka
278cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    public void cancelLoadingThumbnailsAndIcons(RecentsPanelView caller) {
279cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        // Only oblige this request if it comes from the current RecentsPanel
280cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        // (eg when you rotate, the old RecentsPanel request should be ignored)
281cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        if (mRecentsPanel == caller) {
282cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            cancelLoadingThumbnailsAndIcons();
283cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        }
284cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    }
285cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka
286cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka
287cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    private void cancelLoadingThumbnailsAndIcons() {
28845eed3c69b718fe5dedaff0322e2ed4c2f55b9d3Michael Jurka        if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
28945eed3c69b718fe5dedaff0322e2ed4c2f55b9d3Michael Jurka            return;
29045eed3c69b718fe5dedaff0322e2ed4c2f55b9d3Michael Jurka        }
29145eed3c69b718fe5dedaff0322e2ed4c2f55b9d3Michael Jurka
29299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        if (mTaskLoader != null) {
29399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            mTaskLoader.cancel(false);
29499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            mTaskLoader = null;
29599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        }
296ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        if (mThumbnailLoader != null) {
297ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka            mThumbnailLoader.cancel(false);
298ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka            mThumbnailLoader = null;
299ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka        }
300cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        mLoadedTasks = null;
301cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        if (mRecentsPanel != null) {
302cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            mRecentsPanel.onTaskLoadingCancelled();
303cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        }
304cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        mFirstScreenful = false;
305cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        mState = State.CANCELLED;
306ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    }
307ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
30880343f646f9686528212f82163a77ef48e30f4c3Michael Jurka    private void clearFirstTask() {
30980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka        synchronized (mFirstTaskLock) {
31080343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            mFirstTask = null;
31180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            mFirstTaskLoaded = false;
31280343f646f9686528212f82163a77ef48e30f4c3Michael Jurka        }
31380343f646f9686528212f82163a77ef48e30f4c3Michael Jurka    }
31480343f646f9686528212f82163a77ef48e30f4c3Michael Jurka
31580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka    public void preloadFirstTask() {
31680343f646f9686528212f82163a77ef48e30f4c3Michael Jurka        Thread bgLoad = new Thread() {
31780343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            public void run() {
31880343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                TaskDescription first = loadFirstTask();
31980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                synchronized(mFirstTaskLock) {
32080343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                    if (mCancelPreloadingFirstTask) {
32180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                        clearFirstTask();
32280343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                    } else {
32380343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                        mFirstTask = first;
32480343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                        mFirstTaskLoaded = true;
32580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                    }
32680343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                    mPreloadingFirstTask = false;
32780343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                }
32880343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            }
32980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka        };
33080343f646f9686528212f82163a77ef48e30f4c3Michael Jurka        synchronized(mFirstTaskLock) {
33180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            if (!mPreloadingFirstTask) {
33280343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                clearFirstTask();
33380343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                mPreloadingFirstTask = true;
33480343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                bgLoad.start();
33580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            }
33680343f646f9686528212f82163a77ef48e30f4c3Michael Jurka        }
33780343f646f9686528212f82163a77ef48e30f4c3Michael Jurka    }
33880343f646f9686528212f82163a77ef48e30f4c3Michael Jurka
33980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka    public void cancelPreloadingFirstTask() {
34080343f646f9686528212f82163a77ef48e30f4c3Michael Jurka        synchronized(mFirstTaskLock) {
34180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            if (mPreloadingFirstTask) {
34280343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                mCancelPreloadingFirstTask = true;
34380343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            } else {
34480343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                clearFirstTask();
34580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            }
34680343f646f9686528212f82163a77ef48e30f4c3Michael Jurka        }
34780343f646f9686528212f82163a77ef48e30f4c3Michael Jurka    }
34880343f646f9686528212f82163a77ef48e30f4c3Michael Jurka
34980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka    boolean mPreloadingFirstTask;
35080343f646f9686528212f82163a77ef48e30f4c3Michael Jurka    boolean mCancelPreloadingFirstTask;
35180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka    public TaskDescription getFirstTask() {
35280343f646f9686528212f82163a77ef48e30f4c3Michael Jurka        while(true) {
35380343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            synchronized(mFirstTaskLock) {
35480343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                if (mFirstTaskLoaded) {
35580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                    return mFirstTask;
35680343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                } else if (!mFirstTaskLoaded && !mPreloadingFirstTask) {
35780343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                    mFirstTask = loadFirstTask();
35880343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                    mFirstTaskLoaded = true;
35980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                    return mFirstTask;
36080343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                }
36180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            }
36280343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            try {
36380343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                Thread.sleep(3);
36480343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            } catch (InterruptedException e) {
36580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            }
36680343f646f9686528212f82163a77ef48e30f4c3Michael Jurka        }
36780343f646f9686528212f82163a77ef48e30f4c3Michael Jurka    }
36880343f646f9686528212f82163a77ef48e30f4c3Michael Jurka
36980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka    public TaskDescription loadFirstTask() {
37080343f646f9686528212f82163a77ef48e30f4c3Michael Jurka        final ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
37180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka
37280343f646f9686528212f82163a77ef48e30f4c3Michael Jurka        final List<ActivityManager.RecentTaskInfo> recentTasks = am.getRecentTasksForUser(
37380343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                1, ActivityManager.RECENT_IGNORE_UNAVAILABLE, UserHandle.CURRENT.getIdentifier());
37480343f646f9686528212f82163a77ef48e30f4c3Michael Jurka        TaskDescription item = null;
37580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka        if (recentTasks.size() > 0) {
37680343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(0);
37780343f646f9686528212f82163a77ef48e30f4c3Michael Jurka
37880343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            Intent intent = new Intent(recentInfo.baseIntent);
37980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            if (recentInfo.origActivity != null) {
38080343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                intent.setComponent(recentInfo.origActivity);
38180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            }
38280343f646f9686528212f82163a77ef48e30f4c3Michael Jurka
38380343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            // Don't load the current home activity.
38480343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            if (isCurrentHomeActivity(intent.getComponent(), null)) {
38580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                return null;
38680343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            }
38780343f646f9686528212f82163a77ef48e30f4c3Michael Jurka
38880343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            // Don't load ourselves
38980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            if (intent.getComponent().getPackageName().equals(mContext.getPackageName())) {
39080343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                return null;
39180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            }
39280343f646f9686528212f82163a77ef48e30f4c3Michael Jurka
39380343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            item = createTaskDescription(recentInfo.id,
39480343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                    recentInfo.persistentId, recentInfo.baseIntent,
39580343f646f9686528212f82163a77ef48e30f4c3Michael Jurka                    recentInfo.origActivity, recentInfo.description);
3962a430cccc2a801da72e212d5c5b6a63676e4860cMichael Jurka            if (item != null) {
3972a430cccc2a801da72e212d5c5b6a63676e4860cMichael Jurka                loadThumbnailAndIcon(item);
3982a430cccc2a801da72e212d5c5b6a63676e4860cMichael Jurka            }
39980343f646f9686528212f82163a77ef48e30f4c3Michael Jurka            return item;
40080343f646f9686528212f82163a77ef48e30f4c3Michael Jurka        }
40180343f646f9686528212f82163a77ef48e30f4c3Michael Jurka        return null;
40280343f646f9686528212f82163a77ef48e30f4c3Michael Jurka    }
40380343f646f9686528212f82163a77ef48e30f4c3Michael Jurka
40499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka    public void loadTasksInBackground() {
405cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        loadTasksInBackground(false);
406cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    }
407cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka    public void loadTasksInBackground(final boolean zeroeth) {
408cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        if (mState != State.CANCELLED) {
409cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka            return;
410cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        }
411cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        mState = State.LOADING;
412cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka        mFirstScreenful = true;
413cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka
41499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        final LinkedBlockingQueue<TaskDescription> tasksWaitingForThumbnails =
41599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                new LinkedBlockingQueue<TaskDescription>();
41699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        mTaskLoader = new AsyncTask<Void, ArrayList<TaskDescription>, Void>() {
41799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            @Override
41899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            protected void onProgressUpdate(ArrayList<TaskDescription>... values) {
41999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                if (!isCancelled()) {
42099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    ArrayList<TaskDescription> newTasks = values[0];
42199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    // do a callback to RecentsPanelView to let it know we have more values
42299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    // how do we let it know we're all done? just always call back twice
423cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                    if (mRecentsPanel != null) {
424cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                        mRecentsPanel.onTasksLoaded(newTasks, mFirstScreenful);
425cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                    }
426cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                    if (mLoadedTasks == null) {
427cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                        mLoadedTasks = new ArrayList<TaskDescription>();
428cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                    }
429cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                    mLoadedTasks.addAll(newTasks);
430cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                    mFirstScreenful = false;
43199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                }
43299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            }
43399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            @Override
43499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            protected Void doInBackground(Void... params) {
43599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                // We load in two stages: first, we update progress with just the first screenful
43699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                // of items. Then, we update with the rest of the items
43799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                final int origPri = Process.getThreadPriority(Process.myTid());
438252030b79ce10d926f8ed4f752c7ddfa714dc100Glenn Kasten                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
43999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                final PackageManager pm = mContext.getPackageManager();
44099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                final ActivityManager am = (ActivityManager)
441ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka                mContext.getSystemService(Context.ACTIVITY_SERVICE);
442ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
44399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                final List<ActivityManager.RecentTaskInfo> recentTasks =
444d2e99565f5377a9afa839eab738b10e7b5e0a761Amith Yamasani                        am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
44599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                int numTasks = recentTasks.size();
44699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN)
44799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                        .addCategory(Intent.CATEGORY_HOME).resolveActivityInfo(pm, 0);
448ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
44999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                boolean firstScreenful = true;
45099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                ArrayList<TaskDescription> tasks = new ArrayList<TaskDescription>();
451ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
45299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                // skip the first task - assume it's either the home screen or the current activity.
453cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                final int first = 0;
45499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                for (int i = first, index = 0; i < numTasks && (index < MAX_TASKS); ++i) {
45599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    if (isCancelled()) {
45699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                        break;
45799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    }
45899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
459cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka
460cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                    Intent intent = new Intent(recentInfo.baseIntent);
461cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                    if (recentInfo.origActivity != null) {
462cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                        intent.setComponent(recentInfo.origActivity);
463cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                    }
464cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka
465cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                    // Don't load the current home activity.
466cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                    if (isCurrentHomeActivity(intent.getComponent(), homeInfo)) {
467cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                        continue;
468cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                    }
469cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka
470cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                    // Don't load ourselves
471cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                    if (intent.getComponent().getPackageName().equals(mContext.getPackageName())) {
472cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                        continue;
473cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                    }
474cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka
47599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    TaskDescription item = createTaskDescription(recentInfo.id,
47699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                            recentInfo.persistentId, recentInfo.baseIntent,
477cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                            recentInfo.origActivity, recentInfo.description);
47899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka
47999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    if (item != null) {
48099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                        while (true) {
48199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                            try {
48299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                                tasksWaitingForThumbnails.put(item);
48399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                                break;
48499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                            } catch (InterruptedException e) {
48599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                            }
48699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                        }
48799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                        tasks.add(item);
48899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                        if (firstScreenful && tasks.size() == mNumTasksInFirstScreenful) {
48999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                            publishProgress(tasks);
49099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                            tasks = new ArrayList<TaskDescription>();
49199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                            firstScreenful = false;
49299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                            //break;
49399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                        }
49499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                        ++index;
49599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    }
49699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                }
497ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
49899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                if (!isCancelled()) {
49999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    publishProgress(tasks);
50099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    if (firstScreenful) {
50199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                        // always should publish two updates
50299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                        publishProgress(new ArrayList<TaskDescription>());
50399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    }
50499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                }
505ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
50699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                while (true) {
50799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    try {
50899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                        tasksWaitingForThumbnails.put(new TaskDescription());
50999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                        break;
51099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    } catch (InterruptedException e) {
51199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    }
51299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                }
513ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
51499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                Process.setThreadPriority(origPri);
51599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                return null;
516ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka            }
51799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        };
51899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        mTaskLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
51999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        loadThumbnailsAndIconsInBackground(tasksWaitingForThumbnails);
520ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    }
521ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka
52299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka    private void loadThumbnailsAndIconsInBackground(
52399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            final BlockingQueue<TaskDescription> tasksWaitingForThumbnails) {
52499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        // continually read items from tasksWaitingForThumbnails and load
52599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        // thumbnails and icons for them. finish thread when cancelled or there
52699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        // is a null item in tasksWaitingForThumbnails
52799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        mThumbnailLoader = new AsyncTask<Void, TaskDescription, Void>() {
52899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            @Override
52999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            protected void onProgressUpdate(TaskDescription... values) {
53099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                if (!isCancelled()) {
53199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    TaskDescription td = values[0];
532cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                    if (td.isNull()) { // end sentinel
533cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                        mState = State.LOADED;
534cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                    } else {
535cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                        if (mRecentsPanel != null) {
536cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                            mRecentsPanel.onTaskThumbnailLoaded(td);
537cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                        }
538cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                    }
53999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                }
54099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            }
54199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            @Override
54299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka            protected Void doInBackground(Void... params) {
54399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                final int origPri = Process.getThreadPriority(Process.myTid());
544252030b79ce10d926f8ed4f752c7ddfa714dc100Glenn Kasten                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
54599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka
54699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                while (true) {
54799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    if (isCancelled()) {
54899a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                        break;
549ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka                    }
55099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    TaskDescription td = null;
55199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    while (td == null) {
55299a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                        try {
55399a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                            td = tasksWaitingForThumbnails.take();
55499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                        } catch (InterruptedException e) {
555ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka                        }
556ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka                    }
557cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                    if (td.isNull()) { // end sentinel
558cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                        publishProgress(td);
55999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                        break;
56099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    }
56199a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                    loadThumbnailAndIcon(td);
562cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka
563cb2522c86d75fff277dc38ec7e444a5b5f5130eaMichael Jurka                    publishProgress(td);
56499a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                }
56599a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka
56699a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                Process.setThreadPriority(origPri);
56799a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka                return null;
568ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka            }
56999a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        };
57099a9655b9333c3bff6e462b12baa56a5fcd4cb20Michael Jurka        mThumbnailLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
571ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka    }
572ab48b681401628a191a4a90d4906fa88edde95baMichael Jurka}
573