Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6ec89da1 authored by Winson Chung's avatar Winson Chung Committed by Android Git Automerger
Browse files

am ceb9b437: Merge "Adding system service proxy to help test UI/performance."

* commit 'ceb9b437':
  Adding system service proxy to help test UI/performance.
parents ae6ffcc3 ceb9b437
Loading
Loading
Loading
Loading
+11 −20
Original line number Diff line number Diff line
@@ -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<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;
@@ -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;
            }

@@ -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;

+6 −2
Original line number Diff line number Diff line
@@ -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 {
+1 −0
Original line number Diff line number Diff line
@@ -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;
+158 −167
Original line number Diff line number Diff line
@@ -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,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,
@@ -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,
@@ -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,
@@ -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
@@ -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;
@@ -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,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]",
@@ -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;
            }
@@ -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
@@ -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 {
@@ -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 {
@@ -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");
@@ -499,9 +493,6 @@ public class RecentsTaskLoader {
            }
        }
        */
        } catch (Exception e) {
            e.printStackTrace();
        }

        // Start the task loader
        mLoader.start(context);
+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