summaryrefslogtreecommitdiffstats
path: root/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
diff options
context:
space:
mode:
Diffstat (limited to 'packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java')
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java273
1 files changed, 163 insertions, 110 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index 4145fc4..92f4ca9 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -16,12 +16,6 @@
package com.android.systemui.recent;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
@@ -36,15 +30,17 @@ import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Process;
-import android.os.SystemClock;
-import android.util.DisplayMetrics;
import android.util.Log;
-import android.util.LruCache;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.tablet.TabletStatusBar;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
public class RecentTasksLoader {
static final String TAG = "RecentTasksLoader";
static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
@@ -55,11 +51,14 @@ public class RecentTasksLoader {
private Context mContext;
private RecentsPanelView mRecentsPanel;
- private AsyncTask<Void, Integer, Void> mThumbnailLoader;
+ private AsyncTask<Void, ArrayList<TaskDescription>, Void> mTaskLoader;
+ private AsyncTask<Void, TaskDescription, Void> mThumbnailLoader;
private final Handler mHandler;
private int mIconDpi;
private Bitmap mDefaultThumbnailBackground;
+ private Bitmap mDefaultIconBackground;
+ private int mNumTasksInFirstScreenful;
public RecentTasksLoader(Context context) {
mContext = context;
@@ -76,12 +75,20 @@ public class RecentTasksLoader {
mIconDpi = res.getDisplayMetrics().densityDpi;
}
+ // Render default icon (just a blank image)
+ int defaultIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.app_icon_size);
+ int iconSize = (int) (defaultIconSize * mIconDpi / res.getDisplayMetrics().densityDpi);
+ mDefaultIconBackground = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
+
// Render the default thumbnail background
- int width = (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
- int height = (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
+ int thumbnailWidth =
+ (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
+ int thumbnailHeight =
+ (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
int color = res.getColor(R.drawable.status_bar_recents_app_thumbnail_background);
- mDefaultThumbnailBackground = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ mDefaultThumbnailBackground =
+ Bitmap.createBitmap(thumbnailWidth, thumbnailHeight, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(mDefaultThumbnailBackground);
c.drawColor(color);
@@ -95,12 +102,17 @@ public class RecentTasksLoader {
public void setRecentsPanel(RecentsPanelView recentsPanel) {
mRecentsPanel = recentsPanel;
+ mNumTasksInFirstScreenful = mRecentsPanel.numItemsInOneScreenful();
}
public Bitmap getDefaultThumbnail() {
return mDefaultThumbnailBackground;
}
+ public Bitmap getDefaultIcon() {
+ return mDefaultIconBackground;
+ }
+
// Create an TaskDescription, returning null if the title or icon is null, or if it's the
// home activity
TaskDescription createTaskDescription(int taskId, int persistentTaskId, Intent baseIntent,
@@ -114,6 +126,12 @@ public class RecentTasksLoader {
homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
.resolveActivityInfo(pm, 0);
}
+ // Don't load the current home activity.
+ if (homeInfo != null
+ && homeInfo.packageName.equals(intent.getComponent().getPackageName())
+ && homeInfo.name.equals(intent.getComponent().getClassName())) {
+ return null;
+ }
intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
| Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -121,9 +139,8 @@ public class RecentTasksLoader {
if (resolveInfo != null) {
final ActivityInfo info = resolveInfo.activityInfo;
final String title = info.loadLabel(pm).toString();
- Drawable icon = getFullResIcon(resolveInfo, pm);
- if (title != null && title.length() > 0 && icon != null) {
+ if (title != null && title.length() > 0) {
if (DEBUG) Log.v(TAG, "creating activity desc for id="
+ persistentTaskId + ", label=" + title);
@@ -131,14 +148,6 @@ public class RecentTasksLoader {
persistentTaskId, resolveInfo, baseIntent, info.packageName,
description);
item.setLabel(title);
- item.setIcon(icon);
-
- // Don't load the current home activity.
- if (homeInfo != null
- && homeInfo.packageName.equals(intent.getComponent().getPackageName())
- && homeInfo.name.equals(intent.getComponent().getClassName())) {
- return null;
- }
return item;
} else {
@@ -148,10 +157,12 @@ public class RecentTasksLoader {
return null;
}
- void loadThumbnail(TaskDescription td) {
+ void loadThumbnailAndIcon(TaskDescription td) {
final ActivityManager am = (ActivityManager)
mContext.getSystemService(Context.ACTIVITY_SERVICE);
+ final PackageManager pm = mContext.getPackageManager();
ActivityManager.TaskThumbnails thumbs = am.getTaskThumbnails(td.persistentTaskId);
+ Drawable icon = getFullResIcon(td.resolveInfo, pm);
if (DEBUG) Log.v(TAG, "Loaded bitmap for task "
+ td + ": " + thumbs.mainThumbnail);
@@ -161,6 +172,10 @@ public class RecentTasksLoader {
} else {
td.setThumbnail(mDefaultThumbnailBackground);
}
+ if (icon != null) {
+ td.setIcon(icon);
+ }
+ td.setLoaded(true);
}
}
@@ -194,111 +209,149 @@ public class RecentTasksLoader {
return getFullResDefaultActivityIcon();
}
- public void cancelLoadingThumbnails() {
+ public void cancelLoadingThumbnailsAndIcons() {
+ if (mTaskLoader != null) {
+ mTaskLoader.cancel(false);
+ mTaskLoader = null;
+ }
if (mThumbnailLoader != null) {
mThumbnailLoader.cancel(false);
mThumbnailLoader = null;
}
}
- // return a snapshot of the current list of recent apps
- ArrayList<TaskDescription> getRecentTasks() {
- cancelLoadingThumbnails();
-
- ArrayList<TaskDescription> tasks = new ArrayList<TaskDescription>();
- final PackageManager pm = mContext.getPackageManager();
- final ActivityManager am = (ActivityManager)
+ public void loadTasksInBackground() {
+ // cancel all previous loading of tasks and thumbnails
+ cancelLoadingThumbnailsAndIcons();
+ final LinkedBlockingQueue<TaskDescription> tasksWaitingForThumbnails =
+ new LinkedBlockingQueue<TaskDescription>();
+ final ArrayList<TaskDescription> taskDescriptionsWaitingToLoad =
+ new ArrayList<TaskDescription>();
+ mTaskLoader = new AsyncTask<Void, ArrayList<TaskDescription>, Void>() {
+ @Override
+ protected void onProgressUpdate(ArrayList<TaskDescription>... values) {
+ if (!isCancelled()) {
+ ArrayList<TaskDescription> newTasks = values[0];
+ // do a callback to RecentsPanelView to let it know we have more values
+ // how do we let it know we're all done? just always call back twice
+ mRecentsPanel.onTasksLoaded(newTasks);
+ }
+ }
+ @Override
+ protected Void doInBackground(Void... params) {
+ // We load in two stages: first, we update progress with just the first screenful
+ // of items. Then, we update with the rest of the items
+ final int origPri = Process.getThreadPriority(Process.myTid());
+ Process.setThreadPriority(Process.THREAD_GROUP_BG_NONINTERACTIVE);
+ final PackageManager pm = mContext.getPackageManager();
+ final ActivityManager am = (ActivityManager)
mContext.getSystemService(Context.ACTIVITY_SERVICE);
- final List<ActivityManager.RecentTaskInfo> recentTasks =
- am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
+ final List<ActivityManager.RecentTaskInfo> recentTasks =
+ am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
+ int numTasks = recentTasks.size();
+ ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME).resolveActivityInfo(pm, 0);
- ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
- .resolveActivityInfo(pm, 0);
+ boolean firstScreenful = true;
+ ArrayList<TaskDescription> tasks = new ArrayList<TaskDescription>();
- HashSet<Integer> recentTasksToKeepInCache = new HashSet<Integer>();
- int numTasks = recentTasks.size();
+ // skip the first task - assume it's either the home screen or the current activity.
+ final int first = 1;
+ for (int i = first, index = 0; i < numTasks && (index < MAX_TASKS); ++i) {
+ if (isCancelled()) {
+ break;
+ }
+ final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
+ TaskDescription item = createTaskDescription(recentInfo.id,
+ recentInfo.persistentId, recentInfo.baseIntent,
+ recentInfo.origActivity, recentInfo.description, homeInfo);
+
+ if (item != null) {
+ while (true) {
+ try {
+ tasksWaitingForThumbnails.put(item);
+ break;
+ } catch (InterruptedException e) {
+ }
+ }
+ tasks.add(item);
+ if (firstScreenful && tasks.size() == mNumTasksInFirstScreenful) {
+ publishProgress(tasks);
+ tasks = new ArrayList<TaskDescription>();
+ firstScreenful = false;
+ //break;
+ }
+ ++index;
+ }
+ }
- // skip the first task - assume it's either the home screen or the current activity.
- final int first = 1;
- recentTasksToKeepInCache.add(recentTasks.get(0).persistentId);
- for (int i = first, index = 0; i < numTasks && (index < MAX_TASKS); ++i) {
- final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
+ if (!isCancelled()) {
+ publishProgress(tasks);
+ if (firstScreenful) {
+ // always should publish two updates
+ publishProgress(new ArrayList<TaskDescription>());
+ }
+ }
- TaskDescription item = createTaskDescription(recentInfo.id,
- recentInfo.persistentId, recentInfo.baseIntent,
- recentInfo.origActivity, recentInfo.description, homeInfo);
+ while (true) {
+ try {
+ tasksWaitingForThumbnails.put(new TaskDescription());
+ break;
+ } catch (InterruptedException e) {
+ }
+ }
- if (item != null) {
- tasks.add(item);
- ++index;
+ Process.setThreadPriority(origPri);
+ return null;
}
- }
-
- // when we're not using the TaskDescription cache, we load the thumbnails in the
- // background
- loadThumbnailsInBackground(new ArrayList<TaskDescription>(tasks));
- return tasks;
+ };
+ mTaskLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ loadThumbnailsAndIconsInBackground(tasksWaitingForThumbnails);
}
- private void loadThumbnailsInBackground(final ArrayList<TaskDescription> descriptions) {
- if (descriptions.size() > 0) {
- if (DEBUG) Log.v(TAG, "Showing " + descriptions.size() + " tasks");
- loadThumbnail(descriptions.get(0));
- if (descriptions.size() > 1) {
- mThumbnailLoader = new AsyncTask<Void, Integer, Void>() {
- @Override
- protected void onProgressUpdate(Integer... values) {
- final TaskDescription td = descriptions.get(values[0]);
- if (!isCancelled()) {
- mRecentsPanel.onTaskThumbnailLoaded(td);
- }
- // This is to prevent the loader thread from getting ahead
- // of our UI updates.
- mHandler.post(new Runnable() {
- @Override public void run() {
- synchronized (td) {
- td.notifyAll();
- }
- }
- });
+ private void loadThumbnailsAndIconsInBackground(
+ final BlockingQueue<TaskDescription> tasksWaitingForThumbnails) {
+ // continually read items from tasksWaitingForThumbnails and load
+ // thumbnails and icons for them. finish thread when cancelled or there
+ // is a null item in tasksWaitingForThumbnails
+ mThumbnailLoader = new AsyncTask<Void, TaskDescription, Void>() {
+ @Override
+ protected void onProgressUpdate(TaskDescription... values) {
+ if (!isCancelled()) {
+ TaskDescription td = values[0];
+ mRecentsPanel.onTaskThumbnailLoaded(td);
+ }
+ }
+ @Override
+ protected Void doInBackground(Void... params) {
+ final int origPri = Process.getThreadPriority(Process.myTid());
+ Process.setThreadPriority(Process.THREAD_GROUP_BG_NONINTERACTIVE);
+
+ while (true) {
+ if (isCancelled()) {
+ break;
}
-
- @Override
- protected Void doInBackground(Void... params) {
- final int origPri = Process.getThreadPriority(Process.myTid());
- Process.setThreadPriority(Process.THREAD_GROUP_BG_NONINTERACTIVE);
- long nextTime = SystemClock.uptimeMillis();
- for (int i=1; i<descriptions.size(); i++) {
- TaskDescription td = descriptions.get(i);
- loadThumbnail(td);
- long now = SystemClock.uptimeMillis();
- nextTime += 0;
- if (nextTime > now) {
- try {
- Thread.sleep(nextTime-now);
- } catch (InterruptedException e) {
- }
- }
-
- if (isCancelled()) {
- break;
- }
- synchronized (td) {
- publishProgress(i);
- try {
- td.wait(500);
- } catch (InterruptedException e) {
- }
- }
+ TaskDescription td = null;
+ while (td == null) {
+ try {
+ td = tasksWaitingForThumbnails.take();
+ } catch (InterruptedException e) {
}
- Process.setThreadPriority(origPri);
- return null;
}
- };
- mThumbnailLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ if (td.isNull()) {
+ break;
+ }
+ loadThumbnailAndIcon(td);
+ synchronized(td) {
+ publishProgress(td);
+ }
+ }
+
+ Process.setThreadPriority(origPri);
+ return null;
}
- }
+ };
+ mThumbnailLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
-
}