diff options
5 files changed, 200 insertions, 179 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java index da07aecd2c0b..287bb224dbee 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java @@ -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(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index 880fe10e2b79..9e27d3e689c5 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -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); diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 330d138ccedb..002f6707e5fa 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -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; - try { - mIam.registerTaskStackListener(listener); - } catch (Exception e) { - e.printStackTrace(); + mTaskStackListeners.add(listener); + if (mTaskStackListeners.size() == 1) { + // Register mTaskStackListener to IActivityManager only once if needed. + try { + mIam.registerTaskStackListener(mTaskStackListener); + } catch (Exception e) { + 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; + } + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index c32ef0e9daf6..726aed329124 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -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 diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java index 95cee4c0438e..acb1a7f21e78 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java @@ -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. |