From bb2980a0e0b2aa52c03dc80601d6d6fb3431bd24 Mon Sep 17 00:00:00 2001 From: Jacqueline Bronger Date: Thu, 31 Mar 2022 15:09:43 +0200 Subject: [PATCH] Handle PiP params changes in onTaskInfoChanged Before, there were two paths for listening to pip params changes, either via onTaskInfoChanged (only handle aspect ratio changes the same way for all form factors) and PinnedTaskListener. Now all PiP params changes are handled in onTaskInfoChanged and use similar listeners to allow for different behavior for different form factors. Also adds a TvPipTaskOrganizer so that only relevant params are checked. Bug: 218456378 Bug: 220042536 Bug: 228854691 Test: atest PinnedStackTests Change-Id: I673ab69ee9253db782c41da96695b5a374345086 --- .../android/view/IPinnedTaskListener.aidl | 16 -- .../android/wm/shell/dagger/TvPipModule.java | 15 +- .../wm/shell/dagger/WMShellModule.java | 18 +- .../pip/PinnedStackListenerForwarder.java | 52 ------ .../wm/shell/pip/PipMenuController.java | 5 +- .../shell/pip/PipParamsChangedForwarder.java | 125 ++++++++++++++ .../wm/shell/pip/PipTaskOrganizer.java | 51 +++--- .../com/android/wm/shell/pip/PipUtils.java | 48 ++++++ .../pip/phone/PhonePipMenuController.java | 23 +-- .../wm/shell/pip/phone/PipController.java | 60 +++++-- .../wm/shell/pip/tv/TvPipBoundsState.java | 3 + .../wm/shell/pip/tv/TvPipController.java | 154 ++++++++---------- .../wm/shell/pip/tv/TvPipMenuController.java | 6 +- .../wm/shell/pip/tv/TvPipMenuView.java | 16 +- .../wm/shell/pip/tv/TvPipTaskOrganizer.java | 85 ++++++++++ .../wm/shell/pip/PipTaskOrganizerTest.java | 10 +- .../wm/shell/pip/phone/PipControllerTest.java | 8 +- .../server/wm/ActivityClientController.java | 13 -- .../server/wm/ActivityTaskManagerService.java | 10 -- .../server/wm/PinnedTaskController.java | 103 ------------ .../core/java/com/android/server/wm/Task.java | 54 ------ 21 files changed, 462 insertions(+), 413 deletions(-) create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipParamsChangedForwarder.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java diff --git a/core/java/android/view/IPinnedTaskListener.aidl b/core/java/android/view/IPinnedTaskListener.aidl index 595a846e069ad..e4e2d6f30aabb 100644 --- a/core/java/android/view/IPinnedTaskListener.aidl +++ b/core/java/android/view/IPinnedTaskListener.aidl @@ -43,12 +43,6 @@ oneway interface IPinnedTaskListener { */ void onImeVisibilityChanged(boolean imeVisible, int imeHeight); - /** - * Called when the set of actions for the current PiP activity changes, or when the listener - * is first registered to allow the listener to synchronize its state with the controller. - */ - void onActionsChanged(in ParceledListSlice actions, in RemoteAction closeAction); - /** * Called by the window manager to notify the listener that Activity (was or is in pinned mode) * is hidden (either stopped or removed). This is generally used as a signal to reset saved @@ -56,14 +50,4 @@ oneway interface IPinnedTaskListener { * {@param componentName} represents the application component of PiP window. */ void onActivityHidden(in ComponentName componentName); - - /** - * Called by the window manager when the aspect ratio is reset. - */ - void onAspectRatioChanged(float aspectRatio); - - /** - * Called by the window manager when the expanded aspect ratio is reset. - */ - void onExpandedAspectRatioChanged(float aspectRatio); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java index 1dd5ebcd993ef..72c8141c8f2a5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java @@ -30,6 +30,7 @@ import com.android.wm.shell.common.annotations.ShellMainThread; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.PipAnimationController; import com.android.wm.shell.pip.PipMediaController; +import com.android.wm.shell.pip.PipParamsChangedForwarder; import com.android.wm.shell.pip.PipSnapAlgorithm; import com.android.wm.shell.pip.PipSurfaceTransactionHelper; import com.android.wm.shell.pip.PipTaskOrganizer; @@ -41,6 +42,7 @@ import com.android.wm.shell.pip.tv.TvPipBoundsState; import com.android.wm.shell.pip.tv.TvPipController; import com.android.wm.shell.pip.tv.TvPipMenuController; import com.android.wm.shell.pip.tv.TvPipNotificationController; +import com.android.wm.shell.pip.tv.TvPipTaskOrganizer; import com.android.wm.shell.pip.tv.TvPipTransition; import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.transition.Transitions; @@ -67,6 +69,7 @@ public abstract class TvPipModule { PipTransitionController pipTransitionController, TvPipNotificationController tvPipNotificationController, TaskStackListenerImpl taskStackListener, + PipParamsChangedForwarder pipParamsChangedForwarder, DisplayController displayController, WindowManagerShellWrapper windowManagerShellWrapper, @ShellMainThread ShellExecutor mainExecutor, @@ -82,6 +85,7 @@ public abstract class TvPipModule { pipMediaController, tvPipNotificationController, taskStackListener, + pipParamsChangedForwarder, displayController, windowManagerShellWrapper, mainExecutor, @@ -163,15 +167,22 @@ public abstract class TvPipModule { TvPipBoundsAlgorithm tvPipBoundsAlgorithm, PipAnimationController pipAnimationController, PipTransitionController pipTransitionController, + PipParamsChangedForwarder pipParamsChangedForwarder, PipSurfaceTransactionHelper pipSurfaceTransactionHelper, Optional splitScreenControllerOptional, DisplayController displayController, PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer, @ShellMainThread ShellExecutor mainExecutor) { - return new PipTaskOrganizer(context, + return new TvPipTaskOrganizer(context, syncTransactionQueue, pipTransitionState, tvPipBoundsState, tvPipBoundsAlgorithm, tvPipMenuController, pipAnimationController, pipSurfaceTransactionHelper, - pipTransitionController, splitScreenControllerOptional, + pipTransitionController, pipParamsChangedForwarder, splitScreenControllerOptional, displayController, pipUiEventLogger, shellTaskOrganizer, mainExecutor); } + + @WMSingleton + @Provides + static PipParamsChangedForwarder providePipParamsChangedForwarder() { + return new PipParamsChangedForwarder(); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index e43f4fc34adfc..7513e5129ade2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -54,6 +54,7 @@ import com.android.wm.shell.pip.PipAnimationController; import com.android.wm.shell.pip.PipBoundsAlgorithm; import com.android.wm.shell.pip.PipBoundsState; import com.android.wm.shell.pip.PipMediaController; +import com.android.wm.shell.pip.PipParamsChangedForwarder; import com.android.wm.shell.pip.PipSnapAlgorithm; import com.android.wm.shell.pip.PipSurfaceTransactionHelper; import com.android.wm.shell.pip.PipTaskOrganizer; @@ -216,14 +217,14 @@ public class WMShellModule { PipTouchHandler pipTouchHandler, PipTransitionController pipTransitionController, WindowManagerShellWrapper windowManagerShellWrapper, TaskStackListenerImpl taskStackListener, + PipParamsChangedForwarder pipParamsChangedForwarder, Optional oneHandedController, @ShellMainThread ShellExecutor mainExecutor) { return Optional.ofNullable(PipController.create(context, displayController, pipAppOpsListener, pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState, - pipMotionHelper, - pipMediaController, phonePipMenuController, pipTaskOrganizer, pipTouchHandler, - pipTransitionController, windowManagerShellWrapper, taskStackListener, - oneHandedController, mainExecutor)); + pipMotionHelper, pipMediaController, phonePipMenuController, pipTaskOrganizer, + pipTouchHandler, pipTransitionController, windowManagerShellWrapper, + taskStackListener, pipParamsChangedForwarder, oneHandedController, mainExecutor)); } @WMSingleton @@ -297,6 +298,7 @@ public class WMShellModule { PipAnimationController pipAnimationController, PipSurfaceTransactionHelper pipSurfaceTransactionHelper, PipTransitionController pipTransitionController, + PipParamsChangedForwarder pipParamsChangedForwarder, Optional splitScreenControllerOptional, DisplayController displayController, PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer, @@ -304,7 +306,7 @@ public class WMShellModule { return new PipTaskOrganizer(context, syncTransactionQueue, pipTransitionState, pipBoundsState, pipBoundsAlgorithm, menuPhoneController, pipAnimationController, pipSurfaceTransactionHelper, - pipTransitionController, splitScreenControllerOptional, + pipTransitionController, pipParamsChangedForwarder, splitScreenControllerOptional, displayController, pipUiEventLogger, shellTaskOrganizer, mainExecutor); } @@ -391,4 +393,10 @@ public class WMShellModule { rootTaskDisplayAreaOrganizer ); } + + @WMSingleton + @Provides + static PipParamsChangedForwarder providePipParamsChangedForwarder() { + return new PipParamsChangedForwarder(); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java index 87eca74acd0b2..ce98458c05756 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java @@ -16,9 +16,7 @@ package com.android.wm.shell.pip; -import android.app.RemoteAction; import android.content.ComponentName; -import android.content.pm.ParceledListSlice; import android.os.RemoteException; import android.view.IPinnedTaskListener; import android.view.WindowManagerGlobal; @@ -72,31 +70,12 @@ public class PinnedStackListenerForwarder { } } - private void onActionsChanged(ParceledListSlice actions, - RemoteAction closeAction) { - for (PinnedTaskListener listener : mListeners) { - listener.onActionsChanged(actions, closeAction); - } - } - private void onActivityHidden(ComponentName componentName) { for (PinnedTaskListener listener : mListeners) { listener.onActivityHidden(componentName); } } - private void onAspectRatioChanged(float aspectRatio) { - for (PinnedTaskListener listener : mListeners) { - listener.onAspectRatioChanged(aspectRatio); - } - } - - private void onExpandedAspectRatioChanged(float aspectRatio) { - for (PinnedTaskListener listener : mListeners) { - listener.onExpandedAspectRatioChanged(aspectRatio); - } - } - @BinderThread private class PinnedTaskListenerImpl extends IPinnedTaskListener.Stub { @Override @@ -113,36 +92,12 @@ public class PinnedStackListenerForwarder { }); } - @Override - public void onActionsChanged(ParceledListSlice actions, - RemoteAction closeAction) { - mMainExecutor.execute(() -> { - PinnedStackListenerForwarder.this.onActionsChanged(actions, closeAction); - }); - } - @Override public void onActivityHidden(ComponentName componentName) { mMainExecutor.execute(() -> { PinnedStackListenerForwarder.this.onActivityHidden(componentName); }); } - - @Override - public void onAspectRatioChanged(float aspectRatio) { - mMainExecutor.execute(() -> { - PinnedStackListenerForwarder.this.onAspectRatioChanged(aspectRatio); - }); - } - - @Override - public void onExpandedAspectRatioChanged(float aspectRatio) { - mMainExecutor.execute(() -> { - PinnedStackListenerForwarder.this.onExpandedAspectRatioChanged(aspectRatio); - }); - } - - } /** @@ -154,13 +109,6 @@ public class PinnedStackListenerForwarder { public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {} - public void onActionsChanged(ParceledListSlice actions, - RemoteAction closeAction) {} - public void onActivityHidden(ComponentName componentName) {} - - public void onAspectRatioChanged(float aspectRatio) {} - - public void onExpandedAspectRatioChanged(float aspectRatio) {} } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java index f6ff294b43286..16f1d1c2944c3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java @@ -26,12 +26,13 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import android.annotation.Nullable; import android.app.ActivityManager.RunningTaskInfo; import android.app.RemoteAction; -import android.content.pm.ParceledListSlice; import android.graphics.PixelFormat; import android.graphics.Rect; import android.view.SurfaceControl; import android.view.WindowManager; +import java.util.List; + /** * Interface to allow {@link com.android.wm.shell.pip.PipTaskOrganizer} to call into * PiP menu when certain events happen (task appear/vanish, PiP move, etc.) @@ -66,7 +67,7 @@ public interface PipMenuController { /** * Given a set of actions, update the menu. */ - void setAppActions(ParceledListSlice appActions, RemoteAction closeAction); + void setAppActions(List appActions, RemoteAction closeAction); /** * Resize the PiP menu with the given bounds. The PiP SurfaceControl is given if there is a diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipParamsChangedForwarder.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipParamsChangedForwarder.java new file mode 100644 index 0000000000000..21ba85459c48c --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipParamsChangedForwarder.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2022 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.wm.shell.pip; + +import android.app.RemoteAction; + +import java.util.ArrayList; +import java.util.List; + +/** + * Forwards changes to the Picture-in-Picture params to all listeners. + */ +public class PipParamsChangedForwarder { + + private final List + mPipParamsChangedListeners = new ArrayList<>(); + + /** + * Add a listener that implements at least one of the callbacks. + */ + public void addListener(PipParamsChangedCallback listener) { + if (mPipParamsChangedListeners.contains(listener)) { + return; + } + mPipParamsChangedListeners.add(listener); + } + + /** + * Call to notify all listeners of the changed aspect ratio. + */ + public void notifyAspectRatioChanged(float aspectRatio) { + for (PipParamsChangedCallback listener : mPipParamsChangedListeners) { + listener.onAspectRatioChanged(aspectRatio); + } + } + + /** + * Call to notify all listeners of the changed expanded aspect ratio. + */ + public void notifyExpandedAspectRatioChanged(float aspectRatio) { + for (PipParamsChangedCallback listener : mPipParamsChangedListeners) { + listener.onExpandedAspectRatioChanged(aspectRatio); + } + } + + /** + * Call to notify all listeners of the changed title. + */ + public void notifyTitleChanged(CharSequence title) { + String value = title == null ? null : title.toString(); + for (PipParamsChangedCallback listener : mPipParamsChangedListeners) { + listener.onTitleChanged(value); + } + } + + /** + * Call to notify all listeners of the changed subtitle. + */ + public void notifySubtitleChanged(CharSequence subtitle) { + String value = subtitle == null ? null : subtitle.toString(); + for (PipParamsChangedCallback listener : mPipParamsChangedListeners) { + listener.onSubtitleChanged(value); + } + } + + /** + * Call to notify all listeners of the changed app actions or close action. + */ + public void notifyActionsChanged(List actions, RemoteAction closeAction) { + for (PipParamsChangedCallback listener : mPipParamsChangedListeners) { + listener.onActionsChanged(actions, closeAction); + } + } + + /** + * Contains callbacks for PiP params changes. Subclasses can choose which changes they want to + * listen to by only overriding those selectively. + */ + public interface PipParamsChangedCallback { + + /** + * Called if aspect ratio changed. + */ + default void onAspectRatioChanged(float aspectRatio) { + } + + /** + * Called if expanded aspect ratio changed. + */ + default void onExpandedAspectRatioChanged(float aspectRatio) { + } + + /** + * Called if either the actions or the close action changed. + */ + default void onActionsChanged(List actions, RemoteAction closeAction) { + } + + /** + * Called if the title changed. + */ + default void onTitleChanged(String title) { + } + + /** + * Called if the subtitle changed. + */ + default void onSubtitleChanged(String subtitle) { + } + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index fbdf6f0b539fb..4690e16bc3859 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -62,7 +62,6 @@ import android.content.res.Configuration; import android.graphics.Rect; import android.os.RemoteException; import android.os.SystemClock; -import android.util.Rational; import android.view.Display; import android.view.Surface; import android.view.SurfaceControl; @@ -127,6 +126,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, private final @NonNull PipMenuController mPipMenuController; private final PipAnimationController mPipAnimationController; private final PipTransitionController mPipTransitionController; + protected final PipParamsChangedForwarder mPipParamsChangedForwarder; private final PipUiEventLogger mPipUiEventLoggerLogger; private final int mEnterAnimationDuration; private final int mExitAnimationDuration; @@ -219,7 +219,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, private long mLastOneShotAlphaAnimationTime; private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mSurfaceControlTransactionFactory; - private PictureInPictureParams mPictureInPictureParams; + protected PictureInPictureParams mPictureInPictureParams; private IntConsumer mOnDisplayIdChangeCallback; /** * The end transaction of PiP animation for switching between PiP and fullscreen with @@ -259,6 +259,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, @NonNull PipAnimationController pipAnimationController, @NonNull PipSurfaceTransactionHelper surfaceTransactionHelper, @NonNull PipTransitionController pipTransitionController, + @NonNull PipParamsChangedForwarder pipParamsChangedForwarder, Optional splitScreenOptional, @NonNull DisplayController displayController, @NonNull PipUiEventLogger pipUiEventLogger, @@ -271,6 +272,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mPipBoundsAlgorithm = boundsHandler; mPipMenuController = pipMenuController; mPipTransitionController = pipTransitionController; + mPipParamsChangedForwarder = pipParamsChangedForwarder; mEnterAnimationDuration = context.getResources() .getInteger(R.integer.config_pipEnterAnimationDuration); mExitAnimationDuration = context.getResources() @@ -559,6 +561,14 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mPictureInPictureParams = mTaskInfo.pictureInPictureParams; setBoundsStateForEntry(mTaskInfo.topActivity, mPictureInPictureParams, mTaskInfo.topActivityInfo); + if (mPictureInPictureParams != null) { + mPipParamsChangedForwarder.notifyActionsChanged(mPictureInPictureParams.getActions(), + mPictureInPictureParams.getCloseAction()); + mPipParamsChangedForwarder.notifyTitleChanged( + mPictureInPictureParams.getTitle()); + mPipParamsChangedForwarder.notifySubtitleChanged( + mPictureInPictureParams.getSubtitle()); + } mPipUiEventLoggerLogger.setTaskInfo(mTaskInfo); mPipUiEventLoggerLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_ENTER); @@ -819,17 +829,13 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mPipBoundsState.setOverrideMinSize( mPipBoundsAlgorithm.getMinimalSize(info.topActivityInfo)); final PictureInPictureParams newParams = info.pictureInPictureParams; - if (newParams == null || !applyPictureInPictureParams(newParams)) { - ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: Ignored onTaskInfoChanged with PiP param: %s", TAG, newParams); + + // mPictureInPictureParams is only null if there is no PiP + if (newParams == null || mPictureInPictureParams == null) { return; } - // Aspect ratio changed, re-calculate bounds if valid. - final Rect destinationBounds = mPipBoundsAlgorithm.getAdjustedDestinationBounds( - mPipBoundsState.getBounds(), mPipBoundsState.getAspectRatio()); - Objects.requireNonNull(destinationBounds, "Missing destination bounds"); - scheduleAnimateResizePip(destinationBounds, mEnterAnimationDuration, - null /* updateBoundsCallback */); + applyNewPictureInPictureParams(newParams); + mPictureInPictureParams = newParams; } @Override @@ -1076,20 +1082,19 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, } /** - * @return {@code true} if the aspect ratio is changed since no other parameters within - * {@link PictureInPictureParams} would affect the bounds. + * Handles all changes to the PictureInPictureParams. */ - private boolean applyPictureInPictureParams(@NonNull PictureInPictureParams params) { - final Rational currentAspectRatio = - mPictureInPictureParams != null ? mPictureInPictureParams.getAspectRatio() - : null; - final boolean aspectRatioChanged = !Objects.equals(currentAspectRatio, - params.getAspectRatio()); - mPictureInPictureParams = params; - if (aspectRatioChanged) { - mPipBoundsState.setAspectRatio(params.getAspectRatioFloat()); + protected void applyNewPictureInPictureParams(@NonNull PictureInPictureParams params) { + if (PipUtils.aspectRatioChanged(params.getAspectRatioFloat(), + mPictureInPictureParams.getAspectRatioFloat())) { + mPipParamsChangedForwarder.notifyAspectRatioChanged(params.getAspectRatioFloat()); + } + if (PipUtils.remoteActionsChanged(params.getActions(), mPictureInPictureParams.getActions()) + || !PipUtils.remoteActionsMatch(params.getCloseAction(), + mPictureInPictureParams.getCloseAction())) { + mPipParamsChangedForwarder.notifyActionsChanged(params.getActions(), + params.getCloseAction()); } - return aspectRatioChanged; } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUtils.java index d7b69adf12412..c6cf8b8b05667 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUtils.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUtils.java @@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import android.app.ActivityTaskManager; import android.app.ActivityTaskManager.RootTaskInfo; +import android.app.RemoteAction; import android.content.ComponentName; import android.content.Context; import android.os.RemoteException; @@ -29,10 +30,16 @@ import android.util.Pair; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.protolog.ShellProtoLogGroup; +import java.util.List; +import java.util.Objects; + /** A class that includes convenience methods. */ public class PipUtils { private static final String TAG = "PipUtils"; + // Minimum difference between two floats (e.g. aspect ratios) to consider them not equal. + private static final double EPSILON = 1e-7; + /** * @return the ComponentName and user id of the top non-SystemUI activity in the pinned stack. * The component name may be null if no such activity exists. @@ -58,4 +65,45 @@ public class PipUtils { } return new Pair<>(null, 0); } + + /** + * @return true if the aspect ratios differ + */ + public static boolean aspectRatioChanged(float aspectRatio1, float aspectRatio2) { + return Math.abs(aspectRatio1 - aspectRatio2) > EPSILON; + } + + /** + * Checks whether title, description and intent match. + * Comparing icons would be good, but using equals causes false negatives + */ + public static boolean remoteActionsMatch(RemoteAction action1, RemoteAction action2) { + if (action1 == action2) return true; + if (action1 == null || action2 == null) return false; + return Objects.equals(action1.getTitle(), action2.getTitle()) + && Objects.equals(action1.getContentDescription(), action2.getContentDescription()) + && Objects.equals(action1.getActionIntent(), action2.getActionIntent()); + } + + /** + * Returns true if the actions in the lists match each other according to {@link + * PipUtils#remoteActionsMatch(RemoteAction, RemoteAction)}, including their position. + */ + public static boolean remoteActionsChanged(List list1, List list2) { + if (list1 == null && list2 == null) { + return false; + } + if (list1 == null || list2 == null) { + return true; + } + if (list1.size() != list2.size()) { + return true; + } + for (int i = 0; i < list1.size(); i++) { + if (!remoteActionsMatch(list1.get(i), list2.get(i))) { + return true; + } + } + return false; + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java index bbec4eccce3c7..4942987742a0c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java @@ -22,7 +22,6 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.app.RemoteAction; import android.content.Context; -import android.content.pm.ParceledListSlice; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.RectF; @@ -120,9 +119,11 @@ public class PhonePipMenuController implements PipMenuController { private final SystemWindows mSystemWindows; private final Optional mSplitScreenController; private final PipUiEventLogger mPipUiEventLogger; - private ParceledListSlice mAppActions; + + private List mAppActions; private RemoteAction mCloseAction; - private ParceledListSlice mMediaActions; + private List mMediaActions; + private SyncRtSurfaceTransactionApplier mApplier; private int mMenuState; @@ -131,7 +132,7 @@ public class PhonePipMenuController implements PipMenuController { private ActionListener mMediaActionListener = new ActionListener() { @Override public void onMediaActionsChanged(List mediaActions) { - mMediaActions = new ParceledListSlice<>(mediaActions); + mMediaActions = new ArrayList<>(mediaActions); updateMenuActions(); } }; @@ -183,6 +184,9 @@ public class PhonePipMenuController implements PipMenuController { getPipMenuLayoutParams(MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */), 0, SHELL_ROOT_LAYER_PIP); setShellRootAccessibilityWindow(); + + // Make sure the initial actions are set + updateMenuActions(); } private void detachPipMenuView() { @@ -457,7 +461,7 @@ public class PhonePipMenuController implements PipMenuController { * Sets the menu actions to the actions provided by the current PiP menu. */ @Override - public void setAppActions(ParceledListSlice appActions, + public void setAppActions(List appActions, RemoteAction closeAction) { mAppActions = appActions; mCloseAction = closeAction; @@ -479,7 +483,7 @@ public class PhonePipMenuController implements PipMenuController { /** * @return the best set of actions to show in the PiP menu. */ - private ParceledListSlice resolveMenuActions() { + private List resolveMenuActions() { if (isValidActions(mAppActions)) { return mAppActions; } @@ -491,17 +495,16 @@ public class PhonePipMenuController implements PipMenuController { */ private void updateMenuActions() { if (mPipMenuView != null) { - final ParceledListSlice menuActions = resolveMenuActions(); mPipMenuView.setActions(mPipBoundsState.getBounds(), - menuActions == null ? null : menuActions.getList(), mCloseAction); + resolveMenuActions(), mCloseAction); } } /** * Returns whether the set of actions are valid. */ - private static boolean isValidActions(ParceledListSlice actions) { - return actions != null && actions.getList().size() > 0; + private static boolean isValidActions(List actions) { + return actions != null && actions.size() > 0; } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index 272331b7cd3fd..2e8b5b7979d01 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -40,7 +40,6 @@ import android.app.RemoteAction; import android.content.ComponentName; import android.content.Context; import android.content.pm.ActivityInfo; -import android.content.pm.ParceledListSlice; import android.content.res.Configuration; import android.graphics.Rect; import android.os.RemoteException; @@ -80,6 +79,7 @@ import com.android.wm.shell.pip.PipAnimationController; import com.android.wm.shell.pip.PipBoundsAlgorithm; import com.android.wm.shell.pip.PipBoundsState; import com.android.wm.shell.pip.PipMediaController; +import com.android.wm.shell.pip.PipParamsChangedForwarder; import com.android.wm.shell.pip.PipSnapAlgorithm; import com.android.wm.shell.pip.PipTaskOrganizer; import com.android.wm.shell.pip.PipTransitionController; @@ -88,6 +88,8 @@ import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.transition.Transitions; import java.io.PrintWriter; +import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; @@ -113,10 +115,12 @@ public class PipController implements PipTransitionController.PipTransitionCallb private PipTouchHandler mTouchHandler; private PipTransitionController mPipTransitionController; private TaskStackListenerImpl mTaskStackListener; + private PipParamsChangedForwarder mPipParamsChangedForwarder; private Optional mOneHandedController; protected final PipImpl mImpl; private final Rect mTmpInsetBounds = new Rect(); + private final int mEnterAnimationDuration; private boolean mIsInFixedRotation; private PipAnimationListener mPinnedStackAnimationRecentsCallback; @@ -269,12 +273,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb null /* windowContainerTransaction */); } - @Override - public void onActionsChanged(ParceledListSlice actions, - RemoteAction closeAction) { - mMenuController.setAppActions(actions, closeAction); - } - @Override public void onActivityHidden(ComponentName componentName) { if (componentName.equals(mPipBoundsState.getLastPipComponentName())) { @@ -283,14 +281,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb mPipBoundsState.setLastPipComponentName(null); } } - - @Override - public void onAspectRatioChanged(float aspectRatio) { - // TODO(b/169373982): Remove this callback as it is redundant with PipTaskOrg params - // change. - mPipBoundsState.setAspectRatio(aspectRatio); - mTouchHandler.onAspectRatioChanged(); - } } /** @@ -305,6 +295,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb PipTouchHandler pipTouchHandler, PipTransitionController pipTransitionController, WindowManagerShellWrapper windowManagerShellWrapper, TaskStackListenerImpl taskStackListener, + PipParamsChangedForwarder pipParamsChangedForwarder, Optional oneHandedController, ShellExecutor mainExecutor) { if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) { @@ -315,8 +306,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb return new PipController(context, displayController, pipAppOpsListener, pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState, pipMotionHelper, pipMediaController, - phonePipMenuController, pipTaskOrganizer, pipTouchHandler, pipTransitionController, - windowManagerShellWrapper, taskStackListener, oneHandedController, mainExecutor) + phonePipMenuController, pipTaskOrganizer, pipTouchHandler, pipTransitionController, + windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder, + oneHandedController, mainExecutor) .mImpl; } @@ -334,6 +326,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb PipTransitionController pipTransitionController, WindowManagerShellWrapper windowManagerShellWrapper, TaskStackListenerImpl taskStackListener, + PipParamsChangedForwarder pipParamsChangedForwarder, Optional oneHandedController, ShellExecutor mainExecutor ) { @@ -360,6 +353,11 @@ public class PipController implements PipTransitionController.PipTransitionCallb mOneHandedController = oneHandedController; mPipTransitionController = pipTransitionController; mTaskStackListener = taskStackListener; + + mEnterAnimationDuration = mContext.getResources() + .getInteger(R.integer.config_pipEnterAnimationDuration); + mPipParamsChangedForwarder = pipParamsChangedForwarder; + //TODO: move this to ShellInit when PipController can be injected mMainExecutor.execute(this::init); } @@ -457,6 +455,34 @@ public class PipController implements PipTransitionController.PipTransitionCallb } }); + mPipParamsChangedForwarder.addListener( + new PipParamsChangedForwarder.PipParamsChangedCallback() { + @Override + public void onAspectRatioChanged(float ratio) { + mPipBoundsState.setAspectRatio(ratio); + + final Rect destinationBounds = + mPipBoundsAlgorithm.getAdjustedDestinationBounds( + mPipBoundsState.getBounds(), + mPipBoundsState.getAspectRatio()); + Objects.requireNonNull(destinationBounds, "Missing destination bounds"); + mPipTaskOrganizer.scheduleAnimateResizePip(destinationBounds, + mEnterAnimationDuration, + null /* updateBoundsCallback */); + + mTouchHandler.onAspectRatioChanged(); + updateMovementBounds(null /* toBounds */, false /* fromRotation */, + false /* fromImeAdjustment */, false /* fromShelfAdjustment */, + null /* windowContainerTransaction */); + } + + @Override + public void onActionsChanged(List actions, + RemoteAction closeAction) { + mMenuController.setAppActions(actions, closeAction); + } + }); + mOneHandedController.ifPresent(controller -> { controller.asOneHanded().registerTransitionCallback( new OneHandedTransitionCallback() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java index a3048bd8fabed..ca22882187d8f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java @@ -77,6 +77,9 @@ public class TvPipBoundsState extends PipBoundsState { public void setBoundsStateForEntry(ComponentName componentName, ActivityInfo activityInfo, PictureInPictureParams params, PipBoundsAlgorithm pipBoundsAlgorithm) { super.setBoundsStateForEntry(componentName, activityInfo, params, pipBoundsAlgorithm); + if (params == null) { + return; + } setDesiredTvExpandedAspectRatio(params.getExpandedAspectRatioFloat(), true); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java index 0e1f5a24f4a73..7f155cae4ff5e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java @@ -27,7 +27,6 @@ import android.app.RemoteAction; import android.app.TaskInfo; import android.content.ComponentName; import android.content.Context; -import android.content.pm.ParceledListSlice; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Rect; @@ -48,6 +47,7 @@ import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.PipAnimationController; import com.android.wm.shell.pip.PipBoundsState; import com.android.wm.shell.pip.PipMediaController; +import com.android.wm.shell.pip.PipParamsChangedForwarder; import com.android.wm.shell.pip.PipTaskOrganizer; import com.android.wm.shell.pip.PipTransitionController; import com.android.wm.shell.pip.tv.TvPipKeepClearAlgorithm.Placement; @@ -55,6 +55,7 @@ import com.android.wm.shell.protolog.ShellProtoLogGroup; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.List; import java.util.Set; /** @@ -66,7 +67,6 @@ public class TvPipController implements PipTransitionController.PipTransitionCal private static final String TAG = "TvPipController"; static final boolean DEBUG = false; - private static final double EPS = 1e-7; private static final int NONEXISTENT_TASK_ID = -1; @Retention(RetentionPolicy.SOURCE) @@ -127,6 +127,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal PipMediaController pipMediaController, TvPipNotificationController pipNotificationController, TaskStackListenerImpl taskStackListener, + PipParamsChangedForwarder pipParamsChangedForwarder, DisplayController displayController, WindowManagerShellWrapper wmShell, ShellExecutor mainExecutor, @@ -141,6 +142,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal pipMediaController, pipNotificationController, taskStackListener, + pipParamsChangedForwarder, displayController, wmShell, mainExecutor, @@ -157,6 +159,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal PipMediaController pipMediaController, TvPipNotificationController pipNotificationController, TaskStackListenerImpl taskStackListener, + PipParamsChangedForwarder pipParamsChangedForwarder, DisplayController displayController, WindowManagerShellWrapper wmShell, ShellExecutor mainExecutor, @@ -183,6 +186,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal loadConfigurations(); + registerPipParamsChangedListener(pipParamsChangedForwarder); registerTaskStackListenerCallback(taskStackListener); registerWmShellPinnedStackListener(wmShell); displayController.addDisplayWindowListener(this); @@ -540,6 +544,72 @@ public class TvPipController implements PipTransitionController.PipTransitionCal }); } + private void registerPipParamsChangedListener(PipParamsChangedForwarder provider) { + provider.addListener(new PipParamsChangedForwarder.PipParamsChangedCallback() { + @Override + public void onActionsChanged(List actions, + RemoteAction closeAction) { + ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, + "%s: onActionsChanged()", TAG); + + mTvPipMenuController.setAppActions(actions, closeAction); + mCloseAction = closeAction; + } + + @Override + public void onAspectRatioChanged(float ratio) { + ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, + "%s: onAspectRatioChanged: %f", TAG, ratio); + + mTvPipBoundsState.setAspectRatio(ratio); + if (!mTvPipBoundsState.isTvPipExpanded()) { + updatePinnedStackBounds(); + } + } + + @Override + public void onExpandedAspectRatioChanged(float ratio) { + ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, + "%s: onExpandedAspectRatioChanged: %f", TAG, ratio); + + mTvPipBoundsState.setDesiredTvExpandedAspectRatio(ratio, false); + + // 1) PiP is expanded and only aspect ratio changed, but wasn't disabled + // --> update bounds, but don't toggle + if (mTvPipBoundsState.isTvPipExpanded() && ratio != 0) { + mTvPipBoundsAlgorithm.updateExpandedPipSize(); + updatePinnedStackBounds(); + } + + // 2) PiP is expanded, but expanded PiP was disabled + // --> collapse PiP + if (mTvPipBoundsState.isTvPipExpanded() && ratio == 0) { + int saveGravity = mTvPipBoundsAlgorithm + .updateGravityOnExpandToggled(mPreviousGravity, false); + if (saveGravity != Gravity.NO_GRAVITY) { + mPreviousGravity = saveGravity; + } + mTvPipBoundsState.setTvPipExpanded(false); + updatePinnedStackBounds(); + } + + // 3) PiP not expanded and not manually collapsed and expand was enabled + // --> expand to new ratio + if (!mTvPipBoundsState.isTvPipExpanded() && ratio != 0 + && !mTvPipBoundsState.isTvPipManuallyCollapsed()) { + mTvPipBoundsAlgorithm.updateExpandedPipSize(); + int saveGravity = mTvPipBoundsAlgorithm + .updateGravityOnExpandToggled(mPreviousGravity, true); + if (saveGravity != Gravity.NO_GRAVITY) { + mPreviousGravity = saveGravity; + } + mTvPipBoundsState.setTvPipExpanded(true); + updatePinnedStackBounds(); + } + } + }); + } + private void registerWmShellPinnedStackListener(WindowManagerShellWrapper wmShell) { try { wmShell.addPinnedStackListener(new PinnedStackListenerForwarder.PinnedTaskListener() { @@ -563,86 +633,6 @@ public class TvPipController implements PipTransitionController.PipTransitionCal updatePinnedStackBounds(); } } - - @Override - public void onAspectRatioChanged(float ratio) { - if (DEBUG) { - ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: onAspectRatioChanged: %f", TAG, ratio); - } - - boolean ratioChanged = mTvPipBoundsState.getAspectRatio() != ratio; - mTvPipBoundsState.setAspectRatio(ratio); - - if (!mTvPipBoundsState.isTvPipExpanded() && ratioChanged) { - updatePinnedStackBounds(); - } - } - - @Override - public void onExpandedAspectRatioChanged(float ratio) { - if (DEBUG) { - ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: onExpandedAspectRatioChanged: %f", TAG, ratio); - } - - // 0) No update to the ratio --> don't do anything - - if (Math.abs(mTvPipBoundsState.getDesiredTvExpandedAspectRatio() - ratio) - < EPS) { - return; - } - - mTvPipBoundsState.setDesiredTvExpandedAspectRatio(ratio, false); - - // 1) PiP is expanded and only aspect ratio changed, but wasn't disabled - // --> update bounds, but don't toggle - if (mTvPipBoundsState.isTvPipExpanded() && ratio != 0) { - mTvPipBoundsAlgorithm.updateExpandedPipSize(); - updatePinnedStackBounds(); - } - - // 2) PiP is expanded, but expanded PiP was disabled - // --> collapse PiP - if (mTvPipBoundsState.isTvPipExpanded() && ratio == 0) { - int saveGravity = mTvPipBoundsAlgorithm - .updateGravityOnExpandToggled(mPreviousGravity, false); - if (saveGravity != Gravity.NO_GRAVITY) { - mPreviousGravity = saveGravity; - } - mTvPipBoundsState.setTvPipExpanded(false); - updatePinnedStackBounds(); - } - - // 3) PiP not expanded and not manually collapsed and expand was enabled - // --> expand to new ratio - if (!mTvPipBoundsState.isTvPipExpanded() && ratio != 0 - && !mTvPipBoundsState.isTvPipManuallyCollapsed()) { - mTvPipBoundsAlgorithm.updateExpandedPipSize(); - int saveGravity = mTvPipBoundsAlgorithm - .updateGravityOnExpandToggled(mPreviousGravity, true); - if (saveGravity != Gravity.NO_GRAVITY) { - mPreviousGravity = saveGravity; - } - mTvPipBoundsState.setTvPipExpanded(true); - updatePinnedStackBounds(); - } - } - - @Override - public void onMovementBoundsChanged(boolean fromImeAdjustment) {} - - @Override - public void onActionsChanged(ParceledListSlice actions, - RemoteAction closeAction) { - if (DEBUG) { - ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: onActionsChanged()", TAG); - } - - mTvPipMenuController.setAppActions(actions, closeAction); - mCloseAction = closeAction; - } }); } catch (RemoteException e) { ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java index 2d67254f36109..bbd21b4940a5e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java @@ -24,7 +24,6 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.ParceledListSlice; import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.Rect; @@ -169,6 +168,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis mPipMenuView.setListener(this); setUpViewSurfaceZOrder(mPipMenuView, 1); addPipMenuViewToSystemWindows(mPipMenuView, MENU_WINDOW_TITLE); + maybeUpdateMenuViewActions(); } private void attachPipBackgroundView() { @@ -336,12 +336,12 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis } @Override - public void setAppActions(ParceledListSlice actions, RemoteAction closeAction) { + public void setAppActions(List actions, RemoteAction closeAction) { if (DEBUG) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: setAppActions()", TAG); } - updateAdditionalActionsList(mAppActions, actions.getList(), closeAction); + updateAdditionalActionsList(mAppActions, actions, closeAction); } private void onMediaActionsChanged(List actions) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java index 5b0db8c865299..3161b02d15454 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java @@ -53,12 +53,12 @@ import androidx.annotation.Nullable; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.R; +import com.android.wm.shell.pip.PipUtils; import com.android.wm.shell.protolog.ShellProtoLogGroup; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Objects; /** * A View that represents Pip Menu on TV. It's responsible for displaying 3 ever-present Pip Menu @@ -398,7 +398,7 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { final TvPipMenuActionButton button = mAdditionalButtons.get(index); // Remove action if it matches the custom close action. - if (actionsMatch(action, closeAction)) { + if (PipUtils.remoteActionsMatch(action, closeAction)) { button.setVisibility(GONE); continue; } @@ -406,18 +406,6 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { } } - /** - * Checks whether title, description and intent match. - * Comparing icons would be good, but using equals causes false negatives - */ - private boolean actionsMatch(RemoteAction action1, RemoteAction action2) { - if (action1 == action2) return true; - if (action1 == null || action2 == null) return false; - return Objects.equals(action1.getTitle(), action2.getTitle()) - && Objects.equals(action1.getContentDescription(), action2.getContentDescription()) - && Objects.equals(action1.getActionIntent(), action2.getActionIntent()); - } - private void setActionForButton(RemoteAction action, TvPipMenuActionButton button, Handler mainHandler) { button.setVisibility(View.VISIBLE); // Ensure the button is visible. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java new file mode 100644 index 0000000000000..42fd1aab44f89 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2022 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.wm.shell.pip.tv; + +import android.app.PictureInPictureParams; +import android.content.Context; + +import androidx.annotation.NonNull; + +import com.android.wm.shell.ShellTaskOrganizer; +import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.common.SyncTransactionQueue; +import com.android.wm.shell.pip.PipAnimationController; +import com.android.wm.shell.pip.PipBoundsAlgorithm; +import com.android.wm.shell.pip.PipBoundsState; +import com.android.wm.shell.pip.PipMenuController; +import com.android.wm.shell.pip.PipParamsChangedForwarder; +import com.android.wm.shell.pip.PipSurfaceTransactionHelper; +import com.android.wm.shell.pip.PipTaskOrganizer; +import com.android.wm.shell.pip.PipTransitionController; +import com.android.wm.shell.pip.PipTransitionState; +import com.android.wm.shell.pip.PipUiEventLogger; +import com.android.wm.shell.pip.PipUtils; +import com.android.wm.shell.splitscreen.SplitScreenController; + +import java.util.Objects; +import java.util.Optional; + +/** + * TV specific changes to the PipTaskOrganizer. + */ +public class TvPipTaskOrganizer extends PipTaskOrganizer { + + public TvPipTaskOrganizer(Context context, + @NonNull SyncTransactionQueue syncTransactionQueue, + @NonNull PipTransitionState pipTransitionState, + @NonNull PipBoundsState pipBoundsState, + @NonNull PipBoundsAlgorithm boundsHandler, + @NonNull PipMenuController pipMenuController, + @NonNull PipAnimationController pipAnimationController, + @NonNull PipSurfaceTransactionHelper surfaceTransactionHelper, + @NonNull PipTransitionController pipTransitionController, + @NonNull PipParamsChangedForwarder pipParamsChangedForwarder, + Optional splitScreenOptional, + @NonNull DisplayController displayController, + @NonNull PipUiEventLogger pipUiEventLogger, + @NonNull ShellTaskOrganizer shellTaskOrganizer, + ShellExecutor mainExecutor) { + super(context, syncTransactionQueue, pipTransitionState, pipBoundsState, boundsHandler, + pipMenuController, pipAnimationController, surfaceTransactionHelper, + pipTransitionController, pipParamsChangedForwarder, splitScreenOptional, + displayController, pipUiEventLogger, shellTaskOrganizer, mainExecutor); + } + + @Override + protected void applyNewPictureInPictureParams(@NonNull PictureInPictureParams params) { + super.applyNewPictureInPictureParams(params); + if (PipUtils.aspectRatioChanged(params.getExpandedAspectRatioFloat(), + mPictureInPictureParams.getExpandedAspectRatioFloat())) { + mPipParamsChangedForwarder.notifyExpandedAspectRatioChanged( + params.getExpandedAspectRatioFloat()); + } + if (!Objects.equals(params.getTitle(), mPictureInPictureParams.getTitle())) { + mPipParamsChangedForwarder.notifyTitleChanged(params.getTitle()); + } + if (!Objects.equals(params.getSubtitle(), mPictureInPictureParams.getSubtitle())) { + mPipParamsChangedForwarder.notifySubtitleChanged(params.getSubtitle()); + } + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java index def9ad20a632b..4b85496f2a7fe 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java @@ -81,6 +81,7 @@ public class PipTaskOrganizerTest extends ShellTestCase { private PipBoundsState mPipBoundsState; private PipTransitionState mPipTransitionState; private PipBoundsAlgorithm mPipBoundsAlgorithm; + private PipParamsChangedForwarder mPipParamsChangedForwarder; private ComponentName mComponent1; private ComponentName mComponent2; @@ -97,11 +98,10 @@ public class PipTaskOrganizerTest extends ShellTestCase { mMainExecutor = new TestShellExecutor(); mSpiedPipTaskOrganizer = spy(new PipTaskOrganizer(mContext, mMockSyncTransactionQueue, mPipTransitionState, mPipBoundsState, - mPipBoundsAlgorithm, mMockPhonePipMenuController, - mMockPipAnimationController, mMockPipSurfaceTransactionHelper, - mMockPipTransitionController, mMockOptionalSplitScreen, - mMockDisplayController, mMockPipUiEventLogger, - mMockShellTaskOrganizer, mMainExecutor)); + mPipBoundsAlgorithm, mMockPhonePipMenuController, mMockPipAnimationController, + mMockPipSurfaceTransactionHelper, mMockPipTransitionController, + mPipParamsChangedForwarder, mMockOptionalSplitScreen, mMockDisplayController, + mMockPipUiEventLogger, mMockShellTaskOrganizer, mMainExecutor)); mMainExecutor.flushAll(); preparePipTaskOrg(); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java index deb955b308427..5368b7db3dc10 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java @@ -48,6 +48,7 @@ import com.android.wm.shell.onehanded.OneHandedController; import com.android.wm.shell.pip.PipBoundsAlgorithm; import com.android.wm.shell.pip.PipBoundsState; import com.android.wm.shell.pip.PipMediaController; +import com.android.wm.shell.pip.PipParamsChangedForwarder; import com.android.wm.shell.pip.PipSnapAlgorithm; import com.android.wm.shell.pip.PipTaskOrganizer; import com.android.wm.shell.pip.PipTransitionController; @@ -86,6 +87,7 @@ public class PipControllerTest extends ShellTestCase { @Mock private TaskStackListenerImpl mMockTaskStackListener; @Mock private ShellExecutor mMockExecutor; @Mock private Optional mMockOneHandedController; + @Mock private PipParamsChangedForwarder mPipParamsChangedForwarder; @Mock private DisplayLayout mMockDisplayLayout1; @Mock private DisplayLayout mMockDisplayLayout2; @@ -102,7 +104,8 @@ public class PipControllerTest extends ShellTestCase { mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController, mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper, - mMockTaskStackListener, mMockOneHandedController, mMockExecutor); + mMockTaskStackListener, mPipParamsChangedForwarder, mMockOneHandedController, + mMockExecutor); when(mMockPipBoundsAlgorithm.getSnapAlgorithm()).thenReturn(mMockPipSnapAlgorithm); when(mMockPipTouchHandler.getMotionHelper()).thenReturn(mMockPipMotionHelper); } @@ -134,7 +137,8 @@ public class PipControllerTest extends ShellTestCase { mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController, mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper, - mMockTaskStackListener, mMockOneHandedController, mMockExecutor)); + mMockTaskStackListener, mPipParamsChangedForwarder, mMockOneHandedController, + mMockExecutor)); } @Test diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java index 4822ddbc0ebb6..f21f906317928 100644 --- a/services/core/java/com/android/server/wm/ActivityClientController.java +++ b/services/core/java/com/android/server/wm/ActivityClientController.java @@ -739,20 +739,7 @@ class ActivityClientController extends IActivityClientController.Stub { synchronized (mGlobalLock) { final ActivityRecord r = ensureValidPictureInPictureActivityParams( "setPictureInPictureParams", token, params); - - // Only update the saved args from the args that are set. r.setPictureInPictureParams(params); - if (r.inPinnedWindowingMode()) { - // If the activity is already in picture-in-picture, update the pinned task now - // if it is not already expanding to fullscreen. Otherwise, the arguments will - // be used the next time the activity enters PiP. - final Task rootTask = r.getRootTask(); - rootTask.setPictureInPictureAspectRatio( - r.pictureInPictureArgs.getAspectRatioFloat(), - r.pictureInPictureArgs.getExpandedAspectRatioFloat()); - rootTask.setPictureInPictureActions(r.pictureInPictureArgs.getActions(), - r.pictureInPictureArgs.getCloseAction()); - } } } finally { Binder.restoreCallingIdentity(origId); diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index d254aaff1a1c6..640db6e70ae4c 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -147,7 +147,6 @@ import android.app.PendingIntent; import android.app.PictureInPictureParams; import android.app.PictureInPictureUiState; import android.app.ProfilerInfo; -import android.app.RemoteAction; import android.app.WaitResult; import android.app.admin.DevicePolicyCache; import android.app.assist.AssistContent; @@ -3465,19 +3464,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { Slog.e(TAG, "Skip enterPictureInPictureMode, destroyed " + r); return; } - // Only update the saved args from the args that are set r.setPictureInPictureParams(params); - final float aspectRatio = r.pictureInPictureArgs.getAspectRatioFloat(); - final float expandedAspectRatio = - r.pictureInPictureArgs.getExpandedAspectRatioFloat(); - final List actions = r.pictureInPictureArgs.getActions(); - final RemoteAction closeAction = r.pictureInPictureArgs.getCloseAction(); mRootWindowContainer.moveActivityToPinnedRootTask(r, null /* launchIntoPipHostActivity */, "enterPictureInPictureMode"); final Task task = r.getTask(); - task.setPictureInPictureAspectRatio(aspectRatio, expandedAspectRatio); - task.setPictureInPictureActions(actions, closeAction); - // Continue the pausing process after entering pip. if (task.getPausingActivity() == r) { task.schedulePauseActivity(r, false /* userLeaving */, diff --git a/services/core/java/com/android/server/wm/PinnedTaskController.java b/services/core/java/com/android/server/wm/PinnedTaskController.java index 43d077664fd54..1ddeee9f46d9f 100644 --- a/services/core/java/com/android/server/wm/PinnedTaskController.java +++ b/services/core/java/com/android/server/wm/PinnedTaskController.java @@ -22,9 +22,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.app.PictureInPictureParams; -import android.app.RemoteAction; import android.content.ComponentName; -import android.content.pm.ParceledListSlice; import android.content.res.Resources; import android.graphics.Insets; import android.graphics.Matrix; @@ -40,8 +38,6 @@ import android.view.SurfaceControl; import android.window.PictureInPictureSurfaceTransaction; import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; /** * Holds the common state of the pinned task between the system and SystemUI. If SystemUI ever @@ -90,12 +86,6 @@ class PinnedTaskController { private boolean mIsImeShowing; private int mImeHeight; - // The set of actions and aspect-ratio for the that are currently allowed on the PiP activity - private ArrayList mActions = new ArrayList<>(); - private RemoteAction mCloseAction; - private float mAspectRatio = -1f; - private float mExpandedAspectRatio = 0f; - // The aspect ratio bounds of the PIP. private float mMinAspectRatio; private float mMaxAspectRatio; @@ -155,7 +145,6 @@ class PinnedTaskController { mPinnedTaskListener = listener; notifyImeVisibilityChanged(mIsImeShowing, mImeHeight); notifyMovementBoundsChanged(false /* fromImeAdjustment */); - notifyActionsChanged(mActions, mCloseAction); } catch (RemoteException e) { Log.e(TAG, "Failed to register pinned task listener", e); } @@ -369,55 +358,6 @@ class PinnedTaskController { notifyMovementBoundsChanged(true /* fromImeAdjustment */); } - /** - * Sets the current aspect ratio. - */ - void setAspectRatio(float aspectRatio) { - if (Float.compare(mAspectRatio, aspectRatio) != 0) { - mAspectRatio = aspectRatio; - notifyAspectRatioChanged(aspectRatio); - notifyMovementBoundsChanged(false /* fromImeAdjustment */); - } - } - - /** - * @return the current aspect ratio. - */ - float getAspectRatio() { - return mAspectRatio; - } - - /** - * Sets the current aspect ratio. - */ - void setExpandedAspectRatio(float aspectRatio) { - if (Float.compare(mExpandedAspectRatio, aspectRatio) != 0) { - mExpandedAspectRatio = aspectRatio; - notifyExpandedAspectRatioChanged(aspectRatio); - notifyMovementBoundsChanged(false /* fromImeAdjustment */); - } - } - - /** - * @return the current aspect ratio. - */ - float getExpandedAspectRatio() { - return mExpandedAspectRatio; - } - - - /** - * Sets the current set of actions. - */ - void setActions(List actions, RemoteAction closeAction) { - mActions.clear(); - if (actions != null) { - mActions.addAll(actions); - } - mCloseAction = closeAction; - notifyActionsChanged(mActions, closeAction); - } - /** * Notifies listeners that the PIP needs to be adjusted for the IME. */ @@ -431,37 +371,6 @@ class PinnedTaskController { } } - private void notifyAspectRatioChanged(float aspectRatio) { - if (mPinnedTaskListener == null) return; - try { - mPinnedTaskListener.onAspectRatioChanged(aspectRatio); - } catch (RemoteException e) { - Slog.e(TAG_WM, "Error delivering aspect ratio changed event.", e); - } - } - - private void notifyExpandedAspectRatioChanged(float aspectRatio) { - if (mPinnedTaskListener == null) return; - try { - mPinnedTaskListener.onExpandedAspectRatioChanged(aspectRatio); - } catch (RemoteException e) { - Slog.e(TAG_WM, "Error delivering aspect ratio changed event.", e); - } - } - - /** - * Notifies listeners that the PIP actions have changed. - */ - private void notifyActionsChanged(List actions, RemoteAction closeAction) { - if (mPinnedTaskListener != null) { - try { - mPinnedTaskListener.onActionsChanged(new ParceledListSlice(actions), closeAction); - } catch (RemoteException e) { - Slog.e(TAG_WM, "Error delivering actions changed event.", e); - } - } - } - /** * Notifies listeners that the PIP movement bounds have changed. */ @@ -490,19 +399,7 @@ class PinnedTaskController { } pw.println(prefix + " mIsImeShowing=" + mIsImeShowing); pw.println(prefix + " mImeHeight=" + mImeHeight); - pw.println(prefix + " mAspectRatio=" + mAspectRatio); pw.println(prefix + " mMinAspectRatio=" + mMinAspectRatio); pw.println(prefix + " mMaxAspectRatio=" + mMaxAspectRatio); - if (mActions.isEmpty()) { - pw.println(prefix + " mActions=[]"); - } else { - pw.println(prefix + " mActions=["); - for (int i = 0; i < mActions.size(); i++) { - RemoteAction action = mActions.get(i); - pw.print(prefix + " Action[" + i + "]: "); - action.dump("", pw); - } - pw.println(prefix + " ]"); - } } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index f97f768872fdd..1c00a394aeb9b 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -148,7 +148,6 @@ import android.app.ActivityTaskManager; import android.app.AppGlobals; import android.app.IActivityController; import android.app.PictureInPictureParams; -import android.app.RemoteAction; import android.app.TaskInfo; import android.app.WindowConfiguration; import android.content.ComponentName; @@ -217,7 +216,6 @@ import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; -import java.util.List; import java.util.Objects; import java.util.function.Consumer; import java.util.function.Predicate; @@ -6072,58 +6070,6 @@ class Task extends TaskFragment { } } - /** - * Sets the current picture-in-picture aspect ratios. - */ - void setPictureInPictureAspectRatio(float aspectRatio, float expandedAspectRatio) { - if (!mWmService.mAtmService.mSupportsPictureInPicture) { - return; - } - - final DisplayContent displayContent = getDisplayContent(); - if (displayContent == null) { - return; - } - - if (!inPinnedWindowingMode()) { - return; - } - - final PinnedTaskController pinnedTaskController = - getDisplayContent().getPinnedTaskController(); - - // Notify the pinned stack controller about aspect ratio change. - // This would result a callback delivered from SystemUI to WM to start animation, - // if the bounds are ought to be altered due to aspect ratio change. - if (Float.compare(aspectRatio, pinnedTaskController.getAspectRatio()) != 0) { - pinnedTaskController.setAspectRatio( - pinnedTaskController.isValidPictureInPictureAspectRatio(aspectRatio) - ? aspectRatio : -1f); - } - - if (mWmService.mAtmService.mSupportsExpandedPictureInPicture && Float.compare( - expandedAspectRatio, pinnedTaskController.getExpandedAspectRatio()) != 0) { - pinnedTaskController.setExpandedAspectRatio(pinnedTaskController - .isValidExpandedPictureInPictureAspectRatio(expandedAspectRatio) - ? expandedAspectRatio : 0f); - } - } - - /** - * Sets the current picture-in-picture actions. - */ - void setPictureInPictureActions(List actions, RemoteAction closeAction) { - if (!mWmService.mAtmService.mSupportsPictureInPicture) { - return; - } - - if (!inPinnedWindowingMode()) { - return; - } - - getDisplayContent().getPinnedTaskController().setActions(actions, closeAction); - } - public DisplayInfo getDisplayInfo() { return mDisplayContent.getDisplayInfo(); }