diff options
Diffstat (limited to 'libs')
29 files changed, 588 insertions, 310 deletions
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java index 68ff806c6765..65955b1d9bcc 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java @@ -21,6 +21,7 @@ import static androidx.window.util.ExtensionHelper.isZero; import android.annotation.IntDef; import android.annotation.Nullable; import android.graphics.Rect; +import android.hardware.devicestate.DeviceStateManager; import android.util.Log; import androidx.annotation.NonNull; @@ -33,7 +34,8 @@ import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; -/** A representation of a folding feature for both Extension and Sidecar. +/** + * A representation of a folding feature for both Extension and Sidecar. * For Sidecar this is the same as combining {@link androidx.window.sidecar.SidecarDeviceState} and * {@link androidx.window.sidecar.SidecarDisplayFeature}. For Extensions this is the mirror of * {@link androidx.window.extensions.layout.FoldingFeature}. @@ -67,10 +69,11 @@ public final class CommonFoldingFeature { public static final int COMMON_STATE_UNKNOWN = -1; /** - * A common state to represent a FLAT hinge. This is needed because the definitions in Sidecar - * and Extensions do not match exactly. + * A common state that contains no folding features. For example, an in-folding device in the + * "closed" device state. */ - public static final int COMMON_STATE_FLAT = 3; + public static final int COMMON_STATE_NO_FOLDING_FEATURES = 1; + /** * A common state to represent a HALF_OPENED hinge. This is needed because the definitions in * Sidecar and Extensions do not match exactly. @@ -78,9 +81,27 @@ public final class CommonFoldingFeature { public static final int COMMON_STATE_HALF_OPENED = 2; /** - * The possible states for a folding hinge. + * A common state to represent a FLAT hinge. This is needed because the definitions in Sidecar + * and Extensions do not match exactly. + */ + public static final int COMMON_STATE_FLAT = 3; + + /** + * A common state where the hinge state should be derived using the base state from + * {@link DeviceStateManager.DeviceStateCallback#onBaseStateChanged(int)} instead of the + * emulated state. This is an internal state and must not be passed to clients. */ - @IntDef({COMMON_STATE_UNKNOWN, COMMON_STATE_FLAT, COMMON_STATE_HALF_OPENED}) + public static final int COMMON_STATE_USE_BASE_STATE = 1000; + + /** + * The possible states for a folding hinge. Common in this context means normalized between + * extensions and sidecar. + */ + @IntDef({COMMON_STATE_UNKNOWN, + COMMON_STATE_NO_FOLDING_FEATURES, + COMMON_STATE_HALF_OPENED, + COMMON_STATE_FLAT, + COMMON_STATE_USE_BASE_STATE}) @Retention(RetentionPolicy.SOURCE) public @interface State { } @@ -167,7 +188,7 @@ public final class CommonFoldingFeature { } String stateString = featureMatcher.group(6); stateString = stateString == null ? "" : stateString; - final int state; + @State final int state; switch (stateString) { case PATTERN_STATE_FLAT: state = COMMON_STATE_FLAT; @@ -191,8 +212,8 @@ public final class CommonFoldingFeature { @NonNull private final Rect mRect; - CommonFoldingFeature(int type, int state, @NonNull Rect rect) { - assertValidState(state); + CommonFoldingFeature(int type, @State int state, @NonNull Rect rect) { + assertReportableState(state); this.mType = type; this.mState = state; if (rect.width() == 0 && rect.height() == 0) { @@ -231,13 +252,22 @@ public final class CommonFoldingFeature { } @Override + public String toString() { + return "CommonFoldingFeature=[Type: " + mType + ", state: " + mState + "]"; + } + + @Override public int hashCode() { return Objects.hash(mType, mState, mRect); } - private static void assertValidState(@Nullable Integer state) { - if (state != null && state != COMMON_STATE_FLAT - && state != COMMON_STATE_HALF_OPENED && state != COMMON_STATE_UNKNOWN) { + /** + * Checks if the provided folding feature state should be reported to clients. See + * {@link androidx.window.extensions.layout.FoldingFeature} + */ + private static void assertReportableState(@State int state) { + if (state != COMMON_STATE_FLAT && state != COMMON_STATE_HALF_OPENED + && state != COMMON_STATE_UNKNOWN) { throw new IllegalArgumentException("Invalid state: " + state + "must be either COMMON_STATE_FLAT or COMMON_STATE_HALF_OPENED"); } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java index 0bdf98c8680f..66f27f517ab3 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java @@ -19,6 +19,7 @@ package androidx.window.common; import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE; import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_UNKNOWN; +import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_USE_BASE_STATE; import static androidx.window.common.CommonFoldingFeature.parseListFromString; import android.annotation.NonNull; @@ -52,13 +53,54 @@ public final class DeviceStateManagerFoldingFeatureProducer DeviceStateManagerFoldingFeatureProducer.class.getSimpleName(); private static final boolean DEBUG = false; + /** + * Emulated device state {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)} to + * {@link CommonFoldingFeature.State} map. + */ private final SparseIntArray mDeviceStateToPostureMap = new SparseIntArray(); + /** + * Emulated device state received via + * {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)}. + * "Emulated" states differ from "base" state in the sense that they may not correspond 1:1 with + * physical device states. They represent the state of the device when various software + * features and APIs are applied. The emulated states generally consist of all "base" states, + * but may have additional states such as "concurrent" or "rear display". Concurrent mode for + * example is activated via public API and can be active in both the "open" and "half folded" + * device states. + */ private int mCurrentDeviceState = INVALID_DEVICE_STATE; + /** + * Base device state received via + * {@link DeviceStateManager.DeviceStateCallback#onBaseStateChanged(int)}. + * "Base" in this context means the "physical" state of the device. + */ + private int mCurrentBaseDeviceState = INVALID_DEVICE_STATE; + @NonNull private final BaseDataProducer<String> mRawFoldSupplier; + private final DeviceStateCallback mDeviceStateCallback = new DeviceStateCallback() { + @Override + public void onStateChanged(int state) { + mCurrentDeviceState = state; + mRawFoldSupplier.getData(DeviceStateManagerFoldingFeatureProducer + .this::notifyFoldingFeatureChange); + } + + @Override + public void onBaseStateChanged(int state) { + mCurrentBaseDeviceState = state; + + if (mDeviceStateToPostureMap.get(mCurrentDeviceState) + == COMMON_STATE_USE_BASE_STATE) { + mRawFoldSupplier.getData(DeviceStateManagerFoldingFeatureProducer + .this::notifyFoldingFeatureChange); + } + } + }; + public DeviceStateManagerFoldingFeatureProducer(@NonNull Context context, @NonNull BaseDataProducer<String> rawFoldSupplier) { mRawFoldSupplier = rawFoldSupplier; @@ -92,12 +134,8 @@ public final class DeviceStateManagerFoldingFeatureProducer } if (mDeviceStateToPostureMap.size() > 0) { - DeviceStateCallback deviceStateCallback = (state) -> { - mCurrentDeviceState = state; - mRawFoldSupplier.getData(this::notifyFoldingFeatureChange); - }; Objects.requireNonNull(context.getSystemService(DeviceStateManager.class)) - .registerCallback(context.getMainExecutor(), deviceStateCallback); + .registerCallback(context.getMainExecutor(), mDeviceStateCallback); } } @@ -178,11 +216,18 @@ public final class DeviceStateManagerFoldingFeatureProducer } private List<CommonFoldingFeature> calculateFoldingFeature(String displayFeaturesString) { - final int globalHingeState = globalHingeState(); - return parseListFromString(displayFeaturesString, globalHingeState); + return parseListFromString(displayFeaturesString, currentHingeState()); } - private int globalHingeState() { - return mDeviceStateToPostureMap.get(mCurrentDeviceState, COMMON_STATE_UNKNOWN); + @CommonFoldingFeature.State + private int currentHingeState() { + @CommonFoldingFeature.State + int posture = mDeviceStateToPostureMap.get(mCurrentDeviceState, COMMON_STATE_UNKNOWN); + + if (posture == CommonFoldingFeature.COMMON_STATE_USE_BASE_STATE) { + posture = mDeviceStateToPostureMap.get(mCurrentBaseDeviceState, COMMON_STATE_UNKNOWN); + } + + return posture; } } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java index 274dcaee5a43..575b0cea78f7 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java @@ -263,8 +263,10 @@ public class WindowAreaComponentImpl implements WindowAreaComponent, return; } @WindowAreaStatus int currentStatus = getCurrentRearDisplayPresentationModeStatus(); + DisplayMetrics metrics = + currentStatus == STATUS_UNSUPPORTED ? null : getRearDisplayMetrics(); consumer.accept( - new RearDisplayPresentationStatus(currentStatus, getRearDisplayMetrics())); + new RearDisplayPresentationStatus(currentStatus, metrics)); } } @@ -408,6 +410,10 @@ public class WindowAreaComponentImpl implements WindowAreaComponent, @GuardedBy("mLock") private int getCurrentRearDisplayModeStatus() { + if (mRearDisplayState == INVALID_DEVICE_STATE) { + return WindowAreaComponent.STATUS_UNSUPPORTED; + } + if (mRearDisplaySessionStatus == WindowAreaComponent.SESSION_STATE_ACTIVE || !ArrayUtils.contains(mCurrentSupportedDeviceStates, mRearDisplayState) || isRearDisplayActive()) { @@ -441,6 +447,10 @@ public class WindowAreaComponentImpl implements WindowAreaComponent, @GuardedBy("mLock") private int getCurrentRearDisplayPresentationModeStatus() { + if (mConcurrentDisplayState == INVALID_DEVICE_STATE) { + return WindowAreaComponent.STATUS_UNSUPPORTED; + } + if (mCurrentDeviceState == mConcurrentDisplayState || !ArrayUtils.contains(mCurrentSupportedDeviceStates, mConcurrentDisplayState) || isDeviceFolded()) { 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 ab968563854c..3d1ed87f1305 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 @@ -31,6 +31,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.PipAppOpsListener; +import com.android.wm.shell.pip.PipDisplayLayoutState; import com.android.wm.shell.pip.PipMediaController; import com.android.wm.shell.pip.PipParamsChangedForwarder; import com.android.wm.shell.pip.PipSnapAlgorithm; @@ -70,7 +71,7 @@ public abstract class TvPipModule { ShellInit shellInit, ShellController shellController, TvPipBoundsState tvPipBoundsState, - PipSizeSpecHandler pipSizeSpecHandler, + PipDisplayLayoutState pipDisplayLayoutState, TvPipBoundsAlgorithm tvPipBoundsAlgorithm, TvPipBoundsController tvPipBoundsController, PipAppOpsListener pipAppOpsListener, @@ -91,7 +92,7 @@ public abstract class TvPipModule { shellInit, shellController, tvPipBoundsState, - pipSizeSpecHandler, + pipDisplayLayoutState, tvPipBoundsAlgorithm, tvPipBoundsController, pipAppOpsListener, @@ -141,14 +142,15 @@ public abstract class TvPipModule { @WMSingleton @Provides static TvPipBoundsState provideTvPipBoundsState(Context context, - PipSizeSpecHandler pipSizeSpecHandler) { - return new TvPipBoundsState(context, pipSizeSpecHandler); + PipSizeSpecHandler pipSizeSpecHandler, PipDisplayLayoutState pipDisplayLayoutState) { + return new TvPipBoundsState(context, pipSizeSpecHandler, pipDisplayLayoutState); } @WMSingleton @Provides - static PipSizeSpecHandler providePipSizeSpecHelper(Context context) { - return new PipSizeSpecHandler(context); + static PipSizeSpecHandler providePipSizeSpecHelper(Context context, + PipDisplayLayoutState pipDisplayLayoutState) { + return new PipSizeSpecHandler(context, pipDisplayLayoutState); } // Handler needed for loadDrawableAsync() in PipControlsViewController @@ -203,7 +205,7 @@ public abstract class TvPipModule { TvPipMenuController tvPipMenuController, SyncTransactionQueue syncTransactionQueue, TvPipBoundsState tvPipBoundsState, - PipSizeSpecHandler pipSizeSpecHandler, + PipDisplayLayoutState pipDisplayLayoutState, PipTransitionState pipTransitionState, TvPipBoundsAlgorithm tvPipBoundsAlgorithm, PipAnimationController pipAnimationController, @@ -215,7 +217,7 @@ public abstract class TvPipModule { PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer, @ShellMainThread ShellExecutor mainExecutor) { return new TvPipTaskOrganizer(context, - syncTransactionQueue, pipTransitionState, tvPipBoundsState, pipSizeSpecHandler, + syncTransactionQueue, pipTransitionState, tvPipBoundsState, pipDisplayLayoutState, tvPipBoundsAlgorithm, tvPipMenuController, pipAnimationController, pipSurfaceTransactionHelper, pipTransitionController, pipParamsChangedForwarder, splitScreenControllerOptional, displayController, pipUiEventLogger, 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 948bf2d100f9..ba0f07376468 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 @@ -65,6 +65,7 @@ import com.android.wm.shell.pip.PipAnimationController; import com.android.wm.shell.pip.PipAppOpsListener; import com.android.wm.shell.pip.PipBoundsAlgorithm; import com.android.wm.shell.pip.PipBoundsState; +import com.android.wm.shell.pip.PipDisplayLayoutState; import com.android.wm.shell.pip.PipMediaController; import com.android.wm.shell.pip.PipParamsChangedForwarder; import com.android.wm.shell.pip.PipSnapAlgorithm; @@ -344,6 +345,7 @@ public abstract class WMShellModule { PhonePipKeepClearAlgorithm pipKeepClearAlgorithm, PipBoundsState pipBoundsState, PipSizeSpecHandler pipSizeSpecHandler, + PipDisplayLayoutState pipDisplayLayoutState, PipMotionHelper pipMotionHelper, PipMediaController pipMediaController, PhonePipMenuController phonePipMenuController, @@ -360,18 +362,18 @@ public abstract class WMShellModule { return Optional.ofNullable(PipController.create( context, shellInit, shellCommandHandler, shellController, displayController, pipAnimationController, pipAppOpsListener, pipBoundsAlgorithm, - pipKeepClearAlgorithm, pipBoundsState, pipSizeSpecHandler, pipMotionHelper, - pipMediaController, phonePipMenuController, pipTaskOrganizer, pipTransitionState, - pipTouchHandler, pipTransitionController, windowManagerShellWrapper, - taskStackListener, pipParamsChangedForwarder, displayInsetsController, - oneHandedController, mainExecutor)); + pipKeepClearAlgorithm, pipBoundsState, pipSizeSpecHandler, pipDisplayLayoutState, + pipMotionHelper, pipMediaController, phonePipMenuController, pipTaskOrganizer, + pipTransitionState, pipTouchHandler, pipTransitionController, + windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder, + displayInsetsController, oneHandedController, mainExecutor)); } @WMSingleton @Provides static PipBoundsState providePipBoundsState(Context context, - PipSizeSpecHandler pipSizeSpecHandler) { - return new PipBoundsState(context, pipSizeSpecHandler); + PipSizeSpecHandler pipSizeSpecHandler, PipDisplayLayoutState pipDisplayLayoutState) { + return new PipBoundsState(context, pipSizeSpecHandler, pipDisplayLayoutState); } @WMSingleton @@ -388,8 +390,9 @@ public abstract class WMShellModule { @WMSingleton @Provides - static PipSizeSpecHandler providePipSizeSpecHelper(Context context) { - return new PipSizeSpecHandler(context); + static PipSizeSpecHandler providePipSizeSpecHelper(Context context, + PipDisplayLayoutState pipDisplayLayoutState) { + return new PipSizeSpecHandler(context, pipDisplayLayoutState); } @WMSingleton @@ -446,7 +449,7 @@ public abstract class WMShellModule { SyncTransactionQueue syncTransactionQueue, PipTransitionState pipTransitionState, PipBoundsState pipBoundsState, - PipSizeSpecHandler pipSizeSpecHandler, + PipDisplayLayoutState pipDisplayLayoutState, PipBoundsAlgorithm pipBoundsAlgorithm, PhonePipMenuController menuPhoneController, PipAnimationController pipAnimationController, @@ -458,7 +461,7 @@ public abstract class WMShellModule { PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer, @ShellMainThread ShellExecutor mainExecutor) { return new PipTaskOrganizer(context, - syncTransactionQueue, pipTransitionState, pipBoundsState, pipSizeSpecHandler, + syncTransactionQueue, pipTransitionState, pipBoundsState, pipDisplayLayoutState, pipBoundsAlgorithm, menuPhoneController, pipAnimationController, pipSurfaceTransactionHelper, pipTransitionController, pipParamsChangedForwarder, splitScreenControllerOptional, displayController, pipUiEventLogger, @@ -477,12 +480,12 @@ public abstract class WMShellModule { static PipTransitionController providePipTransitionController(Context context, ShellInit shellInit, ShellTaskOrganizer shellTaskOrganizer, Transitions transitions, PipAnimationController pipAnimationController, PipBoundsAlgorithm pipBoundsAlgorithm, - PipBoundsState pipBoundsState, PipSizeSpecHandler pipSizeSpecHandler, + PipBoundsState pipBoundsState, PipDisplayLayoutState pipDisplayLayoutState, PipTransitionState pipTransitionState, PhonePipMenuController pipMenuController, PipSurfaceTransactionHelper pipSurfaceTransactionHelper, Optional<SplitScreenController> splitScreenOptional) { return new PipTransition(context, shellInit, shellTaskOrganizer, transitions, - pipBoundsState, pipSizeSpecHandler, pipTransitionState, pipMenuController, + pipBoundsState, pipDisplayLayoutState, pipTransitionState, pipMenuController, pipBoundsAlgorithm, pipAnimationController, pipSurfaceTransactionHelper, splitScreenOptional); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java index 23f73f614294..fe8ede67c415 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java @@ -36,6 +36,7 @@ import android.window.TaskSnapshot; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.SfVsyncFrameCallbackProvider; +import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.animation.Interpolators; import com.android.wm.shell.transition.Transitions; @@ -372,7 +373,8 @@ public class PipAnimationController { void setAppIconContentOverlay(Context context, Rect bounds, ActivityInfo activityInfo) { reattachContentOverlay( - new PipContentOverlay.PipAppIconOverlay(context, bounds, activityInfo)); + new PipContentOverlay.PipAppIconOverlay(context, bounds, + () -> new IconProvider(context).getIcon(activityInfo))); } private void reattachContentOverlay(PipContentOverlay overlay) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java index 5be18d852990..f6648085075d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java @@ -30,7 +30,6 @@ import android.graphics.Rect; import android.os.RemoteException; import android.util.ArraySet; import android.util.Size; -import android.view.Display; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; @@ -77,6 +76,7 @@ public class PipBoundsState { private final @NonNull Rect mExpandedBounds = new Rect(); private final @NonNull Rect mNormalMovementBounds = new Rect(); private final @NonNull Rect mExpandedMovementBounds = new Rect(); + private final @NonNull PipDisplayLayoutState mPipDisplayLayoutState; private final Point mMaxSize = new Point(); private final Point mMinSize = new Point(); private final @NonNull Context mContext; @@ -86,8 +86,6 @@ public class PipBoundsState { private @Nullable PipReentryState mPipReentryState; private final @Nullable PipSizeSpecHandler mPipSizeSpecHandler; private @Nullable ComponentName mLastPipComponentName; - private int mDisplayId = Display.DEFAULT_DISPLAY; - private final @NonNull DisplayLayout mDisplayLayout = new DisplayLayout(); private final @NonNull MotionBoundsState mMotionBoundsState = new MotionBoundsState(); private boolean mIsImeShowing; private int mImeHeight; @@ -120,10 +118,12 @@ public class PipBoundsState { private @Nullable TriConsumer<Boolean, Integer, Boolean> mOnShelfVisibilityChangeCallback; private List<Consumer<Rect>> mOnPipExclusionBoundsChangeCallbacks = new ArrayList<>(); - public PipBoundsState(@NonNull Context context, PipSizeSpecHandler pipSizeSpecHandler) { + public PipBoundsState(@NonNull Context context, PipSizeSpecHandler pipSizeSpecHandler, + PipDisplayLayoutState pipDisplayLayoutState) { mContext = context; reloadResources(); mPipSizeSpecHandler = pipSizeSpecHandler; + mPipDisplayLayoutState = pipDisplayLayoutState; } /** Reloads the resources. */ @@ -290,31 +290,16 @@ public class PipBoundsState { return mLastPipComponentName; } - /** Get the current display id. */ - public int getDisplayId() { - return mDisplayId; - } - - /** Set the current display id for the associated display layout. */ - public void setDisplayId(int displayId) { - mDisplayId = displayId; - } - /** Returns the display's bounds. */ @NonNull public Rect getDisplayBounds() { - return new Rect(0, 0, mDisplayLayout.width(), mDisplayLayout.height()); - } - - /** Update the display layout. */ - public void setDisplayLayout(@NonNull DisplayLayout displayLayout) { - mDisplayLayout.set(displayLayout); + return mPipDisplayLayoutState.getDisplayBounds(); } /** Get a copy of the display layout. */ @NonNull public DisplayLayout getDisplayLayout() { - return new DisplayLayout(mDisplayLayout); + return mPipDisplayLayoutState.getDisplayLayout(); } @VisibleForTesting @@ -568,7 +553,6 @@ public class PipBoundsState { pw.println(innerPrefix + "mExpandedMovementBounds=" + mExpandedMovementBounds); pw.println(innerPrefix + "mLastPipComponentName=" + mLastPipComponentName); pw.println(innerPrefix + "mAspectRatio=" + mAspectRatio); - pw.println(innerPrefix + "mDisplayId=" + mDisplayId); pw.println(innerPrefix + "mStashedState=" + mStashedState); pw.println(innerPrefix + "mStashOffset=" + mStashOffset); pw.println(innerPrefix + "mIsImeShowing=" + mIsImeShowing); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java index 53bf42a3c911..d228dfbb7705 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java @@ -20,9 +20,6 @@ import static android.util.TypedValue.COMPLEX_UNIT_DIP; import android.annotation.Nullable; import android.content.Context; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageManager; -import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -35,6 +32,8 @@ import android.view.SurfaceControl; import android.view.SurfaceSession; import android.window.TaskSnapshot; +import java.util.function.Supplier; + /** * Represents the content overlay used during the entering PiP animation. */ @@ -177,7 +176,9 @@ public abstract class PipContentOverlay { /** A {@link PipContentOverlay} shows app icon on solid color background. */ public static final class PipAppIconOverlay extends PipContentOverlay { private static final String TAG = PipAppIconOverlay.class.getSimpleName(); - private static final int APP_ICON_SIZE_DP = 48; + // Align with the practical / reasonable launcher:iconImageSize as in + // vendor/unbundled_google/packages/NexusLauncher/res/xml/device_profiles.xml + private static final int APP_ICON_SIZE_DP = 66; private final Context mContext; private final int mAppIconSizePx; @@ -187,14 +188,14 @@ public abstract class PipContentOverlay { private Bitmap mBitmap; - public PipAppIconOverlay(Context context, Rect appBounds, ActivityInfo activityInfo) { + public PipAppIconOverlay(Context context, Rect appBounds, Supplier<Drawable> iconSupplier) { mContext = context; mAppIconSizePx = (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, APP_ICON_SIZE_DP, context.getResources().getDisplayMetrics()); mAppBounds = new Rect(appBounds); mBitmap = Bitmap.createBitmap(appBounds.width(), appBounds.height(), Bitmap.Config.ARGB_8888); - prepareAppIconOverlay(activityInfo); + prepareAppIconOverlay(iconSupplier); mLeash = new SurfaceControl.Builder(new SurfaceSession()) .setCallsite(TAG) .setName(LAYER_NAME) @@ -237,7 +238,7 @@ public abstract class PipContentOverlay { } } - private void prepareAppIconOverlay(ActivityInfo activityInfo) { + private void prepareAppIconOverlay(Supplier<Drawable> iconSupplier) { final Canvas canvas = new Canvas(); canvas.setBitmap(mBitmap); final TypedArray ta = mContext.obtainStyledAttributes(new int[] { @@ -251,8 +252,7 @@ public abstract class PipContentOverlay { } finally { ta.recycle(); } - final Drawable appIcon = loadActivityInfoIcon(activityInfo, - mContext.getResources().getConfiguration().densityDpi); + final Drawable appIcon = iconSupplier.get(); final Rect appIconBounds = new Rect( mAppBounds.centerX() - mAppIconSizePx / 2, mAppBounds.centerY() - mAppIconSizePx / 2, @@ -262,24 +262,5 @@ public abstract class PipContentOverlay { appIcon.draw(canvas); mBitmap = mBitmap.copy(Bitmap.Config.HARDWARE, false /* mutable */); } - - // Copied from com.android.launcher3.icons.IconProvider#loadActivityInfoIcon - private Drawable loadActivityInfoIcon(ActivityInfo ai, int density) { - final int iconRes = ai.getIconResource(); - Drawable icon = null; - // Get the preferred density icon from the app's resources - if (density != 0 && iconRes != 0) { - try { - final Resources resources = mContext.getPackageManager() - .getResourcesForApplication(ai.applicationInfo); - icon = resources.getDrawableForDensity(iconRes, density); - } catch (PackageManager.NameNotFoundException | Resources.NotFoundException exc) { } - } - // Get the default density icon - if (icon == null) { - icon = ai.loadIcon(mContext.getPackageManager()); - } - return icon; - } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipDisplayLayoutState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipDisplayLayoutState.java new file mode 100644 index 000000000000..0f76af48199f --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipDisplayLayoutState.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2023 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.content.Context; +import android.graphics.Rect; +import android.view.Surface; + +import androidx.annotation.NonNull; + +import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.dagger.WMSingleton; + +import java.io.PrintWriter; + +import javax.inject.Inject; + +/** + * Acts as a source of truth for display related information for PIP. + */ +@WMSingleton +public class PipDisplayLayoutState { + private static final String TAG = PipDisplayLayoutState.class.getSimpleName(); + + private Context mContext; + private int mDisplayId; + @NonNull private DisplayLayout mDisplayLayout; + + @Inject + public PipDisplayLayoutState(Context context) { + mContext = context; + mDisplayLayout = new DisplayLayout(); + } + + /** Update the display layout. */ + public void setDisplayLayout(@NonNull DisplayLayout displayLayout) { + mDisplayLayout.set(displayLayout); + } + + /** Get a copy of the display layout. */ + @NonNull + public DisplayLayout getDisplayLayout() { + return new DisplayLayout(mDisplayLayout); + } + + /** Get the display bounds */ + @NonNull + public Rect getDisplayBounds() { + return new Rect(0, 0, mDisplayLayout.width(), mDisplayLayout.height()); + } + + /** + * Apply a rotation to this layout and its parameters. + * @param targetRotation + */ + public void rotateTo(@Surface.Rotation int targetRotation) { + mDisplayLayout.rotateTo(mContext.getResources(), targetRotation); + } + + /** Get the current display id */ + public int getDisplayId() { + return mDisplayId; + } + + /** Set the current display id for the associated display layout. */ + public void setDisplayId(int displayId) { + mDisplayId = displayId; + } + + /** Dumps internal state. */ + public void dump(PrintWriter pw, String prefix) { + final String innerPrefix = prefix + " "; + pw.println(prefix + TAG); + pw.println(innerPrefix + "mDisplayId=" + mDisplayId); + pw.println(innerPrefix + "getDisplayBounds=" + getDisplayBounds()); + } +} 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 eb336d56b62c..d5b9c5e8d8ff 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 @@ -79,13 +79,11 @@ import com.android.wm.shell.R; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.animation.Interpolators; import com.android.wm.shell.common.DisplayController; -import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ScreenshotUtils; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.annotations.ShellMainThread; import com.android.wm.shell.pip.phone.PipMotionHelper; -import com.android.wm.shell.pip.phone.PipSizeSpecHandler; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.transition.Transitions; @@ -128,7 +126,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, private final Context mContext; private final SyncTransactionQueue mSyncTransactionQueue; private final PipBoundsState mPipBoundsState; - private final PipSizeSpecHandler mPipSizeSpecHandler; + private final PipDisplayLayoutState mPipDisplayLayoutState; private final PipBoundsAlgorithm mPipBoundsAlgorithm; private final @NonNull PipMenuController mPipMenuController; private final PipAnimationController mPipAnimationController; @@ -316,7 +314,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, @NonNull SyncTransactionQueue syncTransactionQueue, @NonNull PipTransitionState pipTransitionState, @NonNull PipBoundsState pipBoundsState, - @NonNull PipSizeSpecHandler pipSizeSpecHandler, + @NonNull PipDisplayLayoutState pipDisplayLayoutState, @NonNull PipBoundsAlgorithm boundsHandler, @NonNull PipMenuController pipMenuController, @NonNull PipAnimationController pipAnimationController, @@ -332,7 +330,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mSyncTransactionQueue = syncTransactionQueue; mPipTransitionState = pipTransitionState; mPipBoundsState = pipBoundsState; - mPipSizeSpecHandler = pipSizeSpecHandler; + mPipDisplayLayoutState = pipDisplayLayoutState; mPipBoundsAlgorithm = boundsHandler; mPipMenuController = pipMenuController; mPipTransitionController = pipTransitionController; @@ -653,7 +651,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, // If the displayId of the task is different than what PipBoundsHandler has, then update // it. This is possible if we entered PiP on an external display. - if (info.displayId != mPipBoundsState.getDisplayId() + if (info.displayId != mPipDisplayLayoutState.getDisplayId() && mOnDisplayIdChangeCallback != null) { mOnDisplayIdChangeCallback.accept(info.displayId); } @@ -1635,15 +1633,15 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, return animator; } - /** Computes destination bounds in old rotation and returns source hint rect if available. */ + /** Computes destination bounds in old rotation and returns source hint rect if available. + * + * Note: updates the internal state of {@link PipDisplayLayoutState} by applying a rotation + * transformation onto the display layout. + */ private @Nullable Rect computeRotatedBounds(int rotationDelta, int direction, Rect outDestinationBounds, Rect sourceHintRect) { if (direction == TRANSITION_DIRECTION_TO_PIP) { - DisplayLayout layoutCopy = mPipBoundsState.getDisplayLayout(); - - layoutCopy.rotateTo(mContext.getResources(), mNextRotation); - mPipBoundsState.setDisplayLayout(layoutCopy); - mPipSizeSpecHandler.setDisplayLayout(layoutCopy); + mPipDisplayLayoutState.rotateTo(mNextRotation); final Rect displayBounds = mPipBoundsState.getDisplayBounds(); outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds()); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java index a91a3424f3a0..87cf6559a0f0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java @@ -64,8 +64,6 @@ import androidx.annotation.Nullable; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.R; import com.android.wm.shell.ShellTaskOrganizer; -import com.android.wm.shell.common.DisplayLayout; -import com.android.wm.shell.pip.phone.PipSizeSpecHandler; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.sysui.ShellInit; @@ -85,7 +83,7 @@ public class PipTransition extends PipTransitionController { private final Context mContext; private final PipTransitionState mPipTransitionState; - private final PipSizeSpecHandler mPipSizeSpecHandler; + private final PipDisplayLayoutState mPipDisplayLayoutState; private final int mEnterExitAnimationDuration; private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; private final Optional<SplitScreenController> mSplitScreenOptional; @@ -116,7 +114,7 @@ public class PipTransition extends PipTransitionController { @NonNull ShellTaskOrganizer shellTaskOrganizer, @NonNull Transitions transitions, PipBoundsState pipBoundsState, - PipSizeSpecHandler pipSizeSpecHandler, + PipDisplayLayoutState pipDisplayLayoutState, PipTransitionState pipTransitionState, PipMenuController pipMenuController, PipBoundsAlgorithm pipBoundsAlgorithm, @@ -127,7 +125,7 @@ public class PipTransition extends PipTransitionController { pipBoundsAlgorithm, pipAnimationController); mContext = context; mPipTransitionState = pipTransitionState; - mPipSizeSpecHandler = pipSizeSpecHandler; + mPipDisplayLayoutState = pipDisplayLayoutState; mEnterExitAnimationDuration = context.getResources() .getInteger(R.integer.config_pipResizeAnimationDuration); mSurfaceTransactionHelper = pipSurfaceTransactionHelper; @@ -313,11 +311,7 @@ public class PipTransition extends PipTransitionController { // initial state under the new rotation. int rotationDelta = deltaRotation(startRotation, endRotation); if (rotationDelta != Surface.ROTATION_0) { - DisplayLayout layoutCopy = mPipBoundsState.getDisplayLayout(); - - layoutCopy.rotateTo(mContext.getResources(), endRotation); - mPipBoundsState.setDisplayLayout(layoutCopy); - mPipSizeSpecHandler.setDisplayLayout(layoutCopy); + mPipDisplayLayoutState.rotateTo(endRotation); final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds(); wct.setBounds(mRequestedEnterTask, destinationBounds); @@ -398,7 +392,7 @@ public class PipTransition extends PipTransitionController { // Launcher may update the Shelf height during the animation, which will update the // destination bounds. Because this is in fixed rotation, We need to make sure the // finishTransaction is using the updated bounds in the display rotation. - final Rect displayBounds = mPipBoundsState.getDisplayBounds(); + final Rect displayBounds = mPipDisplayLayoutState.getDisplayBounds(); final Rect finishBounds = new Rect(destinationBounds); rotateBounds(finishBounds, displayBounds, mEndFixedRotation, displayRotation); mSurfaceTransactionHelper.crop(mFinishTransaction, leash, finishBounds); @@ -640,7 +634,7 @@ public class PipTransition extends PipTransitionController { @NonNull TaskInfo taskInfo) { startTransaction.apply(); finishTransaction.setWindowCrop(info.getChanges().get(0).getLeash(), - mPipBoundsState.getDisplayBounds()); + mPipDisplayLayoutState.getDisplayBounds()); mPipOrganizer.onExitPipFinished(taskInfo); finishCallback.onTransitionFinished(null, null); } @@ -803,8 +797,15 @@ public class PipTransition extends PipTransitionController { if (sourceHintRect == null) { // We use content overlay when there is no source rect hint to enter PiP use bounds // animation. + // TODO(b/272819817): cleanup the null-check and extra logging. + final boolean hasTopActivityInfo = taskInfo.topActivityInfo != null; + if (!hasTopActivityInfo) { + ProtoLog.w(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, + "%s: TaskInfo.topActivityInfo is null", TAG); + } if (SystemProperties.getBoolean( - "persist.wm.debug.enable_pip_app_icon_overlay", true)) { + "persist.wm.debug.enable_pip_app_icon_overlay", true) + && hasTopActivityInfo) { animator.setAppIconContentOverlay( mContext, currentBounds, taskInfo.topActivityInfo); } else { @@ -834,13 +835,9 @@ public class PipTransition extends PipTransitionController { /** Computes destination bounds in old rotation and updates source hint rect if available. */ private void computeEnterPipRotatedBounds(int rotationDelta, int startRotation, int endRotation, TaskInfo taskInfo, Rect outDestinationBounds, @Nullable Rect outSourceHintRect) { - DisplayLayout layoutCopy = mPipBoundsState.getDisplayLayout(); - - layoutCopy.rotateTo(mContext.getResources(), endRotation); - mPipBoundsState.setDisplayLayout(layoutCopy); - mPipSizeSpecHandler.setDisplayLayout(layoutCopy); + mPipDisplayLayoutState.rotateTo(endRotation); - final Rect displayBounds = mPipBoundsState.getDisplayBounds(); + final Rect displayBounds = mPipDisplayLayoutState.getDisplayBounds(); outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds()); // Transform the destination bounds to current display coordinates. rotateBounds(outDestinationBounds, displayBounds, endRotation, startRotation); 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 99cd00a67cf7..db6ef1dffc9c 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 @@ -83,6 +83,7 @@ import com.android.wm.shell.pip.PipAnimationController; import com.android.wm.shell.pip.PipAppOpsListener; import com.android.wm.shell.pip.PipBoundsAlgorithm; import com.android.wm.shell.pip.PipBoundsState; +import com.android.wm.shell.pip.PipDisplayLayoutState; import com.android.wm.shell.pip.PipKeepClearAlgorithmInterface; import com.android.wm.shell.pip.PipMediaController; import com.android.wm.shell.pip.PipParamsChangedForwarder; @@ -139,6 +140,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb private PipKeepClearAlgorithmInterface mPipKeepClearAlgorithm; private PipBoundsState mPipBoundsState; private PipSizeSpecHandler mPipSizeSpecHandler; + private PipDisplayLayoutState mPipDisplayLayoutState; private PipMotionHelper mPipMotionHelper; private PipTouchHandler mTouchHandler; private PipTransitionController mPipTransitionController; @@ -310,7 +312,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb @Override public void onDisplayAdded(int displayId) { - if (displayId != mPipBoundsState.getDisplayId()) { + if (displayId != mPipDisplayLayoutState.getDisplayId()) { return; } onDisplayChanged(mDisplayController.getDisplayLayout(displayId), @@ -319,7 +321,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb @Override public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) { - if (displayId != mPipBoundsState.getDisplayId()) { + if (displayId != mPipDisplayLayoutState.getDisplayId()) { return; } onDisplayChanged(mDisplayController.getDisplayLayout(displayId), @@ -329,7 +331,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb @Override public void onKeepClearAreasChanged(int displayId, Set<Rect> restricted, Set<Rect> unrestricted) { - if (mPipBoundsState.getDisplayId() == displayId) { + if (mPipDisplayLayoutState.getDisplayId() == displayId) { if (mEnablePipKeepClearAlgorithm) { mPipBoundsState.setKeepClearAreas(restricted, unrestricted); @@ -389,6 +391,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb PipKeepClearAlgorithmInterface pipKeepClearAlgorithm, PipBoundsState pipBoundsState, PipSizeSpecHandler pipSizeSpecHandler, + PipDisplayLayoutState pipDisplayLayoutState, PipMotionHelper pipMotionHelper, PipMediaController pipMediaController, PhonePipMenuController phonePipMenuController, @@ -411,8 +414,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb return new PipController(context, shellInit, shellCommandHandler, shellController, displayController, pipAnimationController, pipAppOpsListener, pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState, pipSizeSpecHandler, - pipMotionHelper, pipMediaController, phonePipMenuController, pipTaskOrganizer, - pipTransitionState, pipTouchHandler, pipTransitionController, + pipDisplayLayoutState, pipMotionHelper, pipMediaController, phonePipMenuController, + pipTaskOrganizer, pipTransitionState, pipTouchHandler, pipTransitionController, windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder, displayInsetsController, oneHandedController, mainExecutor) .mImpl; @@ -429,6 +432,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb PipKeepClearAlgorithmInterface pipKeepClearAlgorithm, @NonNull PipBoundsState pipBoundsState, PipSizeSpecHandler pipSizeSpecHandler, + @NonNull PipDisplayLayoutState pipDisplayLayoutState, PipMotionHelper pipMotionHelper, PipMediaController pipMediaController, PhonePipMenuController phonePipMenuController, @@ -455,6 +459,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb mPipKeepClearAlgorithm = pipKeepClearAlgorithm; mPipBoundsState = pipBoundsState; mPipSizeSpecHandler = pipSizeSpecHandler; + mPipDisplayLayoutState = pipDisplayLayoutState; mPipMotionHelper = pipMotionHelper; mPipTaskOrganizer = pipTaskOrganizer; mPipTransitionState = pipTransitionState; @@ -482,7 +487,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb INPUT_CONSUMER_PIP, mMainExecutor); mPipTransitionController.registerPipTransitionCallback(this); mPipTaskOrganizer.registerOnDisplayIdChangeCallback((int displayId) -> { - mPipBoundsState.setDisplayId(displayId); + mPipDisplayLayoutState.setDisplayId(displayId); onDisplayChanged(mDisplayController.getDisplayLayout(displayId), false /* saveRestoreSnapFraction */); }); @@ -522,11 +527,10 @@ public class PipController implements PipTransitionController.PipTransitionCallb // Ensure that we have the display info in case we get calls to update the bounds before the // listener calls back - mPipBoundsState.setDisplayId(mContext.getDisplayId()); + mPipDisplayLayoutState.setDisplayId(mContext.getDisplayId()); DisplayLayout layout = new DisplayLayout(mContext, mContext.getDisplay()); - mPipSizeSpecHandler.setDisplayLayout(layout); - mPipBoundsState.setDisplayLayout(layout); + mPipDisplayLayoutState.setDisplayLayout(layout); try { mWindowManagerShellWrapper.addPinnedStackListener(mPinnedTaskListener); @@ -621,12 +625,12 @@ public class PipController implements PipTransitionController.PipTransitionCallb } }); - mDisplayInsetsController.addInsetsChangedListener(mPipBoundsState.getDisplayId(), + mDisplayInsetsController.addInsetsChangedListener(mPipDisplayLayoutState.getDisplayId(), new DisplayInsetsController.OnInsetsChangedListener() { @Override public void insetsChanged(InsetsState insetsState) { - DisplayLayout pendingLayout = - mDisplayController.getDisplayLayout(mPipBoundsState.getDisplayId()); + DisplayLayout pendingLayout = mDisplayController + .getDisplayLayout(mPipDisplayLayoutState.getDisplayId()); if (mIsInFixedRotation || pendingLayout.rotation() != mPipBoundsState.getDisplayLayout().rotation()) { @@ -634,8 +638,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb return; } int oldMaxMovementBound = mPipBoundsState.getMovementBounds().bottom; - onDisplayChangedUncheck( - mDisplayController.getDisplayLayout(mPipBoundsState.getDisplayId()), + onDisplayChangedUncheck(mDisplayController + .getDisplayLayout(mPipDisplayLayoutState.getDisplayId()), false /* saveRestoreSnapFraction */); int newMaxMovementBound = mPipBoundsState.getMovementBounds().bottom; if (!mEnablePipKeepClearAlgorithm) { @@ -721,7 +725,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb } private void onDisplayChanged(DisplayLayout layout, boolean saveRestoreSnapFraction) { - if (!mPipBoundsState.getDisplayLayout().isSameGeometry(layout)) { + if (!mPipDisplayLayoutState.getDisplayLayout().isSameGeometry(layout)) { PipAnimationController.PipTransitionAnimator animator = mPipAnimationController.getCurrentAnimator(); if (animator != null && animator.isRunning()) { @@ -735,11 +739,10 @@ public class PipController implements PipTransitionController.PipTransitionCallb private void onDisplayChangedUncheck(DisplayLayout layout, boolean saveRestoreSnapFraction) { Runnable updateDisplayLayout = () -> { final boolean fromRotation = Transitions.ENABLE_SHELL_TRANSITIONS - && mPipBoundsState.getDisplayLayout().rotation() != layout.rotation(); + && mPipDisplayLayoutState.getDisplayLayout().rotation() != layout.rotation(); // update the internal state of objects subscribed to display changes - mPipSizeSpecHandler.setDisplayLayout(layout); - mPipBoundsState.setDisplayLayout(layout); + mPipDisplayLayoutState.setDisplayLayout(layout); final WindowContainerTransaction wct = fromRotation ? new WindowContainerTransaction() : null; @@ -763,11 +766,13 @@ public class PipController implements PipTransitionController.PipTransitionCallb mPipBoundsState.getStashedState()); // Scale PiP on density dpi change, so it appears to be the same size physically. - final boolean densityDpiChanged = mPipBoundsState.getDisplayLayout().densityDpi() != 0 - && (mPipBoundsState.getDisplayLayout().densityDpi() != layout.densityDpi()); + final boolean densityDpiChanged = + mPipDisplayLayoutState.getDisplayLayout().densityDpi() != 0 + && (mPipDisplayLayoutState.getDisplayLayout().densityDpi() + != layout.densityDpi()); if (densityDpiChanged) { final float scale = (float) layout.densityDpi() - / mPipBoundsState.getDisplayLayout().densityDpi(); + / mPipDisplayLayoutState.getDisplayLayout().densityDpi(); postChangeBounds.set(0, 0, (int) (postChangeBounds.width() * scale), (int) (postChangeBounds.height() * scale)); @@ -782,8 +787,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb pipSnapAlgorithm.applySnapFraction(postChangeBounds, postChangeMovementBounds, snapFraction, mPipBoundsState.getStashedState(), mPipBoundsState.getStashOffset(), - mPipBoundsState.getDisplayBounds(), - mPipBoundsState.getDisplayLayout().stableInsets()); + mPipDisplayLayoutState.getDisplayBounds(), + mPipDisplayLayoutState.getDisplayLayout().stableInsets()); if (densityDpiChanged) { // Using PipMotionHelper#movePip directly here may cause race condition since @@ -1040,7 +1045,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb // Populate inset / normal bounds and DisplayInfo from mPipBoundsHandler before // passing to mTouchHandler/mPipTaskOrganizer final Rect outBounds = new Rect(toBounds); - final int rotation = mPipBoundsState.getDisplayLayout().rotation(); + final int rotation = mPipDisplayLayoutState.getDisplayLayout().rotation(); mPipBoundsAlgorithm.getInsetBounds(mTmpInsetBounds); mPipBoundsState.setNormalBounds(mPipBoundsAlgorithm.getNormalBounds()); @@ -1064,11 +1069,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb private void onDisplayRotationChangedNotInPip(Context context, int toRotation) { // Update the display layout, note that we have to do this on every rotation even if we // aren't in PIP since we need to update the display layout to get the right resources - DisplayLayout layoutCopy = mPipBoundsState.getDisplayLayout(); - - layoutCopy.rotateTo(context.getResources(), toRotation); - mPipBoundsState.setDisplayLayout(layoutCopy); - mPipSizeSpecHandler.setDisplayLayout(layoutCopy); + mPipDisplayLayoutState.rotateTo(toRotation); } /** @@ -1081,7 +1082,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb Rect outInsetBounds, int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) { // Bail early if the event is not sent to current display - if ((displayId != mPipBoundsState.getDisplayId()) || (fromRotation == toRotation)) { + if ((displayId != mPipDisplayLayoutState.getDisplayId()) || (fromRotation == toRotation)) { return false; } @@ -1105,11 +1106,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb mPipBoundsState.getStashedState()); // Update the display layout - DisplayLayout layoutCopy = mPipBoundsState.getDisplayLayout(); - - layoutCopy.rotateTo(context.getResources(), toRotation); - mPipBoundsState.setDisplayLayout(layoutCopy); - mPipSizeSpecHandler.setDisplayLayout(layoutCopy); + mPipDisplayLayoutState.rotateTo(toRotation); // Calculate the stack bounds in the new orientation based on same fraction along the // rotated movement bounds. @@ -1117,8 +1114,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb postChangeStackBounds, false /* adjustForIme */); pipSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds, snapFraction, mPipBoundsState.getStashedState(), mPipBoundsState.getStashOffset(), - mPipBoundsState.getDisplayBounds(), - mPipBoundsState.getDisplayLayout().stableInsets()); + mPipDisplayLayoutState.getDisplayBounds(), + mPipDisplayLayoutState.getDisplayLayout().stableInsets()); mPipBoundsAlgorithm.getInsetBounds(outInsetBounds); outBounds.set(postChangeStackBounds); @@ -1136,6 +1133,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb mPipBoundsState.dump(pw, innerPrefix); mPipInputConsumer.dump(pw, innerPrefix); mPipSizeSpecHandler.dump(pw, innerPrefix); + mPipDisplayLayoutState.dump(pw, innerPrefix); } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java index d03d075b38af..23988a62735d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java @@ -31,6 +31,7 @@ import android.util.Size; import com.android.internal.annotations.VisibleForTesting; import com.android.wm.shell.R; import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.pip.PipDisplayLayoutState; import java.io.PrintWriter; @@ -40,10 +41,9 @@ import java.io.PrintWriter; public class PipSizeSpecHandler { private static final String TAG = PipSizeSpecHandler.class.getSimpleName(); - @NonNull private final DisplayLayout mDisplayLayout = new DisplayLayout(); + @NonNull private final PipDisplayLayoutState mPipDisplayLayoutState; - @VisibleForTesting - final SizeSpecSource mSizeSpecSourceImpl; + private final SizeSpecSource mSizeSpecSourceImpl; /** The preferred minimum (and default minimum) size specified by apps. */ @Nullable private Size mOverrideMinSize; @@ -361,8 +361,9 @@ public class PipSizeSpecHandler { } } - public PipSizeSpecHandler(Context context) { + public PipSizeSpecHandler(Context context, PipDisplayLayoutState pipDisplayLayoutState) { mContext = context; + mPipDisplayLayoutState = pipDisplayLayoutState; boolean enablePipSizeLargeScreen = SystemProperties .getBoolean("persist.wm.debug.enable_pip_size_large_screen", false); @@ -403,15 +404,9 @@ public class PipSizeSpecHandler { mSizeSpecSourceImpl.reloadResources(); } - /** Returns the display's bounds. */ @NonNull - public Rect getDisplayBounds() { - return new Rect(0, 0, mDisplayLayout.width(), mDisplayLayout.height()); - } - - /** Update the display layout. */ - public void setDisplayLayout(@NonNull DisplayLayout displayLayout) { - mDisplayLayout.set(displayLayout); + private Rect getDisplayBounds() { + return mPipDisplayLayoutState.getDisplayBounds(); } public Point getScreenEdgeInsets() { @@ -423,11 +418,12 @@ public class PipSizeSpecHandler { */ public Rect getInsetBounds() { Rect insetBounds = new Rect(); - Rect insets = mDisplayLayout.stableInsets(); + DisplayLayout displayLayout = mPipDisplayLayoutState.getDisplayLayout(); + Rect insets = displayLayout.stableInsets(); insetBounds.set(insets.left + mScreenEdgeInsets.x, insets.top + mScreenEdgeInsets.y, - mDisplayLayout.width() - insets.right - mScreenEdgeInsets.x, - mDisplayLayout.height() - insets.bottom - mScreenEdgeInsets.y); + displayLayout.width() - insets.right - mScreenEdgeInsets.x, + displayLayout.height() - insets.bottom - mScreenEdgeInsets.y); return insetBounds; } @@ -522,8 +518,8 @@ public class PipSizeSpecHandler { public void dump(PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; pw.println(prefix + TAG); - pw.println(innerPrefix + "mSizeSpecSourceImpl=" + mSizeSpecSourceImpl.toString()); - pw.println(innerPrefix + "mDisplayLayout=" + mDisplayLayout); + pw.println(innerPrefix + "mSizeSpecSourceImpl=" + mSizeSpecSourceImpl); pw.println(innerPrefix + "mOverrideMinSize=" + mOverrideMinSize); + pw.println(innerPrefix + "mScreenEdgeInsets=" + mScreenEdgeInsets); } } 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 22b3f4987e82..e1737eccc6e1 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 @@ -31,6 +31,7 @@ import android.view.View; import com.android.wm.shell.pip.PipBoundsAlgorithm; import com.android.wm.shell.pip.PipBoundsState; +import com.android.wm.shell.pip.PipDisplayLayoutState; import com.android.wm.shell.pip.phone.PipSizeSpecHandler; import java.lang.annotation.Retention; @@ -75,8 +76,9 @@ public class TvPipBoundsState extends PipBoundsState { private Insets mPipMenuTemporaryDecorInsets = Insets.NONE; public TvPipBoundsState(@NonNull Context context, - @NonNull PipSizeSpecHandler pipSizeSpecHandler) { - super(context, pipSizeSpecHandler); + @NonNull PipSizeSpecHandler pipSizeSpecHandler, + @NonNull PipDisplayLayoutState pipDisplayLayoutState) { + super(context, pipSizeSpecHandler, pipDisplayLayoutState); mContext = context; updateDefaultGravity(); mPreviousCollapsedGravity = mDefaultGravity; 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 a437a3bc2826..d73723cc02ff 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 @@ -51,11 +51,11 @@ import com.android.wm.shell.pip.PinnedStackListenerForwarder; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.PipAnimationController; import com.android.wm.shell.pip.PipAppOpsListener; +import com.android.wm.shell.pip.PipDisplayLayoutState; 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.phone.PipSizeSpecHandler; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.sysui.ConfigurationChangeListener; import com.android.wm.shell.sysui.ShellController; @@ -119,7 +119,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal private final ShellController mShellController; private final TvPipBoundsState mTvPipBoundsState; - private final PipSizeSpecHandler mPipSizeSpecHandler; + private final PipDisplayLayoutState mPipDisplayLayoutState; private final TvPipBoundsAlgorithm mTvPipBoundsAlgorithm; private final TvPipBoundsController mTvPipBoundsController; private final PipAppOpsListener mAppOpsListener; @@ -154,7 +154,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal ShellInit shellInit, ShellController shellController, TvPipBoundsState tvPipBoundsState, - PipSizeSpecHandler pipSizeSpecHandler, + PipDisplayLayoutState pipDisplayLayoutState, TvPipBoundsAlgorithm tvPipBoundsAlgorithm, TvPipBoundsController tvPipBoundsController, PipAppOpsListener pipAppOpsListener, @@ -174,7 +174,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal shellInit, shellController, tvPipBoundsState, - pipSizeSpecHandler, + pipDisplayLayoutState, tvPipBoundsAlgorithm, tvPipBoundsController, pipAppOpsListener, @@ -196,7 +196,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal ShellInit shellInit, ShellController shellController, TvPipBoundsState tvPipBoundsState, - PipSizeSpecHandler pipSizeSpecHandler, + PipDisplayLayoutState pipDisplayLayoutState, TvPipBoundsAlgorithm tvPipBoundsAlgorithm, TvPipBoundsController tvPipBoundsController, PipAppOpsListener pipAppOpsListener, @@ -220,10 +220,11 @@ public class TvPipController implements PipTransitionController.PipTransitionCal DisplayLayout layout = new DisplayLayout(context, context.getDisplay()); mTvPipBoundsState = tvPipBoundsState; - mTvPipBoundsState.setDisplayLayout(layout); - mTvPipBoundsState.setDisplayId(context.getDisplayId()); - mPipSizeSpecHandler = pipSizeSpecHandler; - mPipSizeSpecHandler.setDisplayLayout(layout); + + mPipDisplayLayoutState = pipDisplayLayoutState; + mPipDisplayLayoutState.setDisplayLayout(layout); + mPipDisplayLayoutState.setDisplayId(context.getDisplayId()); + mTvPipBoundsAlgorithm = tvPipBoundsAlgorithm; mTvPipBoundsController = tvPipBoundsController; mTvPipBoundsController.setListener(this); @@ -392,7 +393,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal @Override public void onKeepClearAreasChanged(int displayId, Set<Rect> restricted, Set<Rect> unrestricted) { - if (mTvPipBoundsState.getDisplayId() == displayId) { + if (mPipDisplayLayoutState.getDisplayId() == displayId) { boolean unrestrictedAreasChanged = !Objects.equals(unrestricted, mTvPipBoundsState.getUnrestrictedKeepClearAreas()); mTvPipBoundsState.setKeepClearAreas(restricted, unrestricted); 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 index be9b9361b359..f6856f15f16f 100644 --- 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 @@ -28,6 +28,7 @@ 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.PipDisplayLayoutState; import com.android.wm.shell.pip.PipMenuController; import com.android.wm.shell.pip.PipParamsChangedForwarder; import com.android.wm.shell.pip.PipSurfaceTransactionHelper; @@ -36,7 +37,6 @@ 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.pip.phone.PipSizeSpecHandler; import com.android.wm.shell.splitscreen.SplitScreenController; import java.util.Objects; @@ -51,7 +51,7 @@ public class TvPipTaskOrganizer extends PipTaskOrganizer { @NonNull SyncTransactionQueue syncTransactionQueue, @NonNull PipTransitionState pipTransitionState, @NonNull PipBoundsState pipBoundsState, - @NonNull PipSizeSpecHandler pipSizeSpecHandler, + @NonNull PipDisplayLayoutState pipDisplayLayoutState, @NonNull PipBoundsAlgorithm boundsHandler, @NonNull PipMenuController pipMenuController, @NonNull PipAnimationController pipAnimationController, @@ -63,8 +63,8 @@ public class TvPipTaskOrganizer extends PipTaskOrganizer { @NonNull PipUiEventLogger pipUiEventLogger, @NonNull ShellTaskOrganizer shellTaskOrganizer, ShellExecutor mainExecutor) { - super(context, syncTransactionQueue, pipTransitionState, pipBoundsState, pipSizeSpecHandler, - boundsHandler, pipMenuController, pipAnimationController, + super(context, syncTransactionQueue, pipTransitionState, pipBoundsState, + pipDisplayLayoutState, boundsHandler, pipMenuController, pipAnimationController, surfaceTransactionHelper, pipTransitionController, pipParamsChangedForwarder, splitScreenOptional, displayController, pipUiEventLogger, shellTaskOrganizer, mainExecutor); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 18a3849ea17d..a5546e554422 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -207,6 +207,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, private boolean mIsDividerRemoteAnimating; private boolean mIsDropEntering; private boolean mIsExiting; + private boolean mIsRootTranslucent; private DefaultMixedHandler mMixedHandler; private final Toast mSplitUnsupportedToast; @@ -422,6 +423,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } } + if (!isSplitActive()) { + // prevent the fling divider to center transitioni if split screen didn't active. + mIsDropEntering = true; + } + setSideStagePosition(sideStagePosition, wct); final WindowContainerTransaction evictWct = new WindowContainerTransaction(); targetStage.evictAllChildren(evictWct); @@ -436,28 +442,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // reparent the task to an invisible split root will make the activity invisible. Reorder // the root task to front to make the entering transition from pip to split smooth. wct.reorder(mRootTaskInfo.token, true); - wct.setForceTranslucent(mRootTaskInfo.token, true); wct.reorder(targetStage.mRootTaskInfo.token, true); - wct.setForceTranslucent(targetStage.mRootTaskInfo.token, true); - // prevent the fling divider to center transition - mIsDropEntering = true; - targetStage.addTask(task, wct); - if (ENABLE_SHELL_TRANSITIONS) { - prepareEnterSplitScreen(wct); - mSplitTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, wct, - null, this, null /* consumedCallback */, (finishWct, finishT) -> { - if (!evictWct.isEmpty()) { - finishWct.merge(evictWct, true); - } - } /* finishedCallback */); - } else { - if (!evictWct.isEmpty()) { - wct.merge(evictWct, true /* transfer */); - } - mTaskOrganizer.applyTransaction(wct); + if (!evictWct.isEmpty()) { + wct.merge(evictWct, true /* transfer */); } + mTaskOrganizer.applyTransaction(wct); return true; } @@ -716,7 +707,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSplitLayout.setDivideRatio(splitRatio); updateWindowBounds(mSplitLayout, wct); wct.reorder(mRootTaskInfo.token, true); - wct.setForceTranslucent(mRootTaskInfo.token, false); + setRootForceTranslucent(false, wct); // Make sure the launch options will put tasks in the corresponding split roots mainOptions = mainOptions != null ? mainOptions : new Bundle(); @@ -923,7 +914,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, updateWindowBounds(mSplitLayout, wct); wct.reorder(mRootTaskInfo.token, true); - wct.setForceTranslucent(mRootTaskInfo.token, false); + setRootForceTranslucent(false, wct); // TODO(b/268008375): Merge APIs to start a split pair into one. if (mainTaskId != INVALID_TASK_ID) { @@ -1351,7 +1342,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSideStage.removeAllTasks(wct, false /* toTop */); mMainStage.deactivate(wct, false /* toTop */); wct.reorder(mRootTaskInfo.token, false /* onTop */); - wct.setForceTranslucent(mRootTaskInfo.token, true); + setRootForceTranslucent(true, wct); wct.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1); onTransitionAnimationComplete(); } else { @@ -1383,7 +1374,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mMainStage.deactivate(finishedWCT, childrenToTop == mMainStage /* toTop */); mSideStage.removeAllTasks(finishedWCT, childrenToTop == mSideStage /* toTop */); finishedWCT.reorder(mRootTaskInfo.token, false /* toTop */); - finishedWCT.setForceTranslucent(mRootTaskInfo.token, true); + setRootForceTranslucent(true, wct); finishedWCT.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1); mSyncQueue.queue(finishedWCT); mSyncQueue.runInSync(at -> { @@ -1505,7 +1496,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mMainStage.activate(wct, true /* includingTopTask */); updateWindowBounds(mSplitLayout, wct); wct.reorder(mRootTaskInfo.token, true); - wct.setForceTranslucent(mRootTaskInfo.token, false); + setRootForceTranslucent(false, wct); } void finishEnterSplitScreen(SurfaceControl.Transaction t) { @@ -1709,6 +1700,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mRootTaskInfo = null; mRootTaskLeash = null; + mIsRootTranslucent = false; } @@ -1727,7 +1719,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // Make the stages adjacent to each other so they occlude what's behind them. wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token); wct.setLaunchAdjacentFlagRoot(mSideStage.mRootTaskInfo.token); - wct.setForceTranslucent(mRootTaskInfo.token, true); + setRootForceTranslucent(true, wct); mSplitLayout.getInvisibleBounds(mTempRect1); wct.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1); mSyncQueue.queue(wct); @@ -1751,7 +1743,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSideStage.evictOtherChildren(wct, taskId); updateWindowBounds(mSplitLayout, wct); wct.reorder(mRootTaskInfo.token, true); - wct.setForceTranslucent(mRootTaskInfo.token, false); + setRootForceTranslucent(false, wct); mSyncQueue.queue(wct); mSyncQueue.runInSync(t -> { @@ -1775,6 +1767,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mDisplayInsetsController.removeInsetsChangedListener(mDisplayId, mSplitLayout); } + private void setRootForceTranslucent(boolean translucent, WindowContainerTransaction wct) { + if (mIsRootTranslucent == translucent) return; + + mIsRootTranslucent = translucent; + wct.setForceTranslucent(mRootTaskInfo.token, translucent); + } + private void onStageVisibilityChanged(StageListenerImpl stageListener) { // If split didn't active, just ignore this callback because we should already did these // on #applyExitSplitScreen. @@ -1801,12 +1800,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // Split entering background. wct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token, true /* setReparentLeafTaskIfRelaunch */); - if (!mMainStage.mRootTaskInfo.isSleeping && !mSideStage.mRootTaskInfo.isSleeping) { - wct.setForceTranslucent(mRootTaskInfo.token, true); - } + setRootForceTranslucent(true, wct); } else { wct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token, false /* setReparentLeafTaskIfRelaunch */); + setRootForceTranslucent(false, wct); } mSyncQueue.queue(wct); @@ -1938,7 +1936,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mMainStage.activate(wct, true /* includingTopTask */); updateWindowBounds(mSplitLayout, wct); wct.reorder(mRootTaskInfo.token, true); - wct.setForceTranslucent(mRootTaskInfo.token, false); + setRootForceTranslucent(false, wct); } mSyncQueue.queue(wct); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java index 9224b3cbd798..6b7ca421f5ed 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java @@ -193,6 +193,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { private final DragDetector mDragDetector; private int mDragPointerId = -1; + private boolean mIsDragging; private CaptionTouchEventListener( RunningTaskInfo taskInfo, @@ -223,19 +224,15 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { if (v.getId() != R.id.caption) { return false; } - mDragDetector.onMotionEvent(e); - - if (e.getAction() != MotionEvent.ACTION_DOWN) { - return false; - } - final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId); - if (taskInfo.isFocused) { - return false; + if (e.getAction() == MotionEvent.ACTION_DOWN) { + final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId); + if (!taskInfo.isFocused) { + final WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.reorder(mTaskToken, true /* onTop */); + mSyncQueue.queue(wct); + } } - final WindowContainerTransaction wct = new WindowContainerTransaction(); - wct.reorder(mTaskToken, true /* onTop */); - mSyncQueue.queue(wct); - return true; + return mDragDetector.onMotionEvent(e); } /** @@ -253,20 +250,24 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { mDragPointerId = e.getPointerId(0); mDragPositioningCallback.onDragPositioningStart( 0 /* ctrlType */, e.getRawX(0), e.getRawY(0)); - break; + mIsDragging = false; + return false; } case MotionEvent.ACTION_MOVE: { int dragPointerIdx = e.findPointerIndex(mDragPointerId); mDragPositioningCallback.onDragPositioningMove( e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx)); - break; + mIsDragging = true; + return true; } case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { int dragPointerIdx = e.findPointerIndex(mDragPointerId); mDragPositioningCallback.onDragPositioningEnd( e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx)); - break; + final boolean wasDragging = mIsDragging; + mIsDragging = false; + return wasDragging; } } return true; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index 2aa6d1217fa6..6b45149e35a2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -223,6 +223,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { private final DragPositioningCallback mDragPositioningCallback; private final DragDetector mDragDetector; + private boolean mIsDragging; private int mDragPointerId = -1; private DesktopModeTouchEventListener( @@ -273,23 +274,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { if (id != R.id.caption_handle && id != R.id.desktop_mode_caption) { return false; } - switch (e.getAction()) { - case MotionEvent.ACTION_DOWN: - mDragDetector.onMotionEvent(e); - final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId); - if (taskInfo.isFocused) { - return mDragDetector.isDragEvent(); - } - return false; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - boolean res = mDragDetector.isDragEvent(); - mDragDetector.onMotionEvent(e); - return res; - default: - mDragDetector.onMotionEvent(e); - return mDragDetector.isDragEvent(); - } + return mDragDetector.onMotionEvent(e); } /** @@ -313,13 +298,15 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mDragPointerId = e.getPointerId(0); mDragPositioningCallback.onDragPositioningStart( 0 /* ctrlType */, e.getRawX(0), e.getRawY(0)); - break; + mIsDragging = false; + return false; } case MotionEvent.ACTION_MOVE: { final int dragPointerIdx = e.findPointerIndex(mDragPointerId); mDragPositioningCallback.onDragPositioningMove( e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx)); - break; + mIsDragging = true; + return true; } case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { @@ -336,7 +323,9 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { c -> c.moveToFullscreen(taskInfo)); } } - break; + final boolean wasDragging = mIsDragging; + mIsDragging = false; + return wasDragging; } } return true; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java index cf1850b92373..65b5a7a17afe 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java @@ -56,10 +56,15 @@ class DragDetector { * {@link #mEventHandler} handles the previous down event if the event shouldn't be passed */ boolean onMotionEvent(MotionEvent ev) { + final boolean isTouchScreen = + (ev.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN; + if (!isTouchScreen) { + // Only touches generate noisy moves, so mouse/trackpad events don't need to filtered + // to take the slop threshold into consideration. + return mEventHandler.handleMotionEvent(ev); + } switch (ev.getActionMasked()) { case ACTION_DOWN: { - // Only touch screens generate noisy moves. - mIsDragEvent = (ev.getSource() & SOURCE_TOUCHSCREEN) != SOURCE_TOUCHSCREEN; mDragPointerId = ev.getPointerId(0); float rawX = ev.getRawX(0); float rawY = ev.getRawY(0); @@ -72,8 +77,12 @@ class DragDetector { int dragPointerIndex = ev.findPointerIndex(mDragPointerId); float dx = ev.getRawX(dragPointerIndex) - mInputDownPoint.x; float dy = ev.getRawY(dragPointerIndex) - mInputDownPoint.y; + // Touches generate noisy moves, so only once the move is past the touch + // slop threshold should it be considered a drag. mIsDragEvent = Math.hypot(dx, dy) > mTouchSlop; } + // The event handler should only be notified about 'move' events if a drag has been + // detected. if (mIsDragEvent) { return mEventHandler.handleMotionEvent(ev); } else { @@ -94,10 +103,6 @@ class DragDetector { mTouchSlop = touchSlop; } - boolean isDragEvent() { - return mIsDragEvent; - } - private void resetState() { mIsDragEvent = false; mInputDownPoint.set(0, 0); diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt new file mode 100644 index 000000000000..53ce3936fbe4 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2023 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.flicker.pip + +import android.platform.test.annotations.Postsubmit +import android.tools.common.Rotation +import android.tools.device.flicker.junit.FlickerParametersRunnerFactory +import android.graphics.Rect +import android.tools.device.flicker.legacy.FlickerBuilder +import android.tools.device.flicker.legacy.FlickerTest +import android.tools.device.flicker.legacy.FlickerTestFactory +import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule +import androidx.test.filters.RequiresDevice +import com.android.server.wm.flicker.helpers.setRotation +import com.android.server.wm.flicker.testapp.ActivityOptions +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test the snapping of a PIP window via dragging, releasing, and checking its final location. + */ +@RequiresDevice +@RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class PipDragThenSnapTest(flicker: FlickerTest) : PipTransition(flicker){ + // represents the direction in which the pip window should be snapping + private var willSnapRight: Boolean = true + + override val transition: FlickerBuilder.() -> Unit + get() = { + val stringExtras: Map<String, String> = + mapOf(ActivityOptions.Pip.EXTRA_ENTER_PIP to "true") + + // cache the starting bounds here + val startBounds = Rect() + + setup { + // Launch the PIP activity and wait for it to enter PiP mode + setRotation(Rotation.ROTATION_0) + RemoveAllTasksButHomeRule.removeAllTasksButHome() + pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = stringExtras) + + // get the initial region bounds and cache them + val initRegion = pipApp.getWindowRect(wmHelper) + startBounds + .set(initRegion.left, initRegion.top, initRegion.right, initRegion.bottom) + + // drag the pip window away from the edge + pipApp.dragPipWindowAwayFromEdge(wmHelper, 50) + + // determine the direction in which the snapping should occur + willSnapRight = pipApp.isCloserToRightEdge(wmHelper) + } + transitions { + // continue the transition until the PIP snaps + pipApp.waitForPipToSnapTo(wmHelper, startBounds) + } + } + + /** + * Checks that the visible region area of [pipApp] moves to closest edge during the animation. + */ + @Postsubmit + @Test + fun pipLayerMovesToClosestEdge() { + flicker.assertLayers { + val pipLayerList = layers { pipApp.layerMatchesAnyOf(it) && it.isVisible } + pipLayerList.zipWithNext { previous, current -> + if (willSnapRight) { + current.visibleRegion.isToTheRight(previous.visibleRegion.region) + } else { + previous.visibleRegion.isToTheRight(current.visibleRegion.region) + } + } + } + } + + companion object { + /** + * Creates the test configurations. + * + * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and + * navigation modes. + */ + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): List<FlickerTest> { + return FlickerTestFactory.nonRotationTests( + supportedRotations = listOf(Rotation.ROTATION_0) + ) + } + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java index ec264a643785..addc2338144f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java @@ -55,25 +55,28 @@ public class PipBoundsAlgorithmTest extends ShellTestCase { private static final float MAX_ASPECT_RATIO = 2f; private static final int DEFAULT_MIN_EDGE_SIZE = 100; + /** The minimum possible size of the override min size's width or height */ + private static final int OVERRIDABLE_MIN_SIZE = 40; + private PipBoundsAlgorithm mPipBoundsAlgorithm; private DisplayInfo mDefaultDisplayInfo; - private PipBoundsState mPipBoundsState; - private PipSizeSpecHandler mPipSizeSpecHandler; + private PipBoundsState mPipBoundsState; private PipSizeSpecHandler mPipSizeSpecHandler; + private PipDisplayLayoutState mPipDisplayLayoutState; @Before public void setUp() throws Exception { initializeMockResources(); - mPipSizeSpecHandler = new PipSizeSpecHandler(mContext); - mPipBoundsState = new PipBoundsState(mContext, mPipSizeSpecHandler); + mPipDisplayLayoutState = new PipDisplayLayoutState(mContext); + mPipSizeSpecHandler = new PipSizeSpecHandler(mContext, mPipDisplayLayoutState); + mPipBoundsState = new PipBoundsState(mContext, mPipSizeSpecHandler, mPipDisplayLayoutState); mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState, new PipSnapAlgorithm(), new PipKeepClearAlgorithmInterface() {}, mPipSizeSpecHandler); DisplayLayout layout = new DisplayLayout(mDefaultDisplayInfo, mContext.getResources(), true, true); - mPipBoundsState.setDisplayLayout(layout); - mPipSizeSpecHandler.setDisplayLayout(layout); + mPipDisplayLayoutState.setDisplayLayout(layout); } private void initializeMockResources() { @@ -88,6 +91,9 @@ public class PipBoundsAlgorithmTest extends ShellTestCase { R.dimen.default_minimal_size_pip_resizable_task, DEFAULT_MIN_EDGE_SIZE); res.addOverride( + R.dimen.overridable_minimal_size_pip_resizable_task, + OVERRIDABLE_MIN_SIZE); + res.addOverride( R.string.config_defaultPictureInPictureScreenEdgeInsets, "16x16"); res.addOverride( diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java index 341a451eeb43..f32000445ca9 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java @@ -27,11 +27,13 @@ import android.content.ComponentName; import android.graphics.Rect; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.testing.TestableResources; import android.util.Size; import androidx.test.filters.SmallTest; import com.android.internal.util.function.TriConsumer; +import com.android.wm.shell.R; import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.pip.phone.PipSizeSpecHandler; @@ -52,13 +54,23 @@ public class PipBoundsStateTest extends ShellTestCase { private static final Size DEFAULT_SIZE = new Size(10, 10); private static final float DEFAULT_SNAP_FRACTION = 1.0f; + /** The minimum possible size of the override min size's width or height */ + private static final int OVERRIDABLE_MIN_SIZE = 40; + private PipBoundsState mPipBoundsState; private ComponentName mTestComponentName1; private ComponentName mTestComponentName2; @Before public void setUp() { - mPipBoundsState = new PipBoundsState(mContext, new PipSizeSpecHandler(mContext)); + final TestableResources res = mContext.getOrCreateTestableResources(); + res.addOverride( + R.dimen.overridable_minimal_size_pip_resizable_task, + OVERRIDABLE_MIN_SIZE); + + PipDisplayLayoutState pipDisplayLayoutState = new PipDisplayLayoutState(mContext); + mPipBoundsState = new PipBoundsState(mContext, + new PipSizeSpecHandler(mContext, pipDisplayLayoutState), pipDisplayLayoutState); mTestComponentName1 = new ComponentName(mContext, "component1"); mTestComponentName2 = new ComponentName(mContext, "component2"); } 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 e907cd3ca0ad..15bb10ed4f2b 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 @@ -88,6 +88,7 @@ public class PipTaskOrganizerTest extends ShellTestCase { private PipTransitionState mPipTransitionState; private PipBoundsAlgorithm mPipBoundsAlgorithm; private PipSizeSpecHandler mPipSizeSpecHandler; + private PipDisplayLayoutState mPipDisplayLayoutState; private ComponentName mComponent1; private ComponentName mComponent2; @@ -97,15 +98,16 @@ public class PipTaskOrganizerTest extends ShellTestCase { MockitoAnnotations.initMocks(this); mComponent1 = new ComponentName(mContext, "component1"); mComponent2 = new ComponentName(mContext, "component2"); - mPipSizeSpecHandler = new PipSizeSpecHandler(mContext); - mPipBoundsState = new PipBoundsState(mContext, mPipSizeSpecHandler); + mPipDisplayLayoutState = new PipDisplayLayoutState(mContext); + mPipSizeSpecHandler = new PipSizeSpecHandler(mContext, mPipDisplayLayoutState); + mPipBoundsState = new PipBoundsState(mContext, mPipSizeSpecHandler, mPipDisplayLayoutState); mPipTransitionState = new PipTransitionState(); mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState, new PipSnapAlgorithm(), new PipKeepClearAlgorithmInterface() {}, mPipSizeSpecHandler); mMainExecutor = new TestShellExecutor(); mPipTaskOrganizer = new PipTaskOrganizer(mContext, mMockSyncTransactionQueue, - mPipTransitionState, mPipBoundsState, mPipSizeSpecHandler, + mPipTransitionState, mPipBoundsState, mPipDisplayLayoutState, mPipBoundsAlgorithm, mMockPhonePipMenuController, mMockPipAnimationController, mMockPipSurfaceTransactionHelper, mMockPipTransitionController, mMockPipParamsChangedForwarder, mMockOptionalSplitScreen, mMockDisplayController, @@ -259,8 +261,7 @@ public class PipTaskOrganizerTest extends ShellTestCase { final DisplayInfo info = new DisplayInfo(); DisplayLayout layout = new DisplayLayout(info, mContext.getResources(), true, true); - mPipBoundsState.setDisplayLayout(layout); - mPipSizeSpecHandler.setDisplayLayout(layout); + mPipDisplayLayoutState.setDisplayLayout(layout); mPipTaskOrganizer.setOneShotAnimationType(PipAnimationController.ANIM_TYPE_ALPHA); mPipTaskOrganizer.setSurfaceControlTransactionFactory( MockSurfaceControlHelper::createMockSurfaceControlTransaction); 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 4a68287a4486..0e14c69bdc00 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 @@ -59,6 +59,7 @@ import com.android.wm.shell.pip.PipAnimationController; import com.android.wm.shell.pip.PipAppOpsListener; import com.android.wm.shell.pip.PipBoundsAlgorithm; import com.android.wm.shell.pip.PipBoundsState; +import com.android.wm.shell.pip.PipDisplayLayoutState; import com.android.wm.shell.pip.PipMediaController; import com.android.wm.shell.pip.PipParamsChangedForwarder; import com.android.wm.shell.pip.PipSnapAlgorithm; @@ -108,6 +109,7 @@ public class PipControllerTest extends ShellTestCase { @Mock private WindowManagerShellWrapper mMockWindowManagerShellWrapper; @Mock private PipBoundsState mMockPipBoundsState; @Mock private PipSizeSpecHandler mMockPipSizeSpecHandler; + @Mock private PipDisplayLayoutState mMockPipDisplayLayoutState; @Mock private TaskStackListenerImpl mMockTaskStackListener; @Mock private ShellExecutor mMockExecutor; @Mock private Optional<OneHandedController> mMockOneHandedController; @@ -130,12 +132,12 @@ public class PipControllerTest extends ShellTestCase { mPipController = new PipController(mContext, mShellInit, mMockShellCommandHandler, mShellController, mMockDisplayController, mMockPipAnimationController, mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm, - mMockPipBoundsState, mMockPipSizeSpecHandler, mMockPipMotionHelper, - mMockPipMediaController, mMockPhonePipMenuController, mMockPipTaskOrganizer, - mMockPipTransitionState, mMockPipTouchHandler, mMockPipTransitionController, - mMockWindowManagerShellWrapper, mMockTaskStackListener, - mMockPipParamsChangedForwarder, mMockDisplayInsetsController, - mMockOneHandedController, mMockExecutor); + mMockPipBoundsState, mMockPipSizeSpecHandler, mMockPipDisplayLayoutState, + mMockPipMotionHelper, mMockPipMediaController, mMockPhonePipMenuController, + mMockPipTaskOrganizer, mMockPipTransitionState, mMockPipTouchHandler, + mMockPipTransitionController, mMockWindowManagerShellWrapper, + mMockTaskStackListener, mMockPipParamsChangedForwarder, + mMockDisplayInsetsController, mMockOneHandedController, mMockExecutor); mShellInit.init(); when(mMockPipBoundsAlgorithm.getSnapAlgorithm()).thenReturn(mMockPipSnapAlgorithm); when(mMockPipTouchHandler.getMotionHelper()).thenReturn(mMockPipMotionHelper); @@ -221,12 +223,12 @@ public class PipControllerTest extends ShellTestCase { assertNull(PipController.create(spyContext, shellInit, mMockShellCommandHandler, mShellController, mMockDisplayController, mMockPipAnimationController, mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm, - mMockPipBoundsState, mMockPipSizeSpecHandler, mMockPipMotionHelper, - mMockPipMediaController, mMockPhonePipMenuController, mMockPipTaskOrganizer, - mMockPipTransitionState, mMockPipTouchHandler, mMockPipTransitionController, - mMockWindowManagerShellWrapper, mMockTaskStackListener, - mMockPipParamsChangedForwarder, mMockDisplayInsetsController, - mMockOneHandedController, mMockExecutor)); + mMockPipBoundsState, mMockPipSizeSpecHandler, mMockPipDisplayLayoutState, + mMockPipMotionHelper, mMockPipMediaController, mMockPhonePipMenuController, + mMockPipTaskOrganizer, mMockPipTransitionState, mMockPipTouchHandler, + mMockPipTransitionController, mMockWindowManagerShellWrapper, + mMockTaskStackListener, mMockPipParamsChangedForwarder, + mMockDisplayInsetsController, mMockOneHandedController, mMockExecutor)); } @Test @@ -283,8 +285,8 @@ public class PipControllerTest extends ShellTestCase { when(mMockPipBoundsState.getMinSize()).thenReturn(new Point(1, 1)); when(mMockPipBoundsState.getMaxSize()).thenReturn(new Point(MAX_VALUE, MAX_VALUE)); when(mMockPipBoundsState.getBounds()).thenReturn(bounds); - when(mMockPipBoundsState.getDisplayId()).thenReturn(displayId); - when(mMockPipBoundsState.getDisplayLayout()).thenReturn(mMockDisplayLayout1); + when(mMockPipDisplayLayoutState.getDisplayId()).thenReturn(displayId); + when(mMockPipDisplayLayoutState.getDisplayLayout()).thenReturn(mMockDisplayLayout1); when(mMockDisplayController.getDisplayLayout(displayId)).thenReturn(mMockDisplayLayout2); when(mMockPipTaskOrganizer.isInPip()).thenReturn(true); @@ -299,8 +301,8 @@ public class PipControllerTest extends ShellTestCase { final int displayId = 1; final Rect bounds = new Rect(0, 0, 10, 10); when(mMockPipBoundsAlgorithm.getDefaultBounds()).thenReturn(bounds); - when(mMockPipBoundsState.getDisplayId()).thenReturn(displayId); - when(mMockPipBoundsState.getDisplayLayout()).thenReturn(mMockDisplayLayout1); + when(mMockPipDisplayLayoutState.getDisplayId()).thenReturn(displayId); + when(mMockPipDisplayLayoutState.getDisplayLayout()).thenReturn(mMockDisplayLayout1); when(mMockDisplayController.getDisplayLayout(displayId)).thenReturn(mMockDisplayLayout2); when(mMockPipTaskOrganizer.isInPip()).thenReturn(false); @@ -314,7 +316,7 @@ public class PipControllerTest extends ShellTestCase { public void onKeepClearAreasChanged_featureDisabled_pipBoundsStateDoesntChange() { final int displayId = 1; final Rect keepClearArea = new Rect(0, 0, 10, 10); - when(mMockPipBoundsState.getDisplayId()).thenReturn(displayId); + when(mMockPipDisplayLayoutState.getDisplayId()).thenReturn(displayId); mPipController.mDisplaysChangedListener.onKeepClearAreasChanged( displayId, Set.of(keepClearArea), Set.of()); @@ -327,7 +329,7 @@ public class PipControllerTest extends ShellTestCase { mPipController.setEnablePipKeepClearAlgorithm(true); final int displayId = 1; final Rect keepClearArea = new Rect(0, 0, 10, 10); - when(mMockPipBoundsState.getDisplayId()).thenReturn(displayId); + when(mMockPipDisplayLayoutState.getDisplayId()).thenReturn(displayId); mPipController.mDisplaysChangedListener.onKeepClearAreasChanged( displayId, Set.of(keepClearArea), Set.of()); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java index c7b9eb3d1074..5b62a940c074 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java @@ -37,6 +37,7 @@ import com.android.wm.shell.common.FloatingContentCoordinator; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.pip.PipBoundsAlgorithm; import com.android.wm.shell.pip.PipBoundsState; +import com.android.wm.shell.pip.PipDisplayLayoutState; import com.android.wm.shell.pip.PipKeepClearAlgorithmInterface; import com.android.wm.shell.pip.PipSnapAlgorithm; import com.android.wm.shell.pip.PipTaskOrganizer; @@ -87,11 +88,14 @@ public class PipResizeGestureHandlerTest extends ShellTestCase { private PipSizeSpecHandler mPipSizeSpecHandler; + private PipDisplayLayoutState mPipDisplayLayoutState; + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mPipSizeSpecHandler = new PipSizeSpecHandler(mContext); - mPipBoundsState = new PipBoundsState(mContext, mPipSizeSpecHandler); + mPipDisplayLayoutState = new PipDisplayLayoutState(mContext); + mPipSizeSpecHandler = new PipSizeSpecHandler(mContext, mPipDisplayLayoutState); + mPipBoundsState = new PipBoundsState(mContext, mPipSizeSpecHandler, mPipDisplayLayoutState); final PipSnapAlgorithm pipSnapAlgorithm = new PipSnapAlgorithm(); final PipKeepClearAlgorithmInterface pipKeepClearAlgorithm = new PipKeepClearAlgorithmInterface() {}; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java index d9ff7d1f1089..390c830069eb 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java @@ -33,6 +33,7 @@ import android.view.DisplayInfo; import com.android.dx.mockito.inline.extended.StaticMockitoSession; import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.pip.PipDisplayLayoutState; import org.junit.After; import org.junit.Assert; @@ -74,6 +75,7 @@ public class PipSizeSpecHandlerTest extends ShellTestCase { @Mock private Context mContext; @Mock private Resources mResources; + private PipDisplayLayoutState mPipDisplayLayoutState; private PipSizeSpecHandler mPipSizeSpecHandler; /** @@ -137,7 +139,6 @@ public class PipSizeSpecHandlerTest extends ShellTestCase { @Before public void setUp() { initExpectedSizes(); - setUpStaticSystemPropertiesSession(); when(mResources.getDimensionPixelSize(anyInt())).thenReturn(DEFAULT_MIN_EDGE_SIZE); when(mResources.getFloat(anyInt())).thenReturn(OPTIMIZED_ASPECT_RATIO); @@ -148,11 +149,6 @@ public class PipSizeSpecHandlerTest extends ShellTestCase { // set up the mock context for spec handler specifically when(mContext.getResources()).thenReturn(mResources); - mPipSizeSpecHandler = new PipSizeSpecHandler(mContext); - - // no overridden min edge size by default - mPipSizeSpecHandler.setOverrideMinSize(null); - DisplayInfo displayInfo = new DisplayInfo(); displayInfo.logicalWidth = DISPLAY_EDGE_SIZE; displayInfo.logicalHeight = DISPLAY_EDGE_SIZE; @@ -161,7 +157,14 @@ public class PipSizeSpecHandlerTest extends ShellTestCase { // this is done to avoid unnecessary mocking while allowing for custom display dimensions DisplayLayout displayLayout = new DisplayLayout(displayInfo, getContext().getResources(), false, false); - mPipSizeSpecHandler.setDisplayLayout(displayLayout); + mPipDisplayLayoutState = new PipDisplayLayoutState(mContext); + mPipDisplayLayoutState.setDisplayLayout(displayLayout); + + setUpStaticSystemPropertiesSession(); + mPipSizeSpecHandler = new PipSizeSpecHandler(mContext, mPipDisplayLayoutState); + + // no overridden min edge size by default + mPipSizeSpecHandler.setOverrideMinSize(null); } @After diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java index 5c4863ff752f..d36060fd165f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java @@ -35,6 +35,7 @@ import com.android.wm.shell.common.FloatingContentCoordinator; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.pip.PipBoundsAlgorithm; import com.android.wm.shell.pip.PipBoundsState; +import com.android.wm.shell.pip.PipDisplayLayoutState; import com.android.wm.shell.pip.PipKeepClearAlgorithmInterface; import com.android.wm.shell.pip.PipSnapAlgorithm; import com.android.wm.shell.pip.PipTaskOrganizer; @@ -92,6 +93,7 @@ public class PipTouchHandlerTest extends ShellTestCase { private PipMotionHelper mMotionHelper; private PipResizeGestureHandler mPipResizeGestureHandler; private PipSizeSpecHandler mPipSizeSpecHandler; + private PipDisplayLayoutState mPipDisplayLayoutState; private DisplayLayout mDisplayLayout; private Rect mInsetBounds; @@ -105,8 +107,9 @@ public class PipTouchHandlerTest extends ShellTestCase { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mPipSizeSpecHandler = new PipSizeSpecHandler(mContext); - mPipBoundsState = new PipBoundsState(mContext, mPipSizeSpecHandler); + mPipDisplayLayoutState = new PipDisplayLayoutState(mContext); + mPipSizeSpecHandler = new PipSizeSpecHandler(mContext, mPipDisplayLayoutState); + mPipBoundsState = new PipBoundsState(mContext, mPipSizeSpecHandler, mPipDisplayLayoutState); mPipSnapAlgorithm = new PipSnapAlgorithm(); mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState, mPipSnapAlgorithm, new PipKeepClearAlgorithmInterface() {}, mPipSizeSpecHandler); @@ -124,8 +127,7 @@ public class PipTouchHandlerTest extends ShellTestCase { mPipTouchHandler.setPipResizeGestureHandler(mPipResizeGestureHandler); mDisplayLayout = new DisplayLayout(mContext, mContext.getDisplay()); - mPipBoundsState.setDisplayLayout(mDisplayLayout); - mPipSizeSpecHandler.setDisplayLayout(mDisplayLayout); + mPipDisplayLayoutState.setDisplayLayout(mDisplayLayout); mInsetBounds = new Rect(mPipBoundsState.getDisplayBounds().left + INSET, mPipBoundsState.getDisplayBounds().top + INSET, mPipBoundsState.getDisplayBounds().right - INSET, 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 index 30096cb99a64..f9b772345b14 100644 --- 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 @@ -26,6 +26,7 @@ import static org.junit.Assert.assertEquals; import android.view.Gravity; import com.android.wm.shell.ShellTestCase; +import com.android.wm.shell.pip.PipDisplayLayoutState; import com.android.wm.shell.pip.PipSnapAlgorithm; import com.android.wm.shell.pip.phone.PipSizeSpecHandler; @@ -47,6 +48,7 @@ public class TvPipGravityTest extends ShellTestCase { private TvPipBoundsState mTvPipBoundsState; private TvPipBoundsAlgorithm mTvPipBoundsAlgorithm; private PipSizeSpecHandler mPipSizeSpecHandler; + private PipDisplayLayoutState mPipDisplayLayoutState; @Before public void setUp() { @@ -54,8 +56,10 @@ public class TvPipGravityTest extends ShellTestCase { return; } MockitoAnnotations.initMocks(this); - mPipSizeSpecHandler = new PipSizeSpecHandler(mContext); - mTvPipBoundsState = new TvPipBoundsState(mContext, mPipSizeSpecHandler); + mPipDisplayLayoutState = new PipDisplayLayoutState(mContext); + mPipSizeSpecHandler = new PipSizeSpecHandler(mContext, mPipDisplayLayoutState); + mTvPipBoundsState = new TvPipBoundsState(mContext, mPipSizeSpecHandler, + mPipDisplayLayoutState); mTvPipBoundsAlgorithm = new TvPipBoundsAlgorithm(mContext, mTvPipBoundsState, mMockPipSnapAlgorithm, mPipSizeSpecHandler); |