From a10370fc2eb8eb95631592160c5f6281b9d75722 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Wed, 2 Apr 2014 12:25:04 -0700 Subject: [PATCH] Adding system service proxy to help test UI/performance. Change-Id: I29851ff7b7ced0a69b041e5aa5c9070fc4ab43a5 --- .../recents/AlternateRecentsComponent.java | 31 +- .../android/systemui/recents/Constants.java | 8 +- .../systemui/recents/RecentsActivity.java | 1 + .../systemui/recents/RecentsTaskLoader.java | 329 +++++++++--------- .../systemui/recents/SystemServicesProxy.java | 182 ++++++++++ .../android/systemui/recents/model/Task.java | 10 +- .../systemui/recents/views/RecentsView.java | 12 +- .../systemui/recents/views/TaskStackView.java | 12 +- 8 files changed, 368 insertions(+), 217 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java index 227e19dd58d49..8543b97f864d8 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java @@ -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; @@ -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; @@ -127,6 +119,7 @@ public class AlternateRecentsComponent { public AlternateRecentsComponent(Context context) { mContext = context; + mSystemServicesProxy = new SystemServicesProxy(context); mMessenger = new Messenger(new RecentsMessageHandler()); } @@ -219,17 +212,16 @@ public class AlternateRecentsComponent { /** Loads the first task thumbnail */ Bitmap loadFirstTaskThumbnail() { - ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); - List tasks = am.getRecentTasksForUser(1, - ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_PROFILES, + SystemServicesProxy ssp = mSystemServicesProxy; + List 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; @@ -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 tasks = am.getRecentTasksForUser(1, - ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_PROFILES, + SystemServicesProxy ssp = mSystemServicesProxy; + List 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; } @@ -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 tasks = am.getRunningTasks(1); + SystemServicesProxy ssp = mSystemServicesProxy; + List tasks = ssp.getRunningTasks(1); if (!tasks.isEmpty()) { ComponentName topActivity = tasks.get(0).topActivity; diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java index 2b08141fef169..8c5c8fa15f841 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java @@ -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"; @@ -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 { diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index dd75921c37a72..2436aeeff9e8d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -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; diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java index 928c7324c3233..e375f0848922d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java @@ -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; @@ -109,6 +108,7 @@ class TaskResourceLoader implements Runnable { Handler mLoadThreadHandler; Handler mMainThreadHandler; + SystemServicesProxy mSystemServicesProxy; TaskResourceLoadQueue mLoadQueue; DrawableLruCache mIconCache; BitmapLruCache mThumbnailCache; @@ -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(); @@ -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) { @@ -175,66 +177,60 @@ class TaskResourceLoader implements Runnable { } } } else { + SystemServicesProxy ssp = mSystemServicesProxy; + // Load the next item from the queue Pair 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, - " [TaskResourceLoader|load]", - t + " icon: " + loadIcon + " thumbnail: " + loadThumbnail + - " 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); - if (!mCancelled) { - if (icon != null) { - Console.log(Constants.DebugFlags.App.TaskDataLoader, - " [TaskResourceLoader|loadIcon]", - icon); - loadIcon = icon; - mIconCache.put(t.key, icon); - } - } - } - // Load the thumbnail - if (loadThumbnail == null || forceLoadTask) { - ActivityManager am = (ActivityManager) - mContext.getSystemService(Context.ACTIVITY_SERVICE); - Bitmap thumbnail = am.getTaskTopThumbnail(t.key.id); - if (!mCancelled) { - if (thumbnail != null) { - Console.log(Constants.DebugFlags.App.TaskDataLoader, - " [TaskResourceLoader|loadThumbnail]", - thumbnail); - loadThumbnail = thumbnail; - mThumbnailCache.put(t.key, thumbnail); - } else { - Console.logError(mContext, - "Failed to load task top thumbnail for: " + - t.key.baseIntent.getComponent().getPackageName()); - } - } - } + Drawable loadIcon = mIconCache.get(t.key); + Bitmap loadThumbnail = mThumbnailCache.get(t.key); + Console.log(Constants.DebugFlags.App.TaskDataLoader, + " [TaskResourceLoader|load]", + t + " icon: " + loadIcon + " thumbnail: " + loadThumbnail + + " forceLoad: " + forceLoadTask); + // Load the icon + if (loadIcon == null || forceLoadTask) { + ActivityInfo info = ssp.getActivityInfo(t.key.baseIntent.getComponent()); + Drawable icon = ssp.getActivityIcon(info); if (!mCancelled) { - // Notify that the task data has changed - final Drawable newIcon = loadIcon; - final Bitmap newThumbnail = loadThumbnail; - mMainThreadHandler.post(new Runnable() { - @Override - public void run() { - t.notifyTaskDataLoaded(newThumbnail, newIcon, forceLoadTask); - } - }); + if (icon != null) { + Console.log(Constants.DebugFlags.App.TaskDataLoader, + " [TaskResourceLoader|loadIcon]", + icon); + loadIcon = icon; + mIconCache.put(t.key, icon); + } } - } catch (PackageManager.NameNotFoundException ne) { - ne.printStackTrace(); + } + // Load the thumbnail + if (loadThumbnail == null || forceLoadTask) { + Bitmap thumbnail = ssp.getTaskThumbnail(t.key.id); + if (!mCancelled) { + if (thumbnail != null) { + Console.log(Constants.DebugFlags.App.TaskDataLoader, + " [TaskResourceLoader|loadThumbnail]", + thumbnail); + loadThumbnail = thumbnail; + mThumbnailCache.put(t.key, thumbnail); + } else { + Console.logError(mContext, + "Failed to load task top thumbnail for: " + + t.key.baseIntent.getComponent().getPackageName()); + } + } + } + if (!mCancelled) { + // Notify that the task data has changed + final Drawable newIcon = loadIcon; + final Bitmap newThumbnail = loadThumbnail; + mMainThreadHandler.post(new Runnable() { + @Override + public void run() { + t.notifyTaskDataLoaded(newThumbnail, newIcon, forceLoadTask); + } + }); } } @@ -296,6 +292,7 @@ class BitmapLruCache extends LruCache { public class RecentsTaskLoader { static RecentsTaskLoader sInstance; + SystemServicesProxy mSystemServicesProxy; DrawableLruCache mIconCache; BitmapLruCache mThumbnailCache; TaskResourceLoadQueue mLoadQueue; @@ -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); @@ -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]"); @@ -367,141 +370,129 @@ public class RecentsTaskLoader { SpaceNode root = new SpaceNode(context); root.setStack(stack); - try { - long t1 = System.currentTimeMillis(); + long t1 = System.currentTimeMillis(); - PackageManager pm = context.getPackageManager(); - ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + // Get the recent tasks + SystemServicesProxy ssp = mSystemServicesProxy; + List tasks = + ssp.getRecentTasks(25, UserHandle.CURRENT.getIdentifier()); + Collections.reverse(tasks); + Console.log(Constants.DebugFlags.App.TimeSystemCalls, + "[RecentsTaskLoader|getRecentTasks]", + "" + (System.currentTimeMillis() - t1) + "ms"); + Console.log(Constants.DebugFlags.App.TaskDataLoader, + "[RecentsTaskLoader|tasks]", "" + tasks.size()); - // Get the recent tasks - List tasks = am.getRecentTasksForUser(25, - ActivityManager.RECENT_IGNORE_UNAVAILABLE | - ActivityManager.RECENT_INCLUDE_PROFILES, UserHandle.CURRENT.getIdentifier()); - Collections.reverse(tasks); - Console.log(Constants.DebugFlags.App.TimeSystemCalls, - "[RecentsTaskLoader|getRecentTasks]", - "" + (System.currentTimeMillis() - t1) + "ms"); - Console.log(Constants.DebugFlags.App.TaskDataLoader, - "[RecentsTaskLoader|tasks]", "" + tasks.size()); + // Remove home/recents tasks + Iterator iter = tasks.iterator(); + while (iter.hasNext()) { + ActivityManager.RecentTaskInfo t = iter.next(); - // Remove home/recents tasks - Iterator iter = tasks.iterator(); - while (iter.hasNext()) { - ActivityManager.RecentTaskInfo t = iter.next(); - - // Skip tasks in the home stack - if (am.isInHomeStack(t.persistentId)) { - iter.remove(); - continue; - } - // Skip tasks from this Recents package - if (t.baseIntent.getComponent().getPackageName().equals(context.getPackageName())) { - iter.remove(); - continue; - } + // Skip tasks in the home stack + if (ssp.isInHomeStack(t.persistentId)) { + iter.remove(); + continue; } + // Skip tasks from this Recents package + if (t.baseIntent.getComponent().getPackageName().equals(context.getPackageName())) { + iter.remove(); + continue; + } + } - // Add each task to the task stack - t1 = System.currentTimeMillis(); - 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(); - boolean isForemostTask = (i == (taskCount - 1)); + // Add each task to the task stack + t1 = System.currentTimeMillis(); + int taskCount = tasks.size(); + for (int i = 0; i < taskCount; i++) { + ActivityManager.RecentTaskInfo t = tasks.get(i); + ActivityInfo info = ssp.getActivityInfo(t.baseIntent.getComponent()); + String title = ssp.getActivityLabel(info); + boolean isForemostTask = (i == (taskCount - 1)); - // Preload the specified number of apps - if (i >= (taskCount - preloadCount)) { - Console.log(Constants.DebugFlags.App.TaskDataLoader, - "[RecentsTaskLoader|preloadTask]", - "i: " + i + " task: " + t.baseIntent.getComponent().getPackageName()); + // Preload the specified number of apps + if (i >= (taskCount - preloadCount)) { + Console.log(Constants.DebugFlags.App.TaskDataLoader, + "[RecentsTaskLoader|preloadTask]", + "i: " + i + " task: " + t.baseIntent.getComponent().getPackageName()); - String label = (t.activityLabel == null ? title : t.activityLabel.toString()); - BitmapDrawable bd = null; - if (t.activityIcon != null) { - bd = new BitmapDrawable(res, t.activityIcon); - } - Task task = new Task(t.persistentId, (t.id > -1), t.baseIntent, label, bd); + String label = (t.activityLabel == null ? title : t.activityLabel.toString()); + BitmapDrawable bd = null; + if (t.activityIcon != null) { + bd = new BitmapDrawable(res, t.activityIcon); + } + Task task = new Task(t.persistentId, (t.id > -1), t.baseIntent, label, bd); - // Load the icon (if possible and not the foremost task, from the cache) - if (task.icon != null) { - mIconCache.put(task.key, task.icon); - } else { - if (!isForemostTask) { - task.icon = mIconCache.get(task.key); - if (task.icon != null) { - // Even though we get things from the cache, we should update them - // if they've changed in the bg - tasksToForceLoad.add(task); - } - } - if (task.icon == null) { - task.icon = info.loadIcon(pm); - if (task.icon != null) { - mIconCache.put(task.key, task.icon); - } else { - task.icon = mDefaultIcon; - } - } - } - - // Load the thumbnail (if possible and not the foremost task, from the cache) + // Load the icon (if possible and not the foremost task, from the cache) + if (task.icon != null) { + mIconCache.put(task.key, task.icon); + } else { if (!isForemostTask) { - task.thumbnail = mThumbnailCache.get(task.key); - if (task.thumbnail != null) { - // Even though we get things from the cache, we should update them if - // they've changed in the bg + task.icon = mIconCache.get(task.key); + if (task.icon != null) { + // Even though we get things from the cache, we should update them + // if they've changed in the bg tasksToForceLoad.add(task); } } - if (task.thumbnail == null) { - Console.log(Constants.DebugFlags.App.TaskDataLoader, - "[RecentsTaskLoader|loadingTaskThumbnail]"); - task.thumbnail = am.getTaskTopThumbnail(t.id); - if (task.thumbnail != null) { - mThumbnailCache.put(task.key, task.thumbnail); + if (task.icon == null) { + task.icon = ssp.getActivityIcon(info); + if (task.icon != null) { + mIconCache.put(task.key, task.icon); } else { - task.thumbnail = mDefaultThumbnail; + task.icon = mDefaultIcon; } } + } - // Create as many tasks a we want to multiply by - for (int j = 0; j < Constants.Values.RecentsTaskLoader.TaskEntryMultiplier; j++) { - 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++) { - 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)); + // Load the thumbnail (if possible and not the foremost task, from the cache) + if (!isForemostTask) { + task.thumbnail = mThumbnailCache.get(task.key); + if (task.thumbnail != null) { + // Even though we get things from the cache, we should update them if + // they've changed in the bg + tasksToForceLoad.add(task); } } - } - Console.log(Constants.DebugFlags.App.TimeSystemCalls, - "[RecentsTaskLoader|getAllTaskTopThumbnail]", - "" + (System.currentTimeMillis() - t1) + "ms"); - - /* - // Get all the stacks - t1 = System.currentTimeMillis(); - List stackInfos = ams.getAllStackInfos(); - Console.log(Constants.DebugFlags.App.TimeSystemCalls, "[RecentsTaskLoader|getAllStackInfos]", "" + (System.currentTimeMillis() - t1) + "ms"); - Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|stacks]", "" + tasks.size()); - for (ActivityManager.StackInfo s : stackInfos) { - Console.log(Constants.DebugFlags.App.TaskDataLoader, " [RecentsTaskLoader|stack]", s.toString()); - if (stacks.containsKey(s.stackId)) { - stacks.get(s.stackId).setRect(s.bounds); + if (task.thumbnail == null) { + Console.log(Constants.DebugFlags.App.TaskDataLoader, + "[RecentsTaskLoader|loadingTaskThumbnail]"); + task.thumbnail = ssp.getTaskThumbnail(task.key.id); + if (task.thumbnail != null) { + mThumbnailCache.put(task.key, task.thumbnail); + } else { + task.thumbnail = mDefaultThumbnail; + } } + + // Add the task to the stack + Console.log(Constants.DebugFlags.App.TaskDataLoader, + " [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName()); + stack.addTask(task); + } else { + // 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)); } - */ - } catch (Exception e) { - e.printStackTrace(); } + Console.log(Constants.DebugFlags.App.TimeSystemCalls, + "[RecentsTaskLoader|getAllTaskTopThumbnail]", + "" + (System.currentTimeMillis() - t1) + "ms"); + + /* + // Get all the stacks + t1 = System.currentTimeMillis(); + List stackInfos = ams.getAllStackInfos(); + Console.log(Constants.DebugFlags.App.TimeSystemCalls, "[RecentsTaskLoader|getAllStackInfos]", "" + (System.currentTimeMillis() - t1) + "ms"); + Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|stacks]", "" + tasks.size()); + for (ActivityManager.StackInfo s : stackInfos) { + Console.log(Constants.DebugFlags.App.TaskDataLoader, " [RecentsTaskLoader|stack]", s.toString()); + if (stacks.containsKey(s.stackId)) { + stacks.get(s.stackId).setRect(s.bounds); + } + } + */ // Start the task loader mLoader.start(context); diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java new file mode 100644 index 0000000000000..57d6524a86400 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java @@ -0,0 +1,182 @@ +/* + * 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 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 tasks = + new ArrayList(); + 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 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); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java index 677334d7297be..25a9aeb3fd905 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java @@ -19,7 +19,6 @@ package com.android.systemui.recents.model; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; -import com.android.systemui.recents.Constants; /** @@ -106,14 +105,7 @@ public class Task { @Override public boolean equals(Object o) { - // If we have multiple task entries for the same task, then we do the simple object - // equality check - if (Constants.Values.RecentsTaskLoader.TaskEntryMultiplier > 1) { - return super.equals(o); - } - - // Otherwise, check that the id and intent match (the other fields can be asynchronously - // loaded and is unsuitable to testing the identity of this Task) + // Check that the id matches Task t = (Task) o; return key.equals(t.key); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index e89bde5927f4d..cb5279490ff0e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -16,7 +16,6 @@ package com.android.systemui.recents.views; -import android.app.ActivityManager; import android.app.ActivityOptions; import android.content.ActivityNotFoundException; import android.content.Context; @@ -30,6 +29,7 @@ import android.widget.FrameLayout; import com.android.systemui.recents.Console; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; +import com.android.systemui.recents.RecentsTaskLoader; import com.android.systemui.recents.model.SpaceNode; import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; @@ -246,14 +246,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV if (task.isActive) { // Bring an active task to the foreground - ActivityManager am = (ActivityManager) - stackView.getContext().getSystemService(Context.ACTIVITY_SERVICE); - if (opts != null) { - am.moveTaskToFront(task.key.id, ActivityManager.MOVE_TASK_WITH_HOME, - opts.toBundle()); - } else { - am.moveTaskToFront(task.key.id, ActivityManager.MOVE_TASK_WITH_HOME); - } + RecentsTaskLoader.getInstance().getSystemServicesProxy() + .moveTaskToFront(task.key.id, opts); } else { // Launch the activity with the desired animation Intent i = new Intent(task.key.baseIntent); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index aeb571d6c56ad..dfd608cb43422 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -22,7 +22,6 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.app.Activity; -import android.app.ActivityManager; import android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; @@ -40,6 +39,7 @@ import com.android.systemui.recents.Console; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.RecentsTaskLoader; +import com.android.systemui.recents.SystemServicesProxy; import com.android.systemui.recents.Utilities; import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; @@ -234,7 +234,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // When we are picking up a new view from the view pool, prepare it for any // following animation by putting it in a reasonable place if (mStackViewsAnimationDuration > 0 && i != 0) { - int fromIndex = (transform.t < 0) ? (i - 1) : (i + 1); + int fromIndex = (transform.t < 0) ? (visibleRange[0] - 1) : + (visibleRange[1] + 1); tv.updateViewPropertiesToTaskTransform(null, getStackTransform(fromIndex, stackScroll), 0); } @@ -1268,12 +1269,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { loader.deleteTaskData(task); // Remove the task from activity manager - final ActivityManager am = (ActivityManager) - activity.getSystemService(Context.ACTIVITY_SERVICE); - if (am != null) { - am.removeTask(tv.getTask().key.id, - ActivityManager.REMOVE_TASK_KILL_PROCESS); - } + RecentsTaskLoader.getInstance().getSystemServicesProxy().removeTask(tv.getTask().key.id); // If there are no remaining tasks, then either unfilter the current stack, or just close // the activity if there are no filtered stacks