diff options
Diffstat (limited to 'libs')
7 files changed, 363 insertions, 30 deletions
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java index bdf703c9bd38..7e9c4189dabb 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java @@ -20,11 +20,14 @@ import android.app.ActivityThread; import android.content.Context; import androidx.annotation.NonNull; +import androidx.window.extensions.area.WindowAreaComponent; +import androidx.window.extensions.area.WindowAreaComponentImpl; import androidx.window.extensions.embedding.ActivityEmbeddingComponent; import androidx.window.extensions.embedding.SplitController; import androidx.window.extensions.layout.WindowLayoutComponent; import androidx.window.extensions.layout.WindowLayoutComponentImpl; + /** * The reference implementation of {@link WindowExtensions} that implements the initial API version. */ @@ -33,10 +36,12 @@ public class WindowExtensionsImpl implements WindowExtensions { private final Object mLock = new Object(); private volatile WindowLayoutComponent mWindowLayoutComponent; private volatile SplitController mSplitController; + private volatile WindowAreaComponent mWindowAreaComponent; + // TODO(b/241126279) Introduce constants to better version functionality @Override public int getVendorApiLevel() { - return 1; + return 2; } /** @@ -75,4 +80,23 @@ public class WindowExtensionsImpl implements WindowExtensions { } return mSplitController; } + + /** + * Returns a reference implementation of {@link WindowAreaComponent} if available, + * {@code null} otherwise. The implementation must match the API level reported in + * {@link WindowExtensions#getWindowAreaComponent()}. + * @return {@link WindowAreaComponent} OEM implementation. + */ + public WindowAreaComponent getWindowAreaComponent() { + if (mWindowAreaComponent == null) { + synchronized (mLock) { + if (mWindowAreaComponent == null) { + Context context = ActivityThread.currentApplication(); + mWindowAreaComponent = + new WindowAreaComponentImpl(context); + } + } + } + return mWindowAreaComponent; + } } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java new file mode 100644 index 000000000000..3adae7006369 --- /dev/null +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package androidx.window.extensions.area; + +import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE; + +import android.app.Activity; +import android.content.Context; +import android.hardware.devicestate.DeviceStateManager; +import android.hardware.devicestate.DeviceStateRequest; +import android.util.ArraySet; + +import androidx.annotation.NonNull; + +import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; + +import java.util.concurrent.Executor; +import java.util.function.Consumer; + +/** + * Reference implementation of androidx.window.extensions.area OEM interface for use with + * WindowManager Jetpack. + * + * This component currently supports Rear Display mode with the ability to add and remove + * status listeners for this mode. + * + * The public methods in this class are thread-safe. + **/ +public class WindowAreaComponentImpl implements WindowAreaComponent, + DeviceStateManager.DeviceStateCallback { + + private final Object mLock = new Object(); + + private final DeviceStateManager mDeviceStateManager; + private final Executor mExecutor; + + @GuardedBy("mLock") + private final ArraySet<Consumer<Integer>> mRearDisplayStatusListeners = new ArraySet<>(); + private final int mRearDisplayState; + @WindowAreaSessionState + private int mRearDisplaySessionStatus = WindowAreaComponent.SESSION_STATE_INACTIVE; + + @GuardedBy("mLock") + private int mCurrentDeviceState = INVALID_DEVICE_STATE; + @GuardedBy("mLock") + private int mCurrentDeviceBaseState = INVALID_DEVICE_STATE; + @GuardedBy("mLock") + private DeviceStateRequest mDeviceStateRequest; + + public WindowAreaComponentImpl(@NonNull Context context) { + mDeviceStateManager = context.getSystemService(DeviceStateManager.class); + mExecutor = context.getMainExecutor(); + + // TODO(b/236022708) Move rear display state to device state config file + mRearDisplayState = context.getResources().getInteger( + R.integer.config_deviceStateRearDisplay); + + mDeviceStateManager.registerCallback(mExecutor, this); + } + + /** + * Adds a listener interested in receiving updates on the RearDisplayStatus + * of the device. Because this is being called from the OEM provided + * extensions, we will post the result of the listener on the executor + * provided by the developer at the initial call site. + * + * Depending on the initial state of the device, we will return either + * {@link WindowAreaComponent#STATUS_AVAILABLE} or + * {@link WindowAreaComponent#STATUS_UNAVAILABLE} if the feature is supported or not in that + * state respectively. When the rear display feature is triggered, we update the status to be + * {@link WindowAreaComponent#STATUS_UNAVAILABLE}. TODO(b/240727590) Prefix with AREA_ + * + * TODO(b/239833099) Add a STATUS_ACTIVE option to let apps know if a feature is currently + * enabled. + * + * @param consumer {@link Consumer} interested in receiving updates to the status of + * rear display mode. + */ + public void addRearDisplayStatusListener( + @NonNull Consumer<@WindowAreaStatus Integer> consumer) { + synchronized (mLock) { + mRearDisplayStatusListeners.add(consumer); + + // If current device state is still invalid, we haven't gotten our initial value yet + if (mCurrentDeviceState == INVALID_DEVICE_STATE) { + return; + } + consumer.accept(getCurrentStatus()); + } + } + + /** + * Removes a listener no longer interested in receiving updates. + * @param consumer no longer interested in receiving updates to RearDisplayStatus + */ + public void removeRearDisplayStatusListener( + @NonNull Consumer<@WindowAreaStatus Integer> consumer) { + synchronized (mLock) { + mRearDisplayStatusListeners.remove(consumer); + } + } + + /** + * Creates and starts a rear display session and provides updates to the + * callback provided. Because this is being called from the OEM provided + * extensions, we will post the result of the listener on the executor + * provided by the developer at the initial call site. + * + * When we enable rear display mode, we submit a request to {@link DeviceStateManager} + * to override the device state to the state that corresponds to RearDisplay + * mode. When the {@link DeviceStateRequest} is activated, we let the + * consumer know that the session is active by sending + * {@link WindowAreaComponent#SESSION_STATE_ACTIVE}. + * + * @param activity to provide updates to the client on + * the status of the Session + * @param rearDisplaySessionCallback to provide updates to the client on + * the status of the Session + */ + public void startRearDisplaySession(@NonNull Activity activity, + @NonNull Consumer<@WindowAreaSessionState Integer> rearDisplaySessionCallback) { + synchronized (mLock) { + if (mDeviceStateRequest != null) { + // Rear display session is already active + throw new IllegalStateException( + "Unable to start new rear display session as one is already active"); + } + mDeviceStateRequest = DeviceStateRequest.newBuilder(mRearDisplayState).build(); + mDeviceStateManager.requestState( + mDeviceStateRequest, + mExecutor, + new DeviceStateRequestCallbackAdapter(rearDisplaySessionCallback) + ); + } + } + + /** + * Ends the current rear display session and provides updates to the + * callback provided. Because this is being called from the OEM provided + * extensions, we will post the result of the listener on the executor + * provided by the developer. + */ + public void endRearDisplaySession() { + synchronized (mLock) { + if (mDeviceStateRequest != null || isRearDisplayActive()) { + mDeviceStateRequest = null; + mDeviceStateManager.cancelStateRequest(); + } else { + throw new IllegalStateException( + "Unable to cancel a rear display session as there is no active session"); + } + } + } + + @Override + public void onBaseStateChanged(int state) { + synchronized (mLock) { + mCurrentDeviceBaseState = state; + if (state == mCurrentDeviceState) { + updateStatusConsumers(getCurrentStatus()); + } + } + } + + @Override + public void onStateChanged(int state) { + synchronized (mLock) { + mCurrentDeviceState = state; + updateStatusConsumers(getCurrentStatus()); + } + } + + @GuardedBy("mLock") + private int getCurrentStatus() { + if (mRearDisplaySessionStatus == WindowAreaComponent.SESSION_STATE_ACTIVE + || isRearDisplayActive()) { + return WindowAreaComponent.STATUS_UNAVAILABLE; + } + return WindowAreaComponent.STATUS_AVAILABLE; + } + + /** + * Helper method to determine if a rear display session is currently active by checking + * if the current device configuration matches that of rear display. This would be true + * if there is a device override currently active (base state != current state) and the current + * state is that which corresponds to {@code mRearDisplayState} + * @return {@code true} if the device is in rear display mode and {@code false} if not + */ + @GuardedBy("mLock") + private boolean isRearDisplayActive() { + return (mCurrentDeviceState != mCurrentDeviceBaseState) && (mCurrentDeviceState + == mRearDisplayState); + } + + @GuardedBy("mLock") + private void updateStatusConsumers(@WindowAreaStatus int windowAreaStatus) { + synchronized (mLock) { + for (int i = 0; i < mRearDisplayStatusListeners.size(); i++) { + mRearDisplayStatusListeners.valueAt(i).accept(windowAreaStatus); + } + } + } + + /** + * Callback for the {@link DeviceStateRequest} to be notified of when the request has been + * activated or cancelled. This callback provides information to the client library + * on the status of the RearDisplay session through {@code mRearDisplaySessionCallback} + */ + private class DeviceStateRequestCallbackAdapter implements DeviceStateRequest.Callback { + + private final Consumer<Integer> mRearDisplaySessionCallback; + + DeviceStateRequestCallbackAdapter(@NonNull Consumer<Integer> callback) { + mRearDisplaySessionCallback = callback; + } + + @Override + public void onRequestActivated(@NonNull DeviceStateRequest request) { + synchronized (mLock) { + if (request.equals(mDeviceStateRequest)) { + mRearDisplaySessionStatus = WindowAreaComponent.SESSION_STATE_ACTIVE; + mRearDisplaySessionCallback.accept(mRearDisplaySessionStatus); + updateStatusConsumers(getCurrentStatus()); + } + } + } + + @Override + public void onRequestCanceled(DeviceStateRequest request) { + synchronized (mLock) { + if (request.equals(mDeviceStateRequest)) { + mDeviceStateRequest = null; + } + mRearDisplaySessionStatus = WindowAreaComponent.SESSION_STATE_INACTIVE; + mRearDisplaySessionCallback.accept(mRearDisplaySessionStatus); + updateStatusConsumers(getCurrentStatus()); + } + } + } +} diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar Binary files differindex 918e514f4c89..e9a1721fba2a 100644 --- a/libs/WindowManager/Jetpack/window-extensions-release.aar +++ b/libs/WindowManager/Jetpack/window-extensions-release.aar diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index 85c8ebf454c9..83ba909e712d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -80,7 +80,10 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange public static final int PARALLAX_DISMISSING = 1; public static final int PARALLAX_ALIGN_CENTER = 2; - private static final int FLING_ANIMATION_DURATION = 250; + private static final int FLING_RESIZE_DURATION = 250; + private static final int FLING_SWITCH_DURATION = 350; + private static final int FLING_ENTER_DURATION = 350; + private static final int FLING_EXIT_DURATION = 350; private final int mDividerWindowWidth; private final int mDividerInsets; @@ -93,6 +96,9 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange private final Rect mBounds1 = new Rect(); // Bounds2 final position should be always at bottom or right private final Rect mBounds2 = new Rect(); + // The temp bounds outside of display bounds for side stage when split screen inactive to avoid + // flicker next time active split screen. + private final Rect mInvisibleBounds = new Rect(); private final Rect mWinBounds1 = new Rect(); private final Rect mWinBounds2 = new Rect(); private final SplitLayoutHandler mSplitLayoutHandler; @@ -141,6 +147,10 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange resetDividerPosition(); mDimNonImeSide = resources.getBoolean(R.bool.config_dimNonImeAttachedSide); + + mInvisibleBounds.set(mRootBounds); + mInvisibleBounds.offset(isLandscape() ? mRootBounds.right : 0, + isLandscape() ? 0 : mRootBounds.bottom); } private int getDividerInsets(Resources resources, Display display) { @@ -239,6 +249,12 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange rect.offset(-mRootBounds.left, -mRootBounds.top); } + /** Gets bounds size equal to root bounds but outside of screen, used for position side stage + * when split inactive to avoid flicker when next time active. */ + public void getInvisibleBounds(Rect rect) { + rect.set(mInvisibleBounds); + } + /** Returns leash of the current divider bar. */ @Nullable public SurfaceControl getDividerLeash() { @@ -284,6 +300,10 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, null); initDividerPosition(mTempRect); + mInvisibleBounds.set(mRootBounds); + mInvisibleBounds.offset(isLandscape() ? mRootBounds.right : 0, + isLandscape() ? 0 : mRootBounds.bottom); + return true; } @@ -405,6 +425,13 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange mFreezeDividerWindow = freezeDividerWindow; } + /** Update current layout as divider put on start or end position. */ + public void setDividerAtBorder(boolean start) { + final int pos = start ? mDividerSnapAlgorithm.getDismissStartTarget().position + : mDividerSnapAlgorithm.getDismissEndTarget().position; + setDividePosition(pos, false /* applyLayoutChange */); + } + /** * Updates bounds with the passing position. Usually used to update recording bounds while * performing animation or dragging divider bar to resize the splits. @@ -449,17 +476,17 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange public void snapToTarget(int currentPosition, DividerSnapAlgorithm.SnapTarget snapTarget) { switch (snapTarget.flag) { case FLAG_DISMISS_START: - flingDividePosition(currentPosition, snapTarget.position, + flingDividePosition(currentPosition, snapTarget.position, FLING_RESIZE_DURATION, () -> mSplitLayoutHandler.onSnappedToDismiss(false /* bottomOrRight */, EXIT_REASON_DRAG_DIVIDER)); break; case FLAG_DISMISS_END: - flingDividePosition(currentPosition, snapTarget.position, + flingDividePosition(currentPosition, snapTarget.position, FLING_RESIZE_DURATION, () -> mSplitLayoutHandler.onSnappedToDismiss(true /* bottomOrRight */, EXIT_REASON_DRAG_DIVIDER)); break; default: - flingDividePosition(currentPosition, snapTarget.position, + flingDividePosition(currentPosition, snapTarget.position, FLING_RESIZE_DURATION, () -> setDividePosition(snapTarget.position, true /* applyLayoutChange */)); break; } @@ -516,12 +543,20 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange public void flingDividerToDismiss(boolean toEnd, int reason) { final int target = toEnd ? mDividerSnapAlgorithm.getDismissEndTarget().position : mDividerSnapAlgorithm.getDismissStartTarget().position; - flingDividePosition(getDividePosition(), target, + flingDividePosition(getDividePosition(), target, FLING_EXIT_DURATION, () -> mSplitLayoutHandler.onSnappedToDismiss(toEnd, reason)); } + /** Fling divider from current position to center position. */ + public void flingDividerToCenter() { + final int pos = mDividerSnapAlgorithm.getMiddleTarget().position; + flingDividePosition(getDividePosition(), pos, FLING_ENTER_DURATION, + () -> setDividePosition(pos, true /* applyLayoutChange */)); + } + @VisibleForTesting - void flingDividePosition(int from, int to, @Nullable Runnable flingFinishedCallback) { + void flingDividePosition(int from, int to, int duration, + @Nullable Runnable flingFinishedCallback) { if (from == to) { // No animation run, still callback to stop resizing. mSplitLayoutHandler.onLayoutSizeChanged(this); @@ -531,7 +566,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange } ValueAnimator animator = ValueAnimator .ofInt(from, to) - .setDuration(FLING_ANIMATION_DURATION); + .setDuration(duration); animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); animator.addUpdateListener( animation -> updateDivideBounds((int) animation.getAnimatedValue())); @@ -588,7 +623,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange AnimatorSet set = new AnimatorSet(); set.playTogether(animator1, animator2, animator3); - set.setDuration(FLING_ANIMATION_DURATION); + set.setDuration(FLING_SWITCH_DURATION); set.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 7e83d2fa0a0b..21fc01e554c8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -25,6 +25,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; +import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.RemoteAnimationTarget.MODE_OPENING; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; @@ -488,13 +489,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, final WindowContainerTransaction wct = new WindowContainerTransaction(); options = resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, wct); - // If split still not active, apply windows bounds first to avoid surface reset to - // wrong pos by SurfaceAnimator from wms. - // TODO(b/223325631): check is it still necessary after improve enter transition done. - if (!mMainStage.isActive()) { - updateWindowBounds(mSplitLayout, wct); - } - wct.sendPendingIntent(intent, fillInIntent, options); mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct); } @@ -641,7 +635,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, wct.startTask(sideTaskId, sideOptions); } // Using legacy transitions, so we can't use blast sync since it conflicts. - mTaskOrganizer.applyTransaction(wct); + mSyncQueue.queue(wct); mSyncQueue.runInSync(t -> { setDividerVisibility(true, t); updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */); @@ -893,10 +887,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mShouldUpdateRecents = false; mIsDividerRemoteAnimating = false; + mSplitLayout.getInvisibleBounds(mTempRect1); if (childrenToTop == null) { mSideStage.removeAllTasks(wct, false /* toTop */); mMainStage.deactivate(wct, false /* toTop */); wct.reorder(mRootTaskInfo.token, false /* onTop */); + wct.setForceTranslucent(mRootTaskInfo.token, true); + wct.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1); onTransitionAnimationComplete(); } else { // Expand to top side split as full screen for fading out decor animation and dismiss @@ -907,27 +904,32 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, ? mSideStage : mMainStage; tempFullStage.resetBounds(wct); wct.setSmallestScreenWidthDp(tempFullStage.mRootTaskInfo.token, - mRootTaskInfo.configuration.smallestScreenWidthDp); + SMALLEST_SCREEN_WIDTH_DP_UNDEFINED); dismissStage.dismiss(wct, false /* toTop */); } mSyncQueue.queue(wct); mSyncQueue.runInSync(t -> { t.setWindowCrop(mMainStage.mRootLeash, null) .setWindowCrop(mSideStage.mRootLeash, null); - t.setPosition(mMainStage.mRootLeash, 0, 0) - .setPosition(mSideStage.mRootLeash, 0, 0); t.hide(mMainStage.mDimLayer).hide(mSideStage.mDimLayer); setDividerVisibility(false, t); - // In this case, exit still under progress, fade out the split decor after first WCT - // done and do remaining WCT after animation finished. - if (childrenToTop != null) { + if (childrenToTop == null) { + t.setPosition(mSideStage.mRootLeash, mTempRect1.left, mTempRect1.right); + } else { + // In this case, exit still under progress, fade out the split decor after first WCT + // done and do remaining WCT after animation finished. childrenToTop.fadeOutDecor(() -> { WindowContainerTransaction finishedWCT = new WindowContainerTransaction(); mIsExiting = false; childrenToTop.dismiss(finishedWCT, true /* toTop */); finishedWCT.reorder(mRootTaskInfo.token, false /* toTop */); - mTaskOrganizer.applyTransaction(finishedWCT); + finishedWCT.setForceTranslucent(mRootTaskInfo.token, true); + finishedWCT.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1); + mSyncQueue.queue(finishedWCT); + mSyncQueue.runInSync(at -> { + at.setPosition(mSideStage.mRootLeash, mTempRect1.left, mTempRect1.right); + }); onTransitionAnimationComplete(); }); } @@ -996,6 +998,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mMainStage.activate(wct, true /* includingTopTask */); updateWindowBounds(mSplitLayout, wct); wct.reorder(mRootTaskInfo.token, true); + wct.setForceTranslucent(mRootTaskInfo.token, false); } void finishEnterSplitScreen(SurfaceControl.Transaction t) { @@ -1221,7 +1224,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // Make the stages adjacent to each other so they occlude what's behind them. wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token); wct.setLaunchAdjacentFlagRoot(mSideStage.mRootTaskInfo.token); - mTaskOrganizer.applyTransaction(wct); + wct.setForceTranslucent(mRootTaskInfo.token, true); + mSplitLayout.getInvisibleBounds(mTempRect1); + wct.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1); + mSyncQueue.queue(wct); + mSyncQueue.runInSync(t -> { + t.setPosition(mSideStage.mRootLeash, mTempRect1.left, mTempRect1.top); + }); } private void onRootTaskVanished() { @@ -1377,10 +1386,17 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // TODO (b/238697912) : Add the validation to prevent entering non-recovered status final WindowContainerTransaction wct = new WindowContainerTransaction(); mSplitLayout.init(); - prepareEnterSplitScreen(wct); + mSplitLayout.setDividerAtBorder(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT); + mMainStage.activate(wct, true /* includingTopTask */); + updateWindowBounds(mSplitLayout, wct); + wct.reorder(mRootTaskInfo.token, true); + wct.setForceTranslucent(mRootTaskInfo.token, false); mSyncQueue.queue(wct); - mSyncQueue.runInSync(t -> - updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */)); + mSyncQueue.runInSync(t -> { + updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */); + + mSplitLayout.flingDividerToCenter(); + }); } if (mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) { mShouldUpdateRecents = true; @@ -1822,6 +1838,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // properly for the animation itself. mSplitLayout.release(); mSplitLayout.resetDividerPosition(); + mSideStagePosition = SPLIT_POSITION_BOTTOM_OR_RIGHT; mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED; } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java index 95725bbfd855..695550dd8fa5 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java @@ -159,7 +159,8 @@ public class SplitLayoutTests extends ShellTestCase { } private void waitDividerFlingFinished() { - verify(mSplitLayout).flingDividePosition(anyInt(), anyInt(), mRunnableCaptor.capture()); + verify(mSplitLayout).flingDividePosition(anyInt(), anyInt(), anyInt(), + mRunnableCaptor.capture()); mRunnableCaptor.getValue().run(); } diff --git a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp index a0bc5aa245d5..2aeb42cc0e20 100644 --- a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp +++ b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp @@ -16,7 +16,8 @@ #include "TestSceneBase.h" -#include <SkColorMatrixFilter.h> +#include <SkColorFilter.h> +#include <SkColorMatrix.h> #include <SkGradientShader.h> class SimpleColorMatrixAnimation; |