diff options
21 files changed, 463 insertions, 414 deletions
diff --git a/core/java/android/view/IPinnedTaskListener.aidl b/core/java/android/view/IPinnedTaskListener.aidl index 595a846e069a..e4e2d6f30aab 100644 --- a/core/java/android/view/IPinnedTaskListener.aidl +++ b/core/java/android/view/IPinnedTaskListener.aidl @@ -44,26 +44,10 @@ 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<RemoteAction> 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 * reentry fraction and size. * {@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 1dd5ebcd993e..72c8141c8f2a 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<SplitScreenController> 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 e43f4fc34adf..7513e5129ade 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> 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<SplitScreenController> 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 87eca74acd0b..ce98458c0575 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<RemoteAction> 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 @@ -114,35 +93,11 @@ public class PinnedStackListenerForwarder { } @Override - public void onActionsChanged(ParceledListSlice<RemoteAction> 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<RemoteAction> 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 f6ff294b4328..16f1d1c2944c 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<RemoteAction> appActions, RemoteAction closeAction); + void setAppActions(List<RemoteAction> 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 000000000000..21ba85459c48 --- /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<PipParamsChangedCallback> + 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<RemoteAction> 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<RemoteAction> 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 fbdf6f0b539f..4690e16bc385 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<SplitScreenController> 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()); - } - return aspectRatioChanged; + 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()); + } } /** 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 d7b69adf1241..c6cf8b8b0566 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<RemoteAction> list1, List<RemoteAction> 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 bbec4eccce3c..4942987742a0 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<SplitScreenController> mSplitScreenController; private final PipUiEventLogger mPipUiEventLogger; - private ParceledListSlice<RemoteAction> mAppActions; + + private List<RemoteAction> mAppActions; private RemoteAction mCloseAction; - private ParceledListSlice<RemoteAction> mMediaActions; + private List<RemoteAction> 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<RemoteAction> 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<RemoteAction> appActions, + public void setAppActions(List<RemoteAction> 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<RemoteAction> resolveMenuActions() { + private List<RemoteAction> resolveMenuActions() { if (isValidActions(mAppActions)) { return mAppActions; } @@ -491,17 +495,16 @@ public class PhonePipMenuController implements PipMenuController { */ private void updateMenuActions() { if (mPipMenuView != null) { - final ParceledListSlice<RemoteAction> 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 272331b7cd3f..2e8b5b7979d0 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<OneHandedController> mOneHandedController; protected final PipImpl mImpl; private final Rect mTmpInsetBounds = new Rect(); + private final int mEnterAnimationDuration; private boolean mIsInFixedRotation; private PipAnimationListener mPinnedStackAnimationRecentsCallback; @@ -270,12 +274,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb } @Override - public void onActionsChanged(ParceledListSlice<RemoteAction> actions, - RemoteAction closeAction) { - mMenuController.setAppActions(actions, closeAction); - } - - @Override public void onActivityHidden(ComponentName componentName) { if (componentName.equals(mPipBoundsState.getLastPipComponentName())) { // The activity was removed, we don't want to restore to the reentry state @@ -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> 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> 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<RemoteAction> 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 a3048bd8fabe..ca22882187d8 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 0e1f5a24f4a7..7f155cae4ff5 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<RemoteAction> 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<RemoteAction> 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 2d67254f3610..bbd21b4940a5 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<RemoteAction> actions, RemoteAction closeAction) { + public void setAppActions(List<RemoteAction> 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<RemoteAction> 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 5b0db8c86529..3161b02d1545 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 000000000000..42fd1aab44f8 --- /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<SplitScreenController> 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 def9ad20a632..4b85496f2a7f 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 deb955b30842..5368b7db3dc1 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<OneHandedController> 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 4822ddbc0ebb..f21f90631792 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 41b724f2596f..8f689be48c21 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -148,7 +148,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; @@ -3471,19 +3470,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<RemoteAction> 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 43d077664fd5..1ddeee9f46d9 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<RemoteAction> 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); } @@ -370,55 +359,6 @@ class PinnedTaskController { } /** - * 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<RemoteAction> 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. */ private void notifyImeVisibilityChanged(boolean imeVisible, int imeHeight) { @@ -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<RemoteAction> 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 00e61171cb68..718ce2870f10 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -149,7 +149,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; @@ -218,7 +217,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; @@ -6076,58 +6074,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<RemoteAction> actions, RemoteAction closeAction) { - if (!mWmService.mAtmService.mSupportsPictureInPicture) { - return; - } - - if (!inPinnedWindowingMode()) { - return; - } - - getDisplayContent().getPinnedTaskController().setActions(actions, closeAction); - } - public DisplayInfo getDisplayInfo() { return mDisplayContent.getDisplayInfo(); } |