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

Commit 7048fea7 authored by Winson Chung's avatar Winson Chung
Browse files

Moving alternate recents component logic into its own file.

- Adding min delay between toggles of recents
- Merging changes to show related recents

Change-Id: I2201a9f98417e26cdfb1c16cb0a2ef095d2cd5fc
parent 0535a9f7
Loading
Loading
Loading
Loading
+15 −319
Original line number Diff line number Diff line
@@ -16,142 +16,54 @@

package com.android.systemui.recent;

import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.content.ActivityNotFoundException;
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;
import com.android.systemui.recents.AlternateRecentsComponent;


public class Recents extends SystemUI implements RecentsComponent {
    /** A handler for messages from the recents implementation */
    class RecentsMessageHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            if (!mUseAlternateRecents) return;
            if (msg.what == MSG_UPDATE_FOR_CONFIGURATION) {
                Resources res = mContext.getResources();
                float statusBarHeight = res.getDimensionPixelSize(
                        com.android.internal.R.dimen.status_bar_height);
                mFirstTaskRect = (Rect) msg.getData().getParcelable("taskRect");
                mFirstTaskRect.offset(0, (int) statusBarHeight);
            }
        }
    }

    /** A service connection to the recents implementation */
    class RecentsServiceConnection implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            if (!mUseAlternateRecents) return;

            Log.d(TAG, "[RecentsComponent|ServiceConnection|onServiceConnected] toggleRecents: " +
                    mToggleRecentsUponServiceBound);
            mService = new Messenger(service);
            mServiceIsBound = true;

            // Toggle recents if this service connection was triggered by hitting the recents button
            if (mToggleRecentsUponServiceBound) {
                startAlternateRecentsActivity();
            }
            mToggleRecentsUponServiceBound = false;
        }

        @Override
        public void onServiceDisconnected(ComponentName className) {
            if (!mUseAlternateRecents) return;

            Log.d(TAG, "[RecentsComponent|ServiceConnection|onServiceDisconnected]");
            mService = null;
            mServiceIsBound = false;
        }
    }

    private static final String TAG = "Recents";
    private static final boolean DEBUG = true;

    final static int MSG_UPDATE_FOR_CONFIGURATION = 0;
    final static int MSG_UPDATE_TASK_THUMBNAIL = 1;
    final static int MSG_PRELOAD_TASKS = 2;
    final static int MSG_CANCEL_PRELOAD_TASKS = 3;
    final static int MSG_CLOSE_RECENTS = 4;
    final static int MSG_TOGGLE_RECENTS = 5;

    final static String sToggleRecentsAction = "com.android.systemui.recents.SHOW_RECENTS";
    final static String sRecentsPackage = "com.android.systemui";
    final static String sRecentsActivity = "com.android.systemui.recents.RecentsActivity";
    final static String sRecentsService = "com.android.systemui.recents.RecentsService";

    // Which recents to use
    boolean mUseAlternateRecents;

    // Recents service binding
    Messenger mService = null;
    Messenger mMessenger;
    boolean mServiceIsBound = false;
    boolean mToggleRecentsUponServiceBound;
    RecentsServiceConnection mConnection = new RecentsServiceConnection();

    View mStatusBarView;
    Rect mFirstTaskRect = new Rect();

    public Recents() {
        mMessenger = new Messenger(new RecentsMessageHandler());
    }
    AlternateRecentsComponent mAlternateRecents;

    @Override
    public void start() {
        mUseAlternateRecents =
                SystemProperties.getBoolean("persist.recents.use_alternate", false);

        putComponent(RecentsComponent.class, this);

        mUseAlternateRecents = SystemProperties.getBoolean("persist.recents.use_alternate", false);
        if (mUseAlternateRecents) {
            Log.d(TAG, "[RecentsComponent|start]");

            // Try to create a long-running connection to the recents service
            bindToRecentsService(false);
            if (mAlternateRecents == null) {
                mAlternateRecents = new AlternateRecentsComponent(mContext);
            }
            mAlternateRecents.onStart();
        }

        putComponent(RecentsComponent.class, this);
    }

    @Override
    public void toggleRecents(Display display, int layoutDirection, View statusBarView) {
        if (mUseAlternateRecents) {
            // Launch the alternate recents if required
            toggleAlternateRecents(display, layoutDirection, statusBarView);
            mAlternateRecents.onToggleRecents(display, layoutDirection, statusBarView);
            return;
        }

@@ -298,222 +210,17 @@ public class Recents extends SystemUI implements RecentsComponent {
        }
    }

    /** Toggles the alternate recents activity */
    public void toggleAlternateRecents(Display display, int layoutDirection, View statusBarView) {
        if (!mUseAlternateRecents) return;

        Log.d(TAG, "[RecentsComponent|toggleRecents] serviceIsBound: " + mServiceIsBound);
        mStatusBarView = statusBarView;
        if (!mServiceIsBound) {
            // Try to create a long-running connection to the recents service before toggling
            // recents
            bindToRecentsService(true);
            return;
        }

        try {
            startAlternateRecentsActivity();
        } catch (ActivityNotFoundException e) {
            Log.e(TAG, "Failed to launch RecentAppsIntent", e);
        }
    }

    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        if (mServiceIsBound) {
            Resources res = mContext.getResources();
            int statusBarHeight = res.getDimensionPixelSize(
                    com.android.internal.R.dimen.status_bar_height);
            int navBarHeight = res.getDimensionPixelSize(
                    com.android.internal.R.dimen.navigation_bar_height);
            Rect rect = new Rect();
            WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
            wm.getDefaultDisplay().getRectSize(rect);

            // Try and update the recents configuration
            try {
                Bundle data = new Bundle();
                data.putParcelable("windowRect", rect);
                data.putParcelable("systemInsets", new Rect(0, statusBarHeight, 0, 0));
                Message msg = Message.obtain(null, MSG_UPDATE_FOR_CONFIGURATION, 0, 0);
                msg.setData(data);
                msg.replyTo = mMessenger;
                mService.send(msg);
            } catch (RemoteException re) {
                re.printStackTrace();
            }
        }
    }

    /** Binds to the recents implementation */
    private void bindToRecentsService(boolean toggleRecentsUponConnection) {
        if (!mUseAlternateRecents) return;

        mToggleRecentsUponServiceBound = toggleRecentsUponConnection;
        Intent intent = new Intent();
        intent.setClassName(sRecentsPackage, sRecentsService);
        mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    /** 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_RELATED,
                UserHandle.CURRENT.getIdentifier());
        for (ActivityManager.RecentTaskInfo t : tasks) {
            // Skip tasks in the home stack
            if (am.isInHomeStack(t.persistentId)) {
                return null;
            }

            Bitmap thumbnail = am.getTaskTopThumbnail(t.persistentId);
            return thumbnail;
        }
        return null;
    }

    /** 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_RELATED,
                UserHandle.CURRENT.getIdentifier());
        for (ActivityManager.RecentTaskInfo t : tasks) {
            // Skip tasks in the home stack
            if (am.isInHomeStack(t.persistentId)) {
                continue;
            }

            return true;
        }
        return false;
    }

    /** Converts from the device rotation to the degree */
    float getDegreesForRotation(int value) {
        switch (value) {
            case Surface.ROTATION_90:
                return 360f - 90f;
            case Surface.ROTATION_180:
                return 360f - 180f;
            case Surface.ROTATION_270:
                return 360f - 270f;
        }
        return 0f;
    }

    /** Takes a screenshot of the surface */
    Bitmap takeScreenshot(Display display) {
        DisplayMetrics dm = new DisplayMetrics();
        display.getRealMetrics(dm);
        float[] dims = {dm.widthPixels, dm.heightPixels};
        float degrees = getDegreesForRotation(display.getRotation());
        boolean requiresRotation = (degrees > 0);
        if (requiresRotation) {
            // Get the dimensions of the device in its native orientation
            Matrix m = new Matrix();
            m.preRotate(-degrees);
            m.mapPoints(dims);
            dims[0] = Math.abs(dims[0]);
            dims[1] = Math.abs(dims[1]);
        }
        return SurfaceControl.screenshot((int) dims[0], (int) dims[1]);
    }

    /** Starts the recents activity */
    void startAlternateRecentsActivity() {
        // 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);
        if (!tasks.isEmpty()) {
            ComponentName topActivity = tasks.get(0).topActivity;
            Log.d(TAG, "[RecentsComponent|topActivity] " + topActivity);

            // Check if the front most activity is recents
            if (topActivity.getPackageName().equals(sRecentsPackage) &&
                    topActivity.getClassName().equals(sRecentsActivity)) {
                // Notify Recents to toggle itself
                try {
                    Bundle data = new Bundle();
                    Message msg = Message.obtain(null, MSG_TOGGLE_RECENTS, 0, 0);
                    msg.setData(data);
                    mService.send(msg);
                } catch (RemoteException re) {
                    re.printStackTrace();
                }
                return;
            }
        }

        // XXX: If window transitions are currently happening, then we should eat up the event here

        // Otherwise, Recents is not the front-most activity and we should animate into it
        Rect taskRect = mFirstTaskRect;
        if (taskRect != null && taskRect.width() > 0 && taskRect.height() > 0 && hasFirstTask()) {
            // Loading from thumbnail
            Bitmap thumbnail;
            Bitmap firstThumbnail = loadFirstTaskThumbnail();
            if (firstThumbnail == null) {
                // Load the thumbnail from the screenshot
                WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
                Display display = wm.getDefaultDisplay();
                Bitmap screenshot = takeScreenshot(display);
                Resources res = mContext.getResources();
                int size = Math.min(screenshot.getWidth(), screenshot.getHeight());
                int statusBarHeight = res.getDimensionPixelSize(
                        com.android.internal.R.dimen.status_bar_height);
                thumbnail = Bitmap.createBitmap(mFirstTaskRect.width(), mFirstTaskRect.height(),
                        Bitmap.Config.ARGB_8888);
                Canvas c = new Canvas(thumbnail);
                c.drawBitmap(screenshot, new Rect(0, statusBarHeight, size, statusBarHeight + size),
                        new Rect(0, 0, mFirstTaskRect.width(), mFirstTaskRect.height()), null);
                c.setBitmap(null);
                // Recycle the old screenshot
                screenshot.recycle();
            } else {
                // Create the thumbnail
                thumbnail = Bitmap.createBitmap(mFirstTaskRect.width(), mFirstTaskRect.height(),
                        Bitmap.Config.ARGB_8888);
                int size = Math.min(firstThumbnail.getWidth(), firstThumbnail.getHeight());
                Canvas c = new Canvas(thumbnail);
                c.drawBitmap(firstThumbnail, new Rect(0, 0, size, size),
                        new Rect(0, 0, mFirstTaskRect.width(), mFirstTaskRect.height()), null);
                c.setBitmap(null);
                // Recycle the old thumbnail
                firstThumbnail.recycle();
            }

            ActivityOptions opts = ActivityOptions.makeThumbnailScaleDownAnimation(mStatusBarView,
                    thumbnail, mFirstTaskRect.left, mFirstTaskRect.top, null);
            startAlternateRecentsActivity(opts);
        } else {
            ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
                    R.anim.recents_from_launcher_enter,
                    R.anim.recents_from_launcher_exit);
            startAlternateRecentsActivity(opts);
        }
    }

    /** Starts the recents activity */
    void startAlternateRecentsActivity(ActivityOptions opts) {
        Intent intent = new Intent(sToggleRecentsAction);
        intent.setClassName(sRecentsPackage, sRecentsActivity);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
        if (opts != null) {
            mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
                    UserHandle.USER_CURRENT));
        } else {
            mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
        if (mUseAlternateRecents) {
            mAlternateRecents.onConfigurationChanged(newConfig);
        }
    }

    @Override
    public void preloadRecentTasksList() {
        if (mUseAlternateRecents) {
            Log.d(TAG, "[RecentsComponent|preloadRecents]");
            mAlternateRecents.onPreloadRecents();
        } else {
            Intent intent = new Intent(RecentsActivity.PRELOAD_INTENT);
            intent.setClassName("com.android.systemui",
@@ -527,7 +234,7 @@ public class Recents extends SystemUI implements RecentsComponent {
    @Override
    public void cancelPreloadingRecentTasksList() {
        if (mUseAlternateRecents) {
            Log.d(TAG, "[RecentsComponent|cancelPreload]");
            mAlternateRecents.onCancelPreloadingRecents();
        } else {
            Intent intent = new Intent(RecentsActivity.CANCEL_PRELOAD_INTENT);
            intent.setClassName("com.android.systemui",
@@ -541,18 +248,7 @@ public class Recents extends SystemUI implements RecentsComponent {
    @Override
    public void closeRecents() {
        if (mUseAlternateRecents) {
            Log.d(TAG, "[RecentsComponent|closeRecents]");
            if (mServiceIsBound) {
                // Try and update the recents configuration
                try {
                    Bundle data = new Bundle();
                    Message msg = Message.obtain(null, MSG_CLOSE_RECENTS, 0, 0);
                    msg.setData(data);
                    mService.send(msg);
                } catch (RemoteException re) {
                    re.printStackTrace();
                }
            }
            mAlternateRecents.onCloseRecents();
        } else {
            Intent intent = new Intent(RecentsActivity.CLOSE_RECENTS_INTENT);
            intent.setPackage("com.android.systemui");
+376 −0

File added.

Preview size limit exceeded, changes collapsed.

+5 −0
Original line number Diff line number Diff line
@@ -67,6 +67,11 @@ public class Console {
        Log.e("Recents", msg);
    }

    /** Logs a raw error */
    public static void logRawError(String msg, Exception e) {
        Log.e("Recents", msg, e);
    }

    /** Logs a divider bar */
    public static void logDivider(boolean condition) {
        if (condition) {
+1 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ public class Constants {
            // This disables the bitmap and icon caches to
            public static final boolean DisableBackgroundCache = false;

            public static final boolean RecentsComponent = false;
            public static final boolean TaskDataLoader = false;
            public static final boolean SystemUIHandshake = false;
            public static final boolean TimeSystemCalls = false;
+2 −1
Original line number Diff line number Diff line
@@ -340,7 +340,8 @@ public class RecentsTaskLoader {

            // Get the recent tasks
            List<ActivityManager.RecentTaskInfo> tasks = am.getRecentTasksForUser(25,
                    ActivityManager.RECENT_IGNORE_UNAVAILABLE, UserHandle.CURRENT.getIdentifier());
                    ActivityManager.RECENT_IGNORE_UNAVAILABLE |
                    ActivityManager.RECENT_INCLUDE_RELATED, UserHandle.CURRENT.getIdentifier());
            Collections.reverse(tasks);
            Console.log(Constants.DebugFlags.App.TimeSystemCalls,
                    "[RecentsTaskLoader|getRecentTasks]",