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

Commit ceb9b437 authored by Winson Chung's avatar Winson Chung Committed by Android (Google) Code Review
Browse files

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

parents 8754b73b a10370fc
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