diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 43ddaeef06371..e7e4bccb95db9 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -484,8 +484,6 @@ package android.app { field public static final int WINDOWING_MODE_FULLSCREEN = 1; // 0x1 field public static final int WINDOWING_MODE_MULTI_WINDOW = 6; // 0x6 field public static final int WINDOWING_MODE_PINNED = 2; // 0x2 - field public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY = 3; // 0x3 - field public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4; // 0x4 field public static final int WINDOWING_MODE_UNDEFINED = 0; // 0x0 } diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java index 5ef3fc05130c0..40edc2e6b8969 100644 --- a/core/java/android/app/WindowConfiguration.java +++ b/core/java/android/app/WindowConfiguration.java @@ -104,19 +104,6 @@ public class WindowConfiguration implements Parcelable, Comparable mLegacySplitScreenOptional; private final Optional mSplitScreenOptional; private final Optional mPipOptional; private final Optional mOneHandedOptional; @@ -54,7 +52,6 @@ public final class ShellCommandHandlerImpl { public ShellCommandHandlerImpl( ShellTaskOrganizer shellTaskOrganizer, KidsModeTaskOrganizer kidsModeTaskOrganizer, - Optional legacySplitScreenOptional, Optional splitScreenOptional, Optional pipOptional, Optional oneHandedOptional, @@ -65,7 +62,6 @@ public final class ShellCommandHandlerImpl { mShellTaskOrganizer = shellTaskOrganizer; mKidsModeTaskOrganizer = kidsModeTaskOrganizer; mRecentTasks = recentTasks; - mLegacySplitScreenOptional = legacySplitScreenOptional; mSplitScreenOptional = splitScreenOptional; mPipOptional = pipOptional; mOneHandedOptional = oneHandedOptional; @@ -84,7 +80,6 @@ public final class ShellCommandHandlerImpl { pw.println(); pw.println(); mPipOptional.ifPresent(pip -> pip.dump(pw)); - mLegacySplitScreenOptional.ifPresent(splitScreen -> splitScreen.dump(pw)); mOneHandedOptional.ifPresent(oneHanded -> oneHanded.dump(pw)); mHideDisplayCutout.ifPresent(hideDisplayCutout -> hideDisplayCutout.dump(pw)); pw.println(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index 2891e744515b8..67c41f06fd010 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -70,8 +70,6 @@ import com.android.wm.shell.fullscreen.FullscreenUnfoldController; import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout; import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController; import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer; -import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; -import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController; import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.onehanded.OneHandedController; import com.android.wm.shell.pip.Pip; @@ -562,18 +560,6 @@ public abstract class WMShellBaseModule { return Optional.empty(); } - // Legacy split (optional feature) - - @WMSingleton - @Provides - static Optional provideLegacySplitScreen( - Optional splitScreenController) { - return splitScreenController.map((controller) -> controller.asLegacySplitScreen()); - } - - @BindsOptionalOf - abstract LegacySplitScreenController optionalLegacySplitScreenController(); - // App Pairs (optional feature) @WMSingleton @@ -710,7 +696,6 @@ public abstract class WMShellBaseModule { static ShellCommandHandlerImpl provideShellCommandHandlerImpl( ShellTaskOrganizer shellTaskOrganizer, KidsModeTaskOrganizer kidsModeTaskOrganizer, - Optional legacySplitScreenOptional, Optional splitScreenOptional, Optional pipOptional, Optional oneHandedOptional, @@ -719,8 +704,8 @@ public abstract class WMShellBaseModule { Optional recentTasksOptional, @ShellMainThread ShellExecutor mainExecutor) { return new ShellCommandHandlerImpl(shellTaskOrganizer, kidsModeTaskOrganizer, - legacySplitScreenOptional, splitScreenOptional, pipOptional, oneHandedOptional, - hideDisplayCutout, appPairsOptional, recentTasksOptional, mainExecutor); + splitScreenOptional, pipOptional, oneHandedOptional, hideDisplayCutout, + appPairsOptional, recentTasksOptional, mainExecutor); } @WMSingleton 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 d198d05fe60c2..9c4ec5313c50c 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 @@ -16,7 +16,6 @@ package com.android.wm.shell.dagger; -import android.animation.AnimationHandler; import android.content.Context; import android.content.pm.LauncherApps; import android.os.Handler; @@ -42,12 +41,10 @@ import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.SystemWindows; import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.common.TransactionPool; -import com.android.wm.shell.common.annotations.ChoreographerSfVsync; import com.android.wm.shell.common.annotations.ShellMainThread; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.freeform.FreeformTaskListener; import com.android.wm.shell.fullscreen.FullscreenUnfoldController; -import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController; import com.android.wm.shell.onehanded.OneHandedController; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.PipAnimationController; @@ -179,20 +176,6 @@ public class WMShellModule { recentTasks, stageTaskUnfoldControllerProvider); } - @WMSingleton - @Provides - static LegacySplitScreenController provideLegacySplitScreen(Context context, - DisplayController displayController, SystemWindows systemWindows, - DisplayImeController displayImeController, TransactionPool transactionPool, - ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue, - TaskStackListenerImpl taskStackListener, Transitions transitions, - @ShellMainThread ShellExecutor mainExecutor, - @ChoreographerSfVsync AnimationHandler sfVsyncAnimationHandler) { - return new LegacySplitScreenController(context, displayController, systemWindows, - displayImeController, transactionPool, shellTaskOrganizer, syncQueue, - taskStackListener, transitions, mainExecutor, sfVsyncAnimationHandler); - } - @WMSingleton @Provides static AppPairsController provideAppPairs(ShellTaskOrganizer shellTaskOrganizer, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java deleted file mode 100644 index aced072c8c717..0000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright (C) 2020 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.legacysplitscreen; - -import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED; -import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; -import android.annotation.Nullable; -import android.graphics.Rect; -import android.util.Slog; -import android.view.Choreographer; -import android.view.SurfaceControl; -import android.window.TaskOrganizer; -import android.window.WindowContainerToken; -import android.window.WindowContainerTransaction; - -import com.android.wm.shell.common.DisplayImeController; -import com.android.wm.shell.common.ShellExecutor; -import com.android.wm.shell.common.TransactionPool; - -class DividerImeController implements DisplayImeController.ImePositionProcessor { - private static final String TAG = "DividerImeController"; - private static final boolean DEBUG = LegacySplitScreenController.DEBUG; - - private static final float ADJUSTED_NONFOCUS_DIM = 0.3f; - - private final LegacySplitScreenTaskListener mSplits; - private final TransactionPool mTransactionPool; - private final ShellExecutor mMainExecutor; - private final TaskOrganizer mTaskOrganizer; - - /** - * These are the y positions of the top of the IME surface when it is hidden and when it is - * shown respectively. These are NOT necessarily the top of the visible IME itself. - */ - private int mHiddenTop = 0; - private int mShownTop = 0; - - // The following are target states (what we are curretly animating towards). - /** - * {@code true} if, at the end of the animation, the split task positions should be - * adjusted by height of the IME. This happens when the secondary split is the IME target. - */ - private boolean mTargetAdjusted = false; - /** - * {@code true} if, at the end of the animation, the IME should be shown/visible - * regardless of what has focus. - */ - private boolean mTargetShown = false; - private float mTargetPrimaryDim = 0.f; - private float mTargetSecondaryDim = 0.f; - - // The following are the current (most recent) states set during animation - /** {@code true} if the secondary split has IME focus. */ - private boolean mSecondaryHasFocus = false; - /** The dimming currently applied to the primary/secondary splits. */ - private float mLastPrimaryDim = 0.f; - private float mLastSecondaryDim = 0.f; - /** The most recent y position of the top of the IME surface */ - private int mLastAdjustTop = -1; - - // The following are states reached last time an animation fully completed. - /** {@code true} if the IME was shown/visible by the last-completed animation. */ - private boolean mImeWasShown = false; - /** {@code true} if the split positions were adjusted by the last-completed animation. */ - private boolean mAdjusted = false; - - /** - * When some aspect of split-screen needs to animate independent from the IME, - * this will be non-null and control split animation. - */ - @Nullable - private ValueAnimator mAnimation = null; - - private boolean mPaused = true; - private boolean mPausedTargetAdjusted = false; - - DividerImeController(LegacySplitScreenTaskListener splits, TransactionPool pool, - ShellExecutor mainExecutor, TaskOrganizer taskOrganizer) { - mSplits = splits; - mTransactionPool = pool; - mMainExecutor = mainExecutor; - mTaskOrganizer = taskOrganizer; - } - - private DividerView getView() { - return mSplits.mSplitScreenController.getDividerView(); - } - - private LegacySplitDisplayLayout getLayout() { - return mSplits.mSplitScreenController.getSplitLayout(); - } - - private boolean isDividerHidden() { - final DividerView view = mSplits.mSplitScreenController.getDividerView(); - return view == null || view.isHidden(); - } - - private boolean getSecondaryHasFocus(int displayId) { - WindowContainerToken imeSplit = mTaskOrganizer.getImeTarget(displayId); - return imeSplit != null - && (imeSplit.asBinder() == mSplits.mSecondary.token.asBinder()); - } - - void reset() { - mPaused = true; - mPausedTargetAdjusted = false; - mAnimation = null; - mAdjusted = mTargetAdjusted = false; - mImeWasShown = mTargetShown = false; - mTargetPrimaryDim = mTargetSecondaryDim = mLastPrimaryDim = mLastSecondaryDim = 0.f; - mSecondaryHasFocus = false; - mLastAdjustTop = -1; - } - - private void updateDimTargets() { - final boolean splitIsVisible = !getView().isHidden(); - mTargetPrimaryDim = (mSecondaryHasFocus && mTargetShown && splitIsVisible) - ? ADJUSTED_NONFOCUS_DIM : 0.f; - mTargetSecondaryDim = (!mSecondaryHasFocus && mTargetShown && splitIsVisible) - ? ADJUSTED_NONFOCUS_DIM : 0.f; - } - - - @Override - public void onImeControlTargetChanged(int displayId, boolean controlling) { - // Restore the split layout when wm-shell is not controlling IME insets anymore. - if (!controlling && mTargetShown) { - mPaused = false; - mTargetAdjusted = mTargetShown = false; - mTargetPrimaryDim = mTargetSecondaryDim = 0.f; - updateImeAdjustState(true /* force */); - startAsyncAnimation(); - } - } - - @Override - @ImeAnimationFlags - public int onImeStartPositioning(int displayId, int hiddenTop, int shownTop, - boolean imeShouldShow, boolean imeIsFloating, SurfaceControl.Transaction t) { - if (isDividerHidden()) { - return 0; - } - mHiddenTop = hiddenTop; - mShownTop = shownTop; - mTargetShown = imeShouldShow; - mSecondaryHasFocus = getSecondaryHasFocus(displayId); - final boolean targetAdjusted = imeShouldShow && mSecondaryHasFocus - && !imeIsFloating && !getLayout().mDisplayLayout.isLandscape() - && !mSplits.mSplitScreenController.isMinimized(); - if (mLastAdjustTop < 0) { - mLastAdjustTop = imeShouldShow ? hiddenTop : shownTop; - } else if (mLastAdjustTop != (imeShouldShow ? mShownTop : mHiddenTop)) { - if (mTargetAdjusted != targetAdjusted && targetAdjusted == mAdjusted) { - // Check for an "interruption" of an existing animation. In this case, we - // need to fake-flip the last-known state direction so that the animation - // completes in the other direction. - mAdjusted = mTargetAdjusted; - } else if (targetAdjusted && mTargetAdjusted && mAdjusted) { - // Already fully adjusted for IME, but IME height has changed; so, force-start - // an async animation to the new IME height. - mAdjusted = false; - } - } - if (mPaused) { - mPausedTargetAdjusted = targetAdjusted; - if (DEBUG) Slog.d(TAG, " ime starting but paused " + dumpState()); - return (targetAdjusted || mAdjusted) ? IME_ANIMATION_NO_ALPHA : 0; - } - mTargetAdjusted = targetAdjusted; - updateDimTargets(); - if (DEBUG) Slog.d(TAG, " ime starting. " + dumpState()); - if (mAnimation != null || (mImeWasShown && imeShouldShow - && mTargetAdjusted != mAdjusted)) { - // We need to animate adjustment independently of the IME position, so - // start our own animation to drive adjustment. This happens when a - // different split's editor has gained focus while the IME is still visible. - startAsyncAnimation(); - } - updateImeAdjustState(); - - return (mTargetAdjusted || mAdjusted) ? IME_ANIMATION_NO_ALPHA : 0; - } - - private void updateImeAdjustState() { - updateImeAdjustState(false /* force */); - } - - private void updateImeAdjustState(boolean force) { - if (mAdjusted != mTargetAdjusted || force) { - // Reposition the server's secondary split position so that it evaluates - // insets properly. - WindowContainerTransaction wct = new WindowContainerTransaction(); - final LegacySplitDisplayLayout splitLayout = getLayout(); - if (mTargetAdjusted) { - splitLayout.updateAdjustedBounds(mShownTop, mHiddenTop, mShownTop); - wct.setBounds(mSplits.mSecondary.token, splitLayout.mAdjustedSecondary); - // "Freeze" the configuration size so that the app doesn't get a config - // or relaunch. This is required because normally nav-bar contributes - // to configuration bounds (via nondecorframe). - Rect adjustAppBounds = new Rect(mSplits.mSecondary.configuration - .windowConfiguration.getAppBounds()); - adjustAppBounds.offset(0, splitLayout.mAdjustedSecondary.top - - splitLayout.mSecondary.top); - wct.setAppBounds(mSplits.mSecondary.token, adjustAppBounds); - wct.setScreenSizeDp(mSplits.mSecondary.token, - mSplits.mSecondary.configuration.screenWidthDp, - mSplits.mSecondary.configuration.screenHeightDp); - - wct.setBounds(mSplits.mPrimary.token, splitLayout.mAdjustedPrimary); - adjustAppBounds = new Rect(mSplits.mPrimary.configuration - .windowConfiguration.getAppBounds()); - adjustAppBounds.offset(0, splitLayout.mAdjustedPrimary.top - - splitLayout.mPrimary.top); - wct.setAppBounds(mSplits.mPrimary.token, adjustAppBounds); - wct.setScreenSizeDp(mSplits.mPrimary.token, - mSplits.mPrimary.configuration.screenWidthDp, - mSplits.mPrimary.configuration.screenHeightDp); - } else { - wct.setBounds(mSplits.mSecondary.token, splitLayout.mSecondary); - wct.setAppBounds(mSplits.mSecondary.token, null); - wct.setScreenSizeDp(mSplits.mSecondary.token, - SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED); - wct.setBounds(mSplits.mPrimary.token, splitLayout.mPrimary); - wct.setAppBounds(mSplits.mPrimary.token, null); - wct.setScreenSizeDp(mSplits.mPrimary.token, - SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED); - } - - if (!mSplits.mSplitScreenController.getWmProxy().queueSyncTransactionIfWaiting(wct)) { - mTaskOrganizer.applyTransaction(wct); - } - } - - // Update all the adjusted-for-ime states - if (!mPaused) { - final DividerView view = getView(); - if (view != null) { - view.setAdjustedForIme(mTargetShown, mTargetShown - ? DisplayImeController.ANIMATION_DURATION_SHOW_MS - : DisplayImeController.ANIMATION_DURATION_HIDE_MS); - } - } - mSplits.mSplitScreenController.setAdjustedForIme(mTargetShown && !mPaused); - } - - @Override - public void onImePositionChanged(int displayId, int imeTop, - SurfaceControl.Transaction t) { - if (mAnimation != null || isDividerHidden() || mPaused) { - // Not synchronized with IME anymore, so return. - return; - } - final float fraction = ((float) imeTop - mHiddenTop) / (mShownTop - mHiddenTop); - final float progress = mTargetShown ? fraction : 1.f - fraction; - onProgress(progress, t); - } - - @Override - public void onImeEndPositioning(int displayId, boolean cancelled, - SurfaceControl.Transaction t) { - if (mAnimation != null || isDividerHidden() || mPaused) { - // Not synchronized with IME anymore, so return. - return; - } - onEnd(cancelled, t); - } - - private void onProgress(float progress, SurfaceControl.Transaction t) { - final DividerView view = getView(); - if (mTargetAdjusted != mAdjusted && !mPaused) { - final LegacySplitDisplayLayout splitLayout = getLayout(); - final float fraction = mTargetAdjusted ? progress : 1.f - progress; - mLastAdjustTop = (int) (fraction * mShownTop + (1.f - fraction) * mHiddenTop); - splitLayout.updateAdjustedBounds(mLastAdjustTop, mHiddenTop, mShownTop); - view.resizeSplitSurfaces(t, splitLayout.mAdjustedPrimary, - splitLayout.mAdjustedSecondary); - } - final float invProg = 1.f - progress; - view.setResizeDimLayer(t, true /* primary */, - mLastPrimaryDim * invProg + progress * mTargetPrimaryDim); - view.setResizeDimLayer(t, false /* primary */, - mLastSecondaryDim * invProg + progress * mTargetSecondaryDim); - } - - void setDimsHidden(SurfaceControl.Transaction t, boolean hidden) { - final DividerView view = getView(); - if (hidden) { - view.setResizeDimLayer(t, true /* primary */, 0.f /* alpha */); - view.setResizeDimLayer(t, false /* primary */, 0.f /* alpha */); - } else { - updateDimTargets(); - view.setResizeDimLayer(t, true /* primary */, mTargetPrimaryDim); - view.setResizeDimLayer(t, false /* primary */, mTargetSecondaryDim); - } - } - - private void onEnd(boolean cancelled, SurfaceControl.Transaction t) { - if (!cancelled) { - onProgress(1.f, t); - mAdjusted = mTargetAdjusted; - mImeWasShown = mTargetShown; - mLastAdjustTop = mAdjusted ? mShownTop : mHiddenTop; - mLastPrimaryDim = mTargetPrimaryDim; - mLastSecondaryDim = mTargetSecondaryDim; - } - } - - private void startAsyncAnimation() { - if (mAnimation != null) { - mAnimation.cancel(); - } - mAnimation = ValueAnimator.ofFloat(0.f, 1.f); - mAnimation.setDuration(DisplayImeController.ANIMATION_DURATION_SHOW_MS); - if (mTargetAdjusted != mAdjusted) { - final float fraction = - ((float) mLastAdjustTop - mHiddenTop) / (mShownTop - mHiddenTop); - final float progress = mTargetAdjusted ? fraction : 1.f - fraction; - mAnimation.setCurrentFraction(progress); - } - - mAnimation.addUpdateListener(animation -> { - SurfaceControl.Transaction t = mTransactionPool.acquire(); - float value = (float) animation.getAnimatedValue(); - onProgress(value, t); - t.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId()); - t.apply(); - mTransactionPool.release(t); - }); - mAnimation.setInterpolator(DisplayImeController.INTERPOLATOR); - mAnimation.addListener(new AnimatorListenerAdapter() { - private boolean mCancel = false; - - @Override - public void onAnimationCancel(Animator animation) { - mCancel = true; - } - - @Override - public void onAnimationEnd(Animator animation) { - SurfaceControl.Transaction t = mTransactionPool.acquire(); - onEnd(mCancel, t); - t.apply(); - mTransactionPool.release(t); - mAnimation = null; - } - }); - mAnimation.start(); - } - - private String dumpState() { - return "top:" + mHiddenTop + "->" + mShownTop - + " adj:" + mAdjusted + "->" + mTargetAdjusted + "(" + mLastAdjustTop + ")" - + " shw:" + mImeWasShown + "->" + mTargetShown - + " dims:" + mLastPrimaryDim + "," + mLastSecondaryDim - + "->" + mTargetPrimaryDim + "," + mTargetSecondaryDim - + " shf:" + mSecondaryHasFocus + " desync:" + (mAnimation != null) - + " paus:" + mPaused + "[" + mPausedTargetAdjusted + "]"; - } - - /** Completely aborts/resets adjustment state */ - public void pause(int displayId) { - if (DEBUG) Slog.d(TAG, "ime pause posting " + dumpState()); - mMainExecutor.execute(() -> { - if (DEBUG) Slog.d(TAG, "ime pause run posted " + dumpState()); - if (mPaused) { - return; - } - mPaused = true; - mPausedTargetAdjusted = mTargetAdjusted; - mTargetAdjusted = false; - mTargetPrimaryDim = mTargetSecondaryDim = 0.f; - updateImeAdjustState(); - startAsyncAnimation(); - if (mAnimation != null) { - mAnimation.end(); - } - }); - } - - public void resume(int displayId) { - if (DEBUG) Slog.d(TAG, "ime resume posting " + dumpState()); - mMainExecutor.execute(() -> { - if (DEBUG) Slog.d(TAG, "ime resume run posted " + dumpState()); - if (!mPaused) { - return; - } - mPaused = false; - mTargetAdjusted = mPausedTargetAdjusted; - updateDimTargets(); - final DividerView view = getView(); - if ((mTargetAdjusted != mAdjusted) && !mSplits.mSplitScreenController.isMinimized() - && view != null) { - // End unminimize animations since they conflict with adjustment animations. - view.finishAnimations(); - } - updateImeAdjustState(); - startAsyncAnimation(); - }); - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerState.java deleted file mode 100644 index af2ab158ab464..0000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerState.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2016 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.legacysplitscreen; - -/** - * Class to hold state of divider that needs to persist across configuration changes. - */ -final class DividerState { - public boolean animateAfterRecentsDrawn; - public float mRatioPositionBeforeMinimized; -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java deleted file mode 100644 index 73be2835d2cd2..0000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java +++ /dev/null @@ -1,1314 +0,0 @@ -/* - * Copyright (C) 2015 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.legacysplitscreen; - -import static android.view.PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW; -import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW; -import static android.view.WindowManager.DOCKED_RIGHT; - -import static com.android.wm.shell.animation.Interpolators.DIM_INTERPOLATOR; -import static com.android.wm.shell.animation.Interpolators.SLOWDOWN_INTERPOLATOR; -import static com.android.wm.shell.common.split.DividerView.TOUCH_ANIMATION_DURATION; -import static com.android.wm.shell.common.split.DividerView.TOUCH_RELEASE_ANIMATION_DURATION; - -import android.animation.AnimationHandler; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; -import android.annotation.Nullable; -import android.content.Context; -import android.content.res.Configuration; -import android.graphics.Matrix; -import android.graphics.Rect; -import android.graphics.Region; -import android.graphics.Region.Op; -import android.hardware.display.DisplayManager; -import android.os.Bundle; -import android.util.AttributeSet; -import android.util.Slog; -import android.view.Choreographer; -import android.view.Display; -import android.view.MotionEvent; -import android.view.PointerIcon; -import android.view.SurfaceControl; -import android.view.SurfaceControl.Transaction; -import android.view.VelocityTracker; -import android.view.View; -import android.view.View.OnTouchListener; -import android.view.ViewConfiguration; -import android.view.ViewTreeObserver.InternalInsetsInfo; -import android.view.ViewTreeObserver.OnComputeInternalInsetsListener; -import android.view.WindowManager; -import android.view.accessibility.AccessibilityNodeInfo; -import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; -import android.view.animation.Interpolator; -import android.view.animation.PathInterpolator; -import android.widget.FrameLayout; - -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.internal.policy.DividerSnapAlgorithm; -import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget; -import com.android.internal.policy.DockedDividerUtils; -import com.android.wm.shell.R; -import com.android.wm.shell.animation.FlingAnimationUtils; -import com.android.wm.shell.animation.Interpolators; -import com.android.wm.shell.common.split.DividerHandleView; - -import java.util.function.Consumer; - -/** - * Docked stack divider. - */ -public class DividerView extends FrameLayout implements OnTouchListener, - OnComputeInternalInsetsListener { - private static final String TAG = "DividerView"; - private static final boolean DEBUG = LegacySplitScreenController.DEBUG; - - interface DividerCallbacks { - void onDraggingStart(); - void onDraggingEnd(); - } - - public static final int INVALID_RECENTS_GROW_TARGET = -1; - - private static final int LOG_VALUE_RESIZE_50_50 = 0; - private static final int LOG_VALUE_RESIZE_DOCKED_SMALLER = 1; - private static final int LOG_VALUE_RESIZE_DOCKED_LARGER = 2; - - private static final int LOG_VALUE_UNDOCK_MAX_DOCKED = 0; - private static final int LOG_VALUE_UNDOCK_MAX_OTHER = 1; - - private static final int TASK_POSITION_SAME = Integer.MAX_VALUE; - - /** - * How much the background gets scaled when we are in the minimized dock state. - */ - private static final float MINIMIZE_DOCK_SCALE = 0f; - private static final float ADJUSTED_FOR_IME_SCALE = 0.5f; - - private static final Interpolator IME_ADJUST_INTERPOLATOR = - new PathInterpolator(0.2f, 0f, 0.1f, 1f); - - private DividerHandleView mHandle; - private View mBackground; - private MinimizedDockShadow mMinimizedShadow; - private int mStartX; - private int mStartY; - private int mStartPosition; - private int mDockSide; - private boolean mMoving; - private int mTouchSlop; - private boolean mBackgroundLifted; - private boolean mIsInMinimizeInteraction; - SnapTarget mSnapTargetBeforeMinimized; - - private int mDividerInsets; - private final Display mDefaultDisplay; - - private int mDividerSize; - private int mTouchElevation; - private int mLongPressEntraceAnimDuration; - - private final Rect mDockedRect = new Rect(); - private final Rect mDockedTaskRect = new Rect(); - private final Rect mOtherTaskRect = new Rect(); - private final Rect mOtherRect = new Rect(); - private final Rect mDockedInsetRect = new Rect(); - private final Rect mOtherInsetRect = new Rect(); - private final Rect mLastResizeRect = new Rect(); - private final Rect mTmpRect = new Rect(); - private LegacySplitScreenController mSplitScreenController; - private WindowManagerProxy mWindowManagerProxy; - private DividerWindowManager mWindowManager; - private VelocityTracker mVelocityTracker; - private FlingAnimationUtils mFlingAnimationUtils; - private LegacySplitDisplayLayout mSplitLayout; - private DividerImeController mImeController; - private DividerCallbacks mCallback; - - private AnimationHandler mSfVsyncAnimationHandler; - private ValueAnimator mCurrentAnimator; - private boolean mEntranceAnimationRunning; - private boolean mExitAnimationRunning; - private int mExitStartPosition; - private boolean mDockedStackMinimized; - private boolean mHomeStackResizable; - private boolean mAdjustedForIme; - private DividerState mState; - - private LegacySplitScreenTaskListener mTiles; - boolean mFirstLayout = true; - int mDividerPositionX; - int mDividerPositionY; - - private final Matrix mTmpMatrix = new Matrix(); - private final float[] mTmpValues = new float[9]; - - // The view is removed or in the process of been removed from the system. - private boolean mRemoved; - - // Whether the surface for this view has been hidden regardless of actual visibility. This is - // used interact with keyguard. - private boolean mSurfaceHidden = false; - - private final AccessibilityDelegate mHandleDelegate = new AccessibilityDelegate() { - @Override - public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { - super.onInitializeAccessibilityNodeInfo(host, info); - final DividerSnapAlgorithm snapAlgorithm = getSnapAlgorithm(); - if (isHorizontalDivision()) { - info.addAction(new AccessibilityAction(R.id.action_move_tl_full, - mContext.getString(R.string.accessibility_action_divider_top_full))); - if (snapAlgorithm.isFirstSplitTargetAvailable()) { - info.addAction(new AccessibilityAction(R.id.action_move_tl_70, - mContext.getString(R.string.accessibility_action_divider_top_70))); - } - if (snapAlgorithm.showMiddleSplitTargetForAccessibility()) { - // Only show the middle target if there are more than 1 split target - info.addAction(new AccessibilityAction(R.id.action_move_tl_50, - mContext.getString(R.string.accessibility_action_divider_top_50))); - } - if (snapAlgorithm.isLastSplitTargetAvailable()) { - info.addAction(new AccessibilityAction(R.id.action_move_tl_30, - mContext.getString(R.string.accessibility_action_divider_top_30))); - } - info.addAction(new AccessibilityAction(R.id.action_move_rb_full, - mContext.getString(R.string.accessibility_action_divider_bottom_full))); - } else { - info.addAction(new AccessibilityAction(R.id.action_move_tl_full, - mContext.getString(R.string.accessibility_action_divider_left_full))); - if (snapAlgorithm.isFirstSplitTargetAvailable()) { - info.addAction(new AccessibilityAction(R.id.action_move_tl_70, - mContext.getString(R.string.accessibility_action_divider_left_70))); - } - if (snapAlgorithm.showMiddleSplitTargetForAccessibility()) { - // Only show the middle target if there are more than 1 split target - info.addAction(new AccessibilityAction(R.id.action_move_tl_50, - mContext.getString(R.string.accessibility_action_divider_left_50))); - } - if (snapAlgorithm.isLastSplitTargetAvailable()) { - info.addAction(new AccessibilityAction(R.id.action_move_tl_30, - mContext.getString(R.string.accessibility_action_divider_left_30))); - } - info.addAction(new AccessibilityAction(R.id.action_move_rb_full, - mContext.getString(R.string.accessibility_action_divider_right_full))); - } - } - - @Override - public boolean performAccessibilityAction(View host, int action, Bundle args) { - int currentPosition = getCurrentPosition(); - SnapTarget nextTarget = null; - DividerSnapAlgorithm snapAlgorithm = mSplitLayout.getSnapAlgorithm(); - if (action == R.id.action_move_tl_full) { - nextTarget = snapAlgorithm.getDismissEndTarget(); - } else if (action == R.id.action_move_tl_70) { - nextTarget = snapAlgorithm.getLastSplitTarget(); - } else if (action == R.id.action_move_tl_50) { - nextTarget = snapAlgorithm.getMiddleTarget(); - } else if (action == R.id.action_move_tl_30) { - nextTarget = snapAlgorithm.getFirstSplitTarget(); - } else if (action == R.id.action_move_rb_full) { - nextTarget = snapAlgorithm.getDismissStartTarget(); - } - if (nextTarget != null) { - startDragging(true /* animate */, false /* touching */); - stopDragging(currentPosition, nextTarget, 250, Interpolators.FAST_OUT_SLOW_IN); - return true; - } - return super.performAccessibilityAction(host, action, args); - } - }; - - private final Runnable mResetBackgroundRunnable = new Runnable() { - @Override - public void run() { - resetBackground(); - } - }; - - public DividerView(Context context) { - this(context, null); - } - - public DividerView(Context context, @Nullable AttributeSet attrs) { - this(context, attrs, 0); - } - - public DividerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { - this(context, attrs, defStyleAttr, 0); - } - - public DividerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, - int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - final DisplayManager displayManager = - (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE); - mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY); - } - - public void setAnimationHandler(AnimationHandler sfVsyncAnimationHandler) { - mSfVsyncAnimationHandler = sfVsyncAnimationHandler; - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mHandle = findViewById(R.id.docked_divider_handle); - mBackground = findViewById(R.id.docked_divider_background); - mMinimizedShadow = findViewById(R.id.minimized_dock_shadow); - mHandle.setOnTouchListener(this); - final int dividerWindowWidth = getResources().getDimensionPixelSize( - com.android.internal.R.dimen.docked_stack_divider_thickness); - mDividerInsets = getResources().getDimensionPixelSize( - com.android.internal.R.dimen.docked_stack_divider_insets); - mDividerSize = dividerWindowWidth - 2 * mDividerInsets; - mTouchElevation = getResources().getDimensionPixelSize( - R.dimen.docked_stack_divider_lift_elevation); - mLongPressEntraceAnimDuration = getResources().getInteger( - R.integer.long_press_dock_anim_duration); - mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop(); - mFlingAnimationUtils = new FlingAnimationUtils(getResources().getDisplayMetrics(), 0.3f); - boolean landscape = getResources().getConfiguration().orientation - == Configuration.ORIENTATION_LANDSCAPE; - mHandle.setPointerIcon(PointerIcon.getSystemIcon(getContext(), - landscape ? TYPE_HORIZONTAL_DOUBLE_ARROW : TYPE_VERTICAL_DOUBLE_ARROW)); - getViewTreeObserver().addOnComputeInternalInsetsListener(this); - mHandle.setAccessibilityDelegate(mHandleDelegate); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - - // Save the current target if not minimized once attached to window - if (mDockSide != WindowManager.DOCKED_INVALID && !mIsInMinimizeInteraction) { - saveSnapTargetBeforeMinimized(mSnapTargetBeforeMinimized); - } - mFirstLayout = true; - } - - void onDividerRemoved() { - mRemoved = true; - mCallback = null; - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - if (mFirstLayout) { - // Wait for first layout so that the ViewRootImpl surface has been created. - initializeSurfaceState(); - mFirstLayout = false; - } - int minimizeLeft = 0; - int minimizeTop = 0; - if (mDockSide == WindowManager.DOCKED_TOP) { - minimizeTop = mBackground.getTop(); - } else if (mDockSide == WindowManager.DOCKED_LEFT) { - minimizeLeft = mBackground.getLeft(); - } else if (mDockSide == WindowManager.DOCKED_RIGHT) { - minimizeLeft = mBackground.getRight() - mMinimizedShadow.getWidth(); - } - mMinimizedShadow.layout(minimizeLeft, minimizeTop, - minimizeLeft + mMinimizedShadow.getMeasuredWidth(), - minimizeTop + mMinimizedShadow.getMeasuredHeight()); - if (changed) { - notifySplitScreenBoundsChanged(); - } - } - - void injectDependencies(LegacySplitScreenController splitScreenController, - DividerWindowManager windowManager, DividerState dividerState, - DividerCallbacks callback, LegacySplitScreenTaskListener tiles, - LegacySplitDisplayLayout sdl, DividerImeController imeController, - WindowManagerProxy wmProxy) { - mSplitScreenController = splitScreenController; - mWindowManager = windowManager; - mState = dividerState; - mCallback = callback; - mTiles = tiles; - mSplitLayout = sdl; - mImeController = imeController; - mWindowManagerProxy = wmProxy; - - if (mState.mRatioPositionBeforeMinimized == 0) { - // Set the middle target as the initial state - mSnapTargetBeforeMinimized = mSplitLayout.getSnapAlgorithm().getMiddleTarget(); - } else { - repositionSnapTargetBeforeMinimized(); - } - } - - /** Gets non-minimized secondary bounds of split screen. */ - public Rect getNonMinimizedSplitScreenSecondaryBounds() { - mOtherTaskRect.set(mSplitLayout.mSecondary); - return mOtherTaskRect; - } - - private boolean inSplitMode() { - return getVisibility() == VISIBLE; - } - - /** Unlike setVisible, this directly hides the surface without changing view visibility. */ - void setHidden(boolean hidden) { - if (mSurfaceHidden == hidden) { - return; - } - mSurfaceHidden = hidden; - post(() -> { - final SurfaceControl sc = getWindowSurfaceControl(); - if (sc == null) { - return; - } - Transaction t = mTiles.getTransaction(); - if (hidden) { - t.hide(sc); - } else { - t.show(sc); - } - mImeController.setDimsHidden(t, hidden); - t.apply(); - mTiles.releaseTransaction(t); - }); - } - - boolean isHidden() { - return getVisibility() != View.VISIBLE || mSurfaceHidden; - } - - /** Starts dragging the divider bar. */ - public boolean startDragging(boolean animate, boolean touching) { - cancelFlingAnimation(); - if (touching) { - mHandle.setTouching(true, animate); - } - mDockSide = mSplitLayout.getPrimarySplitSide(); - - mWindowManagerProxy.setResizing(true); - if (touching) { - mWindowManager.setSlippery(false); - liftBackground(); - } - if (mCallback != null) { - mCallback.onDraggingStart(); - } - return inSplitMode(); - } - - /** Stops dragging the divider bar. */ - public void stopDragging(int position, float velocity, boolean avoidDismissStart, - boolean logMetrics) { - mHandle.setTouching(false, true /* animate */); - fling(position, velocity, avoidDismissStart, logMetrics); - mWindowManager.setSlippery(true); - releaseBackground(); - } - - private void stopDragging(int position, SnapTarget target, long duration, - Interpolator interpolator) { - stopDragging(position, target, duration, 0 /* startDelay*/, 0 /* endDelay */, interpolator); - } - - private void stopDragging(int position, SnapTarget target, long duration, - Interpolator interpolator, long endDelay) { - stopDragging(position, target, duration, 0 /* startDelay*/, endDelay, interpolator); - } - - private void stopDragging(int position, SnapTarget target, long duration, long startDelay, - long endDelay, Interpolator interpolator) { - mHandle.setTouching(false, true /* animate */); - flingTo(position, target, duration, startDelay, endDelay, interpolator); - mWindowManager.setSlippery(true); - releaseBackground(); - } - - private void stopDragging() { - mHandle.setTouching(false, true /* animate */); - mWindowManager.setSlippery(true); - mWindowManagerProxy.setResizing(false); - releaseBackground(); - } - - private void updateDockSide() { - mDockSide = mSplitLayout.getPrimarySplitSide(); - mMinimizedShadow.setDockSide(mDockSide); - } - - public DividerSnapAlgorithm getSnapAlgorithm() { - return mDockedStackMinimized ? mSplitLayout.getMinimizedSnapAlgorithm(mHomeStackResizable) - : mSplitLayout.getSnapAlgorithm(); - } - - public int getCurrentPosition() { - return isHorizontalDivision() ? mDividerPositionY : mDividerPositionX; - } - - public boolean isMinimized() { - return mDockedStackMinimized; - } - - @Override - public boolean onTouch(View v, MotionEvent event) { - convertToScreenCoordinates(event); - final int action = event.getAction() & MotionEvent.ACTION_MASK; - switch (action) { - case MotionEvent.ACTION_DOWN: - mVelocityTracker = VelocityTracker.obtain(); - mVelocityTracker.addMovement(event); - mStartX = (int) event.getX(); - mStartY = (int) event.getY(); - boolean result = startDragging(true /* animate */, true /* touching */); - if (!result) { - - // Weren't able to start dragging successfully, so cancel it again. - stopDragging(); - } - mStartPosition = getCurrentPosition(); - mMoving = false; - return result; - case MotionEvent.ACTION_MOVE: - mVelocityTracker.addMovement(event); - int x = (int) event.getX(); - int y = (int) event.getY(); - boolean exceededTouchSlop = - isHorizontalDivision() && Math.abs(y - mStartY) > mTouchSlop - || (!isHorizontalDivision() && Math.abs(x - mStartX) > mTouchSlop); - if (!mMoving && exceededTouchSlop) { - mStartX = x; - mStartY = y; - mMoving = true; - } - if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) { - SnapTarget snapTarget = getSnapAlgorithm().calculateSnapTarget( - mStartPosition, 0 /* velocity */, false /* hardDismiss */); - resizeStackSurfaces(calculatePosition(x, y), mStartPosition, snapTarget, - null /* transaction */); - } - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - if (!mMoving) { - stopDragging(); - break; - } - - x = (int) event.getRawX(); - y = (int) event.getRawY(); - mVelocityTracker.addMovement(event); - mVelocityTracker.computeCurrentVelocity(1000); - int position = calculatePosition(x, y); - stopDragging(position, isHorizontalDivision() ? mVelocityTracker.getYVelocity() - : mVelocityTracker.getXVelocity(), false /* avoidDismissStart */, - true /* log */); - mMoving = false; - break; - } - return true; - } - - private void logResizeEvent(SnapTarget snapTarget) { - if (snapTarget == mSplitLayout.getSnapAlgorithm().getDismissStartTarget()) { - MetricsLogger.action( - mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_MAX, dockSideTopLeft(mDockSide) - ? LOG_VALUE_UNDOCK_MAX_OTHER - : LOG_VALUE_UNDOCK_MAX_DOCKED); - } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getDismissEndTarget()) { - MetricsLogger.action( - mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_MAX, dockSideBottomRight(mDockSide) - ? LOG_VALUE_UNDOCK_MAX_OTHER - : LOG_VALUE_UNDOCK_MAX_DOCKED); - } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getMiddleTarget()) { - MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE, - LOG_VALUE_RESIZE_50_50); - } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getFirstSplitTarget()) { - MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE, - dockSideTopLeft(mDockSide) - ? LOG_VALUE_RESIZE_DOCKED_SMALLER - : LOG_VALUE_RESIZE_DOCKED_LARGER); - } else if (snapTarget == mSplitLayout.getSnapAlgorithm().getLastSplitTarget()) { - MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_RESIZE, - dockSideTopLeft(mDockSide) - ? LOG_VALUE_RESIZE_DOCKED_LARGER - : LOG_VALUE_RESIZE_DOCKED_SMALLER); - } - } - - private void convertToScreenCoordinates(MotionEvent event) { - event.setLocation(event.getRawX(), event.getRawY()); - } - - private void fling(int position, float velocity, boolean avoidDismissStart, - boolean logMetrics) { - DividerSnapAlgorithm currentSnapAlgorithm = getSnapAlgorithm(); - SnapTarget snapTarget = currentSnapAlgorithm.calculateSnapTarget(position, velocity); - if (avoidDismissStart && snapTarget == currentSnapAlgorithm.getDismissStartTarget()) { - snapTarget = currentSnapAlgorithm.getFirstSplitTarget(); - } - if (logMetrics) { - logResizeEvent(snapTarget); - } - ValueAnimator anim = getFlingAnimator(position, snapTarget, 0 /* endDelay */); - mFlingAnimationUtils.apply(anim, position, snapTarget.position, velocity); - anim.start(); - } - - private void flingTo(int position, SnapTarget target, long duration, long startDelay, - long endDelay, Interpolator interpolator) { - ValueAnimator anim = getFlingAnimator(position, target, endDelay); - anim.setDuration(duration); - anim.setStartDelay(startDelay); - anim.setInterpolator(interpolator); - anim.start(); - } - - private ValueAnimator getFlingAnimator(int position, final SnapTarget snapTarget, - final long endDelay) { - if (mCurrentAnimator != null) { - cancelFlingAnimation(); - updateDockSide(); - } - if (DEBUG) Slog.d(TAG, "Getting fling " + position + "->" + snapTarget.position); - final boolean taskPositionSameAtEnd = snapTarget.flag == SnapTarget.FLAG_NONE; - ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position); - anim.addUpdateListener(animation -> resizeStackSurfaces((int) animation.getAnimatedValue(), - taskPositionSameAtEnd && animation.getAnimatedFraction() == 1f - ? TASK_POSITION_SAME - : snapTarget.taskPosition, - snapTarget, null /* transaction */)); - Consumer endAction = cancelled -> { - if (DEBUG) Slog.d(TAG, "End Fling " + cancelled + " min:" + mIsInMinimizeInteraction); - final boolean wasMinimizeInteraction = mIsInMinimizeInteraction; - // Reset minimized divider position after unminimized state animation finishes. - if (!cancelled && !mDockedStackMinimized && mIsInMinimizeInteraction) { - mIsInMinimizeInteraction = false; - } - boolean dismissed = commitSnapFlags(snapTarget); - mWindowManagerProxy.setResizing(false); - updateDockSide(); - mCurrentAnimator = null; - mEntranceAnimationRunning = false; - mExitAnimationRunning = false; - if (!dismissed && !wasMinimizeInteraction) { - mWindowManagerProxy.applyResizeSplits(snapTarget.position, mSplitLayout); - } - if (mCallback != null) { - mCallback.onDraggingEnd(); - } - - // Record last snap target the divider moved to - if (!mIsInMinimizeInteraction) { - // The last snapTarget position can be negative when the last divider position was - // offscreen. In that case, save the middle (default) SnapTarget so calculating next - // position isn't negative. - final SnapTarget saveTarget; - if (snapTarget.position < 0) { - saveTarget = mSplitLayout.getSnapAlgorithm().getMiddleTarget(); - } else { - saveTarget = snapTarget; - } - final DividerSnapAlgorithm snapAlgo = mSplitLayout.getSnapAlgorithm(); - if (saveTarget.position != snapAlgo.getDismissEndTarget().position - && saveTarget.position != snapAlgo.getDismissStartTarget().position) { - saveSnapTargetBeforeMinimized(saveTarget); - } - } - notifySplitScreenBoundsChanged(); - }; - anim.addListener(new AnimatorListenerAdapter() { - - private boolean mCancelled; - - @Override - public void onAnimationCancel(Animator animation) { - mCancelled = true; - } - - @Override - public void onAnimationEnd(Animator animation) { - long delay = 0; - if (endDelay != 0) { - delay = endDelay; - } else if (mCancelled) { - delay = 0; - } - if (delay == 0) { - endAction.accept(mCancelled); - } else { - final Boolean cancelled = mCancelled; - if (DEBUG) Slog.d(TAG, "Posting endFling " + cancelled + " d:" + delay + "ms"); - getHandler().postDelayed(() -> endAction.accept(cancelled), delay); - } - } - }); - mCurrentAnimator = anim; - mCurrentAnimator.setAnimationHandler(mSfVsyncAnimationHandler); - return anim; - } - - private void notifySplitScreenBoundsChanged() { - if (mSplitLayout.mPrimary == null || mSplitLayout.mSecondary == null) { - return; - } - mOtherTaskRect.set(mSplitLayout.mSecondary); - - mTmpRect.set(mHandle.getLeft(), mHandle.getTop(), mHandle.getRight(), mHandle.getBottom()); - if (isHorizontalDivision()) { - mTmpRect.offsetTo(mHandle.getLeft(), mDividerPositionY); - } else { - mTmpRect.offsetTo(mDividerPositionX, mHandle.getTop()); - } - mWindowManagerProxy.setTouchRegion(mTmpRect); - - mTmpRect.set(mSplitLayout.mDisplayLayout.stableInsets()); - switch (mSplitLayout.getPrimarySplitSide()) { - case WindowManager.DOCKED_LEFT: - mTmpRect.left = 0; - break; - case WindowManager.DOCKED_RIGHT: - mTmpRect.right = 0; - break; - case WindowManager.DOCKED_TOP: - mTmpRect.top = 0; - break; - } - mSplitScreenController.notifyBoundsChanged(mOtherTaskRect, mTmpRect); - } - - private void cancelFlingAnimation() { - if (mCurrentAnimator != null) { - mCurrentAnimator.cancel(); - } - } - - private boolean commitSnapFlags(SnapTarget target) { - if (target.flag == SnapTarget.FLAG_NONE) { - return false; - } - final boolean dismissOrMaximize; - if (target.flag == SnapTarget.FLAG_DISMISS_START) { - dismissOrMaximize = mDockSide == WindowManager.DOCKED_LEFT - || mDockSide == WindowManager.DOCKED_TOP; - } else { - dismissOrMaximize = mDockSide == WindowManager.DOCKED_RIGHT - || mDockSide == WindowManager.DOCKED_BOTTOM; - } - mWindowManagerProxy.dismissOrMaximizeDocked(mTiles, mSplitLayout, dismissOrMaximize); - Transaction t = mTiles.getTransaction(); - setResizeDimLayer(t, true /* primary */, 0f); - setResizeDimLayer(t, false /* primary */, 0f); - t.apply(); - mTiles.releaseTransaction(t); - return true; - } - - private void liftBackground() { - if (mBackgroundLifted) { - return; - } - if (isHorizontalDivision()) { - mBackground.animate().scaleY(1.4f); - } else { - mBackground.animate().scaleX(1.4f); - } - mBackground.animate() - .setInterpolator(Interpolators.TOUCH_RESPONSE) - .setDuration(TOUCH_ANIMATION_DURATION) - .translationZ(mTouchElevation) - .start(); - - // Lift handle as well so it doesn't get behind the background, even though it doesn't - // cast shadow. - mHandle.animate() - .setInterpolator(Interpolators.TOUCH_RESPONSE) - .setDuration(TOUCH_ANIMATION_DURATION) - .translationZ(mTouchElevation) - .start(); - mBackgroundLifted = true; - } - - private void releaseBackground() { - if (!mBackgroundLifted) { - return; - } - mBackground.animate() - .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) - .setDuration(TOUCH_RELEASE_ANIMATION_DURATION) - .translationZ(0) - .scaleX(1f) - .scaleY(1f) - .start(); - mHandle.animate() - .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) - .setDuration(TOUCH_RELEASE_ANIMATION_DURATION) - .translationZ(0) - .start(); - mBackgroundLifted = false; - } - - private void initializeSurfaceState() { - int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position; - // Recalculate the split-layout's internal tile bounds - mSplitLayout.resizeSplits(midPos); - Transaction t = mTiles.getTransaction(); - if (mDockedStackMinimized) { - int position = mSplitLayout.getMinimizedSnapAlgorithm(mHomeStackResizable) - .getMiddleTarget().position; - calculateBoundsForPosition(position, mDockSide, mDockedRect); - calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide), - mOtherRect); - mDividerPositionX = mDividerPositionY = position; - resizeSplitSurfaces(t, mDockedRect, mSplitLayout.mPrimary, - mOtherRect, mSplitLayout.mSecondary); - } else { - resizeSplitSurfaces(t, mSplitLayout.mPrimary, null, - mSplitLayout.mSecondary, null); - } - setResizeDimLayer(t, true /* primary */, 0.f /* alpha */); - setResizeDimLayer(t, false /* secondary */, 0.f /* alpha */); - t.apply(); - mTiles.releaseTransaction(t); - - // Get the actually-visible bar dimensions (relative to full window). This is a thin - // bar going through the center. - final Rect dividerBar = isHorizontalDivision() - ? new Rect(0, mDividerInsets, mSplitLayout.mDisplayLayout.width(), - mDividerInsets + mDividerSize) - : new Rect(mDividerInsets, 0, mDividerInsets + mDividerSize, - mSplitLayout.mDisplayLayout.height()); - final Region touchRegion = new Region(dividerBar); - // Add in the "draggable" portion. While not visible, this is an expanded area that the - // user can interact with. - touchRegion.union(new Rect(mHandle.getLeft(), mHandle.getTop(), - mHandle.getRight(), mHandle.getBottom())); - mWindowManager.setTouchRegion(touchRegion); - } - - void setMinimizedDockStack(boolean minimized, boolean isHomeStackResizable, - Transaction t) { - mHomeStackResizable = isHomeStackResizable; - updateDockSide(); - if (!minimized) { - resetBackground(); - } - mMinimizedShadow.setAlpha(minimized ? 1f : 0f); - if (mDockedStackMinimized != minimized) { - mDockedStackMinimized = minimized; - if (mSplitLayout.mDisplayLayout.rotation() != mDefaultDisplay.getRotation()) { - // Splitscreen to minimize is about to starts after rotating landscape to seascape, - // update display info and snap algorithm targets - repositionSnapTargetBeforeMinimized(); - } - if (mIsInMinimizeInteraction != minimized || mCurrentAnimator != null) { - cancelFlingAnimation(); - if (minimized) { - // Relayout to recalculate the divider shadow when minimizing - requestLayout(); - mIsInMinimizeInteraction = true; - resizeStackSurfaces(mSplitLayout.getMinimizedSnapAlgorithm(mHomeStackResizable) - .getMiddleTarget(), t); - } else { - resizeStackSurfaces(mSnapTargetBeforeMinimized, t); - mIsInMinimizeInteraction = false; - } - } - } - } - - void enterSplitMode(boolean isHomeStackResizable) { - setHidden(false); - - SnapTarget miniMid = - mSplitLayout.getMinimizedSnapAlgorithm(isHomeStackResizable).getMiddleTarget(); - if (mDockedStackMinimized) { - mDividerPositionY = mDividerPositionX = miniMid.position; - } - } - - /** - * Tries to grab a surface control from ViewRootImpl. If this isn't available for some reason - * (ie. the window isn't ready yet), it will get the surfacecontrol that the WindowlessWM has - * assigned to it. - */ - private SurfaceControl getWindowSurfaceControl() { - return mWindowManager.mSystemWindows.getViewSurface(this); - } - - void exitSplitMode() { - // The view is going to be removed right after this function involved, updates the surface - // in the current thread instead of posting it to the view's UI thread. - final SurfaceControl sc = getWindowSurfaceControl(); - if (sc == null) { - return; - } - Transaction t = mTiles.getTransaction(); - t.hide(sc); - mImeController.setDimsHidden(t, true); - t.apply(); - mTiles.releaseTransaction(t); - - // Reset tile bounds - int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position; - mWindowManagerProxy.applyResizeSplits(midPos, mSplitLayout); - } - - void setMinimizedDockStack(boolean minimized, long animDuration, - boolean isHomeStackResizable) { - if (DEBUG) Slog.d(TAG, "setMinDock: " + mDockedStackMinimized + "->" + minimized); - mHomeStackResizable = isHomeStackResizable; - updateDockSide(); - if (mDockedStackMinimized != minimized) { - mIsInMinimizeInteraction = true; - mDockedStackMinimized = minimized; - stopDragging(minimized - ? mSnapTargetBeforeMinimized.position - : getCurrentPosition(), - minimized - ? mSplitLayout.getMinimizedSnapAlgorithm(mHomeStackResizable) - .getMiddleTarget() - : mSnapTargetBeforeMinimized, - animDuration, Interpolators.FAST_OUT_SLOW_IN, 0); - setAdjustedForIme(false, animDuration); - } - if (!minimized) { - mBackground.animate().withEndAction(mResetBackgroundRunnable); - } - mBackground.animate() - .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) - .setDuration(animDuration) - .start(); - } - - // Needed to end any currently playing animations when they might compete with other anims - // (specifically, IME adjust animation immediately after leaving minimized). Someday maybe - // these can be unified, but not today. - void finishAnimations() { - if (mCurrentAnimator != null) { - mCurrentAnimator.end(); - } - } - - void setAdjustedForIme(boolean adjustedForIme, long animDuration) { - if (mAdjustedForIme == adjustedForIme) { - return; - } - updateDockSide(); - mHandle.animate() - .setInterpolator(IME_ADJUST_INTERPOLATOR) - .setDuration(animDuration) - .alpha(adjustedForIme ? 0f : 1f) - .start(); - if (mDockSide == WindowManager.DOCKED_TOP) { - mBackground.setPivotY(0); - mBackground.animate() - .scaleY(adjustedForIme ? ADJUSTED_FOR_IME_SCALE : 1f); - } - if (!adjustedForIme) { - mBackground.animate().withEndAction(mResetBackgroundRunnable); - } - mBackground.animate() - .setInterpolator(IME_ADJUST_INTERPOLATOR) - .setDuration(animDuration) - .start(); - mAdjustedForIme = adjustedForIme; - } - - private void saveSnapTargetBeforeMinimized(SnapTarget target) { - mSnapTargetBeforeMinimized = target; - mState.mRatioPositionBeforeMinimized = (float) target.position - / (isHorizontalDivision() ? mSplitLayout.mDisplayLayout.height() - : mSplitLayout.mDisplayLayout.width()); - } - - private void resetBackground() { - mBackground.setPivotX(mBackground.getWidth() / 2); - mBackground.setPivotY(mBackground.getHeight() / 2); - mBackground.setScaleX(1f); - mBackground.setScaleY(1f); - mMinimizedShadow.setAlpha(0f); - } - - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - } - - private void repositionSnapTargetBeforeMinimized() { - int position = (int) (mState.mRatioPositionBeforeMinimized - * (isHorizontalDivision() ? mSplitLayout.mDisplayLayout.height() - : mSplitLayout.mDisplayLayout.width())); - - // Set the snap target before minimized but do not save until divider is attached and not - // minimized because it does not know its minimized state yet. - mSnapTargetBeforeMinimized = - mSplitLayout.getSnapAlgorithm().calculateNonDismissingSnapTarget(position); - } - - private int calculatePosition(int touchX, int touchY) { - return isHorizontalDivision() ? calculateYPosition(touchY) : calculateXPosition(touchX); - } - - public boolean isHorizontalDivision() { - return getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; - } - - private int calculateXPosition(int touchX) { - return mStartPosition + touchX - mStartX; - } - - private int calculateYPosition(int touchY) { - return mStartPosition + touchY - mStartY; - } - - private void alignTopLeft(Rect containingRect, Rect rect) { - int width = rect.width(); - int height = rect.height(); - rect.set(containingRect.left, containingRect.top, - containingRect.left + width, containingRect.top + height); - } - - private void alignBottomRight(Rect containingRect, Rect rect) { - int width = rect.width(); - int height = rect.height(); - rect.set(containingRect.right - width, containingRect.bottom - height, - containingRect.right, containingRect.bottom); - } - - private void calculateBoundsForPosition(int position, int dockSide, Rect outRect) { - DockedDividerUtils.calculateBoundsForPosition(position, dockSide, outRect, - mSplitLayout.mDisplayLayout.width(), mSplitLayout.mDisplayLayout.height(), - mDividerSize); - } - - private void resizeStackSurfaces(SnapTarget taskSnapTarget, Transaction t) { - resizeStackSurfaces(taskSnapTarget.position, taskSnapTarget.position, taskSnapTarget, t); - } - - void resizeSplitSurfaces(Transaction t, Rect dockedRect, Rect otherRect) { - resizeSplitSurfaces(t, dockedRect, null, otherRect, null); - } - - private void resizeSplitSurfaces(Transaction t, Rect dockedRect, Rect dockedTaskRect, - Rect otherRect, Rect otherTaskRect) { - dockedTaskRect = dockedTaskRect == null ? dockedRect : dockedTaskRect; - otherTaskRect = otherTaskRect == null ? otherRect : otherTaskRect; - - mDividerPositionX = mSplitLayout.getPrimarySplitSide() == DOCKED_RIGHT - ? otherRect.right : dockedRect.right; - mDividerPositionY = dockedRect.bottom; - - if (DEBUG) { - Slog.d(TAG, "Resizing split surfaces: " + dockedRect + " " + dockedTaskRect - + " " + otherRect + " " + otherTaskRect); - } - - t.setPosition(mTiles.mPrimarySurface, dockedTaskRect.left, dockedTaskRect.top); - Rect crop = new Rect(dockedRect); - crop.offsetTo(-Math.min(dockedTaskRect.left - dockedRect.left, 0), - -Math.min(dockedTaskRect.top - dockedRect.top, 0)); - t.setWindowCrop(mTiles.mPrimarySurface, crop); - t.setPosition(mTiles.mSecondarySurface, otherTaskRect.left, otherTaskRect.top); - crop.set(otherRect); - crop.offsetTo(-(otherTaskRect.left - otherRect.left), - -(otherTaskRect.top - otherRect.top)); - t.setWindowCrop(mTiles.mSecondarySurface, crop); - final SurfaceControl dividerCtrl = getWindowSurfaceControl(); - if (dividerCtrl != null) { - if (isHorizontalDivision()) { - t.setPosition(dividerCtrl, 0, mDividerPositionY - mDividerInsets); - } else { - t.setPosition(dividerCtrl, mDividerPositionX - mDividerInsets, 0); - } - } - } - - void setResizeDimLayer(Transaction t, boolean primary, float alpha) { - SurfaceControl dim = primary ? mTiles.mPrimaryDim : mTiles.mSecondaryDim; - if (alpha <= 0.001f) { - t.hide(dim); - } else { - t.setAlpha(dim, alpha); - t.show(dim); - } - } - - void resizeStackSurfaces(int position, int taskPosition, SnapTarget taskSnapTarget, - Transaction transaction) { - if (mRemoved) { - // This divider view has been removed so shouldn't have any additional influence. - return; - } - calculateBoundsForPosition(position, mDockSide, mDockedRect); - calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide), - mOtherRect); - - if (mDockedRect.equals(mLastResizeRect) && !mEntranceAnimationRunning) { - return; - } - - // Make sure shadows are updated - if (mBackground.getZ() > 0f) { - mBackground.invalidate(); - } - - final boolean ownTransaction = transaction == null; - final Transaction t = ownTransaction ? mTiles.getTransaction() : transaction; - mLastResizeRect.set(mDockedRect); - if (mIsInMinimizeInteraction) { - calculateBoundsForPosition(mSnapTargetBeforeMinimized.position, mDockSide, - mDockedTaskRect); - calculateBoundsForPosition(mSnapTargetBeforeMinimized.position, - DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect); - - // Move a right-docked-app to line up with the divider while dragging it - if (mDockSide == DOCKED_RIGHT) { - mDockedTaskRect.offset(Math.max(position, -mDividerSize) - - mDockedTaskRect.left + mDividerSize, 0); - } - resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect); - if (ownTransaction) { - t.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId()); - t.apply(); - mTiles.releaseTransaction(t); - } - return; - } - - if (mEntranceAnimationRunning && taskPosition != TASK_POSITION_SAME) { - calculateBoundsForPosition(taskPosition, mDockSide, mDockedTaskRect); - - // Move a docked app if from the right in position with the divider up to insets - if (mDockSide == DOCKED_RIGHT) { - mDockedTaskRect.offset(Math.max(position, -mDividerSize) - - mDockedTaskRect.left + mDividerSize, 0); - } - calculateBoundsForPosition(taskPosition, DockedDividerUtils.invertDockSide(mDockSide), - mOtherTaskRect); - resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect); - } else if (mExitAnimationRunning && taskPosition != TASK_POSITION_SAME) { - calculateBoundsForPosition(taskPosition, mDockSide, mDockedTaskRect); - mDockedInsetRect.set(mDockedTaskRect); - calculateBoundsForPosition(mExitStartPosition, - DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect); - mOtherInsetRect.set(mOtherTaskRect); - applyExitAnimationParallax(mOtherTaskRect, position); - - // Move a right-docked-app to line up with the divider while dragging it - if (mDockSide == DOCKED_RIGHT) { - mDockedTaskRect.offset(position + mDividerSize, 0); - } - resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect); - } else if (taskPosition != TASK_POSITION_SAME) { - calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide), - mOtherRect); - int dockSideInverted = DockedDividerUtils.invertDockSide(mDockSide); - int taskPositionDocked = - restrictDismissingTaskPosition(taskPosition, mDockSide, taskSnapTarget); - int taskPositionOther = - restrictDismissingTaskPosition(taskPosition, dockSideInverted, taskSnapTarget); - calculateBoundsForPosition(taskPositionDocked, mDockSide, mDockedTaskRect); - calculateBoundsForPosition(taskPositionOther, dockSideInverted, mOtherTaskRect); - mTmpRect.set(0, 0, mSplitLayout.mDisplayLayout.width(), - mSplitLayout.mDisplayLayout.height()); - alignTopLeft(mDockedRect, mDockedTaskRect); - alignTopLeft(mOtherRect, mOtherTaskRect); - mDockedInsetRect.set(mDockedTaskRect); - mOtherInsetRect.set(mOtherTaskRect); - if (dockSideTopLeft(mDockSide)) { - alignTopLeft(mTmpRect, mDockedInsetRect); - alignBottomRight(mTmpRect, mOtherInsetRect); - } else { - alignBottomRight(mTmpRect, mDockedInsetRect); - alignTopLeft(mTmpRect, mOtherInsetRect); - } - applyDismissingParallax(mDockedTaskRect, mDockSide, taskSnapTarget, position, - taskPositionDocked); - applyDismissingParallax(mOtherTaskRect, dockSideInverted, taskSnapTarget, position, - taskPositionOther); - resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect); - } else { - resizeSplitSurfaces(t, mDockedRect, null, mOtherRect, null); - } - SnapTarget closestDismissTarget = getSnapAlgorithm().getClosestDismissTarget(position); - float dimFraction = getDimFraction(position, closestDismissTarget); - setResizeDimLayer(t, isDismissTargetPrimary(closestDismissTarget), dimFraction); - if (ownTransaction) { - t.apply(); - mTiles.releaseTransaction(t); - } - } - - private void applyExitAnimationParallax(Rect taskRect, int position) { - if (mDockSide == WindowManager.DOCKED_TOP) { - taskRect.offset(0, (int) ((position - mExitStartPosition) * 0.25f)); - } else if (mDockSide == WindowManager.DOCKED_LEFT) { - taskRect.offset((int) ((position - mExitStartPosition) * 0.25f), 0); - } else if (mDockSide == WindowManager.DOCKED_RIGHT) { - taskRect.offset((int) ((mExitStartPosition - position) * 0.25f), 0); - } - } - - private float getDimFraction(int position, SnapTarget dismissTarget) { - if (mEntranceAnimationRunning) { - return 0f; - } - float fraction = getSnapAlgorithm().calculateDismissingFraction(position); - fraction = Math.max(0, Math.min(fraction, 1f)); - fraction = DIM_INTERPOLATOR.getInterpolation(fraction); - return fraction; - } - - /** - * When the snap target is dismissing one side, make sure that the dismissing side doesn't get - * 0 size. - */ - private int restrictDismissingTaskPosition(int taskPosition, int dockSide, - SnapTarget snapTarget) { - if (snapTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(dockSide)) { - return Math.max(mSplitLayout.getSnapAlgorithm().getFirstSplitTarget().position, - mStartPosition); - } else if (snapTarget.flag == SnapTarget.FLAG_DISMISS_END - && dockSideBottomRight(dockSide)) { - return Math.min(mSplitLayout.getSnapAlgorithm().getLastSplitTarget().position, - mStartPosition); - } else { - return taskPosition; - } - } - - /** - * Applies a parallax to the task when dismissing. - */ - private void applyDismissingParallax(Rect taskRect, int dockSide, SnapTarget snapTarget, - int position, int taskPosition) { - float fraction = Math.min(1, Math.max(0, - mSplitLayout.getSnapAlgorithm().calculateDismissingFraction(position))); - SnapTarget dismissTarget = null; - SnapTarget splitTarget = null; - int start = 0; - if (position <= mSplitLayout.getSnapAlgorithm().getLastSplitTarget().position - && dockSideTopLeft(dockSide)) { - dismissTarget = mSplitLayout.getSnapAlgorithm().getDismissStartTarget(); - splitTarget = mSplitLayout.getSnapAlgorithm().getFirstSplitTarget(); - start = taskPosition; - } else if (position >= mSplitLayout.getSnapAlgorithm().getLastSplitTarget().position - && dockSideBottomRight(dockSide)) { - dismissTarget = mSplitLayout.getSnapAlgorithm().getDismissEndTarget(); - splitTarget = mSplitLayout.getSnapAlgorithm().getLastSplitTarget(); - start = splitTarget.position; - } - if (dismissTarget != null && fraction > 0f - && isDismissing(splitTarget, position, dockSide)) { - fraction = calculateParallaxDismissingFraction(fraction, dockSide); - int offsetPosition = (int) (start + fraction - * (dismissTarget.position - splitTarget.position)); - int width = taskRect.width(); - int height = taskRect.height(); - switch (dockSide) { - case WindowManager.DOCKED_LEFT: - taskRect.left = offsetPosition - width; - taskRect.right = offsetPosition; - break; - case WindowManager.DOCKED_RIGHT: - taskRect.left = offsetPosition + mDividerSize; - taskRect.right = offsetPosition + width + mDividerSize; - break; - case WindowManager.DOCKED_TOP: - taskRect.top = offsetPosition - height; - taskRect.bottom = offsetPosition; - break; - case WindowManager.DOCKED_BOTTOM: - taskRect.top = offsetPosition + mDividerSize; - taskRect.bottom = offsetPosition + height + mDividerSize; - break; - } - } - } - - /** - * @return for a specified {@code fraction}, this returns an adjusted value that simulates a - * slowing down parallax effect - */ - private static float calculateParallaxDismissingFraction(float fraction, int dockSide) { - float result = SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f; - - // Less parallax at the top, just because. - if (dockSide == WindowManager.DOCKED_TOP) { - result /= 2f; - } - return result; - } - - private static boolean isDismissing(SnapTarget snapTarget, int position, int dockSide) { - if (dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT) { - return position < snapTarget.position; - } else { - return position > snapTarget.position; - } - } - - private boolean isDismissTargetPrimary(SnapTarget dismissTarget) { - return (dismissTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(mDockSide)) - || (dismissTarget.flag == SnapTarget.FLAG_DISMISS_END - && dockSideBottomRight(mDockSide)); - } - - /** - * @return true if and only if {@code dockSide} is top or left - */ - private static boolean dockSideTopLeft(int dockSide) { - return dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT; - } - - /** - * @return true if and only if {@code dockSide} is bottom or right - */ - private static boolean dockSideBottomRight(int dockSide) { - return dockSide == WindowManager.DOCKED_BOTTOM || dockSide == WindowManager.DOCKED_RIGHT; - } - - @Override - public void onComputeInternalInsets(InternalInsetsInfo inoutInfo) { - inoutInfo.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION); - inoutInfo.touchableRegion.set(mHandle.getLeft(), mHandle.getTop(), mHandle.getRight(), - mHandle.getBottom()); - inoutInfo.touchableRegion.op(mBackground.getLeft(), mBackground.getTop(), - mBackground.getRight(), mBackground.getBottom(), Op.UNION); - } - - void onUndockingTask() { - int dockSide = mSplitLayout.getPrimarySplitSide(); - if (inSplitMode()) { - startDragging(false /* animate */, false /* touching */); - SnapTarget target = dockSideTopLeft(dockSide) - ? mSplitLayout.getSnapAlgorithm().getDismissEndTarget() - : mSplitLayout.getSnapAlgorithm().getDismissStartTarget(); - - // Don't start immediately - give a little bit time to settle the drag resize change. - mExitAnimationRunning = true; - mExitStartPosition = getCurrentPosition(); - stopDragging(mExitStartPosition, target, 336 /* duration */, 100 /* startDelay */, - 0 /* endDelay */, Interpolators.FAST_OUT_SLOW_IN); - } - } - - private int calculatePositionForInsetBounds() { - mSplitLayout.mDisplayLayout.getStableBounds(mTmpRect); - return DockedDividerUtils.calculatePositionForBounds(mTmpRect, mDockSide, mDividerSize); - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerWindowManager.java deleted file mode 100644 index 2c3ae68e47492..0000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerWindowManager.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2015 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.legacysplitscreen; - -import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; -import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; -import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; -import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY; -import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH; -import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; -import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; -import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION; -import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; -import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; -import static android.view.WindowManager.SHELL_ROOT_LAYER_DIVIDER; - -import android.graphics.PixelFormat; -import android.graphics.Region; -import android.os.Binder; -import android.view.View; -import android.view.WindowManager; - -import com.android.wm.shell.common.SystemWindows; - -/** - * Manages the window parameters of the docked stack divider. - */ -final class DividerWindowManager { - - private static final String WINDOW_TITLE = "DockedStackDivider"; - - final SystemWindows mSystemWindows; - private WindowManager.LayoutParams mLp; - private View mView; - - DividerWindowManager(SystemWindows systemWindows) { - mSystemWindows = systemWindows; - } - - /** Add a divider view */ - void add(View view, int width, int height, int displayId) { - mLp = new WindowManager.LayoutParams( - width, height, TYPE_DOCK_DIVIDER, - FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL - | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY, - PixelFormat.TRANSLUCENT); - mLp.token = new Binder(); - mLp.setTitle(WINDOW_TITLE); - mLp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY; - mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; - view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); - mSystemWindows.addView(view, mLp, displayId, SHELL_ROOT_LAYER_DIVIDER); - mView = view; - } - - void remove() { - if (mView != null) { - mSystemWindows.removeView(mView); - } - mView = null; - } - - void setSlippery(boolean slippery) { - boolean changed = false; - if (slippery && (mLp.flags & FLAG_SLIPPERY) == 0) { - mLp.flags |= FLAG_SLIPPERY; - changed = true; - } else if (!slippery && (mLp.flags & FLAG_SLIPPERY) != 0) { - mLp.flags &= ~FLAG_SLIPPERY; - changed = true; - } - if (changed) { - mSystemWindows.updateViewLayout(mView, mLp); - } - } - - void setTouchable(boolean touchable) { - if (mView == null) { - return; - } - boolean changed = false; - if (!touchable && (mLp.flags & FLAG_NOT_TOUCHABLE) == 0) { - mLp.flags |= FLAG_NOT_TOUCHABLE; - changed = true; - } else if (touchable && (mLp.flags & FLAG_NOT_TOUCHABLE) != 0) { - mLp.flags &= ~FLAG_NOT_TOUCHABLE; - changed = true; - } - if (changed) { - mSystemWindows.updateViewLayout(mView, mLp); - } - } - - /** Sets the touch region to `touchRegion`. Use null to unset.*/ - void setTouchRegion(Region touchRegion) { - if (mView == null) { - return; - } - mSystemWindows.setTouchableRegion(mView, touchRegion); - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivity.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivity.java deleted file mode 100644 index 4fe28e630114c..0000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivity.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2016 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.legacysplitscreen; - -import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY; -import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN; - -import android.annotation.Nullable; -import android.app.Activity; -import android.app.ActivityManager; -import android.os.Bundle; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnTouchListener; -import android.widget.TextView; - -import com.android.wm.shell.R; - -/** - * Translucent activity that gets started on top of a task in multi-window to inform the user that - * we forced the activity below to be resizable. - * - * Note: This activity runs on the main thread of the process hosting the Shell lib. - */ -public class ForcedResizableInfoActivity extends Activity implements OnTouchListener { - - public static final String EXTRA_FORCED_RESIZEABLE_REASON = "extra_forced_resizeable_reason"; - - private static final long DISMISS_DELAY = 2500; - - private final Runnable mFinishRunnable = new Runnable() { - @Override - public void run() { - finish(); - } - }; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.forced_resizable_activity); - TextView tv = findViewById(com.android.internal.R.id.message); - int reason = getIntent().getIntExtra(EXTRA_FORCED_RESIZEABLE_REASON, -1); - String text; - switch (reason) { - case FORCED_RESIZEABLE_REASON_SPLIT_SCREEN: - text = getString(R.string.dock_forced_resizable); - break; - case FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY: - text = getString(R.string.forced_resizable_secondary_display); - break; - default: - throw new IllegalArgumentException("Unexpected forced resizeable reason: " - + reason); - } - tv.setText(text); - getWindow().setTitle(text); - getWindow().getDecorView().setOnTouchListener(this); - } - - @Override - protected void onStart() { - super.onStart(); - getWindow().getDecorView().postDelayed(mFinishRunnable, DISMISS_DELAY); - } - - @Override - protected void onStop() { - super.onStop(); - finish(); - } - - @Override - public boolean onTouch(View v, MotionEvent event) { - finish(); - return true; - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - finish(); - return true; - } - - @Override - public void finish() { - super.finish(); - overridePendingTransition(0, R.anim.forced_resizable_exit); - } - - @Override - public void setTaskDescription(ActivityManager.TaskDescription taskDescription) { - // Do nothing - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivityController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivityController.java deleted file mode 100644 index 139544f951ce0..0000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/ForcedResizableInfoActivityController.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2016 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.legacysplitscreen; - - -import static com.android.wm.shell.legacysplitscreen.ForcedResizableInfoActivity.EXTRA_FORCED_RESIZEABLE_REASON; - -import android.app.ActivityOptions; -import android.content.Context; -import android.content.Intent; -import android.os.UserHandle; -import android.util.ArraySet; -import android.widget.Toast; - -import com.android.wm.shell.R; -import com.android.wm.shell.common.ShellExecutor; - -import java.util.function.Consumer; - -/** - * Controller that decides when to show the {@link ForcedResizableInfoActivity}. - */ -final class ForcedResizableInfoActivityController implements DividerView.DividerCallbacks { - - private static final String SELF_PACKAGE_NAME = "com.android.systemui"; - - private static final int TIMEOUT = 1000; - private final Context mContext; - private final ShellExecutor mMainExecutor; - private final ArraySet mPendingTasks = new ArraySet<>(); - private final ArraySet mPackagesShownInSession = new ArraySet<>(); - private boolean mDividerDragging; - - private final Runnable mTimeoutRunnable = this::showPending; - - private final Consumer mDockedStackExistsListener = exists -> { - if (!exists) { - mPackagesShownInSession.clear(); - } - }; - - /** Record of force resized task that's pending to be handled. */ - private class PendingTaskRecord { - int mTaskId; - /** - * {@link android.app.ITaskStackListener#FORCED_RESIZEABLE_REASON_SPLIT_SCREEN} or - * {@link android.app.ITaskStackListener#FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY} - */ - int mReason; - - PendingTaskRecord(int taskId, int reason) { - this.mTaskId = taskId; - this.mReason = reason; - } - } - - ForcedResizableInfoActivityController(Context context, - LegacySplitScreenController splitScreenController, - ShellExecutor mainExecutor) { - mContext = context; - mMainExecutor = mainExecutor; - splitScreenController.registerInSplitScreenListener(mDockedStackExistsListener); - } - - @Override - public void onDraggingStart() { - mDividerDragging = true; - mMainExecutor.removeCallbacks(mTimeoutRunnable); - } - - @Override - public void onDraggingEnd() { - mDividerDragging = false; - showPending(); - } - - void onAppTransitionFinished() { - if (!mDividerDragging) { - showPending(); - } - } - - void activityForcedResizable(String packageName, int taskId, int reason) { - if (debounce(packageName)) { - return; - } - mPendingTasks.add(new PendingTaskRecord(taskId, reason)); - postTimeout(); - } - - void activityDismissingSplitScreen() { - Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text, - Toast.LENGTH_SHORT).show(); - } - - void activityLaunchOnSecondaryDisplayFailed() { - Toast.makeText(mContext, R.string.activity_launch_on_secondary_display_failed_text, - Toast.LENGTH_SHORT).show(); - } - - private void showPending() { - mMainExecutor.removeCallbacks(mTimeoutRunnable); - for (int i = mPendingTasks.size() - 1; i >= 0; i--) { - PendingTaskRecord pendingRecord = mPendingTasks.valueAt(i); - Intent intent = new Intent(mContext, ForcedResizableInfoActivity.class); - ActivityOptions options = ActivityOptions.makeBasic(); - options.setLaunchTaskId(pendingRecord.mTaskId); - // Set as task overlay and allow to resume, so that when an app enters split-screen and - // becomes paused, the overlay will still be shown. - options.setTaskOverlay(true, true /* canResume */); - intent.putExtra(EXTRA_FORCED_RESIZEABLE_REASON, pendingRecord.mReason); - mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT); - } - mPendingTasks.clear(); - } - - private void postTimeout() { - mMainExecutor.removeCallbacks(mTimeoutRunnable); - mMainExecutor.executeDelayed(mTimeoutRunnable, TIMEOUT); - } - - private boolean debounce(String packageName) { - if (packageName == null) { - return false; - } - - // We launch ForcedResizableInfoActivity into a task that was forced resizable, so that - // triggers another notification. So ignore our own activity. - if (SELF_PACKAGE_NAME.equals(packageName)) { - return true; - } - boolean debounce = mPackagesShownInSession.contains(packageName); - mPackagesShownInSession.add(packageName); - return debounce; - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java deleted file mode 100644 index f201634d3d4a5..0000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright (C) 2020 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.legacysplitscreen; - -import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; -import static android.content.res.Configuration.ORIENTATION_PORTRAIT; -import static android.util.RotationUtils.rotateBounds; -import static android.view.WindowManager.DOCKED_BOTTOM; -import static android.view.WindowManager.DOCKED_INVALID; -import static android.view.WindowManager.DOCKED_LEFT; -import static android.view.WindowManager.DOCKED_RIGHT; -import static android.view.WindowManager.DOCKED_TOP; - -import android.annotation.NonNull; -import android.content.Context; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.graphics.Rect; -import android.util.TypedValue; -import android.window.WindowContainerTransaction; - -import com.android.internal.policy.DividerSnapAlgorithm; -import com.android.internal.policy.DockedDividerUtils; -import com.android.wm.shell.common.DisplayLayout; - -/** - * Handles split-screen related internal display layout. In general, this represents the - * WM-facing understanding of the splits. - */ -public class LegacySplitDisplayLayout { - /** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to - * restrict IME adjustment so that a min portion of top stack remains visible.*/ - private static final float ADJUSTED_STACK_FRACTION_MIN = 0.3f; - - private static final int DIVIDER_WIDTH_INACTIVE_DP = 4; - - LegacySplitScreenTaskListener mTiles; - DisplayLayout mDisplayLayout; - Context mContext; - - // Lazy stuff - boolean mResourcesValid = false; - int mDividerSize; - int mDividerSizeInactive; - private DividerSnapAlgorithm mSnapAlgorithm = null; - private DividerSnapAlgorithm mMinimizedSnapAlgorithm = null; - Rect mPrimary = null; - Rect mSecondary = null; - Rect mAdjustedPrimary = null; - Rect mAdjustedSecondary = null; - final Rect mTmpBounds = new Rect(); - - public LegacySplitDisplayLayout(Context ctx, DisplayLayout dl, - LegacySplitScreenTaskListener taskTiles) { - mTiles = taskTiles; - mDisplayLayout = dl; - mContext = ctx; - } - - void rotateTo(int newRotation) { - mDisplayLayout.rotateTo(mContext.getResources(), newRotation); - final Configuration config = new Configuration(); - config.unset(); - config.orientation = mDisplayLayout.getOrientation(); - Rect tmpRect = new Rect(0, 0, mDisplayLayout.width(), mDisplayLayout.height()); - tmpRect.inset(mDisplayLayout.nonDecorInsets()); - config.windowConfiguration.setAppBounds(tmpRect); - tmpRect.set(0, 0, mDisplayLayout.width(), mDisplayLayout.height()); - tmpRect.inset(mDisplayLayout.stableInsets()); - config.screenWidthDp = (int) (tmpRect.width() / mDisplayLayout.density()); - config.screenHeightDp = (int) (tmpRect.height() / mDisplayLayout.density()); - mContext = mContext.createConfigurationContext(config); - mSnapAlgorithm = null; - mMinimizedSnapAlgorithm = null; - mResourcesValid = false; - } - - private void updateResources() { - if (mResourcesValid) { - return; - } - mResourcesValid = true; - Resources res = mContext.getResources(); - mDividerSize = DockedDividerUtils.getDividerSize(res, - DockedDividerUtils.getDividerInsets(res)); - mDividerSizeInactive = (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, DIVIDER_WIDTH_INACTIVE_DP, res.getDisplayMetrics()); - } - - int getPrimarySplitSide() { - switch (mDisplayLayout.getNavigationBarPosition(mContext.getResources())) { - case DisplayLayout.NAV_BAR_BOTTOM: - return mDisplayLayout.isLandscape() ? DOCKED_LEFT : DOCKED_TOP; - case DisplayLayout.NAV_BAR_LEFT: - return DOCKED_RIGHT; - case DisplayLayout.NAV_BAR_RIGHT: - return DOCKED_LEFT; - default: - return DOCKED_INVALID; - } - } - - DividerSnapAlgorithm getSnapAlgorithm() { - if (mSnapAlgorithm == null) { - updateResources(); - boolean isHorizontalDivision = !mDisplayLayout.isLandscape(); - mSnapAlgorithm = new DividerSnapAlgorithm(mContext.getResources(), - mDisplayLayout.width(), mDisplayLayout.height(), mDividerSize, - isHorizontalDivision, mDisplayLayout.stableInsets(), getPrimarySplitSide()); - } - return mSnapAlgorithm; - } - - DividerSnapAlgorithm getMinimizedSnapAlgorithm(boolean homeStackResizable) { - if (mMinimizedSnapAlgorithm == null) { - updateResources(); - boolean isHorizontalDivision = !mDisplayLayout.isLandscape(); - mMinimizedSnapAlgorithm = new DividerSnapAlgorithm(mContext.getResources(), - mDisplayLayout.width(), mDisplayLayout.height(), mDividerSize, - isHorizontalDivision, mDisplayLayout.stableInsets(), getPrimarySplitSide(), - true /* isMinimized */, homeStackResizable); - } - return mMinimizedSnapAlgorithm; - } - - /** - * Resize primary bounds and secondary bounds by divider position. - * - * @param position divider position. - * @return true if calculated bounds changed. - */ - boolean resizeSplits(int position) { - mPrimary = mPrimary == null ? new Rect() : mPrimary; - mSecondary = mSecondary == null ? new Rect() : mSecondary; - int dockSide = getPrimarySplitSide(); - boolean boundsChanged; - - mTmpBounds.set(mPrimary); - DockedDividerUtils.calculateBoundsForPosition(position, dockSide, mPrimary, - mDisplayLayout.width(), mDisplayLayout.height(), mDividerSize); - boundsChanged = !mPrimary.equals(mTmpBounds); - - mTmpBounds.set(mSecondary); - DockedDividerUtils.calculateBoundsForPosition(position, - DockedDividerUtils.invertDockSide(dockSide), mSecondary, mDisplayLayout.width(), - mDisplayLayout.height(), mDividerSize); - boundsChanged |= !mSecondary.equals(mTmpBounds); - return boundsChanged; - } - - void resizeSplits(int position, WindowContainerTransaction t) { - if (resizeSplits(position)) { - t.setBounds(mTiles.mPrimary.token, mPrimary); - t.setBounds(mTiles.mSecondary.token, mSecondary); - - t.setSmallestScreenWidthDp(mTiles.mPrimary.token, - getSmallestWidthDpForBounds(mContext, mDisplayLayout, mPrimary)); - t.setSmallestScreenWidthDp(mTiles.mSecondary.token, - getSmallestWidthDpForBounds(mContext, mDisplayLayout, mSecondary)); - } - } - - Rect calcResizableMinimizedHomeStackBounds() { - DividerSnapAlgorithm.SnapTarget miniMid = - getMinimizedSnapAlgorithm(true /* resizable */).getMiddleTarget(); - Rect homeBounds = new Rect(); - DockedDividerUtils.calculateBoundsForPosition(miniMid.position, - DockedDividerUtils.invertDockSide(getPrimarySplitSide()), homeBounds, - mDisplayLayout.width(), mDisplayLayout.height(), mDividerSize); - return homeBounds; - } - - /** - * Updates the adjustment depending on it's current state. - */ - void updateAdjustedBounds(int currImeTop, int hiddenTop, int shownTop) { - adjustForIME(mDisplayLayout, currImeTop, hiddenTop, shownTop, mDividerSize, - mDividerSizeInactive, mPrimary, mSecondary); - } - - /** Assumes top/bottom split. Splits are not adjusted for left/right splits. */ - private void adjustForIME(DisplayLayout dl, int currImeTop, int hiddenTop, int shownTop, - int dividerWidth, int dividerWidthInactive, Rect primaryBounds, Rect secondaryBounds) { - if (mAdjustedPrimary == null) { - mAdjustedPrimary = new Rect(); - mAdjustedSecondary = new Rect(); - } - - final Rect displayStableRect = new Rect(); - dl.getStableBounds(displayStableRect); - - final float shownFraction = ((float) (currImeTop - hiddenTop)) / (shownTop - hiddenTop); - final int currDividerWidth = - (int) (dividerWidthInactive * shownFraction + dividerWidth * (1.f - shownFraction)); - - // Calculate the highest we can move the bottom of the top stack to keep 30% visible. - final int minTopStackBottom = displayStableRect.top - + (int) ((mPrimary.bottom - displayStableRect.top) * ADJUSTED_STACK_FRACTION_MIN); - // Based on that, calculate the maximum amount we'll allow the ime to shift things. - final int maxOffset = mPrimary.bottom - minTopStackBottom; - // Calculate how much we would shift things without limits (basically the height of ime). - final int desiredOffset = hiddenTop - shownTop; - // Calculate an "adjustedTop" which is the currImeTop but restricted by our constraints. - // We want an effect where the adjustment only occurs during the "highest" portion of the - // ime animation. This is done by shifting the adjustment values by the difference in - // offsets (effectively playing the whole adjustment animation some fixed amount of pixels - // below the ime top). - final int topCorrection = Math.max(0, desiredOffset - maxOffset); - final int adjustedTop = currImeTop + topCorrection; - // The actual yOffset is the distance between adjustedTop and the bottom of the display. - // Since our adjustedTop values are playing "below" the ime, we clamp at 0 so we only - // see adjustment upward. - final int yOffset = Math.max(0, dl.height() - adjustedTop); - - // TOP - // Reduce the offset by an additional small amount to squish the divider bar. - mAdjustedPrimary.set(primaryBounds); - mAdjustedPrimary.offset(0, -yOffset + (dividerWidth - currDividerWidth)); - - // BOTTOM - mAdjustedSecondary.set(secondaryBounds); - mAdjustedSecondary.offset(0, -yOffset); - } - - static int getSmallestWidthDpForBounds(@NonNull Context context, DisplayLayout dl, - Rect bounds) { - int dividerSize = DockedDividerUtils.getDividerSize(context.getResources(), - DockedDividerUtils.getDividerInsets(context.getResources())); - - int minWidth = Integer.MAX_VALUE; - - // Go through all screen orientations and find the orientation in which the task has the - // smallest width. - Rect tmpRect = new Rect(); - Rect rotatedDisplayRect = new Rect(); - Rect displayRect = new Rect(0, 0, dl.width(), dl.height()); - - DisplayLayout tmpDL = new DisplayLayout(); - for (int rotation = 0; rotation < 4; rotation++) { - tmpDL.set(dl); - tmpDL.rotateTo(context.getResources(), rotation); - DividerSnapAlgorithm snap = initSnapAlgorithmForRotation(context, tmpDL, dividerSize); - - tmpRect.set(bounds); - rotateBounds(tmpRect, displayRect, dl.rotation(), rotation); - rotatedDisplayRect.set(0, 0, tmpDL.width(), tmpDL.height()); - final int dockSide = getPrimarySplitSide(tmpRect, rotatedDisplayRect, - tmpDL.getOrientation()); - final int position = DockedDividerUtils.calculatePositionForBounds(tmpRect, dockSide, - dividerSize); - - final int snappedPosition = - snap.calculateNonDismissingSnapTarget(position).position; - DockedDividerUtils.calculateBoundsForPosition(snappedPosition, dockSide, tmpRect, - tmpDL.width(), tmpDL.height(), dividerSize); - Rect insettedDisplay = new Rect(rotatedDisplayRect); - insettedDisplay.inset(tmpDL.stableInsets()); - tmpRect.intersect(insettedDisplay); - minWidth = Math.min(tmpRect.width(), minWidth); - } - return (int) (minWidth / dl.density()); - } - - static DividerSnapAlgorithm initSnapAlgorithmForRotation(Context context, DisplayLayout dl, - int dividerSize) { - final Configuration config = new Configuration(); - config.unset(); - config.orientation = dl.getOrientation(); - Rect tmpRect = new Rect(0, 0, dl.width(), dl.height()); - tmpRect.inset(dl.nonDecorInsets()); - config.windowConfiguration.setAppBounds(tmpRect); - tmpRect.set(0, 0, dl.width(), dl.height()); - tmpRect.inset(dl.stableInsets()); - config.screenWidthDp = (int) (tmpRect.width() / dl.density()); - config.screenHeightDp = (int) (tmpRect.height() / dl.density()); - final Context rotationContext = context.createConfigurationContext(config); - return new DividerSnapAlgorithm( - rotationContext.getResources(), dl.width(), dl.height(), dividerSize, - config.orientation == ORIENTATION_PORTRAIT, dl.stableInsets()); - } - - /** - * Get the current primary-split side. Determined by its location of {@param bounds} within - * {@param displayRect} but if both are the same, it will try to dock to each side and determine - * if allowed in its respected {@param orientation}. - * - * @param bounds bounds of the primary split task to get which side is docked - * @param displayRect bounds of the display that contains the primary split task - * @param orientation the origination of device - * @return current primary-split side - */ - static int getPrimarySplitSide(Rect bounds, Rect displayRect, int orientation) { - if (orientation == ORIENTATION_PORTRAIT) { - // Portrait mode, docked either at the top or the bottom. - final int diff = (displayRect.bottom - bounds.bottom) - (bounds.top - displayRect.top); - if (diff < 0) { - return DOCKED_BOTTOM; - } else { - // Top is default - return DOCKED_TOP; - } - } else if (orientation == ORIENTATION_LANDSCAPE) { - // Landscape mode, docked either on the left or on the right. - final int diff = (displayRect.right - bounds.right) - (bounds.left - displayRect.left); - if (diff < 0) { - return DOCKED_RIGHT; - } - return DOCKED_LEFT; - } - return DOCKED_INVALID; - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreen.java deleted file mode 100644 index 499a9c5fa6313..0000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreen.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2020 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.legacysplitscreen; - -import android.graphics.Rect; -import android.window.WindowContainerToken; - -import com.android.wm.shell.common.annotations.ExternalThread; - -import java.io.PrintWriter; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -/** - * Interface to engage split screen feature. - */ -@ExternalThread -public interface LegacySplitScreen { - /** Called when keyguard showing state changed. */ - void onKeyguardVisibilityChanged(boolean isShowing); - - /** Returns {@link DividerView}. */ - DividerView getDividerView(); - - /** Returns {@code true} if one of the split screen is in minimized mode. */ - boolean isMinimized(); - - /** Returns {@code true} if the home stack is resizable. */ - boolean isHomeStackResizable(); - - /** Returns {@code true} if the divider is visible. */ - boolean isDividerVisible(); - - /** Switch to minimized state if appropriate. */ - void setMinimized(boolean minimized); - - /** Called when there's a task undocking. */ - void onUndockingTask(); - - /** Called when app transition finished. */ - void onAppTransitionFinished(); - - /** Dumps current status of Split Screen. */ - void dump(PrintWriter pw); - - /** Registers listener that gets called whenever the existence of the divider changes. */ - void registerInSplitScreenListener(Consumer listener); - - /** Unregisters listener that gets called whenever the existence of the divider changes. */ - void unregisterInSplitScreenListener(Consumer listener); - - /** Registers listener that gets called whenever the split screen bounds changes. */ - void registerBoundsChangeListener(BiConsumer listener); - - /** @return the container token for the secondary split root task. */ - WindowContainerToken getSecondaryRoot(); - - /** - * Splits the primary task if feasible, this is to preserve legacy way to toggle split screen. - * Like triggering split screen through long pressing recents app button or through - * {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN}. - * - * @return {@code true} if it successes to split the primary task. - */ - boolean splitPrimaryTask(); - - /** - * Exits the split to make the primary task fullscreen. - */ - void dismissSplitToPrimaryTask(); -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java deleted file mode 100644 index 67e487de0993a..0000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java +++ /dev/null @@ -1,762 +0,0 @@ -/* - * Copyright (C) 2020 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.legacysplitscreen; - -import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; -import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; -import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; -import static android.view.Display.DEFAULT_DISPLAY; - -import android.animation.AnimationHandler; -import android.app.ActivityManager; -import android.app.ActivityManager.RunningTaskInfo; -import android.app.ActivityTaskManager; -import android.content.Context; -import android.content.res.Configuration; -import android.graphics.Rect; -import android.os.RemoteException; -import android.provider.Settings; -import android.util.Slog; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.Toast; -import android.window.TaskOrganizer; -import android.window.WindowContainerToken; -import android.window.WindowContainerTransaction; - -import com.android.internal.policy.DividerSnapAlgorithm; -import com.android.wm.shell.R; -import com.android.wm.shell.ShellTaskOrganizer; -import com.android.wm.shell.common.DisplayChangeController; -import com.android.wm.shell.common.DisplayController; -import com.android.wm.shell.common.DisplayImeController; -import com.android.wm.shell.common.DisplayLayout; -import com.android.wm.shell.common.ShellExecutor; -import com.android.wm.shell.common.SyncTransactionQueue; -import com.android.wm.shell.common.SystemWindows; -import com.android.wm.shell.common.TaskStackListenerCallback; -import com.android.wm.shell.common.TaskStackListenerImpl; -import com.android.wm.shell.common.TransactionPool; -import com.android.wm.shell.transition.Transitions; - -import java.io.PrintWriter; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -/** - * Controls split screen feature. - */ -public class LegacySplitScreenController implements DisplayController.OnDisplaysChangedListener { - static final boolean DEBUG = false; - - private static final String TAG = "SplitScreenCtrl"; - private static final int DEFAULT_APP_TRANSITION_DURATION = 336; - - private final Context mContext; - private final DisplayChangeController.OnDisplayChangingListener mRotationController; - private final DisplayController mDisplayController; - private final DisplayImeController mImeController; - private final DividerImeController mImePositionProcessor; - private final DividerState mDividerState = new DividerState(); - private final ForcedResizableInfoActivityController mForcedResizableController; - private final ShellExecutor mMainExecutor; - private final AnimationHandler mSfVsyncAnimationHandler; - private final LegacySplitScreenTaskListener mSplits; - private final SystemWindows mSystemWindows; - final TransactionPool mTransactionPool; - private final WindowManagerProxy mWindowManagerProxy; - private final TaskOrganizer mTaskOrganizer; - private final SplitScreenImpl mImpl = new SplitScreenImpl(); - - private final CopyOnWriteArrayList>> mDockedStackExistsListeners - = new CopyOnWriteArrayList<>(); - private final ArrayList>> mBoundsChangedListeners = - new ArrayList<>(); - - - private DividerWindowManager mWindowManager; - private DividerView mView; - - // Keeps track of real-time split geometry including snap positions and ime adjustments - private LegacySplitDisplayLayout mSplitLayout; - - // Transient: this contains the layout calculated for a new rotation requested by WM. This is - // kept around so that we can wait for a matching configuration change and then use the exact - // layout that we sent back to WM. - private LegacySplitDisplayLayout mRotateSplitLayout; - - private boolean mIsKeyguardShowing; - private boolean mVisible = false; - private volatile boolean mMinimized = false; - private volatile boolean mAdjustedForIme = false; - private boolean mHomeStackResizable = false; - - public LegacySplitScreenController(Context context, - DisplayController displayController, SystemWindows systemWindows, - DisplayImeController imeController, TransactionPool transactionPool, - ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue, - TaskStackListenerImpl taskStackListener, Transitions transitions, - ShellExecutor mainExecutor, AnimationHandler sfVsyncAnimationHandler) { - mContext = context; - mDisplayController = displayController; - mSystemWindows = systemWindows; - mImeController = imeController; - mMainExecutor = mainExecutor; - mSfVsyncAnimationHandler = sfVsyncAnimationHandler; - mForcedResizableController = new ForcedResizableInfoActivityController(context, this, - mainExecutor); - mTransactionPool = transactionPool; - mWindowManagerProxy = new WindowManagerProxy(syncQueue, shellTaskOrganizer); - mTaskOrganizer = shellTaskOrganizer; - mSplits = new LegacySplitScreenTaskListener(this, shellTaskOrganizer, transitions, - syncQueue); - mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mMainExecutor, - shellTaskOrganizer); - mRotationController = - (display, fromRotation, toRotation, wct) -> { - if (!mSplits.isSplitScreenSupported() || mWindowManagerProxy == null) { - return; - } - WindowContainerTransaction t = new WindowContainerTransaction(); - DisplayLayout displayLayout = - new DisplayLayout(mDisplayController.getDisplayLayout(display)); - LegacySplitDisplayLayout sdl = - new LegacySplitDisplayLayout(mContext, displayLayout, mSplits); - sdl.rotateTo(toRotation); - mRotateSplitLayout = sdl; - // snap resets to middle target when not minimized and rotation changed. - final int position = mMinimized ? mView.mSnapTargetBeforeMinimized.position - : sdl.getSnapAlgorithm().getMiddleTarget().position; - DividerSnapAlgorithm snap = sdl.getSnapAlgorithm(); - final DividerSnapAlgorithm.SnapTarget target = - snap.calculateNonDismissingSnapTarget(position); - sdl.resizeSplits(target.position, t); - - if (isSplitActive() && mHomeStackResizable) { - mWindowManagerProxy - .applyHomeTasksMinimized(sdl, mSplits.mSecondary.token, t); - } - if (mWindowManagerProxy.queueSyncTransactionIfWaiting(t)) { - // Because sync transactions are serialized, its possible for an "older" - // bounds-change to get applied after a screen rotation. In that case, we - // want to actually defer on that rather than apply immediately. Of course, - // this means that the bounds may not change until after the rotation so - // the user might see some artifacts. This should be rare. - Slog.w(TAG, "Screen rotated while other operations were pending, this may" - + " result in some graphical artifacts."); - } else { - wct.merge(t, true /* transfer */); - } - }; - - mWindowManager = new DividerWindowManager(mSystemWindows); - - // No need to listen to display window container or create root tasks if the device is not - // using legacy split screen. - if (!context.getResources().getBoolean(com.android.internal.R.bool.config_useLegacySplit)) { - return; - } - - - mDisplayController.addDisplayWindowListener(this); - // Don't initialize the divider or anything until we get the default display. - - taskStackListener.addListener( - new TaskStackListenerCallback() { - @Override - public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task, - boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) { - if (!wasVisible || task.getWindowingMode() - != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY - || !mSplits.isSplitScreenSupported()) { - return; - } - - if (isMinimized()) { - onUndockingTask(); - } - } - - @Override - public void onActivityForcedResizable(String packageName, int taskId, - int reason) { - mForcedResizableController.activityForcedResizable(packageName, taskId, - reason); - } - - @Override - public void onActivityDismissingDockedStack() { - mForcedResizableController.activityDismissingSplitScreen(); - } - - @Override - public void onActivityLaunchOnSecondaryDisplayFailed() { - mForcedResizableController.activityLaunchOnSecondaryDisplayFailed(); - } - }); - } - - public LegacySplitScreen asLegacySplitScreen() { - return mImpl; - } - - public void onSplitScreenSupported() { - // Set starting tile bounds based on middle target - final WindowContainerTransaction tct = new WindowContainerTransaction(); - int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position; - mSplitLayout.resizeSplits(midPos, tct); - mTaskOrganizer.applyTransaction(tct); - } - - public void onKeyguardVisibilityChanged(boolean showing) { - if (!isSplitActive() || mView == null) { - return; - } - mView.setHidden(showing); - mIsKeyguardShowing = showing; - } - - @Override - public void onDisplayAdded(int displayId) { - if (displayId != DEFAULT_DISPLAY) { - return; - } - mSplitLayout = new LegacySplitDisplayLayout(mDisplayController.getDisplayContext(displayId), - mDisplayController.getDisplayLayout(displayId), mSplits); - mImeController.addPositionProcessor(mImePositionProcessor); - mDisplayController.addDisplayChangingController(mRotationController); - if (!ActivityTaskManager.supportsSplitScreenMultiWindow(mContext)) { - removeDivider(); - return; - } - try { - mSplits.init(); - } catch (Exception e) { - Slog.e(TAG, "Failed to register docked stack listener", e); - removeDivider(); - return; - } - } - - @Override - public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) { - if (displayId != DEFAULT_DISPLAY || !mSplits.isSplitScreenSupported()) { - return; - } - mSplitLayout = new LegacySplitDisplayLayout(mDisplayController.getDisplayContext(displayId), - mDisplayController.getDisplayLayout(displayId), mSplits); - if (mRotateSplitLayout == null) { - int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position; - final WindowContainerTransaction tct = new WindowContainerTransaction(); - mSplitLayout.resizeSplits(midPos, tct); - mTaskOrganizer.applyTransaction(tct); - } else if (mSplitLayout.mDisplayLayout.rotation() - == mRotateSplitLayout.mDisplayLayout.rotation()) { - mSplitLayout.mPrimary = new Rect(mRotateSplitLayout.mPrimary); - mSplitLayout.mSecondary = new Rect(mRotateSplitLayout.mSecondary); - mRotateSplitLayout = null; - } - if (isSplitActive()) { - update(newConfig); - } - } - - public boolean isMinimized() { - return mMinimized; - } - - public boolean isHomeStackResizable() { - return mHomeStackResizable; - } - - public DividerView getDividerView() { - return mView; - } - - public boolean isDividerVisible() { - return mView != null && mView.getVisibility() == View.VISIBLE; - } - - /** - * This indicates that at-least one of the splits has content. This differs from - * isDividerVisible because the divider is only visible once *everything* is in split mode - * while this only cares if some things are (eg. while entering/exiting as well). - */ - public boolean isSplitActive() { - return mSplits.mPrimary != null && mSplits.mSecondary != null - && (mSplits.mPrimary.topActivityType != ACTIVITY_TYPE_UNDEFINED - || mSplits.mSecondary.topActivityType != ACTIVITY_TYPE_UNDEFINED); - } - - public void addDivider(Configuration configuration) { - Context dctx = mDisplayController.getDisplayContext(mContext.getDisplayId()); - mView = (DividerView) - LayoutInflater.from(dctx).inflate(R.layout.docked_stack_divider, null); - mView.setAnimationHandler(mSfVsyncAnimationHandler); - DisplayLayout displayLayout = mDisplayController.getDisplayLayout(mContext.getDisplayId()); - mView.injectDependencies(this, mWindowManager, mDividerState, mForcedResizableController, - mSplits, mSplitLayout, mImePositionProcessor, mWindowManagerProxy); - mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE); - mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, null /* transaction */); - final int size = dctx.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.docked_stack_divider_thickness); - final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE; - final int width = landscape ? size : displayLayout.width(); - final int height = landscape ? displayLayout.height() : size; - mWindowManager.add(mView, width, height, mContext.getDisplayId()); - } - - public void removeDivider() { - if (mView != null) { - mView.onDividerRemoved(); - } - mWindowManager.remove(); - } - - public void update(Configuration configuration) { - final boolean isDividerHidden = mView != null && mIsKeyguardShowing; - - removeDivider(); - addDivider(configuration); - - if (mMinimized) { - mView.setMinimizedDockStack(true, mHomeStackResizable, null /* transaction */); - updateTouchable(); - } - mView.setHidden(isDividerHidden); - } - - public void onTaskVanished() { - removeDivider(); - } - - public void updateVisibility(final boolean visible) { - if (DEBUG) Slog.d(TAG, "Updating visibility " + mVisible + "->" + visible); - if (mVisible != visible) { - mVisible = visible; - mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); - - if (visible) { - mView.enterSplitMode(mHomeStackResizable); - // Update state because animations won't finish. - mWindowManagerProxy.runInSync( - t -> mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, t)); - - } else { - mView.exitSplitMode(); - mWindowManagerProxy.runInSync( - t -> mView.setMinimizedDockStack(false, mHomeStackResizable, t)); - } - // Notify existence listeners - synchronized (mDockedStackExistsListeners) { - mDockedStackExistsListeners.removeIf(wf -> { - Consumer l = wf.get(); - if (l != null) l.accept(visible); - return l == null; - }); - } - } - } - - public void setMinimized(final boolean minimized) { - if (DEBUG) Slog.d(TAG, "posting ext setMinimized " + minimized + " vis:" + mVisible); - mMainExecutor.execute(() -> { - if (DEBUG) Slog.d(TAG, "run posted ext setMinimized " + minimized + " vis:" + mVisible); - if (!mVisible) { - return; - } - setHomeMinimized(minimized); - }); - } - - public void setHomeMinimized(final boolean minimized) { - if (DEBUG) { - Slog.d(TAG, "setHomeMinimized min:" + mMinimized + "->" + minimized + " hrsz:" - + mHomeStackResizable + " split:" + isDividerVisible()); - } - WindowContainerTransaction wct = new WindowContainerTransaction(); - final boolean minimizedChanged = mMinimized != minimized; - // Update minimized state - if (minimizedChanged) { - mMinimized = minimized; - } - // Always set this because we could be entering split when mMinimized is already true - wct.setFocusable(mSplits.mPrimary.token, !mMinimized); - - // Sync state to DividerView if it exists. - if (mView != null) { - final int displayId = mView.getDisplay() != null - ? mView.getDisplay().getDisplayId() : DEFAULT_DISPLAY; - // pause ime here (before updateMinimizedDockedStack) - if (mMinimized) { - mImePositionProcessor.pause(displayId); - } - if (minimizedChanged) { - // This conflicts with IME adjustment, so only call it when things change. - mView.setMinimizedDockStack(minimized, getAnimDuration(), mHomeStackResizable); - } - if (!mMinimized) { - // afterwards so it can end any animations started in view - mImePositionProcessor.resume(displayId); - } - } - updateTouchable(); - - // If we are only setting focusability, a sync transaction isn't necessary (in fact it - // can interrupt other animations), so see if it can be submitted on pending instead. - if (!mWindowManagerProxy.queueSyncTransactionIfWaiting(wct)) { - mTaskOrganizer.applyTransaction(wct); - } - } - - public void setAdjustedForIme(boolean adjustedForIme) { - if (mAdjustedForIme == adjustedForIme) { - return; - } - mAdjustedForIme = adjustedForIme; - updateTouchable(); - } - - public void updateTouchable() { - mWindowManager.setTouchable(!mAdjustedForIme); - } - - public void onUndockingTask() { - if (mView != null) { - mView.onUndockingTask(); - } - } - - public void onAppTransitionFinished() { - if (mView == null) { - return; - } - mForcedResizableController.onAppTransitionFinished(); - } - - public void dump(PrintWriter pw) { - pw.print(" mVisible="); pw.println(mVisible); - pw.print(" mMinimized="); pw.println(mMinimized); - pw.print(" mAdjustedForIme="); pw.println(mAdjustedForIme); - } - - public long getAnimDuration() { - float transitionScale = Settings.Global.getFloat(mContext.getContentResolver(), - Settings.Global.TRANSITION_ANIMATION_SCALE, - mContext.getResources().getFloat( - com.android.internal.R.dimen - .config_appTransitionAnimationDurationScaleDefault)); - final long transitionDuration = DEFAULT_APP_TRANSITION_DURATION; - return (long) (transitionDuration * transitionScale); - } - - public void registerInSplitScreenListener(Consumer listener) { - listener.accept(isDividerVisible()); - synchronized (mDockedStackExistsListeners) { - mDockedStackExistsListeners.add(new WeakReference<>(listener)); - } - } - - public void unregisterInSplitScreenListener(Consumer listener) { - synchronized (mDockedStackExistsListeners) { - for (int i = mDockedStackExistsListeners.size() - 1; i >= 0; i--) { - if (mDockedStackExistsListeners.get(i) == listener) { - mDockedStackExistsListeners.remove(i); - } - } - } - } - - public void registerBoundsChangeListener(BiConsumer listener) { - synchronized (mBoundsChangedListeners) { - mBoundsChangedListeners.add(new WeakReference<>(listener)); - } - } - - public boolean splitPrimaryTask() { - try { - if (ActivityTaskManager.getService().getLockTaskModeState() == LOCK_TASK_MODE_PINNED) { - return false; - } - } catch (RemoteException e) { - return false; - } - if (isSplitActive() || mSplits.mPrimary == null) { - return false; - } - - // Try fetching the top running task. - final List runningTasks = - ActivityTaskManager.getInstance().getTasks(1 /* maxNum */); - if (runningTasks == null || runningTasks.isEmpty()) { - return false; - } - // Note: The set of running tasks from the system is ordered by recency. - final RunningTaskInfo topRunningTask = runningTasks.get(0); - final int activityType = topRunningTask.getActivityType(); - if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) { - return false; - } - - if (!topRunningTask.supportsSplitScreenMultiWindow) { - Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text, - Toast.LENGTH_SHORT).show(); - return false; - } - - final WindowContainerTransaction wct = new WindowContainerTransaction(); - // Clear out current windowing mode before reparenting to split task. - wct.setWindowingMode(topRunningTask.token, WINDOWING_MODE_UNDEFINED); - wct.reparent(topRunningTask.token, mSplits.mPrimary.token, true /* onTop */); - mWindowManagerProxy.applySyncTransaction(wct); - return true; - } - - public void dismissSplitToPrimaryTask() { - startDismissSplit(true /* toPrimaryTask */); - } - - /** Notifies the bounds of split screen changed. */ - public void notifyBoundsChanged(Rect secondaryWindowBounds, Rect secondaryWindowInsets) { - synchronized (mBoundsChangedListeners) { - mBoundsChangedListeners.removeIf(wf -> { - BiConsumer l = wf.get(); - if (l != null) l.accept(secondaryWindowBounds, secondaryWindowInsets); - return l == null; - }); - } - } - - public void startEnterSplit() { - update(mDisplayController.getDisplayContext( - mContext.getDisplayId()).getResources().getConfiguration()); - // Set resizable directly here because applyEnterSplit already resizes home stack. - mHomeStackResizable = mWindowManagerProxy.applyEnterSplit(mSplits, - mRotateSplitLayout != null ? mRotateSplitLayout : mSplitLayout); - } - - public void prepareEnterSplitTransition(WindowContainerTransaction outWct) { - // Set resizable directly here because buildEnterSplit already resizes home stack. - mHomeStackResizable = mWindowManagerProxy.buildEnterSplit(outWct, mSplits, - mRotateSplitLayout != null ? mRotateSplitLayout : mSplitLayout); - } - - public void finishEnterSplitTransition(boolean minimized) { - update(mDisplayController.getDisplayContext( - mContext.getDisplayId()).getResources().getConfiguration()); - if (minimized) { - ensureMinimizedSplit(); - } else { - ensureNormalSplit(); - } - } - - public void startDismissSplit(boolean toPrimaryTask) { - startDismissSplit(toPrimaryTask, false /* snapped */); - } - - public void startDismissSplit(boolean toPrimaryTask, boolean snapped) { - if (Transitions.ENABLE_SHELL_TRANSITIONS) { - mSplits.getSplitTransitions().dismissSplit( - mSplits, mSplitLayout, !toPrimaryTask, snapped); - } else { - mWindowManagerProxy.applyDismissSplit(mSplits, mSplitLayout, !toPrimaryTask); - onDismissSplit(); - } - } - - public void onDismissSplit() { - updateVisibility(false /* visible */); - mMinimized = false; - // Resets divider bar position to undefined, so new divider bar will apply default position - // next time entering split mode. - mDividerState.mRatioPositionBeforeMinimized = 0; - removeDivider(); - mImePositionProcessor.reset(); - } - - public void ensureMinimizedSplit() { - setHomeMinimized(true /* minimized */); - if (mView != null && !isDividerVisible()) { - // Wasn't in split-mode yet, so enter now. - if (DEBUG) { - Slog.d(TAG, " entering split mode with minimized=true"); - } - updateVisibility(true /* visible */); - } - } - - public void ensureNormalSplit() { - setHomeMinimized(false /* minimized */); - if (mView != null && !isDividerVisible()) { - // Wasn't in split-mode, so enter now. - if (DEBUG) { - Slog.d(TAG, " enter split mode unminimized "); - } - updateVisibility(true /* visible */); - } - } - - public LegacySplitDisplayLayout getSplitLayout() { - return mSplitLayout; - } - - public WindowManagerProxy getWmProxy() { - return mWindowManagerProxy; - } - - public WindowContainerToken getSecondaryRoot() { - if (mSplits == null || mSplits.mSecondary == null) { - return null; - } - return mSplits.mSecondary.token; - } - - private class SplitScreenImpl implements LegacySplitScreen { - @Override - public boolean isMinimized() { - return mMinimized; - } - - @Override - public boolean isHomeStackResizable() { - return mHomeStackResizable; - } - - /** - * TODO: Remove usage from outside the shell. - */ - @Override - public DividerView getDividerView() { - return LegacySplitScreenController.this.getDividerView(); - } - - @Override - public boolean isDividerVisible() { - boolean[] result = new boolean[1]; - try { - mMainExecutor.executeBlocking(() -> { - result[0] = LegacySplitScreenController.this.isDividerVisible(); - }); - } catch (InterruptedException e) { - Slog.e(TAG, "Failed to get divider visible"); - } - return result[0]; - } - - @Override - public void onKeyguardVisibilityChanged(boolean isShowing) { - mMainExecutor.execute(() -> { - LegacySplitScreenController.this.onKeyguardVisibilityChanged(isShowing); - }); - } - - @Override - public void setMinimized(boolean minimized) { - mMainExecutor.execute(() -> { - LegacySplitScreenController.this.setMinimized(minimized); - }); - } - - @Override - public void onUndockingTask() { - mMainExecutor.execute(() -> { - LegacySplitScreenController.this.onUndockingTask(); - }); - } - - @Override - public void onAppTransitionFinished() { - mMainExecutor.execute(() -> { - LegacySplitScreenController.this.onAppTransitionFinished(); - }); - } - - @Override - public void registerInSplitScreenListener(Consumer listener) { - mMainExecutor.execute(() -> { - LegacySplitScreenController.this.registerInSplitScreenListener(listener); - }); - } - - @Override - public void unregisterInSplitScreenListener(Consumer listener) { - mMainExecutor.execute(() -> { - LegacySplitScreenController.this.unregisterInSplitScreenListener(listener); - }); - } - - @Override - public void registerBoundsChangeListener(BiConsumer listener) { - mMainExecutor.execute(() -> { - LegacySplitScreenController.this.registerBoundsChangeListener(listener); - }); - } - - @Override - public WindowContainerToken getSecondaryRoot() { - WindowContainerToken[] result = new WindowContainerToken[1]; - try { - mMainExecutor.executeBlocking(() -> { - result[0] = LegacySplitScreenController.this.getSecondaryRoot(); - }); - } catch (InterruptedException e) { - Slog.e(TAG, "Failed to get secondary root"); - } - return result[0]; - } - - @Override - public boolean splitPrimaryTask() { - boolean[] result = new boolean[1]; - try { - mMainExecutor.executeBlocking(() -> { - result[0] = LegacySplitScreenController.this.splitPrimaryTask(); - }); - } catch (InterruptedException e) { - Slog.e(TAG, "Failed to split primary task"); - } - return result[0]; - } - - @Override - public void dismissSplitToPrimaryTask() { - mMainExecutor.execute(() -> { - LegacySplitScreenController.this.dismissSplitToPrimaryTask(); - }); - } - - @Override - public void dump(PrintWriter pw) { - try { - mMainExecutor.executeBlocking(() -> { - LegacySplitScreenController.this.dump(pw); - }); - } catch (InterruptedException e) { - Slog.e(TAG, "Failed to dump LegacySplitScreenController in 2s"); - } - } - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java deleted file mode 100644 index d2f42c39acd5f..0000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Copyright (C) 2020 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.legacysplitscreen; - -import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; -import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; -import static android.view.Display.DEFAULT_DISPLAY; - -import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG; - -import android.app.ActivityManager.RunningTaskInfo; -import android.graphics.Point; -import android.graphics.Rect; -import android.util.Log; -import android.util.SparseArray; -import android.view.SurfaceControl; -import android.view.SurfaceSession; -import android.window.TaskOrganizer; - -import androidx.annotation.NonNull; - -import com.android.internal.protolog.common.ProtoLog; -import com.android.wm.shell.ShellTaskOrganizer; -import com.android.wm.shell.common.SurfaceUtils; -import com.android.wm.shell.common.SyncTransactionQueue; -import com.android.wm.shell.transition.Transitions; - -import java.io.PrintWriter; -import java.util.ArrayList; - -class LegacySplitScreenTaskListener implements ShellTaskOrganizer.TaskListener { - private static final String TAG = LegacySplitScreenTaskListener.class.getSimpleName(); - private static final boolean DEBUG = LegacySplitScreenController.DEBUG; - - private final ShellTaskOrganizer mTaskOrganizer; - private final SyncTransactionQueue mSyncQueue; - private final SparseArray mLeashByTaskId = new SparseArray<>(); - - // TODO(shell-transitions): Remove when switched to shell-transitions. - private final SparseArray mPositionByTaskId = new SparseArray<>(); - - RunningTaskInfo mPrimary; - RunningTaskInfo mSecondary; - SurfaceControl mPrimarySurface; - SurfaceControl mSecondarySurface; - SurfaceControl mPrimaryDim; - SurfaceControl mSecondaryDim; - Rect mHomeBounds = new Rect(); - final LegacySplitScreenController mSplitScreenController; - private boolean mSplitScreenSupported = false; - - final SurfaceSession mSurfaceSession = new SurfaceSession(); - - private final LegacySplitScreenTransitions mSplitTransitions; - - LegacySplitScreenTaskListener(LegacySplitScreenController splitScreenController, - ShellTaskOrganizer shellTaskOrganizer, - Transitions transitions, - SyncTransactionQueue syncQueue) { - mSplitScreenController = splitScreenController; - mTaskOrganizer = shellTaskOrganizer; - mSplitTransitions = new LegacySplitScreenTransitions(splitScreenController.mTransactionPool, - transitions, mSplitScreenController, this); - transitions.addHandler(mSplitTransitions); - mSyncQueue = syncQueue; - } - - void init() { - synchronized (this) { - try { - mTaskOrganizer.createRootTask( - DEFAULT_DISPLAY, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, this); - mTaskOrganizer.createRootTask( - DEFAULT_DISPLAY, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, this); - } catch (Exception e) { - // teardown to prevent callbacks - mTaskOrganizer.removeListener(this); - throw e; - } - } - } - - boolean isSplitScreenSupported() { - return mSplitScreenSupported; - } - - SurfaceControl.Transaction getTransaction() { - return mSplitScreenController.mTransactionPool.acquire(); - } - - void releaseTransaction(SurfaceControl.Transaction t) { - mSplitScreenController.mTransactionPool.release(t); - } - - TaskOrganizer getTaskOrganizer() { - return mTaskOrganizer; - } - - LegacySplitScreenTransitions getSplitTransitions() { - return mSplitTransitions; - } - - @Override - public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { - synchronized (this) { - if (taskInfo.hasParentTask()) { - handleChildTaskAppeared(taskInfo, leash); - return; - } - - final int winMode = taskInfo.getWindowingMode(); - if (winMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { - ProtoLog.v(WM_SHELL_TASK_ORG, - "%s onTaskAppeared Primary taskId=%d", TAG, taskInfo.taskId); - mPrimary = taskInfo; - mPrimarySurface = leash; - } else if (winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) { - ProtoLog.v(WM_SHELL_TASK_ORG, - "%s onTaskAppeared Secondary taskId=%d", TAG, taskInfo.taskId); - mSecondary = taskInfo; - mSecondarySurface = leash; - } else { - ProtoLog.v(WM_SHELL_TASK_ORG, "%s onTaskAppeared unknown taskId=%d winMode=%d", - TAG, taskInfo.taskId, winMode); - } - - if (!mSplitScreenSupported && mPrimarySurface != null && mSecondarySurface != null) { - mSplitScreenSupported = true; - mSplitScreenController.onSplitScreenSupported(); - ProtoLog.v(WM_SHELL_TASK_ORG, "%s onTaskAppeared Supported", TAG); - - // Initialize dim surfaces: - SurfaceControl.Transaction t = getTransaction(); - mPrimaryDim = SurfaceUtils.makeDimLayer( - t, mPrimarySurface, "Primary Divider Dim", mSurfaceSession); - mSecondaryDim = SurfaceUtils.makeDimLayer( - t, mSecondarySurface, "Secondary Divider Dim", mSurfaceSession); - t.apply(); - releaseTransaction(t); - } - } - } - - @Override - public void onTaskVanished(RunningTaskInfo taskInfo) { - synchronized (this) { - mPositionByTaskId.remove(taskInfo.taskId); - if (taskInfo.hasParentTask()) { - mLeashByTaskId.remove(taskInfo.taskId); - return; - } - - final boolean isPrimaryTask = mPrimary != null - && taskInfo.token.equals(mPrimary.token); - final boolean isSecondaryTask = mSecondary != null - && taskInfo.token.equals(mSecondary.token); - - if (mSplitScreenSupported && (isPrimaryTask || isSecondaryTask)) { - mSplitScreenSupported = false; - - SurfaceControl.Transaction t = getTransaction(); - t.remove(mPrimaryDim); - t.remove(mSecondaryDim); - t.remove(mPrimarySurface); - t.remove(mSecondarySurface); - t.apply(); - releaseTransaction(t); - - mSplitScreenController.onTaskVanished(); - } - } - } - - @Override - public void onTaskInfoChanged(RunningTaskInfo taskInfo) { - if (taskInfo.displayId != DEFAULT_DISPLAY) { - return; - } - synchronized (this) { - if (!taskInfo.supportsMultiWindow) { - if (mSplitScreenController.isDividerVisible()) { - // Dismiss the split screen if the task no longer supports multi window. - if (taskInfo.taskId == mPrimary.taskId - || taskInfo.parentTaskId == mPrimary.taskId) { - // If the primary is focused, dismiss to primary. - mSplitScreenController - .startDismissSplit(taskInfo.isFocused /* toPrimaryTask */); - } else { - // If the secondary is not focused, dismiss to primary. - mSplitScreenController - .startDismissSplit(!taskInfo.isFocused /* toPrimaryTask */); - } - } - return; - } - if (taskInfo.hasParentTask()) { - // changed messages are noisy since it reports on every ensureVisibility. This - // conflicts with legacy app-transitions which "swaps" the position to a - // leash. For now, only update when position actually changes to avoid - // poorly-timed duplicate calls. - if (taskInfo.positionInParent.equals(mPositionByTaskId.get(taskInfo.taskId))) { - return; - } - handleChildTaskChanged(taskInfo); - } else { - handleTaskInfoChanged(taskInfo); - } - mPositionByTaskId.put(taskInfo.taskId, new Point(taskInfo.positionInParent)); - } - } - - private void handleChildTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { - mLeashByTaskId.put(taskInfo.taskId, leash); - mPositionByTaskId.put(taskInfo.taskId, new Point(taskInfo.positionInParent)); - if (Transitions.ENABLE_SHELL_TRANSITIONS) return; - updateChildTaskSurface(taskInfo, leash, true /* firstAppeared */); - } - - private void handleChildTaskChanged(RunningTaskInfo taskInfo) { - if (Transitions.ENABLE_SHELL_TRANSITIONS) return; - final SurfaceControl leash = mLeashByTaskId.get(taskInfo.taskId); - updateChildTaskSurface(taskInfo, leash, false /* firstAppeared */); - } - - private void updateChildTaskSurface( - RunningTaskInfo taskInfo, SurfaceControl leash, boolean firstAppeared) { - final Point taskPositionInParent = taskInfo.positionInParent; - mSyncQueue.runInSync(t -> { - t.setWindowCrop(leash, null); - t.setPosition(leash, taskPositionInParent.x, taskPositionInParent.y); - if (firstAppeared && !Transitions.ENABLE_SHELL_TRANSITIONS) { - t.setAlpha(leash, 1f); - t.setMatrix(leash, 1, 0, 0, 1); - t.show(leash); - } - }); - } - - /** - * This is effectively a finite state machine which moves between the various split-screen - * presentations based on the contents of the split regions. - */ - private void handleTaskInfoChanged(RunningTaskInfo info) { - if (!mSplitScreenSupported) { - // This shouldn't happen; but apparently there is a chance that SysUI crashes without - // system server receiving binder-death (or maybe it receives binder-death too late?). - // In this situation, when sys-ui restarts, the split root-tasks will still exist so - // there is a small window of time during init() where WM might send messages here - // before init() fails. So, avoid a cycle of crashes by returning early. - Log.e(TAG, "Got handleTaskInfoChanged when not initialized: " + info); - return; - } - final boolean secondaryImpliedMinimize = mSecondary.topActivityType == ACTIVITY_TYPE_HOME - || (mSecondary.topActivityType == ACTIVITY_TYPE_RECENTS - && mSplitScreenController.isHomeStackResizable()); - final boolean primaryWasEmpty = mPrimary.topActivityType == ACTIVITY_TYPE_UNDEFINED; - final boolean secondaryWasEmpty = mSecondary.topActivityType == ACTIVITY_TYPE_UNDEFINED; - if (info.token.asBinder() == mPrimary.token.asBinder()) { - mPrimary = info; - } else if (info.token.asBinder() == mSecondary.token.asBinder()) { - mSecondary = info; - } - if (DEBUG) { - Log.d(TAG, "onTaskInfoChanged " + mPrimary + " " + mSecondary); - } - if (Transitions.ENABLE_SHELL_TRANSITIONS) return; - final boolean primaryIsEmpty = mPrimary.topActivityType == ACTIVITY_TYPE_UNDEFINED; - final boolean secondaryIsEmpty = mSecondary.topActivityType == ACTIVITY_TYPE_UNDEFINED; - final boolean secondaryImpliesMinimize = mSecondary.topActivityType == ACTIVITY_TYPE_HOME - || (mSecondary.topActivityType == ACTIVITY_TYPE_RECENTS - && mSplitScreenController.isHomeStackResizable()); - if (primaryIsEmpty == primaryWasEmpty && secondaryWasEmpty == secondaryIsEmpty - && secondaryImpliedMinimize == secondaryImpliesMinimize) { - // No relevant changes - return; - } - if (primaryIsEmpty || secondaryIsEmpty) { - // At-least one of the splits is empty which means we are currently transitioning - // into or out-of split-screen mode. - if (DEBUG) { - Log.d(TAG, " at-least one split empty " + mPrimary.topActivityType - + " " + mSecondary.topActivityType); - } - if (mSplitScreenController.isDividerVisible()) { - // Was in split-mode, which means we are leaving split, so continue that. - // This happens when the stack in the primary-split is dismissed. - if (DEBUG) { - Log.d(TAG, " was in split, so this means leave it " - + mPrimary.topActivityType + " " + mSecondary.topActivityType); - } - mSplitScreenController.startDismissSplit(false /* toPrimaryTask */); - } else if (!primaryIsEmpty && primaryWasEmpty && secondaryWasEmpty) { - // Wasn't in split-mode (both were empty), but now that the primary split is - // populated, we should fully enter split by moving everything else into secondary. - // This just tells window-manager to reparent things, the UI will respond - // when it gets new task info for the secondary split. - if (DEBUG) { - Log.d(TAG, " was not in split, but primary is populated, so enter it"); - } - mSplitScreenController.startEnterSplit(); - } - } else if (secondaryImpliesMinimize) { - // Workaround for b/172686383, we can't rely on the sync bounds change transaction for - // the home task to finish before the last updateChildTaskSurface() call even if it's - // queued on the sync transaction queue, so ensure that the home task surface is updated - // again before we minimize - final ArrayList tasks = new ArrayList<>(); - mSplitScreenController.getWmProxy().getHomeAndRecentsTasks(tasks, - mSplitScreenController.getSecondaryRoot()); - for (int i = 0; i < tasks.size(); i++) { - final RunningTaskInfo taskInfo = tasks.get(i); - final SurfaceControl leash = mLeashByTaskId.get(taskInfo.taskId); - if (leash != null) { - updateChildTaskSurface(taskInfo, leash, false /* firstAppeared */); - } - } - - // Both splits are populated but the secondary split has a home/recents stack on top, - // so enter minimized mode. - mSplitScreenController.ensureMinimizedSplit(); - } else { - // Both splits are populated by normal activities, so make sure we aren't minimized. - mSplitScreenController.ensureNormalSplit(); - } - } - - @Override - public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) { - b.setParent(findTaskSurface(taskId)); - } - - @Override - public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc, - SurfaceControl.Transaction t) { - t.reparent(sc, findTaskSurface(taskId)); - } - - private SurfaceControl findTaskSurface(int taskId) { - if (!mLeashByTaskId.contains(taskId)) { - throw new IllegalArgumentException("There is no surface for taskId=" + taskId); - } - return mLeashByTaskId.get(taskId); - } - - @Override - public void dump(@NonNull PrintWriter pw, String prefix) { - final String innerPrefix = prefix + " "; - final String childPrefix = innerPrefix + " "; - pw.println(prefix + this); - pw.println(innerPrefix + "mSplitScreenSupported=" + mSplitScreenSupported); - if (mPrimary != null) pw.println(innerPrefix + "mPrimary.taskId=" + mPrimary.taskId); - if (mSecondary != null) pw.println(innerPrefix + "mSecondary.taskId=" + mSecondary.taskId); - } - - @Override - public String toString() { - return TAG; - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTransitions.java deleted file mode 100644 index b1fa2ac25fe77..0000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTransitions.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright (C) 2020 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.legacysplitscreen; - -import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; -import static android.view.WindowManager.TRANSIT_CHANGE; -import static android.view.WindowManager.TRANSIT_CLOSE; -import static android.view.WindowManager.TRANSIT_FIRST_CUSTOM; -import static android.view.WindowManager.TRANSIT_OPEN; -import static android.view.WindowManager.TRANSIT_TO_BACK; -import static android.view.WindowManager.TRANSIT_TO_FRONT; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.ActivityManager; -import android.app.WindowConfiguration; -import android.graphics.Rect; -import android.os.IBinder; -import android.view.SurfaceControl; -import android.view.WindowManager; -import android.window.TransitionInfo; -import android.window.TransitionRequestInfo; -import android.window.WindowContainerTransaction; - -import com.android.wm.shell.common.TransactionPool; -import com.android.wm.shell.common.annotations.ExternalThread; -import com.android.wm.shell.transition.Transitions; - -import java.util.ArrayList; - -/** Plays transition animations for split-screen */ -public class LegacySplitScreenTransitions implements Transitions.TransitionHandler { - private static final String TAG = "SplitScreenTransitions"; - - public static final int TRANSIT_SPLIT_DISMISS_SNAP = TRANSIT_FIRST_CUSTOM + 10; - - private final TransactionPool mTransactionPool; - private final Transitions mTransitions; - private final LegacySplitScreenController mSplitScreen; - private final LegacySplitScreenTaskListener mListener; - - private IBinder mPendingDismiss = null; - private boolean mDismissFromSnap = false; - private IBinder mPendingEnter = null; - private IBinder mAnimatingTransition = null; - - /** Keeps track of currently running animations */ - private final ArrayList mAnimations = new ArrayList<>(); - - private Transitions.TransitionFinishCallback mFinishCallback = null; - private SurfaceControl.Transaction mFinishTransaction; - - LegacySplitScreenTransitions(@NonNull TransactionPool pool, @NonNull Transitions transitions, - @NonNull LegacySplitScreenController splitScreen, - @NonNull LegacySplitScreenTaskListener listener) { - mTransactionPool = pool; - mTransitions = transitions; - mSplitScreen = splitScreen; - mListener = listener; - } - - @Override - public WindowContainerTransaction handleRequest(@NonNull IBinder transition, - @Nullable TransitionRequestInfo request) { - WindowContainerTransaction out = null; - final ActivityManager.RunningTaskInfo triggerTask = request.getTriggerTask(); - final @WindowManager.TransitionType int type = request.getType(); - if (mSplitScreen.isDividerVisible()) { - // try to handle everything while in split-screen - out = new WindowContainerTransaction(); - if (triggerTask != null) { - final boolean shouldDismiss = - // if we close the primary-docked task, then leave split-screen since there - // is nothing behind it. - ((type == TRANSIT_CLOSE || type == TRANSIT_TO_BACK) - && triggerTask.parentTaskId == mListener.mPrimary.taskId) - // if an activity that is not supported in multi window mode is launched, - // we also need to leave split-screen. - || ((type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT) - && !triggerTask.supportsMultiWindow); - // In both cases, dismiss the primary - if (shouldDismiss) { - WindowManagerProxy.buildDismissSplit(out, mListener, - mSplitScreen.getSplitLayout(), true /* dismiss */); - if (type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT) { - out.reorder(triggerTask.token, true /* onTop */); - } - mPendingDismiss = transition; - } - } - } else if (triggerTask != null) { - // Not in split mode, so look for an open with a trigger task. - if ((type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT) - && triggerTask.configuration.windowConfiguration.getWindowingMode() - == WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { - out = new WindowContainerTransaction(); - mSplitScreen.prepareEnterSplitTransition(out); - mPendingEnter = transition; - } - } - return out; - } - - // TODO(shell-transitions): real animations - private void startExampleAnimation(@NonNull SurfaceControl leash, boolean show) { - final float end = show ? 1.f : 0.f; - final float start = 1.f - end; - final SurfaceControl.Transaction transaction = mTransactionPool.acquire(); - final ValueAnimator va = ValueAnimator.ofFloat(start, end); - va.setDuration(500); - va.addUpdateListener(animation -> { - float fraction = animation.getAnimatedFraction(); - transaction.setAlpha(leash, start * (1.f - fraction) + end * fraction); - transaction.apply(); - }); - final Runnable finisher = () -> { - transaction.setAlpha(leash, end); - transaction.apply(); - mTransactionPool.release(transaction); - mTransitions.getMainExecutor().execute(() -> { - mAnimations.remove(va); - onFinish(); - }); - }; - va.addListener(new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { } - - @Override - public void onAnimationEnd(Animator animation) { - finisher.run(); - } - - @Override - public void onAnimationCancel(Animator animation) { - finisher.run(); - } - - @Override - public void onAnimationRepeat(Animator animation) { } - }); - mAnimations.add(va); - mTransitions.getAnimExecutor().execute(va::start); - } - - // TODO(shell-transitions): real animations - private void startExampleResizeAnimation(@NonNull SurfaceControl leash, - @NonNull Rect startBounds, @NonNull Rect endBounds) { - final SurfaceControl.Transaction transaction = mTransactionPool.acquire(); - final ValueAnimator va = ValueAnimator.ofFloat(0.f, 1.f); - va.setDuration(500); - va.addUpdateListener(animation -> { - float fraction = animation.getAnimatedFraction(); - transaction.setWindowCrop(leash, - (int) (startBounds.width() * (1.f - fraction) + endBounds.width() * fraction), - (int) (startBounds.height() * (1.f - fraction) - + endBounds.height() * fraction)); - transaction.setPosition(leash, - startBounds.left * (1.f - fraction) + endBounds.left * fraction, - startBounds.top * (1.f - fraction) + endBounds.top * fraction); - transaction.apply(); - }); - final Runnable finisher = () -> { - transaction.setWindowCrop(leash, 0, 0); - transaction.setPosition(leash, endBounds.left, endBounds.top); - transaction.apply(); - mTransactionPool.release(transaction); - mTransitions.getMainExecutor().execute(() -> { - mAnimations.remove(va); - onFinish(); - }); - }; - va.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - finisher.run(); - } - - @Override - public void onAnimationCancel(Animator animation) { - finisher.run(); - } - }); - mAnimations.add(va); - mTransitions.getAnimExecutor().execute(va::start); - } - - @Override - public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, - @NonNull SurfaceControl.Transaction startTransaction, - @NonNull SurfaceControl.Transaction finishTransaction, - @NonNull Transitions.TransitionFinishCallback finishCallback) { - if (transition != mPendingDismiss && transition != mPendingEnter) { - // If we're not in split-mode, just abort - if (!mSplitScreen.isDividerVisible()) return false; - // Check to see if HOME is involved - for (int i = info.getChanges().size() - 1; i >= 0; --i) { - final TransitionInfo.Change change = info.getChanges().get(i); - if (change.getTaskInfo() == null - || change.getTaskInfo().getActivityType() != ACTIVITY_TYPE_HOME) continue; - if (change.getMode() == TRANSIT_OPEN || change.getMode() == TRANSIT_TO_FRONT) { - mSplitScreen.ensureMinimizedSplit(); - } else if (change.getMode() == TRANSIT_CLOSE - || change.getMode() == TRANSIT_TO_BACK) { - mSplitScreen.ensureNormalSplit(); - } - } - // Use normal animations. - return false; - } - - mFinishCallback = finishCallback; - mFinishTransaction = mTransactionPool.acquire(); - mAnimatingTransition = transition; - - // Play fade animations - for (int i = info.getChanges().size() - 1; i >= 0; --i) { - final TransitionInfo.Change change = info.getChanges().get(i); - final SurfaceControl leash = change.getLeash(); - final int mode = info.getChanges().get(i).getMode(); - - if (mode == TRANSIT_CHANGE) { - if (change.getParent() != null) { - // This is probably reparented, so we want the parent to be immediately visible - final TransitionInfo.Change parentChange = info.getChange(change.getParent()); - startTransaction.show(parentChange.getLeash()); - startTransaction.setAlpha(parentChange.getLeash(), 1.f); - // and then animate this layer outside the parent (since, for example, this is - // the home task animating from fullscreen to part-screen). - startTransaction.reparent(leash, info.getRootLeash()); - startTransaction.setLayer(leash, info.getChanges().size() - i); - // build the finish reparent/reposition - mFinishTransaction.reparent(leash, parentChange.getLeash()); - mFinishTransaction.setPosition(leash, - change.getEndRelOffset().x, change.getEndRelOffset().y); - } - // TODO(shell-transitions): screenshot here - final Rect startBounds = new Rect(change.getStartAbsBounds()); - final boolean isHome = change.getTaskInfo() != null - && change.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME; - if (mPendingDismiss == transition && mDismissFromSnap && !isHome) { - // Home is special since it doesn't move during fling. Everything else, though, - // when dismissing from snap, the top/left is at 0,0. - startBounds.offsetTo(0, 0); - } - final Rect endBounds = new Rect(change.getEndAbsBounds()); - startBounds.offset(-info.getRootOffset().x, -info.getRootOffset().y); - endBounds.offset(-info.getRootOffset().x, -info.getRootOffset().y); - startExampleResizeAnimation(leash, startBounds, endBounds); - } - if (change.getParent() != null) { - continue; - } - - if (transition == mPendingEnter - && mListener.mPrimary.token.equals(change.getContainer()) - || mListener.mSecondary.token.equals(change.getContainer())) { - startTransaction.setWindowCrop(leash, change.getStartAbsBounds().width(), - change.getStartAbsBounds().height()); - if (mListener.mPrimary.token.equals(change.getContainer())) { - // Move layer to top since we want it above the oversized home task during - // animation even though home task is on top in hierarchy. - startTransaction.setLayer(leash, info.getChanges().size() + 1); - } - } - boolean isOpening = Transitions.isOpeningType(info.getType()); - if (isOpening && (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) { - // fade in - startExampleAnimation(leash, true /* show */); - } else if (!isOpening && (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK)) { - // fade out - if (transition == mPendingDismiss && mDismissFromSnap) { - // Dismissing via snap-to-top/bottom means that the dismissed task is already - // not-visible (usually cropped to oblivion) so immediately set its alpha to 0 - // and don't animate it so it doesn't pop-in when reparented. - startTransaction.setAlpha(leash, 0.f); - } else { - startExampleAnimation(leash, false /* show */); - } - } - } - if (transition == mPendingEnter) { - // If entering, check if we should enter into minimized or normal split - boolean homeIsVisible = false; - for (int i = info.getChanges().size() - 1; i >= 0; --i) { - final TransitionInfo.Change change = info.getChanges().get(i); - if (change.getTaskInfo() == null - || change.getTaskInfo().getActivityType() != ACTIVITY_TYPE_HOME) { - continue; - } - homeIsVisible = change.getMode() == TRANSIT_OPEN - || change.getMode() == TRANSIT_TO_FRONT - || change.getMode() == TRANSIT_CHANGE; - break; - } - mSplitScreen.finishEnterSplitTransition(homeIsVisible); - } - startTransaction.apply(); - onFinish(); - return true; - } - - @ExternalThread - void dismissSplit(LegacySplitScreenTaskListener tiles, LegacySplitDisplayLayout layout, - boolean dismissOrMaximize, boolean snapped) { - final WindowContainerTransaction wct = new WindowContainerTransaction(); - WindowManagerProxy.buildDismissSplit(wct, tiles, layout, dismissOrMaximize); - mTransitions.getMainExecutor().execute(() -> { - mDismissFromSnap = snapped; - mPendingDismiss = mTransitions.startTransition(TRANSIT_SPLIT_DISMISS_SNAP, wct, this); - }); - } - - private void onFinish() { - if (!mAnimations.isEmpty()) return; - mFinishTransaction.apply(); - mTransactionPool.release(mFinishTransaction); - mFinishTransaction = null; - mFinishCallback.onTransitionFinished(null /* wct */, null /* wctCB */); - mFinishCallback = null; - if (mAnimatingTransition == mPendingEnter) { - mPendingEnter = null; - } - if (mAnimatingTransition == mPendingDismiss) { - mSplitScreen.onDismissSplit(); - mPendingDismiss = null; - } - mDismissFromSnap = false; - mAnimatingTransition = null; - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/MinimizedDockShadow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/MinimizedDockShadow.java deleted file mode 100644 index 1e9223cbe3e22..0000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/MinimizedDockShadow.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2016 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.legacysplitscreen; - -import android.annotation.Nullable; -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.LinearGradient; -import android.graphics.Paint; -import android.graphics.Shader; -import android.util.AttributeSet; -import android.view.View; -import android.view.WindowManager; - -import com.android.wm.shell.R; - -/** - * Shadow for the minimized dock state on homescreen. - */ -public class MinimizedDockShadow extends View { - - private final Paint mShadowPaint = new Paint(); - - private int mDockSide = WindowManager.DOCKED_INVALID; - - public MinimizedDockShadow(Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - } - - void setDockSide(int dockSide) { - if (dockSide != mDockSide) { - mDockSide = dockSide; - updatePaint(getLeft(), getTop(), getRight(), getBottom()); - invalidate(); - } - } - - private void updatePaint(int left, int top, int right, int bottom) { - int startColor = mContext.getResources().getColor( - R.color.minimize_dock_shadow_start, null); - int endColor = mContext.getResources().getColor( - R.color.minimize_dock_shadow_end, null); - final int middleColor = Color.argb( - (Color.alpha(startColor) + Color.alpha(endColor)) / 2, 0, 0, 0); - final int quarter = Color.argb( - (int) (Color.alpha(startColor) * 0.25f + Color.alpha(endColor) * 0.75f), - 0, 0, 0); - if (mDockSide == WindowManager.DOCKED_TOP) { - mShadowPaint.setShader(new LinearGradient( - 0, 0, 0, bottom - top, - new int[] { startColor, middleColor, quarter, endColor }, - new float[] { 0f, 0.35f, 0.6f, 1f }, Shader.TileMode.CLAMP)); - } else if (mDockSide == WindowManager.DOCKED_LEFT) { - mShadowPaint.setShader(new LinearGradient( - 0, 0, right - left, 0, - new int[] { startColor, middleColor, quarter, endColor }, - new float[] { 0f, 0.35f, 0.6f, 1f }, Shader.TileMode.CLAMP)); - } else if (mDockSide == WindowManager.DOCKED_RIGHT) { - mShadowPaint.setShader(new LinearGradient( - right - left, 0, 0, 0, - new int[] { startColor, middleColor, quarter, endColor }, - new float[] { 0f, 0.35f, 0.6f, 1f }, Shader.TileMode.CLAMP)); - } - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - if (changed) { - updatePaint(left, top, right, bottom); - invalidate(); - } - } - - @Override - protected void onDraw(Canvas canvas) { - canvas.drawRect(0, 0, getWidth(), getHeight(), mShadowPaint); - } - - @Override - public boolean hasOverlappingRendering() { - return false; - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java deleted file mode 100644 index e42e43bbc2be3..0000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java +++ /dev/null @@ -1,386 +0,0 @@ -/* - * Copyright (C) 2015 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.legacysplitscreen; - -import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; -import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; -import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; -import static android.content.res.Configuration.ORIENTATION_UNDEFINED; -import static android.view.Display.DEFAULT_DISPLAY; - -import android.annotation.NonNull; -import android.app.ActivityManager; -import android.app.ActivityTaskManager; -import android.graphics.Rect; -import android.os.RemoteException; -import android.util.Log; -import android.view.Display; -import android.view.SurfaceControl; -import android.view.WindowManagerGlobal; -import android.window.TaskOrganizer; -import android.window.WindowContainerToken; -import android.window.WindowContainerTransaction; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.util.ArrayUtils; -import com.android.wm.shell.common.SyncTransactionQueue; -import com.android.wm.shell.transition.Transitions; - -import java.util.ArrayList; -import java.util.List; - -/** - * Proxy to simplify calls into window manager/activity manager - */ -class WindowManagerProxy { - - private static final String TAG = "WindowManagerProxy"; - private static final int[] HOME_AND_RECENTS = {ACTIVITY_TYPE_HOME, ACTIVITY_TYPE_RECENTS}; - private static final int[] CONTROLLED_ACTIVITY_TYPES = { - ACTIVITY_TYPE_STANDARD, - ACTIVITY_TYPE_HOME, - ACTIVITY_TYPE_RECENTS, - ACTIVITY_TYPE_UNDEFINED - }; - private static final int[] CONTROLLED_WINDOWING_MODES = { - WINDOWING_MODE_FULLSCREEN, - WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, - WINDOWING_MODE_UNDEFINED - }; - - @GuardedBy("mDockedRect") - private final Rect mDockedRect = new Rect(); - - private final Rect mTmpRect1 = new Rect(); - - @GuardedBy("mDockedRect") - private final Rect mTouchableRegion = new Rect(); - - private final SyncTransactionQueue mSyncTransactionQueue; - private final TaskOrganizer mTaskOrganizer; - - WindowManagerProxy(SyncTransactionQueue syncQueue, TaskOrganizer taskOrganizer) { - mSyncTransactionQueue = syncQueue; - mTaskOrganizer = taskOrganizer; - } - - void dismissOrMaximizeDocked(final LegacySplitScreenTaskListener tiles, - LegacySplitDisplayLayout layout, final boolean dismissOrMaximize) { - if (Transitions.ENABLE_SHELL_TRANSITIONS) { - tiles.mSplitScreenController.startDismissSplit(!dismissOrMaximize, true /* snapped */); - } else { - applyDismissSplit(tiles, layout, dismissOrMaximize); - } - } - - public void setResizing(final boolean resizing) { - try { - ActivityTaskManager.getService().setSplitScreenResizing(resizing); - } catch (RemoteException e) { - Log.w(TAG, "Error calling setDockedStackResizing: " + e); - } - } - - /** Sets a touch region */ - public void setTouchRegion(Rect region) { - try { - synchronized (mDockedRect) { - mTouchableRegion.set(region); - } - WindowManagerGlobal.getWindowManagerService().setDockedTaskDividerTouchRegion( - mTouchableRegion); - } catch (RemoteException e) { - Log.w(TAG, "Failed to set touchable region: " + e); - } - } - - void applyResizeSplits(int position, LegacySplitDisplayLayout splitLayout) { - WindowContainerTransaction t = new WindowContainerTransaction(); - splitLayout.resizeSplits(position, t); - applySyncTransaction(t); - } - - boolean getHomeAndRecentsTasks(List out, - WindowContainerToken parent) { - boolean resizable = false; - List rootTasks = parent == null - ? mTaskOrganizer.getRootTasks(Display.DEFAULT_DISPLAY, HOME_AND_RECENTS) - : mTaskOrganizer.getChildTasks(parent, HOME_AND_RECENTS); - for (int i = 0, n = rootTasks.size(); i < n; ++i) { - final ActivityManager.RunningTaskInfo ti = rootTasks.get(i); - out.add(ti); - if (ti.topActivityType == ACTIVITY_TYPE_HOME) { - resizable = ti.isResizeable; - } - } - return resizable; - } - - /** - * Assign a fixed override-bounds to home tasks that reflect their geometry while the primary - * split is minimized. This actually "sticks out" of the secondary split area, but when in - * minimized mode, the secondary split gets a 'negative' crop to expose it. - */ - boolean applyHomeTasksMinimized(LegacySplitDisplayLayout layout, WindowContainerToken parent, - @NonNull WindowContainerTransaction wct) { - // Resize the home/recents stacks to the larger minimized-state size - final Rect homeBounds; - final ArrayList homeStacks = new ArrayList<>(); - boolean isHomeResizable = getHomeAndRecentsTasks(homeStacks, parent); - if (isHomeResizable) { - homeBounds = layout.calcResizableMinimizedHomeStackBounds(); - } else { - // home is not resizable, so lock it to its inherent orientation size. - homeBounds = new Rect(0, 0, 0, 0); - for (int i = homeStacks.size() - 1; i >= 0; --i) { - if (homeStacks.get(i).topActivityType == ACTIVITY_TYPE_HOME) { - final int orient = homeStacks.get(i).configuration.orientation; - final boolean displayLandscape = layout.mDisplayLayout.isLandscape(); - final boolean isLandscape = orient == ORIENTATION_LANDSCAPE - || (orient == ORIENTATION_UNDEFINED && displayLandscape); - homeBounds.right = isLandscape == displayLandscape - ? layout.mDisplayLayout.width() : layout.mDisplayLayout.height(); - homeBounds.bottom = isLandscape == displayLandscape - ? layout.mDisplayLayout.height() : layout.mDisplayLayout.width(); - break; - } - } - } - for (int i = homeStacks.size() - 1; i >= 0; --i) { - // For non-resizable homes, the minimized size is actually the fullscreen-size. As a - // result, we don't minimize for recents since it only shows half-size screenshots. - if (!isHomeResizable) { - if (homeStacks.get(i).topActivityType == ACTIVITY_TYPE_RECENTS) { - continue; - } - wct.setWindowingMode(homeStacks.get(i).token, WINDOWING_MODE_FULLSCREEN); - } - wct.setBounds(homeStacks.get(i).token, homeBounds); - } - layout.mTiles.mHomeBounds.set(homeBounds); - return isHomeResizable; - } - - /** @see #buildEnterSplit */ - boolean applyEnterSplit(LegacySplitScreenTaskListener tiles, LegacySplitDisplayLayout layout) { - // Set launchtile first so that any stack created after - // getAllRootTaskInfos and before reparent (even if unlikely) are placed - // correctly. - WindowContainerTransaction wct = new WindowContainerTransaction(); - wct.setLaunchRoot(tiles.mSecondary.token, CONTROLLED_WINDOWING_MODES, - CONTROLLED_ACTIVITY_TYPES); - final boolean isHomeResizable = buildEnterSplit(wct, tiles, layout); - applySyncTransaction(wct); - return isHomeResizable; - } - - /** - * Finishes entering split-screen by reparenting all FULLSCREEN tasks into the secondary split. - * This assumes there is already something in the primary split since that is usually what - * triggers a call to this. In the same transaction, this overrides the home task bounds via - * {@link #applyHomeTasksMinimized}. - * - * @return whether the home stack is resizable - */ - boolean buildEnterSplit(WindowContainerTransaction outWct, LegacySplitScreenTaskListener tiles, - LegacySplitDisplayLayout layout) { - List rootTasks = - mTaskOrganizer.getRootTasks(DEFAULT_DISPLAY, null /* activityTypes */); - if (rootTasks.isEmpty()) { - return false; - } - ActivityManager.RunningTaskInfo topHomeTask = null; - for (int i = rootTasks.size() - 1; i >= 0; --i) { - final ActivityManager.RunningTaskInfo rootTask = rootTasks.get(i); - // Check whether the task can be moved to split secondary. - if (!rootTask.supportsMultiWindow && rootTask.topActivityType != ACTIVITY_TYPE_HOME) { - continue; - } - // Only move split controlling tasks to split secondary. - final int windowingMode = rootTask.getWindowingMode(); - if (!ArrayUtils.contains(CONTROLLED_WINDOWING_MODES, windowingMode) - || !ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, rootTask.getActivityType()) - // Excludes split screen secondary due to it's the root we're reparenting to. - || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) { - continue; - } - // Since this iterates from bottom to top, update topHomeTask for every fullscreen task - // so it will be left with the status of the top one. - topHomeTask = isHomeOrRecentTask(rootTask) ? rootTask : null; - outWct.reparent(rootTask.token, tiles.mSecondary.token, true /* onTop */); - } - // Move the secondary split-forward. - outWct.reorder(tiles.mSecondary.token, true /* onTop */); - boolean isHomeResizable = applyHomeTasksMinimized(layout, null /* parent */, - outWct); - if (topHomeTask != null && !Transitions.ENABLE_SHELL_TRANSITIONS) { - // Translate/update-crop of secondary out-of-band with sync transaction -- Until BALST - // is enabled, this temporarily syncs the home surface position with offset until - // sync transaction finishes. - outWct.setBoundsChangeTransaction(topHomeTask.token, tiles.mHomeBounds); - } - return isHomeResizable; - } - - static boolean isHomeOrRecentTask(ActivityManager.RunningTaskInfo ti) { - final int atype = ti.getActivityType(); - return atype == ACTIVITY_TYPE_HOME || atype == ACTIVITY_TYPE_RECENTS; - } - - /** @see #buildDismissSplit */ - void applyDismissSplit(LegacySplitScreenTaskListener tiles, LegacySplitDisplayLayout layout, - boolean dismissOrMaximize) { - // TODO(task-org): Once task-org is more complete, consider using Appeared/Vanished - // plus specific APIs to clean this up. - final WindowContainerTransaction wct = new WindowContainerTransaction(); - // Set launch root first so that any task created after getChildContainers and - // before reparent (pretty unlikely) are put into fullscreen. - wct.setLaunchRoot(tiles.mSecondary.token, null, null); - buildDismissSplit(wct, tiles, layout, dismissOrMaximize); - applySyncTransaction(wct); - } - - /** - * Reparents all tile members back to their display and resets home task override bounds. - * @param dismissOrMaximize When {@code true} this resolves the split by closing the primary - * split (thus resulting in the top of the secondary split becoming - * fullscreen. {@code false} resolves the other way. - */ - static void buildDismissSplit(WindowContainerTransaction outWct, - LegacySplitScreenTaskListener tiles, LegacySplitDisplayLayout layout, - boolean dismissOrMaximize) { - // TODO(task-org): Once task-org is more complete, consider using Appeared/Vanished - // plus specific APIs to clean this up. - final TaskOrganizer taskOrg = tiles.getTaskOrganizer(); - List primaryChildren = - taskOrg.getChildTasks(tiles.mPrimary.token, null /* activityTypes */); - List secondaryChildren = - taskOrg.getChildTasks(tiles.mSecondary.token, null /* activityTypes */); - // In some cases (eg. non-resizable is launched), system-server will leave split-screen. - // as a result, the above will not capture any tasks; yet, we need to clean-up the - // home task bounds. - List freeHomeAndRecents = - taskOrg.getRootTasks(DEFAULT_DISPLAY, HOME_AND_RECENTS); - // Filter out the root split tasks - freeHomeAndRecents.removeIf(p -> p.token.equals(tiles.mSecondary.token) - || p.token.equals(tiles.mPrimary.token)); - - if (primaryChildren.isEmpty() && secondaryChildren.isEmpty() - && freeHomeAndRecents.isEmpty()) { - return; - } - if (dismissOrMaximize) { - // Dismissing, so move all primary split tasks first - for (int i = primaryChildren.size() - 1; i >= 0; --i) { - outWct.reparent(primaryChildren.get(i).token, null /* parent */, - true /* onTop */); - } - boolean homeOnTop = false; - // Don't need to worry about home tasks because they are already in the "proper" - // order within the secondary split. - for (int i = secondaryChildren.size() - 1; i >= 0; --i) { - final ActivityManager.RunningTaskInfo ti = secondaryChildren.get(i); - outWct.reparent(ti.token, null /* parent */, true /* onTop */); - if (isHomeOrRecentTask(ti)) { - outWct.setBounds(ti.token, null); - outWct.setWindowingMode(ti.token, WINDOWING_MODE_UNDEFINED); - if (i == 0) { - homeOnTop = true; - } - } - } - if (homeOnTop && !Transitions.ENABLE_SHELL_TRANSITIONS) { - // Translate/update-crop of secondary out-of-band with sync transaction -- instead - // play this in sync with new home-app frame because until BALST is enabled this - // shows up on screen before the syncTransaction returns. - // We only have access to the secondary root surface, though, so in order to - // position things properly, we have to take into account the existing negative - // offset/crop of the minimized-home task. - final boolean landscape = layout.mDisplayLayout.isLandscape(); - final int posX = landscape ? layout.mSecondary.left - tiles.mHomeBounds.left - : layout.mSecondary.left; - final int posY = landscape ? layout.mSecondary.top - : layout.mSecondary.top - tiles.mHomeBounds.top; - final SurfaceControl.Transaction sft = new SurfaceControl.Transaction(); - sft.setPosition(tiles.mSecondarySurface, posX, posY); - final Rect crop = new Rect(0, 0, layout.mDisplayLayout.width(), - layout.mDisplayLayout.height()); - crop.offset(-posX, -posY); - sft.setWindowCrop(tiles.mSecondarySurface, crop); - outWct.setBoundsChangeTransaction(tiles.mSecondary.token, sft); - } - } else { - // Maximize, so move non-home secondary split first - for (int i = secondaryChildren.size() - 1; i >= 0; --i) { - if (isHomeOrRecentTask(secondaryChildren.get(i))) { - continue; - } - outWct.reparent(secondaryChildren.get(i).token, null /* parent */, - true /* onTop */); - } - // Find and place home tasks in-between. This simulates the fact that there was - // nothing behind the primary split's tasks. - for (int i = secondaryChildren.size() - 1; i >= 0; --i) { - final ActivityManager.RunningTaskInfo ti = secondaryChildren.get(i); - if (isHomeOrRecentTask(ti)) { - outWct.reparent(ti.token, null /* parent */, true /* onTop */); - // reset bounds and mode too - outWct.setBounds(ti.token, null); - outWct.setWindowingMode(ti.token, WINDOWING_MODE_UNDEFINED); - } - } - for (int i = primaryChildren.size() - 1; i >= 0; --i) { - outWct.reparent(primaryChildren.get(i).token, null /* parent */, - true /* onTop */); - } - } - for (int i = freeHomeAndRecents.size() - 1; i >= 0; --i) { - outWct.setBounds(freeHomeAndRecents.get(i).token, null); - outWct.setWindowingMode(freeHomeAndRecents.get(i).token, WINDOWING_MODE_UNDEFINED); - } - // Reset focusable to true - outWct.setFocusable(tiles.mPrimary.token, true /* focusable */); - } - - /** - * Utility to apply a sync transaction serially with other sync transactions. - * - * @see SyncTransactionQueue#queue - */ - void applySyncTransaction(WindowContainerTransaction wct) { - mSyncTransactionQueue.queue(wct); - } - - /** - * @see SyncTransactionQueue#queueIfWaiting - */ - boolean queueSyncTransactionIfWaiting(WindowContainerTransaction wct) { - return mSyncTransactionQueue.queueIfWaiting(wct); - } - - /** - * @see SyncTransactionQueue#runInSync - */ - void runInSync(SyncTransactionQueue.TransactionRunnable runnable) { - mSyncTransactionQueue.runInSync(runnable); - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt index 0ec9b2d869a8c..b902e5d1b454e 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt @@ -17,7 +17,6 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation -import android.content.res.Resources import com.android.server.wm.traces.common.FlickerComponentName import com.android.server.wm.traces.parser.toFlickerComponent import com.android.wm.shell.flicker.testapp.Components @@ -32,11 +31,6 @@ class SplitScreenHelper( const val TEST_REPETITIONS = 1 const val TIMEOUT_MS = 3_000L - // TODO: remove all legacy split screen flicker tests when legacy split screen is fully - // deprecated. - fun isUsingLegacySplit(): Boolean = - Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useLegacySplit) - fun getPrimary(instrumentation: Instrumentation): SplitScreenHelper = SplitScreenHelper(instrumentation, Components.SplitScreenActivity.LABEL, diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt deleted file mode 100644 index c86a1229d8d8a..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2021 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.legacysplitscreen - -import android.platform.test.annotations.Presubmit -import android.view.Surface -import android.view.WindowManagerPolicyConstants -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group4 -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.flicker.navBarWindowIsVisible -import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.server.wm.traces.common.FlickerComponentName -import com.android.wm.shell.flicker.dockedStackDividerBecomesVisible -import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd -import com.android.wm.shell.flicker.helpers.SplitScreenHelper -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test open activity and dock to primary split screen - * To run this test: `atest WMShellFlickerTests:EnterSplitScreenDockActivity` - */ -@Presubmit -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group4 -class EnterSplitScreenDockActivity( - testSpec: FlickerTestParameter -) : LegacySplitScreenTransition(testSpec) { - override val transition: FlickerBuilder.() -> Unit - get() = { - super.transition(this) - transitions { - device.launchSplitScreen(wmHelper) - } - } - - override val ignoredWindows: List - get() = listOf(LAUNCHER_COMPONENT, LIVE_WALLPAPER_COMPONENT, - splitScreenApp.component, FlickerComponentName.SPLASH_SCREEN, - FlickerComponentName.SNAPSHOT, LAUNCHER_COMPONENT) - - @Presubmit - @Test - fun dockedStackPrimaryBoundsIsVisibleAtEnd() = - testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.startRotation, - splitScreenApp.component) - - @Presubmit - @Test - fun dockedStackDividerBecomesVisible() = testSpec.dockedStackDividerBecomesVisible() - - @Presubmit - @Test - fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible() - - @Presubmit - @Test - fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible() - - @Presubmit - @Test - fun appWindowIsVisible() { - testSpec.assertWmEnd { - isAppWindowVisible(splitScreenApp.component) - } - } - - @FlakyTest - @Test - override fun visibleLayersShownMoreThanOneConsecutiveEntry() = - super.visibleLayersShownMoreThanOneConsecutiveEntry() - - @Presubmit - @Test - override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = - super.visibleWindowsShownMoreThanOneConsecutiveEntry() - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection { - return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0), // bugId = 179116910 - supportedNavigationModes = listOf( - WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY) - ) - } - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt deleted file mode 100644 index 2f9244be9c18e..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2021 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.legacysplitscreen - -import android.platform.test.annotations.Presubmit -import android.view.Surface -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group4 -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.traces.common.FlickerComponentName -import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd -import com.android.wm.shell.flicker.helpers.SplitScreenHelper -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test enter split screen from a detached recent task - * - * To run this test: `atest WMShellFlickerTests:EnterSplitScreenFromDetachedRecentTask` - */ -@RequiresDevice -@RunWith(Parameterized::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@Group4 -class EnterSplitScreenFromDetachedRecentTask( - testSpec: FlickerTestParameter -) : LegacySplitScreenTransition(testSpec) { - - override val transition: FlickerBuilder.() -> Unit - get() = { - cleanSetup(this) - setup { - eachRun { - splitScreenApp.launchViaIntent(wmHelper) - // Press back to remove the task, but it should still be shown in recent. - device.pressBack() - } - } - transitions { - device.launchSplitScreen(wmHelper) - } - } - - override val ignoredWindows: List - get() = listOf(LAUNCHER_COMPONENT, - FlickerComponentName.SPLASH_SCREEN, - FlickerComponentName.SNAPSHOT, - splitScreenApp.component) - - @Presubmit - @Test - fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd() - - @Presubmit - @Test - fun appWindowIsVisible() { - testSpec.assertWmEnd { - isAppWindowVisible(splitScreenApp.component) - } - } - - @Presubmit - @Test - override fun visibleLayersShownMoreThanOneConsecutiveEntry() = - super.visibleLayersShownMoreThanOneConsecutiveEntry() - - @Presubmit - @Test - override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = - super.visibleWindowsShownMoreThanOneConsecutiveEntry() - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection { - return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0) // bugId = 179116910 - ) - } - } -} \ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt deleted file mode 100644 index 1740c3ec24ca4..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2021 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.legacysplitscreen - -import android.platform.test.annotations.Presubmit -import android.view.Surface -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group4 -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.flicker.helpers.reopenAppFromOverview -import com.android.server.wm.flicker.navBarWindowIsVisible -import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.server.wm.traces.common.FlickerComponentName -import com.android.wm.shell.flicker.dockedStackDividerBecomesVisible -import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd -import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisibleAtEnd -import com.android.wm.shell.flicker.helpers.SplitScreenHelper -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test open activity to primary split screen and dock secondary activity to side - * To run this test: `atest WMShellFlickerTests:EnterSplitScreenLaunchToSide` - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group4 -class EnterSplitScreenLaunchToSide( - testSpec: FlickerTestParameter -) : LegacySplitScreenTransition(testSpec) { - override val transition: FlickerBuilder.() -> Unit - get() = { - super.transition(this) - transitions { - device.launchSplitScreen(wmHelper) - device.reopenAppFromOverview(wmHelper) - } - } - - override val ignoredWindows: List - get() = listOf(LAUNCHER_COMPONENT, splitScreenApp.component, - secondaryApp.component, FlickerComponentName.SPLASH_SCREEN, - FlickerComponentName.SNAPSHOT) - - @Presubmit - @Test - fun dockedStackPrimaryBoundsIsVisibleAtEnd() = - testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.startRotation, - splitScreenApp.component) - - @Presubmit - @Test - fun dockedStackSecondaryBoundsIsVisibleAtEnd() = - testSpec.dockedStackSecondaryBoundsIsVisibleAtEnd(testSpec.startRotation, - secondaryApp.component) - - @Presubmit - @Test - fun dockedStackDividerBecomesVisible() = testSpec.dockedStackDividerBecomesVisible() - - @Presubmit - @Test - fun appWindowBecomesVisible() { - testSpec.assertWm { - // when the app is launched, first the activity becomes visible, then the - // SnapshotStartingWindow appears and then the app window becomes visible. - // Because we log WM once per frame, sometimes the activity and the window - // become visible in the same entry, sometimes not, thus it is not possible to - // assert the visibility of the activity here - this.isAppWindowInvisible(secondaryApp.component) - .then() - // during re-parenting, the window may disappear and reappear from the - // trace, this occurs because we log only 1x per frame - .notContains(secondaryApp.component, isOptional = true) - .then() - .isAppWindowVisible(secondaryApp.component) - } - } - - @Presubmit - @Test - fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible() - - @Presubmit - @Test - fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible() - - @Presubmit - @Test - override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = - super.visibleWindowsShownMoreThanOneConsecutiveEntry() - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection { - return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0) // bugId = 175687842 - ) - } - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt deleted file mode 100644 index 4c063b918e962..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2021 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.legacysplitscreen - -import android.platform.test.annotations.Presubmit -import android.view.Surface -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group4 -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.canSplitScreen -import com.android.server.wm.traces.common.FlickerComponentName -import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd -import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig -import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow -import com.android.wm.shell.flicker.helpers.SplitScreenHelper -import org.junit.After -import org.junit.Assert -import org.junit.Before -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test enter split screen from non-resizable activity. When the device doesn't support - * non-resizable in multi window, there should be no button to enter split screen for non-resizable - * activity. - * - * To run this test: `atest WMShellFlickerTests:EnterSplitScreenNotSupportNonResizable` - */ -@RequiresDevice -@RunWith(Parameterized::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@Group4 -class EnterSplitScreenNotSupportNonResizable( - testSpec: FlickerTestParameter -) : LegacySplitScreenTransition(testSpec) { - - override val transition: FlickerBuilder.() -> Unit - get() = { - cleanSetup(this) - setup { - eachRun { - nonResizeableApp.launchViaIntent(wmHelper) - } - } - transitions { - if (device.canSplitScreen(wmHelper)) { - Assert.fail("Non-resizeable app should not enter split screen") - } - } - } - - override val ignoredWindows: List - get() = listOf(LAUNCHER_COMPONENT, - FlickerComponentName.SPLASH_SCREEN, - FlickerComponentName.SNAPSHOT, - nonResizeableApp.component, - splitScreenApp.component) - - @Before - override fun setup() { - super.setup() - setSupportsNonResizableMultiWindow(instrumentation, -1) - } - - @After - override fun teardown() { - super.teardown() - resetMultiWindowConfig(instrumentation) - } - - @Presubmit - @Test - fun dockedStackDividerNotExistsAtEnd() = testSpec.dockedStackDividerNotExistsAtEnd() - - @Presubmit - @Test - override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = - super.visibleWindowsShownMoreThanOneConsecutiveEntry() - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection { - return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668 - } - } -} \ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt deleted file mode 100644 index f75dee619564c..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2021 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.legacysplitscreen - -import android.platform.test.annotations.Presubmit -import android.view.Surface -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.traces.common.FlickerComponentName -import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd -import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig -import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow -import com.android.wm.shell.flicker.helpers.SplitScreenHelper -import org.junit.After -import org.junit.Before -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test enter split screen from non-resizable activity. When the device supports - * non-resizable in multi window, there should be a button to enter split screen for non-resizable - * activity. - * - * To run this test: `atest WMShellFlickerTests:EnterSplitScreenSupportNonResizable` - */ -@RequiresDevice -@RunWith(Parameterized::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@Group2 -class EnterSplitScreenSupportNonResizable( - testSpec: FlickerTestParameter -) : LegacySplitScreenTransition(testSpec) { - - override val transition: FlickerBuilder.() -> Unit - get() = { - cleanSetup(this) - setup { - eachRun { - nonResizeableApp.launchViaIntent(wmHelper) - } - } - transitions { - device.launchSplitScreen(wmHelper) - } - } - - override val ignoredWindows: List - get() = listOf(LAUNCHER_COMPONENT, - FlickerComponentName.SPLASH_SCREEN, - FlickerComponentName.SNAPSHOT, - nonResizeableApp.component, - splitScreenApp.component) - - @Before - override fun setup() { - super.setup() - setSupportsNonResizableMultiWindow(instrumentation, 1) - } - - @After - override fun teardown() { - super.teardown() - resetMultiWindowConfig(instrumentation) - } - - @Presubmit - @Test - fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd() - - @Presubmit - @Test - fun appWindowIsVisible() { - testSpec.assertWmEnd { - isAppWindowVisible(nonResizeableApp.component) - } - } - - @Presubmit - @Test - override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = - super.visibleWindowsShownMoreThanOneConsecutiveEntry() - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection { - return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668 - } - } -} \ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt deleted file mode 100644 index ef7d65e8a7326..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2020 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.legacysplitscreen - -import android.view.Surface -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.exitSplitScreenFromBottom -import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.flicker.navBarWindowIsVisible -import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.server.wm.traces.common.FlickerComponentName -import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT -import com.android.wm.shell.flicker.helpers.SplitScreenHelper -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test open resizeable activity split in primary, and drag divider to bottom exit split screen - * To run this test: `atest WMShellFlickerTests:ExitLegacySplitScreenFromBottom` - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group2 -class ExitLegacySplitScreenFromBottom( - testSpec: FlickerTestParameter -) : LegacySplitScreenTransition(testSpec) { - override val transition: FlickerBuilder.() -> Unit - get() = { - super.transition(this) - setup { - eachRun { - splitScreenApp.launchViaIntent(wmHelper) - device.launchSplitScreen(wmHelper) - } - } - teardown { - eachRun { - splitScreenApp.exit(wmHelper) - } - } - transitions { - device.exitSplitScreenFromBottom(wmHelper) - } - } - - override val ignoredWindows: List - get() = listOf(LAUNCHER_COMPONENT, FlickerComponentName.SPLASH_SCREEN, - splitScreenApp.component, secondaryApp.component, - FlickerComponentName.SNAPSHOT) - - @FlakyTest - @Test - fun layerBecomesInvisible() { - testSpec.assertLayers { - this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT) - .then() - .isInvisible(DOCKED_STACK_DIVIDER_COMPONENT) - } - } - - @FlakyTest - @Test - fun appWindowBecomesInVisible() { - testSpec.assertWm { - this.isAppWindowVisible(secondaryApp.component) - .then() - .isAppWindowInvisible(secondaryApp.component) - } - } - - @FlakyTest - @Test - fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible() - - @FlakyTest - @Test - fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible() - - @FlakyTest - @Test - override fun visibleLayersShownMoreThanOneConsecutiveEntry() = - super.visibleLayersShownMoreThanOneConsecutiveEntry() - - @FlakyTest - @Test - override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = - super.visibleWindowsShownMoreThanOneConsecutiveEntry() - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection { - return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0) // b/175687842 - ) - } - } -} \ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt deleted file mode 100644 index d913a6d85d3dc..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2021 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.legacysplitscreen - -import android.platform.test.annotations.Presubmit -import android.view.Surface -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.flicker.helpers.reopenAppFromOverview -import com.android.server.wm.flicker.navBarWindowIsVisible -import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.server.wm.traces.common.FlickerComponentName -import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd -import com.android.wm.shell.flicker.helpers.SplitScreenHelper -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test dock activity to primary split screen, and open secondary to side, exit primary split - * and test secondary activity become full screen. - * To run this test: `atest WMShellFlickerTests:ExitPrimarySplitScreenShowSecondaryFullscreen` - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group2 -class ExitPrimarySplitScreenShowSecondaryFullscreen( - testSpec: FlickerTestParameter -) : LegacySplitScreenTransition(testSpec) { - override val transition: FlickerBuilder.() -> Unit - get() = { - super.transition(this) - teardown { - eachRun { - secondaryApp.exit(wmHelper) - } - } - transitions { - splitScreenApp.launchViaIntent(wmHelper) - secondaryApp.launchViaIntent(wmHelper) - device.launchSplitScreen(wmHelper) - device.reopenAppFromOverview(wmHelper) - // TODO(b/175687842) Can not find Split screen divider, use exit() instead - splitScreenApp.exit(wmHelper) - } - } - - override val ignoredWindows: List - get() = listOf(LAUNCHER_COMPONENT, FlickerComponentName.SPLASH_SCREEN, - splitScreenApp.component, secondaryApp.component, - FlickerComponentName.SNAPSHOT) - - @Presubmit - @Test - fun dockedStackDividerNotExistsAtEnd() = testSpec.dockedStackDividerNotExistsAtEnd() - - @FlakyTest - @Test - fun layerBecomesInvisible() { - testSpec.assertLayers { - this.isVisible(splitScreenApp.component) - .then() - .isInvisible(splitScreenApp.component) - } - } - - @FlakyTest - @Test - fun appWindowBecomesInVisible() { - testSpec.assertWm { - this.isAppWindowVisible(splitScreenApp.component) - .then() - .isAppWindowInvisible(splitScreenApp.component) - } - } - - @Presubmit - @Test - fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible() - - @Presubmit - @Test - fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible() - - @Presubmit - @Test - override fun visibleLayersShownMoreThanOneConsecutiveEntry() = - super.visibleLayersShownMoreThanOneConsecutiveEntry() - - @Presubmit - @Test - override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = - super.visibleWindowsShownMoreThanOneConsecutiveEntry() - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection { - return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0) // bugId = 179116910 - ) - } - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt deleted file mode 100644 index f3ff7b156aaf5..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (C) 2021 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.legacysplitscreen - -import android.platform.test.annotations.Presubmit -import android.view.Surface -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.traces.common.FlickerComponentName -import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT -import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd -import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig -import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow -import com.android.wm.shell.flicker.helpers.SplitScreenHelper -import org.junit.After -import org.junit.Before -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test launch non-resizable activity via intent in split screen mode. When the device does not - * support non-resizable in multi window, it should trigger exit split screen. - * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromIntentNotSupportNonResizable` - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group2 -class LegacySplitScreenFromIntentNotSupportNonResizable( - testSpec: FlickerTestParameter -) : LegacySplitScreenTransition(testSpec) { - - override val transition: FlickerBuilder.() -> Unit - get() = { - cleanSetup(this) - setup { - eachRun { - splitScreenApp.launchViaIntent(wmHelper) - device.launchSplitScreen(wmHelper) - } - } - transitions { - nonResizeableApp.launchViaIntent(wmHelper) - wmHelper.waitForAppTransitionIdle() - } - } - - override val ignoredWindows: List - get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT, - nonResizeableApp.component, splitScreenApp.component, - FlickerComponentName.SPLASH_SCREEN, - FlickerComponentName.SNAPSHOT) - - @Before - override fun setup() { - super.setup() - setSupportsNonResizableMultiWindow(instrumentation, -1) - } - - @After - override fun teardown() { - super.teardown() - resetMultiWindowConfig(instrumentation) - } - - @Presubmit - @Test - fun resizableAppLayerBecomesInvisible() { - testSpec.assertLayers { - this.isVisible(splitScreenApp.component) - .then() - .isInvisible(splitScreenApp.component) - } - } - - @Presubmit - @Test - fun nonResizableAppLayerBecomesVisible() { - testSpec.assertLayers { - this.notContains(nonResizeableApp.component) - .then() - .isInvisible(nonResizeableApp.component) - .then() - .isVisible(nonResizeableApp.component) - } - } - - /** - * Assets that [splitScreenApp] exists at the start of the trace and, once it becomes - * invisible, it remains invisible until the end of the trace. - */ - @Presubmit - @Test - fun resizableAppWindowBecomesInvisible() { - testSpec.assertWm { - // when the activity gets PAUSED the window may still be marked as visible - // it will be updated in the next log entry. This occurs because we record 1x - // per frame, thus ignore activity check here - this.isAppWindowVisible(splitScreenApp.component) - .then() - // immediately after the window (after onResume and before perform relayout) - // the activity is invisible. This may or not be logged, since we record 1x - // per frame, thus ignore activity check here - .isAppWindowInvisible(splitScreenApp.component) - } - } - - /** - * Assets that [nonResizeableApp] doesn't exist at the start of the trace, then - * [nonResizeableApp] is created (visible or not) and, once [nonResizeableApp] becomes - * visible, it remains visible until the end of the trace. - */ - @Presubmit - @Test - fun nonResizableAppWindowBecomesVisible() { - testSpec.assertWm { - this.notContains(nonResizeableApp.component) - .then() - // we log once per frame, upon logging, window may be visible or not depending - // on what was processed until that moment. Both behaviors are correct - .isAppWindowInvisible(nonResizeableApp.component, isOptional = true) - .then() - // immediately after the window (after onResume and before perform relayout) - // the activity is invisible. This may or not be logged, since we record 1x - // per frame, thus ignore activity check here - .isAppWindowVisible(nonResizeableApp.component) - } - } - - /** - * Asserts that both the app window and the activity are visible at the end of the trace - */ - @Presubmit - @Test - fun nonResizableAppWindowBecomesVisibleAtEnd() { - testSpec.assertWmEnd { - isAppWindowVisible(nonResizeableApp.component) - } - } - - @Presubmit - @Test - fun dockedStackDividerNotExistsAtEnd() = testSpec.dockedStackDividerNotExistsAtEnd() - - @Presubmit - @Test - fun onlyNonResizableAppWindowIsVisibleAtEnd() { - testSpec.assertWmEnd { - isAppWindowInvisible(splitScreenApp.component) - isAppWindowVisible(nonResizeableApp.component) - } - } - - @Presubmit - @Test - override fun visibleLayersShownMoreThanOneConsecutiveEntry() = - super.visibleLayersShownMoreThanOneConsecutiveEntry() - - @Presubmit - @Test - override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = - super.visibleWindowsShownMoreThanOneConsecutiveEntry() - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection { - return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668 - } - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt deleted file mode 100644 index 42e707ab08507..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2021 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.legacysplitscreen - -import android.platform.test.annotations.Presubmit -import android.view.Surface -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.traces.common.FlickerComponentName -import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT -import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd -import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig -import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow -import com.android.wm.shell.flicker.helpers.SplitScreenHelper -import org.junit.After -import org.junit.Before -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test launch non-resizable activity via intent in split screen mode. When the device supports - * non-resizable in multi window, it should show the non-resizable app in split screen. - * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromIntentSupportNonResizable` - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group2 -class LegacySplitScreenFromIntentSupportNonResizable( - testSpec: FlickerTestParameter -) : LegacySplitScreenTransition(testSpec) { - - override val transition: FlickerBuilder.() -> Unit - get() = { - cleanSetup(this) - setup { - eachRun { - splitScreenApp.launchViaIntent(wmHelper) - device.launchSplitScreen(wmHelper) - } - } - transitions { - nonResizeableApp.launchViaIntent(wmHelper) - wmHelper.waitForAppTransitionIdle() - } - } - - override val ignoredWindows: List - get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT, - nonResizeableApp.component, splitScreenApp.component, - FlickerComponentName.SPLASH_SCREEN, - FlickerComponentName.SNAPSHOT) - - @Before - override fun setup() { - super.setup() - setSupportsNonResizableMultiWindow(instrumentation, 1) - } - - @After - override fun teardown() { - super.teardown() - resetMultiWindowConfig(instrumentation) - } - - @Presubmit - @Test - fun nonResizableAppLayerBecomesVisible() { - testSpec.assertLayers { - this.isInvisible(nonResizeableApp.component) - .then() - .isVisible(nonResizeableApp.component) - } - } - - /** - * Assets that [nonResizeableApp] doesn't exist at the start of the trace, then - * [nonResizeableApp] is created (visible or not) and, once [nonResizeableApp] becomes - * visible, it remains visible until the end of the trace. - */ - @Presubmit - @Test - fun nonResizableAppWindowBecomesVisible() { - testSpec.assertWm { - this.notContains(nonResizeableApp.component) - .then() - // we log once per frame, upon logging, window may be visible or not depending - // on what was processed until that moment. Both behaviors are correct - .isAppWindowInvisible(nonResizeableApp.component, isOptional = true) - .then() - // immediately after the window (after onResume and before perform relayout) - // the activity is invisible. This may or not be logged, since we record 1x - // per frame, thus ignore activity check here - .isAppWindowVisible(nonResizeableApp.component) - } - } - - @Presubmit - @Test - fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd() - - @Presubmit - @Test - fun bothAppsWindowsAreVisibleAtEnd() { - testSpec.assertWmEnd { - isAppWindowVisible(splitScreenApp.component) - isAppWindowVisible(nonResizeableApp.component) - } - } - - @Presubmit - @Test - override fun visibleLayersShownMoreThanOneConsecutiveEntry() = - super.visibleLayersShownMoreThanOneConsecutiveEntry() - - @Presubmit - @Test - override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = - super.visibleWindowsShownMoreThanOneConsecutiveEntry() - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection { - return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668 - } - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt deleted file mode 100644 index c1fba7d1530c3..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) 2021 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.legacysplitscreen - -import android.platform.test.annotations.Presubmit -import android.view.Surface -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.flicker.helpers.reopenAppFromOverview -import com.android.server.wm.traces.common.FlickerComponentName -import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT -import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd -import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig -import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow -import com.android.wm.shell.flicker.helpers.SplitScreenHelper -import org.junit.After -import org.junit.Before -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test launch non-resizable activity via recent overview in split screen mode. When the device does - * not support non-resizable in multi window, it should trigger exit split screen. - * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromRecentNotSupportNonResizable` - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group2 -class LegacySplitScreenFromRecentNotSupportNonResizable( - testSpec: FlickerTestParameter -) : LegacySplitScreenTransition(testSpec) { - - override val transition: FlickerBuilder.() -> Unit - get() = { - cleanSetup(this) - setup { - eachRun { - nonResizeableApp.launchViaIntent(wmHelper) - splitScreenApp.launchViaIntent(wmHelper) - device.launchSplitScreen(wmHelper) - } - } - transitions { - device.reopenAppFromOverview(wmHelper) - } - } - - override val ignoredWindows: List - get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT, - TOAST_COMPONENT, splitScreenApp.component, nonResizeableApp.component, - FlickerComponentName.SPLASH_SCREEN, - FlickerComponentName.SNAPSHOT) - - @Before - override fun setup() { - super.setup() - setSupportsNonResizableMultiWindow(instrumentation, -1) - } - - @After - override fun teardown() { - super.teardown() - resetMultiWindowConfig(instrumentation) - } - - @Presubmit - @Test - fun resizableAppLayerBecomesInvisible() { - testSpec.assertLayers { - this.isVisible(splitScreenApp.component) - .then() - .isInvisible(splitScreenApp.component) - } - } - - @Presubmit - @Test - fun nonResizableAppLayerBecomesVisible() { - testSpec.assertLayers { - this.isInvisible(nonResizeableApp.component) - .then() - .isVisible(nonResizeableApp.component) - } - } - - @Presubmit - @Test - fun resizableAppWindowBecomesInvisible() { - testSpec.assertWm { - // when the activity gets PAUSED the window may still be marked as visible - // it will be updated in the next log entry. This occurs because we record 1x - // per frame, thus ignore activity check here - this.isAppWindowVisible(splitScreenApp.component) - .then() - // immediately after the window (after onResume and before perform relayout) - // the activity is invisible. This may or not be logged, since we record 1x - // per frame, thus ignore activity check here - .isAppWindowInvisible(splitScreenApp.component) - } - } - - @FlakyTest - @Test - fun nonResizableAppWindowBecomesVisible() { - testSpec.assertWm { - this.isAppWindowInvisible(nonResizeableApp.component) - .then() - .isAppWindowVisible(nonResizeableApp.component) - } - } - - @Presubmit - @Test - fun dockedStackDividerNotExistsAtEnd() = testSpec.dockedStackDividerNotExistsAtEnd() - - @Presubmit - @Test - fun onlyNonResizableAppWindowIsVisibleAtEnd() { - testSpec.assertWmEnd { - isAppWindowInvisible(splitScreenApp.component) - isAppWindowVisible(nonResizeableApp.component) - } - } - - @Presubmit - @Test - override fun visibleLayersShownMoreThanOneConsecutiveEntry() = - super.visibleLayersShownMoreThanOneConsecutiveEntry() - - @Presubmit - @Test - override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = - super.visibleWindowsShownMoreThanOneConsecutiveEntry() - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection { - return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668 - } - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt deleted file mode 100644 index 6ac8683ac0548..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2021 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.legacysplitscreen - -import android.platform.test.annotations.Presubmit -import android.view.Surface -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.flicker.helpers.reopenAppFromOverview -import com.android.server.wm.traces.common.FlickerComponentName -import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT -import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd -import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig -import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow -import com.android.wm.shell.flicker.helpers.SplitScreenHelper -import org.junit.After -import org.junit.Before -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test launch non-resizable activity via recent overview in split screen mode. When the device - * supports non-resizable in multi window, it should show the non-resizable app in split screen. - * To run this test: `atest WMShellFlickerTests:LegacySplitScreenFromRecentSupportNonResizable` - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group2 -class LegacySplitScreenFromRecentSupportNonResizable( - testSpec: FlickerTestParameter -) : LegacySplitScreenTransition(testSpec) { - - override val transition: FlickerBuilder.() -> Unit - get() = { - cleanSetup(this) - setup { - eachRun { - nonResizeableApp.launchViaIntent(wmHelper) - splitScreenApp.launchViaIntent(wmHelper) - device.launchSplitScreen(wmHelper) - } - } - transitions { - device.reopenAppFromOverview(wmHelper) - } - } - - override val ignoredWindows: List - get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT, - TOAST_COMPONENT, splitScreenApp.component, nonResizeableApp.component, - FlickerComponentName.SPLASH_SCREEN, - FlickerComponentName.SNAPSHOT) - - @Before - override fun setup() { - super.setup() - setSupportsNonResizableMultiWindow(instrumentation, 1) - } - - @After - override fun teardown() { - super.teardown() - resetMultiWindowConfig(instrumentation) - } - - @Presubmit - @Test - fun nonResizableAppLayerBecomesVisible() { - testSpec.assertLayers { - this.isInvisible(nonResizeableApp.component) - .then() - .isVisible(nonResizeableApp.component) - } - } - - @Presubmit - @Test - fun nonResizableAppWindowBecomesVisible() { - testSpec.assertWm { - // when the app is launched, first the activity becomes visible, then the - // SnapshotStartingWindow appears and then the app window becomes visible. - // Because we log WM once per frame, sometimes the activity and the window - // become visible in the same entry, sometimes not, thus it is not possible to - // assert the visibility of the activity here - this.isAppWindowInvisible(nonResizeableApp.component) - .then() - // during re-parenting, the window may disappear and reappear from the - // trace, this occurs because we log only 1x per frame - .notContains(nonResizeableApp.component, isOptional = true) - .then() - // if the window reappears after re-parenting it will most likely not - // be visible in the first log entry (because we log only 1x per frame) - .isAppWindowInvisible(nonResizeableApp.component, isOptional = true) - .then() - .isAppWindowVisible(nonResizeableApp.component) - } - } - - @Presubmit - @Test - fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd() - - @Presubmit - @Test - fun bothAppsWindowsAreVisibleAtEnd() { - testSpec.assertWmEnd { - isAppWindowVisible(splitScreenApp.component) - isAppWindowVisible(nonResizeableApp.component) - } - } - - @Presubmit - @Test - override fun visibleLayersShownMoreThanOneConsecutiveEntry() = - super.visibleLayersShownMoreThanOneConsecutiveEntry() - - @Presubmit - @Test - override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = - super.visibleWindowsShownMoreThanOneConsecutiveEntry() - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection { - return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668 - } - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt deleted file mode 100644 index b01f41c9e2ec9..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2021 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.legacysplitscreen - -import android.view.Surface -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview -import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen - -abstract class LegacySplitScreenRotateTransition( - testSpec: FlickerTestParameter -) : LegacySplitScreenTransition(testSpec) { - override val transition: FlickerBuilder.() -> Unit - get() = { - setup { - eachRun { - device.wakeUpAndGoToHomeScreen() - device.openQuickStepAndClearRecentAppsFromOverview(wmHelper) - secondaryApp.launchViaIntent(wmHelper) - splitScreenApp.launchViaIntent(wmHelper) - } - } - teardown { - eachRun { - splitScreenApp.exit(wmHelper) - secondaryApp.exit(wmHelper) - this.setRotation(Surface.ROTATION_0) - } - } - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt deleted file mode 100644 index fb1004bda0cbd..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (C) 2020 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.legacysplitscreen - -import android.platform.test.annotations.Presubmit -import android.view.Surface -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.entireScreenCovered -import com.android.server.wm.flicker.helpers.exitSplitScreen -import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview -import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen -import com.android.server.wm.flicker.navBarLayerIsVisible -import com.android.server.wm.flicker.navBarLayerRotatesAndScales -import com.android.server.wm.flicker.navBarWindowIsVisible -import com.android.server.wm.flicker.statusBarLayerIsVisible -import com.android.server.wm.flicker.statusBarLayerRotatesScales -import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.server.wm.traces.common.FlickerComponentName -import com.android.wm.shell.flicker.dockedStackDividerBecomesInvisible -import com.android.wm.shell.flicker.helpers.SimpleAppHelper -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test open app to split screen. - * To run this test: `atest WMShellFlickerTests:LegacySplitScreenToLauncher` - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group2 -class LegacySplitScreenToLauncher( - testSpec: FlickerTestParameter -) : LegacySplitScreenTransition(testSpec) { - private val testApp = SimpleAppHelper(instrumentation) - - override val transition: FlickerBuilder.() -> Unit - get() = { - setup { - test { - device.wakeUpAndGoToHomeScreen() - device.openQuickStepAndClearRecentAppsFromOverview(wmHelper) - } - eachRun { - testApp.launchViaIntent(wmHelper) - this.setRotation(testSpec.endRotation) - device.launchSplitScreen(wmHelper) - device.waitForIdle() - } - } - teardown { - eachRun { - testApp.exit(wmHelper) - } - } - transitions { - device.exitSplitScreen() - } - } - - override val ignoredWindows: List - get() = listOf(LAUNCHER_COMPONENT, FlickerComponentName.SPLASH_SCREEN, - FlickerComponentName.SNAPSHOT) - - @Presubmit - @Test - fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible() - - @Presubmit - @Test - fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible() - - @Presubmit - @Test - fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible() - - @Presubmit - @Test - fun entireScreenCovered() = testSpec.entireScreenCovered() - - @Presubmit - @Test - fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales() - - @FlakyTest(bugId = 206753786) - @Test - fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales() - - @Presubmit - @Test - fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible() - - @FlakyTest - @Test - fun dockedStackDividerBecomesInvisible() = testSpec.dockedStackDividerBecomesInvisible() - - @FlakyTest - @Test - fun layerBecomesInvisible() { - testSpec.assertLayers { - this.isVisible(testApp.component) - .then() - .isInvisible(testApp.component) - } - } - - @FlakyTest - @Test - fun focusDoesNotChange() { - testSpec.assertEventLog { - this.focusDoesNotChange() - } - } - - @Presubmit - @Test - override fun visibleLayersShownMoreThanOneConsecutiveEntry() = - super.visibleLayersShownMoreThanOneConsecutiveEntry() - - @Presubmit - @Test - override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = - super.visibleWindowsShownMoreThanOneConsecutiveEntry() - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection { - // b/161435597 causes the test not to work on 90 degrees - return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0)) - } - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt deleted file mode 100644 index a4a1f617e4970..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2020 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/LICENSE2.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.legacysplitscreen - -import android.app.Instrumentation -import android.content.Context -import android.support.test.launcherhelper.LauncherStrategyFactory -import android.view.Surface -import androidx.test.filters.FlakyTest -import androidx.test.platform.app.InstrumentationRegistry -import com.android.server.wm.flicker.FlickerBuilderProvider -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview -import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen -import com.android.server.wm.traces.common.FlickerComponentName -import com.android.wm.shell.flicker.helpers.BaseAppHelper.Companion.isShellTransitionsEnabled -import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.getDevEnableNonResizableMultiWindow -import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setDevEnableNonResizableMultiWindow -import com.android.wm.shell.flicker.helpers.SplitScreenHelper -import org.junit.After -import org.junit.Assume.assumeFalse -import org.junit.Assume.assumeTrue -import org.junit.Before -import org.junit.Test - -abstract class LegacySplitScreenTransition(protected val testSpec: FlickerTestParameter) { - protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() - protected val context: Context = instrumentation.context - protected val splitScreenApp = SplitScreenHelper.getPrimary(instrumentation) - protected val secondaryApp = SplitScreenHelper.getSecondary(instrumentation) - protected val nonResizeableApp = SplitScreenHelper.getNonResizeable(instrumentation) - protected val LAUNCHER_COMPONENT = FlickerComponentName("", - LauncherStrategyFactory.getInstance(instrumentation) - .launcherStrategy.supportedLauncherPackage) - private var prevDevEnableNonResizableMultiWindow = 0 - - @Before - open fun setup() { - // Only run legacy split tests when the system is using legacy split screen. - assumeTrue(SplitScreenHelper.isUsingLegacySplit()) - // Legacy split is having some issue with Shell transition, and will be deprecated soon. - assumeFalse(isShellTransitionsEnabled()) - prevDevEnableNonResizableMultiWindow = getDevEnableNonResizableMultiWindow(context) - if (prevDevEnableNonResizableMultiWindow != 0) { - // Turn off the development option - setDevEnableNonResizableMultiWindow(context, 0) - } - } - - @After - open fun teardown() { - setDevEnableNonResizableMultiWindow(context, prevDevEnableNonResizableMultiWindow) - } - - /** - * List of windows that are ignored when verifying that visible elements appear on 2 - * consecutive entries in the trace. - * - * b/182720234 - */ - open val ignoredWindows: List = listOf( - FlickerComponentName.SPLASH_SCREEN, - FlickerComponentName.SNAPSHOT) - - protected open val transition: FlickerBuilder.() -> Unit - get() = { - setup { - eachRun { - device.wakeUpAndGoToHomeScreen() - device.openQuickStepAndClearRecentAppsFromOverview(wmHelper) - secondaryApp.launchViaIntent(wmHelper) - splitScreenApp.launchViaIntent(wmHelper) - this.setRotation(testSpec.startRotation) - } - } - teardown { - eachRun { - secondaryApp.exit(wmHelper) - splitScreenApp.exit(wmHelper) - this.setRotation(Surface.ROTATION_0) - } - } - } - - @FlickerBuilderProvider - fun buildFlicker(): FlickerBuilder { - return FlickerBuilder(instrumentation).apply { - transition(this) - } - } - - internal open val cleanSetup: FlickerBuilder.() -> Unit - get() = { - setup { - eachRun { - device.wakeUpAndGoToHomeScreen() - device.openQuickStepAndClearRecentAppsFromOverview(wmHelper) - this.setRotation(testSpec.startRotation) - } - } - teardown { - eachRun { - nonResizeableApp.exit(wmHelper) - splitScreenApp.exit(wmHelper) - device.pressHome() - this.setRotation(Surface.ROTATION_0) - } - } - } - - @FlakyTest(bugId = 178447631) - @Test - open fun visibleWindowsShownMoreThanOneConsecutiveEntry() { - testSpec.assertWm { - this.visibleWindowsShownMoreThanOneConsecutiveEntry(ignoredWindows) - } - } - - @FlakyTest(bugId = 178447631) - @Test - open fun visibleLayersShownMoreThanOneConsecutiveEntry() { - testSpec.assertLayers { - this.visibleLayersShownMoreThanOneConsecutiveEntry(ignoredWindows) - } - } - - companion object { - internal val LIVE_WALLPAPER_COMPONENT = FlickerComponentName("", - "com.breel.wallpapers18.soundviz.wallpaper.variations.SoundVizWallpaperV2") - internal val LETTERBOX_COMPONENT = FlickerComponentName("", "Letterbox") - internal val TOAST_COMPONENT = FlickerComponentName("", "Toast") - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OWNERS b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OWNERS deleted file mode 100644 index 8446b37dbf06f..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -# window manager > wm shell > Split Screen -# Bug component: 928697 diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt deleted file mode 100644 index 087b21c544c53..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2020 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.legacysplitscreen - -import android.platform.test.annotations.Presubmit -import android.view.Surface -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.entireScreenCovered -import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.flicker.statusBarLayerIsVisible -import com.android.server.wm.traces.common.FlickerComponentName -import com.android.wm.shell.flicker.appPairsDividerBecomesVisible -import com.android.wm.shell.flicker.helpers.SplitScreenHelper -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test open app to split screen. - * To run this test: `atest WMShellFlickerTests:OpenAppToLegacySplitScreen` - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group2 -class OpenAppToLegacySplitScreen( - testSpec: FlickerTestParameter -) : LegacySplitScreenTransition(testSpec) { - override val transition: FlickerBuilder.() -> Unit - get() = { - super.transition(this) - transitions { - device.launchSplitScreen(wmHelper) - wmHelper.waitForAppTransitionIdle() - } - } - - override val ignoredWindows: List - get() = listOf(LAUNCHER_COMPONENT, splitScreenApp.component, - FlickerComponentName.SPLASH_SCREEN, - FlickerComponentName.SNAPSHOT) - - @FlakyTest - @Test - fun appWindowBecomesVisible() { - testSpec.assertWm { - this.isAppWindowInvisible(splitScreenApp.component) - .then() - .isAppWindowVisible(splitScreenApp.component) - } - } - - @Presubmit - @Test - fun entireScreenCovered() = testSpec.entireScreenCovered() - - @Presubmit - @Test - fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible() - - @Presubmit - @Test - fun appPairsDividerBecomesVisible() = testSpec.appPairsDividerBecomesVisible() - - @FlakyTest - @Test - fun layerBecomesVisible() { - testSpec.assertLayers { - this.isInvisible(splitScreenApp.component) - .then() - .isVisible(splitScreenApp.component) - } - } - - @Presubmit - @Test - fun focusChanges() { - testSpec.assertEventLog { - this.focusChanges(splitScreenApp.`package`, - "recents_animation_input_consumer", "NexusLauncherActivity") - } - } - - @Presubmit - @Test - override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = - super.visibleWindowsShownMoreThanOneConsecutiveEntry() - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection { - return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0) // bugId = 179116910 - ) - } - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt deleted file mode 100644 index e2da1a4565c08..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (C) 2020 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.legacysplitscreen - -import android.util.Rational -import android.view.Surface -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice -import androidx.test.uiautomator.By -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.entireScreenCovered -import com.android.server.wm.flicker.helpers.ImeAppHelper -import com.android.server.wm.flicker.helpers.WindowUtils -import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.flicker.helpers.resizeSplitScreen -import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen -import com.android.server.wm.flicker.navBarLayerIsVisible -import com.android.server.wm.flicker.navBarLayerRotatesAndScales -import com.android.server.wm.flicker.navBarWindowIsVisible -import com.android.server.wm.flicker.statusBarLayerIsVisible -import com.android.server.wm.flicker.statusBarLayerRotatesScales -import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.server.wm.traces.common.region.Region -import com.android.server.wm.traces.parser.toFlickerComponent -import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT -import com.android.wm.shell.flicker.helpers.SimpleAppHelper -import com.android.wm.shell.flicker.testapp.Components -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test split screen resizing window transitions. - * To run this test: `atest WMShellFlickerTests:ResizeLegacySplitScreen` - * - * Currently it runs only in 0 degrees because of b/156100803 - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@FlakyTest(bugId = 159096424) -@Group2 -class ResizeLegacySplitScreen( - testSpec: FlickerTestParameter -) : LegacySplitScreenTransition(testSpec) { - private val testAppTop = SimpleAppHelper(instrumentation) - private val testAppBottom = ImeAppHelper(instrumentation) - - override val transition: FlickerBuilder.() -> Unit - get() = { - setup { - eachRun { - device.wakeUpAndGoToHomeScreen() - this.setRotation(testSpec.startRotation) - this.launcherStrategy.clearRecentAppsFromOverview() - testAppBottom.launchViaIntent(wmHelper) - device.pressHome() - testAppTop.launchViaIntent(wmHelper) - device.waitForIdle() - device.launchSplitScreen(wmHelper) - val snapshot = - device.findObject(By.res(device.launcherPackageName, "snapshot")) - snapshot.click() - testAppBottom.openIME(device) - device.pressBack() - device.resizeSplitScreen(startRatio) - } - } - teardown { - eachRun { - testAppTop.exit(wmHelper) - testAppBottom.exit(wmHelper) - } - } - transitions { - device.resizeSplitScreen(stopRatio) - } - } - - @Test - fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible() - - @Test - fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible() - - @FlakyTest(bugId = 156223549) - @Test - fun topAppWindowIsAlwaysVisible() { - testSpec.assertWm { - this.isAppWindowVisible(Components.SimpleActivity.COMPONENT.toFlickerComponent()) - } - } - - @FlakyTest(bugId = 156223549) - @Test - fun bottomAppWindowIsAlwaysVisible() { - testSpec.assertWm { - this.isAppWindowVisible(Components.ImeActivity.COMPONENT.toFlickerComponent()) - } - } - - @Test - fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible() - - @Test - fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible() - - @Test - fun entireScreenCovered() = testSpec.entireScreenCovered() - - @Test - fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales() - - @FlakyTest(bugId = 206753786) - @Test - fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales() - - @Test - fun topAppLayerIsAlwaysVisible() { - testSpec.assertLayers { - this.isVisible(Components.SimpleActivity.COMPONENT.toFlickerComponent()) - } - } - - @Test - fun bottomAppLayerIsAlwaysVisible() { - testSpec.assertLayers { - this.isVisible(Components.ImeActivity.COMPONENT.toFlickerComponent()) - } - } - - @Test - fun dividerLayerIsAlwaysVisible() { - testSpec.assertLayers { - this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT) - } - } - - @FlakyTest - @Test - fun appsStartingBounds() { - testSpec.assertLayersStart { - val displayBounds = WindowUtils.displayBounds - val dividerBounds = - layer(DOCKED_STACK_DIVIDER_COMPONENT).visibleRegion.region.bounds - - val topAppBounds = Region.from(0, 0, dividerBounds.right, - dividerBounds.top + WindowUtils.dockedStackDividerInset) - val bottomAppBounds = Region.from(0, - dividerBounds.bottom - WindowUtils.dockedStackDividerInset, - displayBounds.right, - displayBounds.bottom - WindowUtils.navigationBarFrameHeight) - visibleRegion(Components.SimpleActivity.COMPONENT.toFlickerComponent()) - .coversExactly(topAppBounds) - visibleRegion(Components.ImeActivity.COMPONENT.toFlickerComponent()) - .coversExactly(bottomAppBounds) - } - } - - @FlakyTest - @Test - fun appsEndingBounds() { - testSpec.assertLayersStart { - val displayBounds = WindowUtils.displayBounds - val dividerBounds = - layer(DOCKED_STACK_DIVIDER_COMPONENT).visibleRegion.region.bounds - - val topAppBounds = Region.from(0, 0, dividerBounds.right, - dividerBounds.top + WindowUtils.dockedStackDividerInset) - val bottomAppBounds = Region.from(0, - dividerBounds.bottom - WindowUtils.dockedStackDividerInset, - displayBounds.right, - displayBounds.bottom - WindowUtils.navigationBarFrameHeight) - - visibleRegion(Components.SimpleActivity.COMPONENT.toFlickerComponent()) - .coversExactly(topAppBounds) - visibleRegion(Components.ImeActivity.COMPONENT.toFlickerComponent()) - .coversExactly(bottomAppBounds) - } - } - - @Test - fun focusDoesNotChange() { - testSpec.assertEventLog { - focusDoesNotChange() - } - } - - companion object { - private val startRatio = Rational(1, 3) - private val stopRatio = Rational(2, 3) - - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection { - return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0)) - .map { - val description = (startRatio.toString().replace("/", "-") + "_to_" + - stopRatio.toString().replace("/", "-")) - val newName = "${FlickerTestParameter.defaultName(it)}_$description" - FlickerTestParameter(it.config, nameOverride = newName) - } - } - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt deleted file mode 100644 index d703ea082c873..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2020 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.legacysplitscreen - -import android.platform.test.annotations.Presubmit -import android.view.Surface -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.flicker.navBarLayerRotatesAndScales -import com.android.server.wm.flicker.navBarWindowIsVisible -import com.android.server.wm.flicker.statusBarLayerRotatesScales -import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd -import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd -import com.android.wm.shell.flicker.helpers.SplitScreenHelper -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test dock activity to primary split screen and rotate - * To run this test: `atest WMShellFlickerTests:RotateOneLaunchedAppAndEnterSplitScreen` - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group2 -class RotateOneLaunchedAppAndEnterSplitScreen( - testSpec: FlickerTestParameter -) : LegacySplitScreenRotateTransition(testSpec) { - override val transition: FlickerBuilder.() -> Unit - get() = { - super.transition(this) - transitions { - device.launchSplitScreen(wmHelper) - this.setRotation(testSpec.startRotation) - } - } - - @Presubmit - @Test - fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd() - - @Presubmit - @Test - fun dockedStackPrimaryBoundsIsVisibleAtEnd() = - testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.startRotation, - splitScreenApp.component) - - @Presubmit - @Test - fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales() - - @FlakyTest(bugId = 206753786) - @Test - fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales() - - @Presubmit - @Test - fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible() - - @Presubmit - @Test - fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible() - - @FlakyTest - @Test - fun appWindowBecomesVisible() { - testSpec.assertWm { - this.isAppWindowInvisible(splitScreenApp.component) - .then() - .isAppWindowVisible(splitScreenApp.component) - } - } - - @Presubmit - @Test - override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = - super.visibleWindowsShownMoreThanOneConsecutiveEntry() - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection { - return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668 - } - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt deleted file mode 100644 index 6b1883914e597..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2020 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.legacysplitscreen - -import android.platform.test.annotations.Presubmit -import android.view.Surface -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.flicker.navBarLayerRotatesAndScales -import com.android.server.wm.flicker.navBarWindowIsVisible -import com.android.server.wm.flicker.statusBarLayerRotatesScales -import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd -import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd -import com.android.wm.shell.flicker.helpers.SplitScreenHelper -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Rotate - * To run this test: `atest WMShellFlickerTests:RotateOneLaunchedAppInSplitScreenMode` - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group2 -class RotateOneLaunchedAppInSplitScreenMode( - testSpec: FlickerTestParameter -) : LegacySplitScreenRotateTransition(testSpec) { - override val transition: FlickerBuilder.() -> Unit - get() = { - super.transition(this) - transitions { - this.setRotation(testSpec.startRotation) - device.launchSplitScreen(wmHelper) - } - } - - @Presubmit - @Test - fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd() - - @Presubmit - @Test - fun dockedStackPrimaryBoundsIsVisibleAtEnd() = testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd( - testSpec.startRotation, splitScreenApp.component) - - @Presubmit - @Test - fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales() - - @FlakyTest(bugId = 206753786) - @Test - fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales() - - @Presubmit - @Test - fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible() - - @Presubmit - @Test - fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible() - - @FlakyTest - @Test - fun appWindowBecomesVisible() { - testSpec.assertWm { - this.isAppWindowInvisible(splitScreenApp.component) - .then() - .isAppWindowVisible(splitScreenApp.component) - } - } - - @Presubmit - @Test - override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = - super.visibleWindowsShownMoreThanOneConsecutiveEntry() - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection { - return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668 - } - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt deleted file mode 100644 index acd658b5ba566..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2020 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.legacysplitscreen - -import android.platform.test.annotations.Presubmit -import android.view.Surface -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.flicker.helpers.reopenAppFromOverview -import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.flicker.navBarLayerRotatesAndScales -import com.android.server.wm.flicker.navBarWindowIsVisible -import com.android.server.wm.flicker.statusBarLayerRotatesScales -import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd -import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd -import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisibleAtEnd -import com.android.wm.shell.flicker.helpers.SplitScreenHelper -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test open app to split screen. - * To run this test: `atest WMShellFlickerTests:RotateTwoLaunchedAppAndEnterSplitScreen` - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group2 -class RotateTwoLaunchedAppAndEnterSplitScreen( - testSpec: FlickerTestParameter -) : LegacySplitScreenRotateTransition(testSpec) { - override val transition: FlickerBuilder.() -> Unit - get() = { - super.transition(this) - transitions { - this.setRotation(testSpec.startRotation) - device.launchSplitScreen(wmHelper) - device.reopenAppFromOverview(wmHelper) - } - } - - @Presubmit - @Test - fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd() - - @Presubmit - @Test - fun dockedStackPrimaryBoundsIsVisibleAtEnd() = - testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.startRotation, - splitScreenApp.component) - - @Presubmit - @Test - fun dockedStackSecondaryBoundsIsVisibleAtEnd() = - testSpec.dockedStackSecondaryBoundsIsVisibleAtEnd(testSpec.startRotation, - secondaryApp.component) - - @Presubmit - @Test - fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales() - - @FlakyTest(bugId = 206753786) - @Test - fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales() - - @Presubmit - @Test - fun appWindowBecomesVisible() { - testSpec.assertWm { - // when the app is launched, first the activity becomes visible, then the - // SnapshotStartingWindow appears and then the app window becomes visible. - // Because we log WM once per frame, sometimes the activity and the window - // become visible in the same entry, sometimes not, thus it is not possible to - // assert the visibility of the activity here - this.isAppWindowInvisible(secondaryApp.component) - .then() - // during re-parenting, the window may disappear and reappear from the - // trace, this occurs because we log only 1x per frame - .notContains(secondaryApp.component, isOptional = true) - .then() - // if the window reappears after re-parenting it will most likely not - // be visible in the first log entry (because we log only 1x per frame) - .isAppWindowInvisible(secondaryApp.component, isOptional = true) - .then() - .isAppWindowVisible(secondaryApp.component) - } - } - - @Presubmit - @Test - fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible() - - @Presubmit - @Test - fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible() - - @Presubmit - @Test - override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = - super.visibleWindowsShownMoreThanOneConsecutiveEntry() - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection { - return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668 - } - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt deleted file mode 100644 index b40be8b5f4018..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2020 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.legacysplitscreen - -import android.platform.test.annotations.Presubmit -import android.view.Surface -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group2 -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.flicker.helpers.reopenAppFromOverview -import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.flicker.navBarLayerRotatesAndScales -import com.android.server.wm.flicker.navBarWindowIsVisible -import com.android.server.wm.flicker.statusBarLayerRotatesScales -import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd -import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd -import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisibleAtEnd -import com.android.wm.shell.flicker.helpers.SplitScreenHelper -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test open app to split screen. - * To run this test: `atest WMShellFlickerTests:RotateTwoLaunchedAppInSplitScreenMode` - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group2 -class RotateTwoLaunchedAppInSplitScreenMode( - testSpec: FlickerTestParameter -) : LegacySplitScreenRotateTransition(testSpec) { - override val transition: FlickerBuilder.() -> Unit - get() = { - super.transition(this) - setup { - eachRun { - device.launchSplitScreen(wmHelper) - device.reopenAppFromOverview(wmHelper) - this.setRotation(testSpec.startRotation) - } - } - transitions { - this.setRotation(testSpec.startRotation) - } - } - - @Presubmit - @Test - fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd() - - @Presubmit - @Test - fun dockedStackPrimaryBoundsIsVisibleAtEnd() = - testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.startRotation, - splitScreenApp.component) - - @Presubmit - @Test - fun dockedStackSecondaryBoundsIsVisibleAtEnd() = - testSpec.dockedStackSecondaryBoundsIsVisibleAtEnd(testSpec.startRotation, - secondaryApp.component) - - @Presubmit - @Test - fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales() - - @FlakyTest(bugId = 206753786) - @Test - fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales() - - @FlakyTest - @Test - fun appWindowBecomesVisible() { - testSpec.assertWm { - this.isAppWindowInvisible(secondaryApp.component) - .then() - .isAppWindowVisible(secondaryApp.component) - } - } - - @Presubmit - @Test - fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible() - - @Presubmit - @Test - fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible() - - @Presubmit - @Test - override fun visibleLayersShownMoreThanOneConsecutiveEntry() = - super.visibleLayersShownMoreThanOneConsecutiveEntry() - - @Presubmit - @Test - override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = - super.visibleWindowsShownMoreThanOneConsecutiveEntry() - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection { - return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, - supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668 - } - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt deleted file mode 100644 index 21175a0767a59..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (C) 2020 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.Presubmit -import android.view.Surface -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.FlickerParametersRunnerFactory -import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group4 -import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen -import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome -import com.android.wm.shell.flicker.helpers.BaseAppHelper.Companion.isShellTransitionsEnabled -import com.android.wm.shell.flicker.helpers.FixedAppHelper -import com.android.wm.shell.flicker.helpers.ImeAppHelper -import com.android.wm.shell.flicker.helpers.SplitScreenHelper -import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP -import org.junit.Assume.assumeFalse -import org.junit.Assume.assumeTrue -import org.junit.Before -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test Pip with split-screen. - * To run this test: `atest WMShellFlickerTests:PipLegacySplitScreenTest` - */ -@RequiresDevice -@RunWith(Parameterized::class) -@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group4 -class PipLegacySplitScreenTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) { - private val imeApp = ImeAppHelper(instrumentation) - private val testApp = FixedAppHelper(instrumentation) - - @Before - open fun setup() { - // Only run legacy split tests when the system is using legacy split screen. - assumeTrue(SplitScreenHelper.isUsingLegacySplit()) - // Legacy split is having some issue with Shell transition, and will be deprecated soon. - assumeFalse(isShellTransitionsEnabled()) - } - - override val transition: FlickerBuilder.() -> Unit - get() = { - setup { - test { - removeAllTasksButHome() - device.wakeUpAndGoToHomeScreen() - pipApp.launchViaIntent(stringExtras = mapOf(EXTRA_ENTER_PIP to "true"), - wmHelper = wmHelper) - } - } - transitions { - testApp.launchViaIntent(wmHelper) - device.launchSplitScreen(wmHelper) - imeApp.launchViaIntent(wmHelper) - } - teardown { - eachRun { - imeApp.exit(wmHelper) - testApp.exit(wmHelper) - } - test { - removeAllTasksButHome() - } - } - } - - /** {@inheritDoc} */ - @FlakyTest(bugId = 206753786) - @Test - override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales() - - @FlakyTest(bugId = 161435597) - @Test - fun pipWindowInsideDisplayBounds() { - testSpec.assertWmVisibleRegion(pipApp.component) { - coversAtMost(displayBounds) - } - } - - @Presubmit - @Test - fun bothAppWindowsVisible() { - testSpec.assertWmEnd { - isAppWindowVisible(testApp.component) - isAppWindowVisible(imeApp.component) - doNotOverlap(testApp.component, imeApp.component) - } - } - - @FlakyTest(bugId = 161435597) - @Test - fun pipLayerInsideDisplayBounds() { - testSpec.assertLayersVisibleRegion(pipApp.component) { - coversAtMost(displayBounds) - } - } - - @Presubmit - @Test - fun bothAppLayersVisible() { - testSpec.assertLayersEnd { - visibleRegion(testApp.component).coversAtMost(displayBounds) - visibleRegion(imeApp.component).coversAtMost(displayBounds) - } - } - - @FlakyTest(bugId = 161435597) - @Test - override fun entireScreenCovered() = super.entireScreenCovered() - - companion object { - const val TEST_REPETITIONS = 2 - - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection { - return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - supportedRotations = listOf(Surface.ROTATION_0), - repetitions = TEST_REPETITIONS - ) - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java index f5084f5cff769..d70ea9bba9369 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java @@ -29,9 +29,9 @@ import com.android.systemui.dagger.DaggerGlobalRootComponent; import com.android.systemui.dagger.GlobalRootComponent; import com.android.systemui.dagger.SysUIComponent; import com.android.systemui.dagger.WMComponent; -import com.android.wm.shell.dagger.WMShellConcurrencyModule; import com.android.systemui.navigationbar.gestural.BackGestureTfClassifierProvider; import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider; +import com.android.wm.shell.dagger.WMShellConcurrencyModule; import com.android.wm.shell.transition.ShellTransitions; import java.util.Map; @@ -114,7 +114,6 @@ public class SystemUIFactory { // components that shouldn't be run in the test environment builder = prepareSysUIComponentBuilder(builder, mWMComponent) .setPip(mWMComponent.getPip()) - .setLegacySplitScreen(mWMComponent.getLegacySplitScreen()) .setSplitScreen(mWMComponent.getSplitScreen()) .setOneHanded(mWMComponent.getOneHanded()) .setBubbles(mWMComponent.getBubbles()) @@ -135,7 +134,6 @@ public class SystemUIFactory { // is separating this logic into newly creating SystemUITestsFactory. builder = prepareSysUIComponentBuilder(builder, mWMComponent) .setPip(Optional.ofNullable(null)) - .setLegacySplitScreen(Optional.ofNullable(null)) .setSplitScreen(Optional.ofNullable(null)) .setOneHanded(Optional.ofNullable(null)) .setBubbles(Optional.ofNullable(null)) diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java index 5d34a6987b663..6cbd8b132a800 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java @@ -46,7 +46,6 @@ import com.android.wm.shell.compatui.CompatUI; import com.android.wm.shell.displayareahelper.DisplayAreaHelper; import com.android.wm.shell.draganddrop.DragAndDrop; import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout; -import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.recents.RecentTasks; @@ -85,9 +84,6 @@ public interface SysUIComponent { @BindsInstance Builder setPip(Optional p); - @BindsInstance - Builder setLegacySplitScreen(Optional s); - @BindsInstance Builder setSplitScreen(Optional s); diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java index b02074a65e9ad..6dfa7e56c09e1 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java @@ -37,7 +37,6 @@ import com.android.wm.shell.dagger.WMSingleton; import com.android.wm.shell.displayareahelper.DisplayAreaHelper; import com.android.wm.shell.draganddrop.DragAndDrop; import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout; -import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.recents.RecentTasks; @@ -95,9 +94,6 @@ public interface WMComponent { @WMSingleton Optional getPip(); - @WMSingleton - Optional getLegacySplitScreen(); - @WMSingleton Optional getSplitScreen();