Loading packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java +11 −20 Original line number Diff line number Diff line Loading @@ -23,35 +23,26 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.os.SystemProperties; import android.os.UserHandle; import android.util.DisplayMetrics; import android.util.Log; import android.view.Display; import android.view.Surface; import android.view.SurfaceControl; import android.view.View; import android.view.WindowManager; import com.android.systemui.R; import com.android.systemui.RecentsComponent; import com.android.systemui.SystemUI; import java.util.List; Loading Loading @@ -113,6 +104,7 @@ public class AlternateRecentsComponent { final static String sRecentsService = "com.android.systemui.recents.RecentsService"; Context mContext; SystemServicesProxy mSystemServicesProxy; // Recents service binding Messenger mService = null; Loading @@ -127,6 +119,7 @@ public class AlternateRecentsComponent { public AlternateRecentsComponent(Context context) { mContext = context; mSystemServicesProxy = new SystemServicesProxy(context); mMessenger = new Messenger(new RecentsMessageHandler()); } Loading Loading @@ -219,17 +212,16 @@ public class AlternateRecentsComponent { /** Loads the first task thumbnail */ Bitmap loadFirstTaskThumbnail() { ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RecentTaskInfo> tasks = am.getRecentTasksForUser(1, ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_PROFILES, SystemServicesProxy ssp = mSystemServicesProxy; List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(1, UserHandle.CURRENT.getIdentifier()); for (ActivityManager.RecentTaskInfo t : tasks) { // Skip tasks in the home stack if (am.isInHomeStack(t.persistentId)) { if (ssp.isInHomeStack(t.persistentId)) { return null; } Bitmap thumbnail = am.getTaskTopThumbnail(t.persistentId); Bitmap thumbnail = ssp.getTaskThumbnail(t.persistentId); return thumbnail; } return null; Loading @@ -237,13 +229,12 @@ public class AlternateRecentsComponent { /** Returns whether there is a first task */ boolean hasFirstTask() { ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RecentTaskInfo> tasks = am.getRecentTasksForUser(1, ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_PROFILES, SystemServicesProxy ssp = mSystemServicesProxy; List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(1, UserHandle.CURRENT.getIdentifier()); for (ActivityManager.RecentTaskInfo t : tasks) { // Skip tasks in the home stack if (am.isInHomeStack(t.persistentId)) { if (ssp.isInHomeStack(t.persistentId)) { continue; } Loading Loading @@ -294,8 +285,8 @@ public class AlternateRecentsComponent { // If Recents is the front most activity, then we should just communicate with it directly // to launch the first task or dismiss itself ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1); SystemServicesProxy ssp = mSystemServicesProxy; List<ActivityManager.RunningTaskInfo> tasks = ssp.getRunningTasks(1); if (!tasks.isEmpty()) { ComponentName topActivity = tasks.get(0).topActivity; Loading packages/SystemUI/src/com/android/systemui/recents/Constants.java +6 −2 Original line number Diff line number Diff line Loading @@ -31,6 +31,12 @@ public class Constants { public static final boolean EnableToggleNewRecentsActivity = false; // This disables the bitmap and icon caches to public static final boolean DisableBackgroundCache = false; // For debugging, this enables us to create mock recents tasks public static final boolean EnableSystemServicesProxy = false; // For debugging, this defines the number of mock recents packages to create public static final int SystemServicesProxyMockPackageCount = 12; // For debugging, this defines the number of mock recents tasks to create public static final int SystemServicesProxyMockTaskCount = 75; // Timing certain paths public static final String TimeRecentsStartupKey = "startup"; Loading Loading @@ -73,8 +79,6 @@ public class Constants { public static class RecentsTaskLoader { // XXX: This should be calculated on the first load public static final int PreloadFirstTasksCount = 5; // For debugging, this allows us to multiply the number of cards for each task public static final int TaskEntryMultiplier = 1; } public static class TaskStackView { Loading packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +1 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.SystemService; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; Loading packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java +158 −167 Original line number Diff line number Diff line Loading @@ -20,7 +20,6 @@ import android.app.ActivityManager; import android.content.ComponentCallbacks2; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; Loading Loading @@ -109,6 +108,7 @@ class TaskResourceLoader implements Runnable { Handler mLoadThreadHandler; Handler mMainThreadHandler; SystemServicesProxy mSystemServicesProxy; TaskResourceLoadQueue mLoadQueue; DrawableLruCache mIconCache; BitmapLruCache mThumbnailCache; Loading @@ -135,6 +135,7 @@ class TaskResourceLoader implements Runnable { Console.log(Constants.DebugFlags.App.TaskDataLoader, "[TaskResourceLoader|start]"); mContext = context; mCancelled = false; mSystemServicesProxy = new SystemServicesProxy(context); // Notify the load thread to start loading synchronized(mLoadThread) { mLoadThread.notifyAll(); Loading @@ -146,6 +147,7 @@ class TaskResourceLoader implements Runnable { Console.log(Constants.DebugFlags.App.TaskDataLoader, "[TaskResourceLoader|stop]"); // Mark as cancelled for the thread to pick up mCancelled = true; mSystemServicesProxy = null; // If we are waiting for the load queue for more tasks, then we can just reset the // Context now, since nothing is using it if (mWaitingOnLoadQueue) { Loading Loading @@ -175,12 +177,13 @@ class TaskResourceLoader implements Runnable { } } } else { SystemServicesProxy ssp = mSystemServicesProxy; // Load the next item from the queue Pair<Task, Boolean> nextTaskData = mLoadQueue.nextTask(); final Task t = nextTaskData.first; final boolean forceLoadTask = nextTaskData.second; if (t != null) { try { Drawable loadIcon = mIconCache.get(t.key); Bitmap loadThumbnail = mThumbnailCache.get(t.key); Console.log(Constants.DebugFlags.App.TaskDataLoader, Loading @@ -189,10 +192,8 @@ class TaskResourceLoader implements Runnable { " forceLoad: " + forceLoadTask); // Load the icon if (loadIcon == null || forceLoadTask) { PackageManager pm = mContext.getPackageManager(); ActivityInfo info = pm.getActivityInfo(t.key.baseIntent.getComponent(), PackageManager.GET_META_DATA); Drawable icon = info.loadIcon(pm); ActivityInfo info = ssp.getActivityInfo(t.key.baseIntent.getComponent()); Drawable icon = ssp.getActivityIcon(info); if (!mCancelled) { if (icon != null) { Console.log(Constants.DebugFlags.App.TaskDataLoader, Loading @@ -205,9 +206,7 @@ class TaskResourceLoader implements Runnable { } // Load the thumbnail if (loadThumbnail == null || forceLoadTask) { ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); Bitmap thumbnail = am.getTaskTopThumbnail(t.key.id); Bitmap thumbnail = ssp.getTaskThumbnail(t.key.id); if (!mCancelled) { if (thumbnail != null) { Console.log(Constants.DebugFlags.App.TaskDataLoader, Loading @@ -233,9 +232,6 @@ class TaskResourceLoader implements Runnable { } }); } } catch (PackageManager.NameNotFoundException ne) { ne.printStackTrace(); } } // If there are no other items in the list, then just wait until something is added Loading Loading @@ -296,6 +292,7 @@ class BitmapLruCache extends LruCache<Task.TaskKey, Bitmap> { public class RecentsTaskLoader { static RecentsTaskLoader sInstance; SystemServicesProxy mSystemServicesProxy; DrawableLruCache mIconCache; BitmapLruCache mThumbnailCache; TaskResourceLoadQueue mLoadQueue; Loading Loading @@ -324,7 +321,8 @@ public class RecentsTaskLoader { "[RecentsTaskLoader|init]", "thumbnailCache: " + thumbnailCacheSize + " iconCache: " + iconCacheSize); // Initialize the cache and loaders // Initialize the proxy, cache and loaders mSystemServicesProxy = new SystemServicesProxy(context); mLoadQueue = new TaskResourceLoadQueue(); mIconCache = new DrawableLruCache(iconCacheSize); mThumbnailCache = new BitmapLruCache(thumbnailCacheSize); Loading Loading @@ -358,6 +356,11 @@ public class RecentsTaskLoader { return sInstance; } /** Returns the system services proxy */ public SystemServicesProxy getSystemServicesProxy() { return mSystemServicesProxy; } /** Reload the set of recent tasks */ SpaceNode reload(Context context, int preloadCount) { Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|reload]"); Loading @@ -367,16 +370,12 @@ public class RecentsTaskLoader { SpaceNode root = new SpaceNode(context); root.setStack(stack); try { long t1 = System.currentTimeMillis(); PackageManager pm = context.getPackageManager(); ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); // Get the recent tasks List<ActivityManager.RecentTaskInfo> tasks = am.getRecentTasksForUser(25, ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_PROFILES, UserHandle.CURRENT.getIdentifier()); SystemServicesProxy ssp = mSystemServicesProxy; List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(25, UserHandle.CURRENT.getIdentifier()); Collections.reverse(tasks); Console.log(Constants.DebugFlags.App.TimeSystemCalls, "[RecentsTaskLoader|getRecentTasks]", Loading @@ -390,7 +389,7 @@ public class RecentsTaskLoader { ActivityManager.RecentTaskInfo t = iter.next(); // Skip tasks in the home stack if (am.isInHomeStack(t.persistentId)) { if (ssp.isInHomeStack(t.persistentId)) { iter.remove(); continue; } Loading @@ -406,9 +405,8 @@ public class RecentsTaskLoader { int taskCount = tasks.size(); for (int i = 0; i < taskCount; i++) { ActivityManager.RecentTaskInfo t = tasks.get(i); ActivityInfo info = pm.getActivityInfo(t.baseIntent.getComponent(), PackageManager.GET_META_DATA); String title = info.loadLabel(pm).toString(); ActivityInfo info = ssp.getActivityInfo(t.baseIntent.getComponent()); String title = ssp.getActivityLabel(info); boolean isForemostTask = (i == (taskCount - 1)); // Preload the specified number of apps Loading Loading @@ -437,7 +435,7 @@ public class RecentsTaskLoader { } } if (task.icon == null) { task.icon = info.loadIcon(pm); task.icon = ssp.getActivityIcon(info); if (task.icon != null) { mIconCache.put(task.key, task.icon); } else { Loading @@ -458,7 +456,7 @@ public class RecentsTaskLoader { if (task.thumbnail == null) { Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|loadingTaskThumbnail]"); task.thumbnail = am.getTaskTopThumbnail(t.id); task.thumbnail = ssp.getTaskThumbnail(task.key.id); if (task.thumbnail != null) { mThumbnailCache.put(task.key, task.thumbnail); } else { Loading @@ -466,22 +464,18 @@ public class RecentsTaskLoader { } } // Create as many tasks a we want to multiply by for (int j = 0; j < Constants.Values.RecentsTaskLoader.TaskEntryMultiplier; j++) { // Add the task to the stack Console.log(Constants.DebugFlags.App.TaskDataLoader, " [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName()); stack.addTask(task); } } else { // Create as many tasks a we want to multiply by for (int j = 0; j < Constants.Values.RecentsTaskLoader.TaskEntryMultiplier; j++) { // Add the task to the stack Console.log(Constants.DebugFlags.App.TaskDataLoader, " [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName()); stack.addTask(new Task(t.persistentId, (t.id > -1), t.baseIntent, title, null, null)); } } } Console.log(Constants.DebugFlags.App.TimeSystemCalls, "[RecentsTaskLoader|getAllTaskTopThumbnail]", "" + (System.currentTimeMillis() - t1) + "ms"); Loading @@ -499,9 +493,6 @@ public class RecentsTaskLoader { } } */ } catch (Exception e) { e.printStackTrace(); } // Start the task loader mLoader.start(context); Loading packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java 0 → 100644 +182 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.recents; import android.app.ActivityManager; import android.app.ActivityOptions; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import java.util.ArrayList; import java.util.List; /** * Acts as a shim around the real system services that we need to access data from, and provides * a point of injection when testing UI. */ public class SystemServicesProxy { ActivityManager mAm; PackageManager mPm; String mPackage; Bitmap mDummyIcon; /** Private constructor */ public SystemServicesProxy(Context context) { mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); mPm = context.getPackageManager(); mPackage = context.getPackageName(); if (Constants.DebugFlags.App.EnableSystemServicesProxy) { // Create a dummy icon mDummyIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8); Canvas c = new Canvas(mDummyIcon); c.drawColor(0xFFFF0000); c.setBitmap(null); } } /** Returns a list of the recents tasks */ public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numTasks, int userId) { if (mAm == null) return null; // If we are mocking, then create some recent tasks if (Constants.DebugFlags.App.EnableSystemServicesProxy) { ArrayList<ActivityManager.RecentTaskInfo> tasks = new ArrayList<ActivityManager.RecentTaskInfo>(); int count = Math.min(numTasks, Constants.DebugFlags.App.SystemServicesProxyMockTaskCount); for (int i = 0; i < count; i++) { // Create a dummy component name int packageIndex = i % Constants.DebugFlags.App.SystemServicesProxyMockPackageCount; ComponentName cn = new ComponentName("com.android.test" + packageIndex, "com.android.test" + i + ".Activity"); // Create the recent task info ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo(); rti.id = rti.persistentId = i; rti.baseIntent = new Intent(); rti.baseIntent.setComponent(cn); rti.description = rti.activityLabel = "Recent Task"; rti.activityIcon = Bitmap.createBitmap(mDummyIcon); tasks.add(rti); } return tasks; } return mAm.getRecentTasksForUser(numTasks, ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_PROFILES, userId); } /** Returns a list of the running tasks */ public List<ActivityManager.RunningTaskInfo> getRunningTasks(int numTasks) { if (mAm == null) return null; return mAm.getRunningTasks(numTasks); } /** Returns whether the specified task is in the home stack */ public boolean isInHomeStack(int taskId) { if (mAm == null) return false; // If we are mocking, then just return false if (Constants.DebugFlags.App.EnableSystemServicesProxy) { return false; } return mAm.isInHomeStack(taskId); } /** Returns the top task thumbnail for the given task id */ public Bitmap getTaskThumbnail(int taskId) { if (mAm == null) return null; // If we are mocking, then just return a dummy thumbnail if (Constants.DebugFlags.App.EnableSystemServicesProxy) { Bitmap thumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(thumbnail); c.drawColor(0xFF00ff00); c.setBitmap(null); return thumbnail; } return mAm.getTaskTopThumbnail(taskId); } /** Moves a task to the front with the specified activity options */ public void moveTaskToFront(int taskId, ActivityOptions opts) { if (mAm == null) return; if (Constants.DebugFlags.App.EnableSystemServicesProxy) return; if (opts != null) { mAm.moveTaskToFront(taskId, ActivityManager.MOVE_TASK_WITH_HOME, opts.toBundle()); } else { mAm.moveTaskToFront(taskId, ActivityManager.MOVE_TASK_WITH_HOME); } } /** Removes the task and kills the process */ public void removeTask(int taskId) { if (mAm == null) return; if (Constants.DebugFlags.App.EnableSystemServicesProxy) return; mAm.removeTask(taskId, ActivityManager.REMOVE_TASK_KILL_PROCESS); } /** Returns the activity info for a given component name */ public ActivityInfo getActivityInfo(ComponentName cn) { if (mPm == null) return null; if (Constants.DebugFlags.App.EnableSystemServicesProxy) return null; try { return mPm.getActivityInfo(cn, PackageManager.GET_META_DATA); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); return null; } } /** Returns the activity label */ public String getActivityLabel(ActivityInfo info) { if (mPm == null) return null; // If we are mocking, then return a mock label if (Constants.DebugFlags.App.EnableSystemServicesProxy) { return "Recent Task"; } return info.loadLabel(mPm).toString(); } /** Returns the activity icon */ public Drawable getActivityIcon(ActivityInfo info) { if (mPm == null) return null; // If we are mocking, then return a mock label if (Constants.DebugFlags.App.EnableSystemServicesProxy) { return new ColorDrawable(0xFFff0000); } return info.loadIcon(mPm); } } Loading
packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java +11 −20 Original line number Diff line number Diff line Loading @@ -23,35 +23,26 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.os.SystemProperties; import android.os.UserHandle; import android.util.DisplayMetrics; import android.util.Log; import android.view.Display; import android.view.Surface; import android.view.SurfaceControl; import android.view.View; import android.view.WindowManager; import com.android.systemui.R; import com.android.systemui.RecentsComponent; import com.android.systemui.SystemUI; import java.util.List; Loading Loading @@ -113,6 +104,7 @@ public class AlternateRecentsComponent { final static String sRecentsService = "com.android.systemui.recents.RecentsService"; Context mContext; SystemServicesProxy mSystemServicesProxy; // Recents service binding Messenger mService = null; Loading @@ -127,6 +119,7 @@ public class AlternateRecentsComponent { public AlternateRecentsComponent(Context context) { mContext = context; mSystemServicesProxy = new SystemServicesProxy(context); mMessenger = new Messenger(new RecentsMessageHandler()); } Loading Loading @@ -219,17 +212,16 @@ public class AlternateRecentsComponent { /** Loads the first task thumbnail */ Bitmap loadFirstTaskThumbnail() { ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RecentTaskInfo> tasks = am.getRecentTasksForUser(1, ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_PROFILES, SystemServicesProxy ssp = mSystemServicesProxy; List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(1, UserHandle.CURRENT.getIdentifier()); for (ActivityManager.RecentTaskInfo t : tasks) { // Skip tasks in the home stack if (am.isInHomeStack(t.persistentId)) { if (ssp.isInHomeStack(t.persistentId)) { return null; } Bitmap thumbnail = am.getTaskTopThumbnail(t.persistentId); Bitmap thumbnail = ssp.getTaskThumbnail(t.persistentId); return thumbnail; } return null; Loading @@ -237,13 +229,12 @@ public class AlternateRecentsComponent { /** Returns whether there is a first task */ boolean hasFirstTask() { ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RecentTaskInfo> tasks = am.getRecentTasksForUser(1, ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_PROFILES, SystemServicesProxy ssp = mSystemServicesProxy; List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(1, UserHandle.CURRENT.getIdentifier()); for (ActivityManager.RecentTaskInfo t : tasks) { // Skip tasks in the home stack if (am.isInHomeStack(t.persistentId)) { if (ssp.isInHomeStack(t.persistentId)) { continue; } Loading Loading @@ -294,8 +285,8 @@ public class AlternateRecentsComponent { // If Recents is the front most activity, then we should just communicate with it directly // to launch the first task or dismiss itself ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1); SystemServicesProxy ssp = mSystemServicesProxy; List<ActivityManager.RunningTaskInfo> tasks = ssp.getRunningTasks(1); if (!tasks.isEmpty()) { ComponentName topActivity = tasks.get(0).topActivity; Loading
packages/SystemUI/src/com/android/systemui/recents/Constants.java +6 −2 Original line number Diff line number Diff line Loading @@ -31,6 +31,12 @@ public class Constants { public static final boolean EnableToggleNewRecentsActivity = false; // This disables the bitmap and icon caches to public static final boolean DisableBackgroundCache = false; // For debugging, this enables us to create mock recents tasks public static final boolean EnableSystemServicesProxy = false; // For debugging, this defines the number of mock recents packages to create public static final int SystemServicesProxyMockPackageCount = 12; // For debugging, this defines the number of mock recents tasks to create public static final int SystemServicesProxyMockTaskCount = 75; // Timing certain paths public static final String TimeRecentsStartupKey = "startup"; Loading Loading @@ -73,8 +79,6 @@ public class Constants { public static class RecentsTaskLoader { // XXX: This should be calculated on the first load public static final int PreloadFirstTasksCount = 5; // For debugging, this allows us to multiply the number of cards for each task public static final int TaskEntryMultiplier = 1; } public static class TaskStackView { Loading
packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +1 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.SystemService; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; Loading
packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java +158 −167 Original line number Diff line number Diff line Loading @@ -20,7 +20,6 @@ import android.app.ActivityManager; import android.content.ComponentCallbacks2; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; Loading Loading @@ -109,6 +108,7 @@ class TaskResourceLoader implements Runnable { Handler mLoadThreadHandler; Handler mMainThreadHandler; SystemServicesProxy mSystemServicesProxy; TaskResourceLoadQueue mLoadQueue; DrawableLruCache mIconCache; BitmapLruCache mThumbnailCache; Loading @@ -135,6 +135,7 @@ class TaskResourceLoader implements Runnable { Console.log(Constants.DebugFlags.App.TaskDataLoader, "[TaskResourceLoader|start]"); mContext = context; mCancelled = false; mSystemServicesProxy = new SystemServicesProxy(context); // Notify the load thread to start loading synchronized(mLoadThread) { mLoadThread.notifyAll(); Loading @@ -146,6 +147,7 @@ class TaskResourceLoader implements Runnable { Console.log(Constants.DebugFlags.App.TaskDataLoader, "[TaskResourceLoader|stop]"); // Mark as cancelled for the thread to pick up mCancelled = true; mSystemServicesProxy = null; // If we are waiting for the load queue for more tasks, then we can just reset the // Context now, since nothing is using it if (mWaitingOnLoadQueue) { Loading Loading @@ -175,12 +177,13 @@ class TaskResourceLoader implements Runnable { } } } else { SystemServicesProxy ssp = mSystemServicesProxy; // Load the next item from the queue Pair<Task, Boolean> nextTaskData = mLoadQueue.nextTask(); final Task t = nextTaskData.first; final boolean forceLoadTask = nextTaskData.second; if (t != null) { try { Drawable loadIcon = mIconCache.get(t.key); Bitmap loadThumbnail = mThumbnailCache.get(t.key); Console.log(Constants.DebugFlags.App.TaskDataLoader, Loading @@ -189,10 +192,8 @@ class TaskResourceLoader implements Runnable { " forceLoad: " + forceLoadTask); // Load the icon if (loadIcon == null || forceLoadTask) { PackageManager pm = mContext.getPackageManager(); ActivityInfo info = pm.getActivityInfo(t.key.baseIntent.getComponent(), PackageManager.GET_META_DATA); Drawable icon = info.loadIcon(pm); ActivityInfo info = ssp.getActivityInfo(t.key.baseIntent.getComponent()); Drawable icon = ssp.getActivityIcon(info); if (!mCancelled) { if (icon != null) { Console.log(Constants.DebugFlags.App.TaskDataLoader, Loading @@ -205,9 +206,7 @@ class TaskResourceLoader implements Runnable { } // Load the thumbnail if (loadThumbnail == null || forceLoadTask) { ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); Bitmap thumbnail = am.getTaskTopThumbnail(t.key.id); Bitmap thumbnail = ssp.getTaskThumbnail(t.key.id); if (!mCancelled) { if (thumbnail != null) { Console.log(Constants.DebugFlags.App.TaskDataLoader, Loading @@ -233,9 +232,6 @@ class TaskResourceLoader implements Runnable { } }); } } catch (PackageManager.NameNotFoundException ne) { ne.printStackTrace(); } } // If there are no other items in the list, then just wait until something is added Loading Loading @@ -296,6 +292,7 @@ class BitmapLruCache extends LruCache<Task.TaskKey, Bitmap> { public class RecentsTaskLoader { static RecentsTaskLoader sInstance; SystemServicesProxy mSystemServicesProxy; DrawableLruCache mIconCache; BitmapLruCache mThumbnailCache; TaskResourceLoadQueue mLoadQueue; Loading Loading @@ -324,7 +321,8 @@ public class RecentsTaskLoader { "[RecentsTaskLoader|init]", "thumbnailCache: " + thumbnailCacheSize + " iconCache: " + iconCacheSize); // Initialize the cache and loaders // Initialize the proxy, cache and loaders mSystemServicesProxy = new SystemServicesProxy(context); mLoadQueue = new TaskResourceLoadQueue(); mIconCache = new DrawableLruCache(iconCacheSize); mThumbnailCache = new BitmapLruCache(thumbnailCacheSize); Loading Loading @@ -358,6 +356,11 @@ public class RecentsTaskLoader { return sInstance; } /** Returns the system services proxy */ public SystemServicesProxy getSystemServicesProxy() { return mSystemServicesProxy; } /** Reload the set of recent tasks */ SpaceNode reload(Context context, int preloadCount) { Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|reload]"); Loading @@ -367,16 +370,12 @@ public class RecentsTaskLoader { SpaceNode root = new SpaceNode(context); root.setStack(stack); try { long t1 = System.currentTimeMillis(); PackageManager pm = context.getPackageManager(); ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); // Get the recent tasks List<ActivityManager.RecentTaskInfo> tasks = am.getRecentTasksForUser(25, ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_PROFILES, UserHandle.CURRENT.getIdentifier()); SystemServicesProxy ssp = mSystemServicesProxy; List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(25, UserHandle.CURRENT.getIdentifier()); Collections.reverse(tasks); Console.log(Constants.DebugFlags.App.TimeSystemCalls, "[RecentsTaskLoader|getRecentTasks]", Loading @@ -390,7 +389,7 @@ public class RecentsTaskLoader { ActivityManager.RecentTaskInfo t = iter.next(); // Skip tasks in the home stack if (am.isInHomeStack(t.persistentId)) { if (ssp.isInHomeStack(t.persistentId)) { iter.remove(); continue; } Loading @@ -406,9 +405,8 @@ public class RecentsTaskLoader { int taskCount = tasks.size(); for (int i = 0; i < taskCount; i++) { ActivityManager.RecentTaskInfo t = tasks.get(i); ActivityInfo info = pm.getActivityInfo(t.baseIntent.getComponent(), PackageManager.GET_META_DATA); String title = info.loadLabel(pm).toString(); ActivityInfo info = ssp.getActivityInfo(t.baseIntent.getComponent()); String title = ssp.getActivityLabel(info); boolean isForemostTask = (i == (taskCount - 1)); // Preload the specified number of apps Loading Loading @@ -437,7 +435,7 @@ public class RecentsTaskLoader { } } if (task.icon == null) { task.icon = info.loadIcon(pm); task.icon = ssp.getActivityIcon(info); if (task.icon != null) { mIconCache.put(task.key, task.icon); } else { Loading @@ -458,7 +456,7 @@ public class RecentsTaskLoader { if (task.thumbnail == null) { Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|loadingTaskThumbnail]"); task.thumbnail = am.getTaskTopThumbnail(t.id); task.thumbnail = ssp.getTaskThumbnail(task.key.id); if (task.thumbnail != null) { mThumbnailCache.put(task.key, task.thumbnail); } else { Loading @@ -466,22 +464,18 @@ public class RecentsTaskLoader { } } // Create as many tasks a we want to multiply by for (int j = 0; j < Constants.Values.RecentsTaskLoader.TaskEntryMultiplier; j++) { // Add the task to the stack Console.log(Constants.DebugFlags.App.TaskDataLoader, " [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName()); stack.addTask(task); } } else { // Create as many tasks a we want to multiply by for (int j = 0; j < Constants.Values.RecentsTaskLoader.TaskEntryMultiplier; j++) { // Add the task to the stack Console.log(Constants.DebugFlags.App.TaskDataLoader, " [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName()); stack.addTask(new Task(t.persistentId, (t.id > -1), t.baseIntent, title, null, null)); } } } Console.log(Constants.DebugFlags.App.TimeSystemCalls, "[RecentsTaskLoader|getAllTaskTopThumbnail]", "" + (System.currentTimeMillis() - t1) + "ms"); Loading @@ -499,9 +493,6 @@ public class RecentsTaskLoader { } } */ } catch (Exception e) { e.printStackTrace(); } // Start the task loader mLoader.start(context); Loading
packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java 0 → 100644 +182 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.recents; import android.app.ActivityManager; import android.app.ActivityOptions; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import java.util.ArrayList; import java.util.List; /** * Acts as a shim around the real system services that we need to access data from, and provides * a point of injection when testing UI. */ public class SystemServicesProxy { ActivityManager mAm; PackageManager mPm; String mPackage; Bitmap mDummyIcon; /** Private constructor */ public SystemServicesProxy(Context context) { mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); mPm = context.getPackageManager(); mPackage = context.getPackageName(); if (Constants.DebugFlags.App.EnableSystemServicesProxy) { // Create a dummy icon mDummyIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8); Canvas c = new Canvas(mDummyIcon); c.drawColor(0xFFFF0000); c.setBitmap(null); } } /** Returns a list of the recents tasks */ public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numTasks, int userId) { if (mAm == null) return null; // If we are mocking, then create some recent tasks if (Constants.DebugFlags.App.EnableSystemServicesProxy) { ArrayList<ActivityManager.RecentTaskInfo> tasks = new ArrayList<ActivityManager.RecentTaskInfo>(); int count = Math.min(numTasks, Constants.DebugFlags.App.SystemServicesProxyMockTaskCount); for (int i = 0; i < count; i++) { // Create a dummy component name int packageIndex = i % Constants.DebugFlags.App.SystemServicesProxyMockPackageCount; ComponentName cn = new ComponentName("com.android.test" + packageIndex, "com.android.test" + i + ".Activity"); // Create the recent task info ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo(); rti.id = rti.persistentId = i; rti.baseIntent = new Intent(); rti.baseIntent.setComponent(cn); rti.description = rti.activityLabel = "Recent Task"; rti.activityIcon = Bitmap.createBitmap(mDummyIcon); tasks.add(rti); } return tasks; } return mAm.getRecentTasksForUser(numTasks, ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_PROFILES, userId); } /** Returns a list of the running tasks */ public List<ActivityManager.RunningTaskInfo> getRunningTasks(int numTasks) { if (mAm == null) return null; return mAm.getRunningTasks(numTasks); } /** Returns whether the specified task is in the home stack */ public boolean isInHomeStack(int taskId) { if (mAm == null) return false; // If we are mocking, then just return false if (Constants.DebugFlags.App.EnableSystemServicesProxy) { return false; } return mAm.isInHomeStack(taskId); } /** Returns the top task thumbnail for the given task id */ public Bitmap getTaskThumbnail(int taskId) { if (mAm == null) return null; // If we are mocking, then just return a dummy thumbnail if (Constants.DebugFlags.App.EnableSystemServicesProxy) { Bitmap thumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(thumbnail); c.drawColor(0xFF00ff00); c.setBitmap(null); return thumbnail; } return mAm.getTaskTopThumbnail(taskId); } /** Moves a task to the front with the specified activity options */ public void moveTaskToFront(int taskId, ActivityOptions opts) { if (mAm == null) return; if (Constants.DebugFlags.App.EnableSystemServicesProxy) return; if (opts != null) { mAm.moveTaskToFront(taskId, ActivityManager.MOVE_TASK_WITH_HOME, opts.toBundle()); } else { mAm.moveTaskToFront(taskId, ActivityManager.MOVE_TASK_WITH_HOME); } } /** Removes the task and kills the process */ public void removeTask(int taskId) { if (mAm == null) return; if (Constants.DebugFlags.App.EnableSystemServicesProxy) return; mAm.removeTask(taskId, ActivityManager.REMOVE_TASK_KILL_PROCESS); } /** Returns the activity info for a given component name */ public ActivityInfo getActivityInfo(ComponentName cn) { if (mPm == null) return null; if (Constants.DebugFlags.App.EnableSystemServicesProxy) return null; try { return mPm.getActivityInfo(cn, PackageManager.GET_META_DATA); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); return null; } } /** Returns the activity label */ public String getActivityLabel(ActivityInfo info) { if (mPm == null) return null; // If we are mocking, then return a mock label if (Constants.DebugFlags.App.EnableSystemServicesProxy) { return "Recent Task"; } return info.loadLabel(mPm).toString(); } /** Returns the activity icon */ public Drawable getActivityIcon(ActivityInfo info) { if (mPm == null) return null; // If we are mocking, then return a mock label if (Constants.DebugFlags.App.EnableSystemServicesProxy) { return new ColorDrawable(0xFFff0000); } return info.loadIcon(mPm); } }