diff options
Diffstat (limited to 'packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java')
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java | 273 |
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); } - } |