diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java index a4b70333850c6..31490e427a535 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java @@ -22,7 +22,6 @@ import static android.view.KeyEvent.KEYCODE_DPAD_RIGHT; import static android.view.KeyEvent.KEYCODE_DPAD_UP; import static com.android.wm.shell.pip.tv.TvPipBoundsState.ORIENTATION_HORIZONTAL; -import static com.android.wm.shell.pip.tv.TvPipBoundsState.ORIENTATION_UNDETERMINED; import static com.android.wm.shell.pip.tv.TvPipBoundsState.ORIENTATION_VERTICAL; import android.content.Context; @@ -63,7 +62,8 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm { @NonNull TvPipBoundsState tvPipBoundsState, @NonNull PipSnapAlgorithm pipSnapAlgorithm) { super(context, tvPipBoundsState, pipSnapAlgorithm, - new PipKeepClearAlgorithm() {}); + new PipKeepClearAlgorithm() { + }); this.mTvPipBoundsState = tvPipBoundsState; this.mKeepClearAlgorithm = new TvPipKeepClearAlgorithm(); reloadResources(context); @@ -98,7 +98,7 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm { && mTvPipBoundsState.getDesiredTvExpandedAspectRatio() != 0 && !mTvPipBoundsState.isTvPipManuallyCollapsed(); if (isPipExpanded) { - updateGravityOnExpandToggled(Gravity.NO_GRAVITY, true); + updateGravityOnExpansionToggled(/* expanding= */ true); } mTvPipBoundsState.setTvPipExpanded(isPipExpanded); return adjustBoundsForTemporaryDecor(getTvPipPlacement().getBounds()); @@ -172,135 +172,85 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm { return placement; } - /** - * @return previous gravity if it is to be saved, or {@link Gravity#NO_GRAVITY} if not. - */ - int updateGravityOnExpandToggled(int previousGravity, boolean expanding) { + void updateGravityOnExpansionToggled(boolean expanding) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: updateGravityOnExpandToggled(), expanding: %b" - + ", mOrientation: %d, previous gravity: %s", - TAG, expanding, mTvPipBoundsState.getTvFixedPipOrientation(), - Gravity.toString(previousGravity)); + "%s: updateGravity, expanding: %b, fixedExpandedOrientation: %d", + TAG, expanding, mTvPipBoundsState.getTvFixedPipOrientation()); - if (!mTvPipBoundsState.isTvExpandedPipSupported()) { - return Gravity.NO_GRAVITY; - } + int currentX = mTvPipBoundsState.getTvPipGravity() & Gravity.HORIZONTAL_GRAVITY_MASK; + int currentY = mTvPipBoundsState.getTvPipGravity() & Gravity.VERTICAL_GRAVITY_MASK; + int previousCollapsedX = mTvPipBoundsState.getTvPipPreviousCollapsedGravity() + & Gravity.HORIZONTAL_GRAVITY_MASK; + int previousCollapsedY = mTvPipBoundsState.getTvPipPreviousCollapsedGravity() + & Gravity.VERTICAL_GRAVITY_MASK; - if (expanding && mTvPipBoundsState.getTvFixedPipOrientation() == ORIENTATION_UNDETERMINED) { - float expandedRatio = mTvPipBoundsState.getDesiredTvExpandedAspectRatio(); - if (expandedRatio == 0) { - return Gravity.NO_GRAVITY; - } - if (expandedRatio < 1) { - mTvPipBoundsState.setTvFixedPipOrientation(ORIENTATION_VERTICAL); - } else { - mTvPipBoundsState.setTvFixedPipOrientation(ORIENTATION_HORIZONTAL); - } - } - - int gravityToSave = Gravity.NO_GRAVITY; - int currentGravity = mTvPipBoundsState.getTvPipGravity(); int updatedGravity; - if (expanding) { - // save collapsed gravity - gravityToSave = mTvPipBoundsState.getTvPipGravity(); + // Save collapsed gravity. + mTvPipBoundsState.setTvPipPreviousCollapsedGravity(mTvPipBoundsState.getTvPipGravity()); if (mTvPipBoundsState.getTvFixedPipOrientation() == ORIENTATION_HORIZONTAL) { - updatedGravity = - Gravity.CENTER_HORIZONTAL | (currentGravity - & Gravity.VERTICAL_GRAVITY_MASK); + updatedGravity = Gravity.CENTER_HORIZONTAL | currentY; } else { - updatedGravity = - Gravity.CENTER_VERTICAL | (currentGravity - & Gravity.HORIZONTAL_GRAVITY_MASK); + updatedGravity = currentX | Gravity.CENTER_VERTICAL; } } else { - if (previousGravity != Gravity.NO_GRAVITY) { - // The pip hasn't been moved since expanding, - // go back to previous collapsed position. - updatedGravity = previousGravity; + // Collapse to the edge that the user moved to before. + if (mTvPipBoundsState.getTvFixedPipOrientation() == ORIENTATION_HORIZONTAL) { + updatedGravity = previousCollapsedX | currentY; } else { - if (mTvPipBoundsState.getTvFixedPipOrientation() == ORIENTATION_HORIZONTAL) { - updatedGravity = - Gravity.RIGHT | (currentGravity & Gravity.VERTICAL_GRAVITY_MASK); - } else { - updatedGravity = - Gravity.BOTTOM | (currentGravity & Gravity.HORIZONTAL_GRAVITY_MASK); - } + updatedGravity = currentX | previousCollapsedY; } } mTvPipBoundsState.setTvPipGravity(updatedGravity); ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: new gravity: %s", TAG, Gravity.toString(updatedGravity)); - - return gravityToSave; } /** - * @return true if gravity changed + * @return true if the gravity changed */ boolean updateGravity(int keycode) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: updateGravity, keycode: %d", TAG, keycode); - // Check if position change is valid + // Check if position change is valid. if (mTvPipBoundsState.isTvPipExpanded()) { - int mOrientation = mTvPipBoundsState.getTvFixedPipOrientation(); - if (mOrientation == ORIENTATION_VERTICAL + int fixedOrientation = mTvPipBoundsState.getTvFixedPipOrientation(); + if (fixedOrientation == ORIENTATION_VERTICAL && (keycode == KEYCODE_DPAD_UP || keycode == KEYCODE_DPAD_DOWN) - || mOrientation == ORIENTATION_HORIZONTAL + || fixedOrientation == ORIENTATION_HORIZONTAL && (keycode == KEYCODE_DPAD_RIGHT || keycode == KEYCODE_DPAD_LEFT)) { return false; } } - int currentGravity = mTvPipBoundsState.getTvPipGravity(); - int updatedGravity; - // First axis + int updatedX = mTvPipBoundsState.getTvPipGravity() & Gravity.HORIZONTAL_GRAVITY_MASK; + int updatedY = mTvPipBoundsState.getTvPipGravity() & Gravity.VERTICAL_GRAVITY_MASK; + switch (keycode) { case KEYCODE_DPAD_UP: - updatedGravity = Gravity.TOP; + updatedY = Gravity.TOP; break; case KEYCODE_DPAD_DOWN: - updatedGravity = Gravity.BOTTOM; + updatedY = Gravity.BOTTOM; break; case KEYCODE_DPAD_LEFT: - updatedGravity = Gravity.LEFT; + updatedX = Gravity.LEFT; break; case KEYCODE_DPAD_RIGHT: - updatedGravity = Gravity.RIGHT; + updatedX = Gravity.RIGHT; break; default: - updatedGravity = currentGravity; + // NOOP - unsupported keycode } - // Second axis - switch (keycode) { - case KEYCODE_DPAD_UP: - case KEYCODE_DPAD_DOWN: - if (mTvPipBoundsState.isTvPipExpanded()) { - updatedGravity |= Gravity.CENTER_HORIZONTAL; - } else { - updatedGravity |= (currentGravity & Gravity.HORIZONTAL_GRAVITY_MASK); - } - break; - case KEYCODE_DPAD_LEFT: - case KEYCODE_DPAD_RIGHT: - if (mTvPipBoundsState.isTvPipExpanded()) { - updatedGravity |= Gravity.CENTER_VERTICAL; - } else { - updatedGravity |= (currentGravity & Gravity.VERTICAL_GRAVITY_MASK); - } - break; - default: - break; - } + int updatedGravity = updatedX | updatedY; - if (updatedGravity != currentGravity) { + if (updatedGravity != mTvPipBoundsState.getTvPipGravity()) { mTvPipBoundsState.setTvPipGravity(updatedGravity); ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: new gravity: %s", TAG, Gravity.toString(updatedGravity)); + "%s: updateGravity, new gravity: %s", TAG, Gravity.toString(updatedGravity)); return true; } return false; 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 1651f8993dc18..9c7c0aef636d3 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 @@ -27,6 +27,7 @@ import android.content.pm.PackageManager; import android.graphics.Insets; import android.util.Size; import android.view.Gravity; +import android.view.View; import com.android.wm.shell.pip.PipBoundsAlgorithm; import com.android.wm.shell.pip.PipBoundsState; @@ -52,24 +53,61 @@ public class TvPipBoundsState extends PipBoundsState { public @interface Orientation { } - public static final int DEFAULT_TV_GRAVITY = Gravity.BOTTOM | Gravity.RIGHT; + private final Context mContext; + + private int mDefaultGravity; + private int mTvPipGravity; + private int mPreviousCollapsedGravity; + private boolean mIsRtl; private final boolean mIsTvExpandedPipSupported; private boolean mIsTvPipExpanded; private boolean mTvPipManuallyCollapsed; private float mDesiredTvExpandedAspectRatio; - private @Orientation int mTvFixedPipOrientation; - private int mTvPipGravity; - private @Nullable Size mTvExpandedSize; - private @NonNull Insets mPipMenuPermanentDecorInsets = Insets.NONE; - private @NonNull Insets mPipMenuTemporaryDecorInsets = Insets.NONE; + @Orientation + private int mTvFixedPipOrientation; + @Nullable + private Size mTvExpandedSize; + @NonNull + private Insets mPipMenuPermanentDecorInsets = Insets.NONE; + @NonNull + private Insets mPipMenuTemporaryDecorInsets = Insets.NONE; public TvPipBoundsState(@NonNull Context context) { super(context); + mContext = context; + updateDefaultGravity(); + mPreviousCollapsedGravity = mDefaultGravity; mIsTvExpandedPipSupported = context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_EXPANDED_PICTURE_IN_PICTURE); } + public int getDefaultGravity() { + return mDefaultGravity; + } + + private void updateDefaultGravity() { + boolean isRtl = mContext.getResources().getConfiguration().getLayoutDirection() + == View.LAYOUT_DIRECTION_RTL; + mDefaultGravity = Gravity.BOTTOM | (isRtl ? Gravity.LEFT : Gravity.RIGHT); + + if (mIsRtl != isRtl) { + int prevGravityX = mPreviousCollapsedGravity & Gravity.HORIZONTAL_GRAVITY_MASK; + int prevGravityY = mPreviousCollapsedGravity & Gravity.VERTICAL_GRAVITY_MASK; + if ((prevGravityX & Gravity.RIGHT) == Gravity.RIGHT) { + mPreviousCollapsedGravity = Gravity.LEFT | prevGravityY; + } else if ((prevGravityX & Gravity.LEFT) == Gravity.LEFT) { + mPreviousCollapsedGravity = Gravity.RIGHT | prevGravityY; + } + } + mIsRtl = isRtl; + } + + @Override + public void onConfigurationChanged() { + updateDefaultGravity(); + } + /** * Initialize states when first entering PiP. */ @@ -86,7 +124,8 @@ public class TvPipBoundsState extends PipBoundsState { /** Resets the TV PiP state for a new activity. */ public void resetTvPipState() { mTvFixedPipOrientation = ORIENTATION_UNDETERMINED; - mTvPipGravity = DEFAULT_TV_GRAVITY; + mTvPipGravity = mDefaultGravity; + mPreviousCollapsedGravity = mDefaultGravity; mTvPipManuallyCollapsed = false; } @@ -102,16 +141,23 @@ public class TvPipBoundsState extends PipBoundsState { } /** Set the PiP aspect ratio for the expanded PiP (TV) that is desired by the app. */ - public void setDesiredTvExpandedAspectRatio(float aspectRatio, boolean override) { + public void setDesiredTvExpandedAspectRatio(float expandedAspectRatio, boolean override) { if (override || mTvFixedPipOrientation == ORIENTATION_UNDETERMINED) { - mDesiredTvExpandedAspectRatio = aspectRatio; resetTvPipState(); + mDesiredTvExpandedAspectRatio = expandedAspectRatio; + if (expandedAspectRatio != 0) { + if (expandedAspectRatio > 1) { + mTvFixedPipOrientation = ORIENTATION_HORIZONTAL; + } else { + mTvFixedPipOrientation = ORIENTATION_VERTICAL; + } + } return; } - if ((aspectRatio > 1 && mTvFixedPipOrientation == ORIENTATION_HORIZONTAL) - || (aspectRatio <= 1 && mTvFixedPipOrientation == ORIENTATION_VERTICAL) - || aspectRatio == 0) { - mDesiredTvExpandedAspectRatio = aspectRatio; + if ((expandedAspectRatio > 1 && mTvFixedPipOrientation == ORIENTATION_HORIZONTAL) + || (expandedAspectRatio <= 1 && mTvFixedPipOrientation == ORIENTATION_VERTICAL) + || expandedAspectRatio == 0) { + mDesiredTvExpandedAspectRatio = expandedAspectRatio; } } @@ -123,11 +169,6 @@ public class TvPipBoundsState extends PipBoundsState { return mDesiredTvExpandedAspectRatio; } - /** Sets the orientation the expanded TV PiP activity has been fixed to. */ - public void setTvFixedPipOrientation(@Orientation int orientation) { - mTvFixedPipOrientation = orientation; - } - /** Returns the fixed orientation of the expanded PiP on TV. */ @Orientation public int getTvFixedPipOrientation() { @@ -144,6 +185,14 @@ public class TvPipBoundsState extends PipBoundsState { return mTvPipGravity; } + public void setTvPipPreviousCollapsedGravity(int gravity) { + mPreviousCollapsedGravity = gravity; + } + + public int getTvPipPreviousCollapsedGravity() { + return mPreviousCollapsedGravity; + } + /** Sets whether the TV PiP is currently expanded. */ public void setTvPipExpanded(boolean expanded) { mIsTvPipExpanded = expanded; @@ -173,7 +222,8 @@ public class TvPipBoundsState extends PipBoundsState { mPipMenuPermanentDecorInsets = permanentInsets; } - public @NonNull Insets getPipMenuPermanentDecorInsets() { + @NonNull + public Insets getPipMenuPermanentDecorInsets() { return mPipMenuPermanentDecorInsets; } @@ -181,7 +231,8 @@ public class TvPipBoundsState extends PipBoundsState { mPipMenuTemporaryDecorInsets = temporaryDecorInsets; } - public @NonNull Insets getPipMenuTemporaryDecorInsets() { + @NonNull + public Insets getPipMenuTemporaryDecorInsets() { return mPipMenuTemporaryDecorInsets; } } 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 76710818f8e5e..fd4fcff54f017 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 @@ -18,6 +18,8 @@ package com.android.wm.shell.pip.tv; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.view.KeyEvent.KEYCODE_DPAD_LEFT; +import static android.view.KeyEvent.KEYCODE_DPAD_RIGHT; import android.annotation.IntDef; import android.app.ActivityManager; @@ -137,7 +139,6 @@ public class TvPipController implements PipTransitionController.PipTransitionCal @State private int mState = STATE_NO_PIP; - private int mPreviousGravity = TvPipBoundsState.DEFAULT_TV_GRAVITY; private int mPinnedTaskId = NONEXISTENT_TASK_ID; // How long the shell will wait for the app to close the PiP if a custom action is set. @@ -214,6 +215,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal mTvPipBoundsState = tvPipBoundsState; mTvPipBoundsState.setDisplayId(context.getDisplayId()); mTvPipBoundsState.setDisplayLayout(new DisplayLayout(context, context.getDisplay())); + mTvPipBoundsAlgorithm = tvPipBoundsAlgorithm; mTvPipBoundsController = tvPipBoundsController; mTvPipBoundsController.setListener(this); @@ -243,7 +245,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal private void onInit() { mPipTransitionController.registerPipTransitionCallback(this); - loadConfigurations(); + reloadResources(); registerPipParamsChangedListener(mPipParamsChangedForwarder); registerTaskStackListenerCallback(mTaskStackListener); @@ -266,9 +268,38 @@ public class TvPipController implements PipTransitionController.PipTransitionCal ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: onConfigurationChanged(), state=%s", TAG, stateToName(mState)); - loadConfigurations(); + int previousDefaultGravityX = mTvPipBoundsState.getDefaultGravity() + & Gravity.HORIZONTAL_GRAVITY_MASK; + + reloadResources(); + mPipNotificationController.onConfigurationChanged(); mTvPipBoundsAlgorithm.onConfigurationChanged(mContext); + mTvPipBoundsState.onConfigurationChanged(); + + int defaultGravityX = mTvPipBoundsState.getDefaultGravity() + & Gravity.HORIZONTAL_GRAVITY_MASK; + if (isPipShown() && previousDefaultGravityX != defaultGravityX) { + movePipToOppositeSide(); + } + } + + private void reloadResources() { + final Resources res = mContext.getResources(); + mResizeAnimationDuration = res.getInteger(R.integer.config_pipResizeAnimationDuration); + mPipForceCloseDelay = res.getInteger(R.integer.config_pipForceCloseDelay); + mEduTextWindowExitAnimationDuration = + res.getInteger(R.integer.pip_edu_text_window_exit_animation_duration); + } + + private void movePipToOppositeSide() { + ProtoLog.i(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, + "%s: movePipToOppositeSide", TAG); + if ((mTvPipBoundsState.getTvPipGravity() & Gravity.RIGHT) == Gravity.RIGHT) { + movePip(KEYCODE_DPAD_LEFT); + } else if ((mTvPipBoundsState.getTvPipGravity() & Gravity.LEFT) == Gravity.LEFT) { + movePip(KEYCODE_DPAD_RIGHT); + } } /** @@ -332,11 +363,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: togglePipExpansion()", TAG); boolean expanding = !mTvPipBoundsState.isTvPipExpanded(); - int saveGravity = mTvPipBoundsAlgorithm - .updateGravityOnExpandToggled(mPreviousGravity, expanding); - if (saveGravity != Gravity.NO_GRAVITY) { - mPreviousGravity = saveGravity; - } + mTvPipBoundsAlgorithm.updateGravityOnExpansionToggled(expanding); mTvPipBoundsState.setTvPipManuallyCollapsed(!expanding); mTvPipBoundsState.setTvPipExpanded(expanding); @@ -347,7 +374,6 @@ public class TvPipController implements PipTransitionController.PipTransitionCal public void movePip(int keycode) { if (mTvPipBoundsAlgorithm.updateGravity(keycode)) { mTvPipMenuController.updateGravity(mTvPipBoundsState.getTvPipGravity()); - mPreviousGravity = Gravity.NO_GRAVITY; updatePinnedStackBounds(); } else { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, @@ -355,15 +381,6 @@ public class TvPipController implements PipTransitionController.PipTransitionCal } } - @Override - public int getPipGravity() { - return mTvPipBoundsState.getTvPipGravity(); - } - - public int getOrientation() { - return mTvPipBoundsState.getTvFixedPipOrientation(); - } - @Override public void onKeepClearAreasChanged(int displayId, Set restricted, Set unrestricted) { @@ -516,14 +533,6 @@ public class TvPipController implements PipTransitionController.PipTransitionCal mState = state; } - private void loadConfigurations() { - final Resources res = mContext.getResources(); - mResizeAnimationDuration = res.getInteger(R.integer.config_pipResizeAnimationDuration); - mPipForceCloseDelay = res.getInteger(R.integer.config_pipForceCloseDelay); - mEduTextWindowExitAnimationDuration = - res.getInteger(R.integer.pip_edu_text_window_exit_animation_duration); - } - private void registerTaskStackListenerCallback(TaskStackListenerImpl taskStackListener) { taskStackListener.addListener(new TaskStackListenerCallback() { @Override @@ -596,11 +605,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal // 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; - } + mTvPipBoundsAlgorithm.updateGravityOnExpansionToggled(/* expanding= */ false); mTvPipBoundsState.setTvPipExpanded(false); updatePinnedStackBounds(); } @@ -610,11 +615,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal if (!mTvPipBoundsState.isTvPipExpanded() && ratio != 0 && !mTvPipBoundsState.isTvPipManuallyCollapsed()) { mTvPipBoundsAlgorithm.updateExpandedPipSize(); - int saveGravity = mTvPipBoundsAlgorithm - .updateGravityOnExpandToggled(mPreviousGravity, true); - if (saveGravity != Gravity.NO_GRAVITY) { - mPreviousGravity = saveGravity; - } + mTvPipBoundsAlgorithm.updateGravityOnExpansionToggled(/* expanding= */ true); mTvPipBoundsState.setTvPipExpanded(true); updatePinnedStackBounds(); } 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 00e4f47e3c6bf..8895fcab0c3d0 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 @@ -199,7 +199,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis "%s: showMovementMenuOnly()", TAG); setInMoveMode(true); if (mMenuIsOpen) { - mPipMenuView.showMoveMenu(mDelegate.getPipGravity()); + mPipMenuView.showMoveMenu(mTvPipBoundsState.getTvPipGravity()); } else { mCloseAfterExitMoveMenu = true; showMenuInternal(); @@ -222,7 +222,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis mMenuIsOpen = true; grantPipMenuFocus(true); if (mInMoveMode) { - mPipMenuView.showMoveMenu(mDelegate.getPipGravity()); + mPipMenuView.showMoveMenu(mTvPipBoundsState.getTvPipGravity()); } else { mPipMenuView.showButtonsMenu(/* exitingMoveMode= */ false); } @@ -236,7 +236,9 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis } void updateGravity(int gravity) { - mPipMenuView.showMovementHints(gravity); + if (mInMoveMode) { + mPipMenuView.showMovementHints(gravity); + } } private Rect calculateMenuSurfaceBounds(Rect pipBounds) { @@ -500,8 +502,6 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis void onInMoveModeChanged(); - int getPipGravity(); - void onMenuClosed(); void closeEduText(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipGravityTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipGravityTest.java new file mode 100644 index 0000000000000..6cf6e821f691d --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipGravityTest.java @@ -0,0 +1,324 @@ +/* + * 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 static android.view.KeyEvent.KEYCODE_DPAD_DOWN; +import static android.view.KeyEvent.KEYCODE_DPAD_LEFT; +import static android.view.KeyEvent.KEYCODE_DPAD_RIGHT; +import static android.view.KeyEvent.KEYCODE_DPAD_UP; + +import static org.junit.Assert.assertEquals; + +import android.view.Gravity; + +import com.android.wm.shell.ShellTestCase; +import com.android.wm.shell.pip.PipSnapAlgorithm; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Locale; + +public class TvPipGravityTest extends ShellTestCase { + + private static final float VERTICAL_EXPANDED_ASPECT_RATIO = 1f / 3; + private static final float HORIZONTAL_EXPANDED_ASPECT_RATIO = 3f; + + @Mock + private PipSnapAlgorithm mMockPipSnapAlgorithm; + + private TvPipBoundsState mTvPipBoundsState; + private TvPipBoundsAlgorithm mTvPipBoundsAlgorithm; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mTvPipBoundsState = new TvPipBoundsState(mContext); + mTvPipBoundsAlgorithm = new TvPipBoundsAlgorithm(mContext, mTvPipBoundsState, + mMockPipSnapAlgorithm); + + setRTL(false); + } + + private void checkGravity(int gravityActual, int gravityExpected) { + assertEquals(gravityExpected, gravityActual); + } + + private void setRTL(boolean isRtl) { + mContext.getResources().getConfiguration().setLayoutDirection( + isRtl ? new Locale("ar") : Locale.ENGLISH); + mTvPipBoundsState.onConfigurationChanged(); + mTvPipBoundsAlgorithm.onConfigurationChanged(mContext); + } + + private void assertGravityAfterExpansion(int gravityFrom, int gravityTo) { + mTvPipBoundsState.setTvPipExpanded(false); + mTvPipBoundsState.setTvPipGravity(gravityFrom); + mTvPipBoundsAlgorithm.updateGravityOnExpansionToggled(true); + checkGravity(mTvPipBoundsState.getTvPipGravity(), gravityTo); + } + + private void assertGravityAfterCollapse(int gravityFrom, int gravityTo) { + mTvPipBoundsState.setTvPipExpanded(true); + mTvPipBoundsState.setTvPipGravity(gravityFrom); + mTvPipBoundsAlgorithm.updateGravityOnExpansionToggled(false); + checkGravity(mTvPipBoundsState.getTvPipGravity(), gravityTo); + } + + private void assertGravityAfterExpandAndCollapse(int gravityStartAndEnd) { + mTvPipBoundsState.setTvPipGravity(gravityStartAndEnd); + mTvPipBoundsAlgorithm.updateGravityOnExpansionToggled(true); + mTvPipBoundsAlgorithm.updateGravityOnExpansionToggled(false); + checkGravity(mTvPipBoundsState.getTvPipGravity(), gravityStartAndEnd); + } + + @Test + public void regularPip_defaultGravity() { + checkGravity(mTvPipBoundsState.getDefaultGravity(), Gravity.RIGHT | Gravity.BOTTOM); + } + + @Test + public void regularPip_defaultGravity_RTL() { + setRTL(true); + checkGravity(mTvPipBoundsState.getDefaultGravity(), Gravity.LEFT | Gravity.BOTTOM); + } + + @Test + public void updateGravity_expand_vertical() { + // Vertical expanded PiP. + mTvPipBoundsState.setDesiredTvExpandedAspectRatio(VERTICAL_EXPANDED_ASPECT_RATIO, true); + + assertGravityAfterExpansion(Gravity.BOTTOM | Gravity.RIGHT, + Gravity.CENTER_VERTICAL | Gravity.RIGHT); + assertGravityAfterExpansion(Gravity.TOP | Gravity.RIGHT, + Gravity.CENTER_VERTICAL | Gravity.RIGHT); + assertGravityAfterExpansion(Gravity.BOTTOM | Gravity.LEFT, + Gravity.CENTER_VERTICAL | Gravity.LEFT); + assertGravityAfterExpansion(Gravity.TOP | Gravity.LEFT, + Gravity.CENTER_VERTICAL | Gravity.LEFT); + } + + @Test + public void updateGravity_expand_horizontal() { + // Horizontal expanded PiP. + mTvPipBoundsState.setDesiredTvExpandedAspectRatio(HORIZONTAL_EXPANDED_ASPECT_RATIO, true); + + assertGravityAfterExpansion(Gravity.BOTTOM | Gravity.RIGHT, + Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL); + assertGravityAfterExpansion(Gravity.TOP | Gravity.RIGHT, + Gravity.TOP | Gravity.CENTER_HORIZONTAL); + assertGravityAfterExpansion(Gravity.BOTTOM | Gravity.LEFT, + Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL); + assertGravityAfterExpansion(Gravity.TOP | Gravity.LEFT, + Gravity.TOP | Gravity.CENTER_HORIZONTAL); + } + + @Test + public void updateGravity_collapse() { + // Vertical expansion + mTvPipBoundsState.setDesiredTvExpandedAspectRatio(VERTICAL_EXPANDED_ASPECT_RATIO, true); + assertGravityAfterCollapse(Gravity.CENTER_VERTICAL | Gravity.RIGHT, + Gravity.BOTTOM | Gravity.RIGHT); + assertGravityAfterCollapse(Gravity.CENTER_VERTICAL | Gravity.LEFT, + Gravity.BOTTOM | Gravity.LEFT); + + // Horizontal expansion + mTvPipBoundsState.setDesiredTvExpandedAspectRatio(HORIZONTAL_EXPANDED_ASPECT_RATIO, true); + assertGravityAfterCollapse(Gravity.TOP | Gravity.CENTER_HORIZONTAL, + Gravity.TOP | Gravity.RIGHT); + assertGravityAfterCollapse(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, + Gravity.BOTTOM | Gravity.RIGHT); + } + + @Test + public void updateGravity_collapse_RTL() { + setRTL(true); + + // Horizontal expansion + mTvPipBoundsState.setDesiredTvExpandedAspectRatio(HORIZONTAL_EXPANDED_ASPECT_RATIO, true); + assertGravityAfterCollapse(Gravity.TOP | Gravity.CENTER_HORIZONTAL, + Gravity.TOP | Gravity.LEFT); + assertGravityAfterCollapse(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, + Gravity.BOTTOM | Gravity.LEFT); + } + + @Test + public void updateGravity_expand_collapse() { + // Vertical expanded PiP. + mTvPipBoundsState.setDesiredTvExpandedAspectRatio(VERTICAL_EXPANDED_ASPECT_RATIO, true); + + assertGravityAfterExpandAndCollapse(Gravity.BOTTOM | Gravity.RIGHT); + assertGravityAfterExpandAndCollapse(Gravity.BOTTOM | Gravity.LEFT); + assertGravityAfterExpandAndCollapse(Gravity.TOP | Gravity.LEFT); + assertGravityAfterExpandAndCollapse(Gravity.TOP | Gravity.RIGHT); + + // Horizontal expanded PiP. + mTvPipBoundsState.setDesiredTvExpandedAspectRatio(HORIZONTAL_EXPANDED_ASPECT_RATIO, true); + + assertGravityAfterExpandAndCollapse(Gravity.BOTTOM | Gravity.RIGHT); + assertGravityAfterExpandAndCollapse(Gravity.BOTTOM | Gravity.LEFT); + assertGravityAfterExpandAndCollapse(Gravity.TOP | Gravity.LEFT); + assertGravityAfterExpandAndCollapse(Gravity.TOP | Gravity.RIGHT); + } + + @Test + public void updateGravity_expand_move_collapse() { + // Vertical expanded PiP. + mTvPipBoundsState.setDesiredTvExpandedAspectRatio(VERTICAL_EXPANDED_ASPECT_RATIO, true); + expandMoveCollapseCheck(Gravity.TOP | Gravity.RIGHT, KEYCODE_DPAD_LEFT, + Gravity.TOP | Gravity.LEFT); + + // Horizontal expanded PiP. + mTvPipBoundsState.setDesiredTvExpandedAspectRatio(HORIZONTAL_EXPANDED_ASPECT_RATIO, true); + expandMoveCollapseCheck(Gravity.BOTTOM | Gravity.LEFT, KEYCODE_DPAD_UP, + Gravity.TOP | Gravity.LEFT); + } + + private void expandMoveCollapseCheck(int gravityFrom, int keycode, int gravityTo) { + // Expand + mTvPipBoundsState.setTvPipExpanded(false); + mTvPipBoundsState.setTvPipGravity(gravityFrom); + mTvPipBoundsAlgorithm.updateGravityOnExpansionToggled(true); + // Move + mTvPipBoundsAlgorithm.updateGravity(keycode); + // Collapse + mTvPipBoundsState.setTvPipExpanded(true); + mTvPipBoundsAlgorithm.updateGravityOnExpansionToggled(false); + + checkGravity(mTvPipBoundsState.getTvPipGravity(), gravityTo); + } + + private void moveAndCheckGravity(int keycode, int gravityEnd, boolean expectChange) { + assertEquals(expectChange, mTvPipBoundsAlgorithm.updateGravity(keycode)); + checkGravity(mTvPipBoundsState.getTvPipGravity(), gravityEnd); + } + + @Test + public void updateGravity_move_regular_valid() { + mTvPipBoundsState.setTvPipGravity(Gravity.BOTTOM | Gravity.RIGHT); + // clockwise + moveAndCheckGravity(KEYCODE_DPAD_LEFT, Gravity.BOTTOM | Gravity.LEFT, true); + moveAndCheckGravity(KEYCODE_DPAD_UP, Gravity.TOP | Gravity.LEFT, true); + moveAndCheckGravity(KEYCODE_DPAD_RIGHT, Gravity.TOP | Gravity.RIGHT, true); + moveAndCheckGravity(KEYCODE_DPAD_DOWN, Gravity.BOTTOM | Gravity.RIGHT, true); + // anti-clockwise + moveAndCheckGravity(KEYCODE_DPAD_UP, Gravity.TOP | Gravity.RIGHT, true); + moveAndCheckGravity(KEYCODE_DPAD_LEFT, Gravity.TOP | Gravity.LEFT, true); + moveAndCheckGravity(KEYCODE_DPAD_DOWN, Gravity.BOTTOM | Gravity.LEFT, true); + moveAndCheckGravity(KEYCODE_DPAD_RIGHT, Gravity.BOTTOM | Gravity.RIGHT, true); + } + + @Test + public void updateGravity_move_expanded_valid() { + mTvPipBoundsState.setTvPipExpanded(true); + + // Vertical expanded PiP. + mTvPipBoundsState.setDesiredTvExpandedAspectRatio(VERTICAL_EXPANDED_ASPECT_RATIO, true); + mTvPipBoundsState.setTvPipGravity(Gravity.CENTER_VERTICAL | Gravity.RIGHT); + moveAndCheckGravity(KEYCODE_DPAD_LEFT, Gravity.CENTER_VERTICAL | Gravity.LEFT, true); + moveAndCheckGravity(KEYCODE_DPAD_RIGHT, Gravity.CENTER_VERTICAL | Gravity.RIGHT, true); + + // Horizontal expanded PiP. + mTvPipBoundsState.setDesiredTvExpandedAspectRatio(HORIZONTAL_EXPANDED_ASPECT_RATIO, true); + mTvPipBoundsState.setTvPipGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL); + moveAndCheckGravity(KEYCODE_DPAD_UP, Gravity.TOP | Gravity.CENTER_HORIZONTAL, true); + moveAndCheckGravity(KEYCODE_DPAD_DOWN, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, true); + } + + @Test + public void updateGravity_move_regular_invalid() { + int gravity = Gravity.BOTTOM | Gravity.RIGHT; + mTvPipBoundsState.setTvPipGravity(gravity); + moveAndCheckGravity(KEYCODE_DPAD_DOWN, gravity, false); + moveAndCheckGravity(KEYCODE_DPAD_RIGHT, gravity, false); + + gravity = Gravity.BOTTOM | Gravity.LEFT; + mTvPipBoundsState.setTvPipGravity(gravity); + moveAndCheckGravity(KEYCODE_DPAD_DOWN, gravity, false); + moveAndCheckGravity(KEYCODE_DPAD_LEFT, gravity, false); + + gravity = Gravity.TOP | Gravity.LEFT; + mTvPipBoundsState.setTvPipGravity(gravity); + moveAndCheckGravity(KEYCODE_DPAD_UP, gravity, false); + moveAndCheckGravity(KEYCODE_DPAD_LEFT, gravity, false); + + gravity = Gravity.TOP | Gravity.RIGHT; + mTvPipBoundsState.setTvPipGravity(gravity); + moveAndCheckGravity(KEYCODE_DPAD_UP, gravity, false); + moveAndCheckGravity(KEYCODE_DPAD_RIGHT, gravity, false); + } + + @Test + public void updateGravity_move_expanded_invalid() { + mTvPipBoundsState.setTvPipExpanded(true); + + // Vertical expanded PiP. + mTvPipBoundsState.setDesiredTvExpandedAspectRatio(VERTICAL_EXPANDED_ASPECT_RATIO, true); + mTvPipBoundsState.setTvPipGravity(Gravity.CENTER_VERTICAL | Gravity.RIGHT); + moveAndCheckGravity(KEYCODE_DPAD_RIGHT, Gravity.CENTER_VERTICAL | Gravity.RIGHT, false); + moveAndCheckGravity(KEYCODE_DPAD_UP, Gravity.CENTER_VERTICAL | Gravity.RIGHT, false); + moveAndCheckGravity(KEYCODE_DPAD_DOWN, Gravity.CENTER_VERTICAL | Gravity.RIGHT, false); + + mTvPipBoundsState.setTvPipGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT); + moveAndCheckGravity(KEYCODE_DPAD_LEFT, Gravity.CENTER_VERTICAL | Gravity.LEFT, false); + moveAndCheckGravity(KEYCODE_DPAD_UP, Gravity.CENTER_VERTICAL | Gravity.LEFT, false); + moveAndCheckGravity(KEYCODE_DPAD_DOWN, Gravity.CENTER_VERTICAL | Gravity.LEFT, false); + + // Horizontal expanded PiP. + mTvPipBoundsState.setDesiredTvExpandedAspectRatio(HORIZONTAL_EXPANDED_ASPECT_RATIO, true); + mTvPipBoundsState.setTvPipGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL); + moveAndCheckGravity(KEYCODE_DPAD_DOWN, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, false); + moveAndCheckGravity(KEYCODE_DPAD_LEFT, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, false); + moveAndCheckGravity(KEYCODE_DPAD_RIGHT, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, false); + + mTvPipBoundsState.setTvPipGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL); + moveAndCheckGravity(KEYCODE_DPAD_UP, Gravity.TOP | Gravity.CENTER_HORIZONTAL, false); + moveAndCheckGravity(KEYCODE_DPAD_LEFT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, false); + moveAndCheckGravity(KEYCODE_DPAD_RIGHT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, false); + } + + @Test + public void previousCollapsedGravity_defaultValue() { + assertEquals(mTvPipBoundsState.getTvPipPreviousCollapsedGravity(), + mTvPipBoundsState.getDefaultGravity()); + setRTL(true); + assertEquals(mTvPipBoundsState.getTvPipPreviousCollapsedGravity(), + mTvPipBoundsState.getDefaultGravity()); + } + + @Test + public void previousCollapsedGravity_changes_on_RTL() { + mTvPipBoundsState.setTvPipPreviousCollapsedGravity(Gravity.TOP | Gravity.LEFT); + setRTL(true); + assertEquals(mTvPipBoundsState.getTvPipPreviousCollapsedGravity(), + Gravity.TOP | Gravity.RIGHT); + setRTL(false); + assertEquals(mTvPipBoundsState.getTvPipPreviousCollapsedGravity(), + Gravity.TOP | Gravity.LEFT); + + mTvPipBoundsState.setTvPipPreviousCollapsedGravity(Gravity.BOTTOM | Gravity.RIGHT); + setRTL(true); + assertEquals(mTvPipBoundsState.getTvPipPreviousCollapsedGravity(), + Gravity.BOTTOM | Gravity.LEFT); + setRTL(false); + assertEquals(mTvPipBoundsState.getTvPipPreviousCollapsedGravity(), + Gravity.BOTTOM | Gravity.RIGHT); + } + +}