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

Commit db0af847 authored by Jaewan Kim's avatar Jaewan Kim Committed by android-build-merger
Browse files

Merge "Refactor SystemServicesProxy to manage ITaskStackListener locally" into nyc-dev

am: 98551e43

* commit '98551e43':
  Refactor SystemServicesProxy to manage ITaskStackListener locally
parents 2227ff22 98551e43
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -180,7 +180,7 @@ public class Recents extends SystemUI
    @Override
    public void start() {
        sDebugFlags = new RecentsDebugFlags(mContext);
        sSystemServicesProxy = new SystemServicesProxy(mContext);
        sSystemServicesProxy = SystemServicesProxy.getInstance(mContext);
        sTaskLoader = new RecentsTaskLoader(mContext);
        sConfiguration = new RecentsConfiguration(mContext);
        mHandler = new Handler();
+5 −29
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;

import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ITaskStackListener;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ActivityNotFoundException;
import android.content.Context;
@@ -59,6 +58,7 @@ import com.android.systemui.recents.events.ui.DraggingInRecentsEvent;
import com.android.systemui.recents.misc.DozeTrigger;
import com.android.systemui.recents.misc.ForegroundThread;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
import com.android.systemui.recents.model.RecentsTaskLoadPlan;
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.Task;
@@ -95,37 +95,13 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
    public final static String RECENTS_ACTIVITY = "com.android.systemui.recents.RecentsActivity";

    /**
     * An implementation of ITaskStackListener, that allows us to listen for changes to the system
     * An implementation of TaskStackListener, that allows us to listen for changes to the system
     * task stacks and update recents accordingly.
     */
    class TaskStackListenerImpl extends ITaskStackListener.Stub implements Runnable {
        Handler mHandler;

        public TaskStackListenerImpl(Handler handler) {
            mHandler = handler;
        }

    class TaskStackListenerImpl extends TaskStackListener {
        @Override
        public void onTaskStackChanged() {
            // Debounce any task stack changes
            mHandler.removeCallbacks(this);
            mHandler.post(this);
        }

        @Override
        public void onActivityPinned() {
        }

        @Override
        public void onPinnedActivityRestartAttempt() {
        }

        @Override
        public void onPinnedStackAnimationEnded() {
        }

        /** Preloads the next task */
        public void run() {
            // Preloads the next task
            RecentsConfiguration config = Recents.getConfiguration();
            if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
                RecentsTaskLoader loader = Recents.getTaskLoader();
@@ -201,7 +177,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
        ForegroundThread.get();

        // Register the task stack listener
        mTaskStackListener = new TaskStackListenerImpl(mHandler);
        mTaskStackListener = new TaskStackListenerImpl();
        SystemServicesProxy ssp = Recents.getSystemServices();
        ssp.registerTaskStackListener(mTaskStackListener);

+120 −7
Original line number Diff line number Diff line
@@ -48,6 +48,9 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -106,6 +109,8 @@ public class SystemServicesProxy {
        sRecentsBlacklist.add("com.android.systemui.tv.pip.PipMenuActivity");
    }

    private static SystemServicesProxy sSystemServicesProxy;

    AccessibilityManager mAccm;
    ActivityManager mAm;
    IActivityManager mIam;
@@ -128,8 +133,58 @@ public class SystemServicesProxy {
    Paint mBgProtectionPaint;
    Canvas mBgProtectionCanvas;

    private final Handler mHandler = new H();

    /**
     * An abstract class to track task stack changes.
     * Classes should implement this instead of {@link android.app.ITaskStackListener}
     * to reduce IPC calls from system services. These callbacks will be called on the main thread.
     */
    public abstract static class TaskStackListener {
        public void onTaskStackChanged() { }
        public void onActivityPinned() { }
        public void onPinnedActivityRestartAttempt() { }
        public void onPinnedStackAnimationEnded() { }
    }

    /**
     * Implementation of {@link android.app.ITaskStackListener} to listen task stack changes from
     * ActivityManagerNative.
     * This simply passes callbacks to listeners through {@link H}.
     * */
    private ITaskStackListener.Stub mTaskStackListener = new ITaskStackListener.Stub() {
        @Override
        public void onTaskStackChanged() throws RemoteException {
            mHandler.removeMessages(H.ON_TASK_STACK_CHANGED);
            mHandler.sendEmptyMessage(H.ON_TASK_STACK_CHANGED);
        }

        @Override
        public void onActivityPinned() throws RemoteException {
            mHandler.removeMessages(H.ON_ACTIVITY_PINNED);
            mHandler.sendEmptyMessage(H.ON_ACTIVITY_PINNED);
        }

        @Override
        public void onPinnedActivityRestartAttempt() throws RemoteException{
            mHandler.removeMessages(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT);
            mHandler.sendEmptyMessage(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT);
        }

        @Override
        public void onPinnedStackAnimationEnded() throws RemoteException {
            mHandler.removeMessages(H.ON_PINNED_STACK_ANIMATION_ENDED);
            mHandler.sendEmptyMessage(H.ON_PINNED_STACK_ANIMATION_ENDED);
        }
    };

    /**
     * List of {@link TaskStackListener} registered from {@link registerTaskStackListener}.
     */
    private List<TaskStackListener> mTaskStackListeners = new ArrayList<>();

    /** Private constructor */
    public SystemServicesProxy(Context context) {
    private SystemServicesProxy(Context context) {
        mAccm = AccessibilityManager.getInstance(context);
        mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        mIam = ActivityManagerNative.getDefault();
@@ -170,6 +225,20 @@ public class SystemServicesProxy {
        }
    }

    /**
     * Returns the single instance of the {@link SystemServicesProxy}.
     * This should only be called on the main thread.
     */
    public static SystemServicesProxy getInstance(Context context) {
        if (!Looper.getMainLooper().isCurrentThread()) {
            throw new RuntimeException("Must be called on the UI thread");
        }
        if (sSystemServicesProxy == null) {
            sSystemServicesProxy = new SystemServicesProxy(context);
        }
        return sSystemServicesProxy;
    }

    /** Returns a list of the recents tasks */
    public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numLatestTasks, int userId,
            boolean isTopTaskHome, ArraySet<Integer> quietProfileIds) {
@@ -982,14 +1051,21 @@ public class SystemServicesProxy {
        }
    }

    /** Registers a task stack listener with the system. */
    public void registerTaskStackListener(ITaskStackListener listener) {
    /**
     * Registers a task stack listener with the system.
     * This should be called on the main thread.
     */
    public void registerTaskStackListener(TaskStackListener listener) {
        if (mIam == null) return;

        mTaskStackListeners.add(listener);
        if (mTaskStackListeners.size() == 1) {
            // Register mTaskStackListener to IActivityManager only once if needed.
            try {
            mIam.registerTaskStackListener(listener);
                mIam.registerTaskStackListener(mTaskStackListener);
            } catch (Exception e) {
            e.printStackTrace();
                Log.w(TAG, "Failed to call registerTaskStackListener", e);
            }
        }
    }

@@ -1039,4 +1115,41 @@ public class SystemServicesProxy {
            e.printStackTrace();
        }
    }

    private final class H extends Handler {
        private static final int ON_TASK_STACK_CHANGED = 1;
        private static final int ON_ACTIVITY_PINNED = 2;
        private static final int ON_PINNED_ACTIVITY_RESTART_ATTEMPT = 3;
        private static final int ON_PINNED_STACK_ANIMATION_ENDED = 4;

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case ON_TASK_STACK_CHANGED: {
                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
                        mTaskStackListeners.get(i).onTaskStackChanged();
                    }
                    break;
                }
                case ON_ACTIVITY_PINNED: {
                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
                        mTaskStackListeners.get(i).onActivityPinned();
                    }
                    break;
                }
                case ON_PINNED_ACTIVITY_RESTART_ATTEMPT: {
                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
                        mTaskStackListeners.get(i).onPinnedActivityRestartAttempt();
                    }
                    break;
                }
                case ON_PINNED_STACK_ANIMATION_ENDED: {
                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
                        mTaskStackListeners.get(i).onPinnedStackAnimationEnded();
                    }
                    break;
                }
            }
        }
    }
}
+5 −40
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.car;

import android.app.ActivityManager;
import android.app.ITaskStackListener;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -33,6 +32,7 @@ import android.view.WindowManager;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.PhoneStatusBar;

@@ -40,9 +40,7 @@ import com.android.systemui.statusbar.phone.PhoneStatusBar;
 * A status bar (and navigation bar) tailored for the automotive use case.
 */
public class CarStatusBar extends PhoneStatusBar {
    private SystemServicesProxy mSystemServicesProxy;
    private TaskStackListenerImpl mTaskStackListener;
    private Handler mHandler;

    private CarNavigationBarView mCarNavigationBar;
    private CarNavigationBarController mController;
@@ -51,10 +49,8 @@ public class CarStatusBar extends PhoneStatusBar {
    @Override
    public void start() {
        super.start();
        mHandler = new Handler();
        mTaskStackListener = new TaskStackListenerImpl(mHandler);
        mSystemServicesProxy = new SystemServicesProxy(mContext);
        mSystemServicesProxy.registerTaskStackListener(mTaskStackListener);
        mTaskStackListener = new TaskStackListenerImpl();
        SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskStackListener);
        registerPackageChangeReceivers();
    }

@@ -114,47 +110,16 @@ public class CarStatusBar extends PhoneStatusBar {
    }

    /**
     * An implementation of ITaskStackListener, that listens for changes in the system task
     * An implementation of TaskStackListener, that listens for changes in the system task
     * stack and notifies the navigation bar.
     */
    private class TaskStackListenerImpl extends ITaskStackListener.Stub implements Runnable {
        private Handler mHandler;

        public TaskStackListenerImpl(Handler handler) {
            this.mHandler = handler;
        }

        @Override
        public void onActivityPinned() {
        }

        @Override
        public void onPinnedActivityRestartAttempt() {
        }

        @Override
        public void onPinnedStackAnimationEnded() {
        }

    private class TaskStackListenerImpl extends TaskStackListener {
        @Override
        public void onTaskStackChanged() {
            mHandler.removeCallbacks(this);
            mHandler.post(this);
        }

        @Override
        public void run() {
            ensureMainThread();
            SystemServicesProxy ssp = Recents.getSystemServices();
            ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getTopMostTask();
            mController.taskChanged(runningTaskInfo.baseActivity.getPackageName());
        }

        private void ensureMainThread() {
            if (!Looper.getMainLooper().isCurrentThread()) {
                throw new RuntimeException("Must be called on the UI thread");
            }
        }
    }

    @Override
+69 −102
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import android.app.ActivityManager.StackInfo;
import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
import android.app.IActivityManager;
import android.app.ITaskStackListener;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -38,6 +37,8 @@ import android.os.SystemProperties;
import android.util.Log;

import com.android.systemui.Prefs;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;

import java.util.ArrayList;
import java.util.List;
@@ -95,89 +96,6 @@ public class PipManager {
    private boolean mIsRecentsShown;
    private boolean mIsPipFocusedInRecent;

    private final Runnable mOnActivityPinnedRunnable = new Runnable() {
        @Override
        public void run() {
            StackInfo stackInfo = null;
            try {
                stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
                if (stackInfo == null) {
                    Log.w(TAG, "Cannot find pinned stack");
                    return;
                }
            } catch (RemoteException e) {
                Log.e(TAG, "getStackInfo failed", e);
                return;
            }
            if (DEBUG) Log.d(TAG, "PINNED_STACK:" + stackInfo);
            mPipTaskId = stackInfo.taskIds[stackInfo.taskIds.length - 1];
            mPipComponentName = ComponentName.unflattenFromString(
                    stackInfo.taskNames[stackInfo.taskNames.length - 1]);
            // Set state to overlay so we show it when the pinned stack animation ends.
            mState = STATE_PIP_OVERLAY;
            mCurrentPipBounds = mPipBounds;
            launchPipOnboardingActivityIfNeeded();
            mMediaSessionManager.addOnActiveSessionsChangedListener(
                    mActiveMediaSessionListener, null);
            updateMediaController(mMediaSessionManager.getActiveSessions(null));
            if (mIsRecentsShown) {
                // If an activity becomes PIPed again after the fullscreen, the Recents is shown
                // behind so we need to resize the pinned stack and show the correct overlay.
                resizePinnedStack(STATE_PIP_OVERLAY);
            }
            for (int i = mListeners.size() - 1; i >= 0; i--) {
                mListeners.get(i).onPipEntered();
            }
        }
    };
    private final Runnable mOnTaskStackChanged = new Runnable() {
        @Override
        public void run() {
            if (mState != STATE_NO_PIP) {
                StackInfo stackInfo = null;
                try {
                    stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
                    if (stackInfo == null) {
                        Log.w(TAG, "There is no pinned stack");
                        closePipInternal(false);
                        return;
                    }
                } catch (RemoteException e) {
                    Log.e(TAG, "getStackInfo failed", e);
                    return;
                }
                for (int i = stackInfo.taskIds.length - 1; i >= 0; --i) {
                    if (stackInfo.taskIds[i] == mPipTaskId) {
                        // PIP task is still alive.
                        return;
                    }
                }
                // PIP task doesn't exist anymore in PINNED_STACK.
                closePipInternal(true);
            }
        }
    };
    private final Runnable mOnPinnedActivityRestartAttempt = new Runnable() {
        @Override
        public void run() {
            // If PIPed activity is launched again by Launcher or intent, make it fullscreen.
            movePipToFullscreen();
        }
    };
    private final Runnable mOnPinnedStackAnimationEnded = new Runnable() {
        @Override
        public void run() {
            switch (mState) {
                case STATE_PIP_OVERLAY:
                    showPipOverlay();
                    break;
                case STATE_PIP_MENU:
                    showPipMenu();
                    break;
            }
        }
    };

    private final Runnable mResizePinnedStackRunnable = new Runnable() {
        @Override
        public void run() {
@@ -241,13 +159,7 @@ public class PipManager {
                (int) (mRecentsPipBounds.bottom + scaleBy * mRecentsPipBounds.height()));

        mActivityManager = ActivityManagerNative.getDefault();
        TaskStackListener taskStackListener = new TaskStackListener();
        IActivityManager iam = ActivityManagerNative.getDefault();
        try {
            iam.registerTaskStackListener(taskStackListener);
        } catch (RemoteException e) {
            Log.e(TAG, "registerTaskStackListener failed", e);
        }
        SystemServicesProxy.getInstance(context).registerTaskStackListener(mTaskStackListener);
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_MEDIA_RESOURCE_GRANTED);
        mContext.registerReceiver(mBroadcastReceiver, intentFilter);
@@ -566,33 +478,88 @@ public class PipManager {
        return mPipMediaController;
    }

    private class TaskStackListener extends ITaskStackListener.Stub {
    TaskStackListener mTaskStackListener = new TaskStackListener() {
        @Override
        public void onTaskStackChanged() throws RemoteException {
            // Post the message back to the UI thread.
            mHandler.post(mOnTaskStackChanged);
        public void onTaskStackChanged() {
            if (mState != STATE_NO_PIP) {
                StackInfo stackInfo = null;
                try {
                    stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
                    if (stackInfo == null) {
                        Log.w(TAG, "There is no pinned stack");
                        closePipInternal(false);
                        return;
                    }
                } catch (RemoteException e) {
                    Log.e(TAG, "getStackInfo failed", e);
                    return;
                }
                for (int i = stackInfo.taskIds.length - 1; i >= 0; --i) {
                    if (stackInfo.taskIds[i] == mPipTaskId) {
                        // PIP task is still alive.
                        return;
                    }
                }
                // PIP task doesn't exist anymore in PINNED_STACK.
                closePipInternal(true);
            }
        }

        @Override
        public void onActivityPinned()  throws RemoteException {
            // Post the message back to the UI thread.
        public void onActivityPinned() {
            if (DEBUG) Log.d(TAG, "onActivityPinned()");
            mHandler.post(mOnActivityPinnedRunnable);
            StackInfo stackInfo = null;
            try {
                stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
                if (stackInfo == null) {
                    Log.w(TAG, "Cannot find pinned stack");
                    return;
                }
            } catch (RemoteException e) {
                Log.e(TAG, "getStackInfo failed", e);
                return;
            }
            if (DEBUG) Log.d(TAG, "PINNED_STACK:" + stackInfo);
            mPipTaskId = stackInfo.taskIds[stackInfo.taskIds.length - 1];
            mPipComponentName = ComponentName.unflattenFromString(
                    stackInfo.taskNames[stackInfo.taskNames.length - 1]);
            // Set state to overlay so we show it when the pinned stack animation ends.
            mState = STATE_PIP_OVERLAY;
            mCurrentPipBounds = mPipBounds;
            launchPipOnboardingActivityIfNeeded();
            mMediaSessionManager.addOnActiveSessionsChangedListener(
                    mActiveMediaSessionListener, null);
            updateMediaController(mMediaSessionManager.getActiveSessions(null));
            if (mIsRecentsShown) {
                // If an activity becomes PIPed again after the fullscreen, the Recents is shown
                // behind so we need to resize the pinned stack and show the correct overlay.
                resizePinnedStack(STATE_PIP_OVERLAY);
            }
            for (int i = mListeners.size() - 1; i >= 0; i--) {
                mListeners.get(i).onPipEntered();
            }
        }

        @Override
        public void onPinnedActivityRestartAttempt() {
            // Post the message back to the UI thread.
            if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()");
            mHandler.post(mOnPinnedActivityRestartAttempt);
            // If PIPed activity is launched again by Launcher or intent, make it fullscreen.
            movePipToFullscreen();
        }

        @Override
        public void onPinnedStackAnimationEnded() {
            if (DEBUG) Log.d(TAG, "onPinnedStackAnimationEnded()");
            mHandler.post(mOnPinnedStackAnimationEnded);
            switch (mState) {
                case STATE_PIP_OVERLAY:
                    showPipOverlay();
                    break;
                case STATE_PIP_MENU:
                    showPipMenu();
                    break;
            }
        }
    };

    /**
     * A listener interface to receive notification on changes in PIP.