Merge "Synchronize display change with the Shell" into tm-qpr-dev am: 343260adfa
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/18140347 Change-Id: I79ae5b123006a43140cb11dd5344483552440e75 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -17,13 +17,15 @@
|
||||
package android.view;
|
||||
|
||||
import android.window.WindowContainerTransaction;
|
||||
import android.window.DisplayAreaInfo;
|
||||
|
||||
/**
|
||||
* Interface to be invoked by the controller when it has finished preparing for a display rotation.
|
||||
* Interface to be invoked by the controller when it has finished preparing for a display
|
||||
* size change.
|
||||
*
|
||||
* @see IDisplayWindowRotationController
|
||||
* @see IDisplayChangeWindowController
|
||||
* @hide
|
||||
*/
|
||||
interface IDisplayWindowRotationCallback {
|
||||
void continueRotateDisplay(int targetRotation, in WindowContainerTransaction t);
|
||||
interface IDisplayChangeWindowCallback {
|
||||
void continueDisplayChange(in WindowContainerTransaction t);
|
||||
}
|
||||
@@ -16,11 +16,12 @@
|
||||
|
||||
package android.view;
|
||||
|
||||
import android.view.IDisplayWindowRotationCallback;
|
||||
import android.view.IDisplayChangeWindowCallback;
|
||||
import android.window.DisplayAreaInfo;
|
||||
|
||||
/**
|
||||
* Singular controller of a "remote" display rotation. When a display rotation is started, WM
|
||||
* freezes the screen. It will then call into this controller and wait for a response via the
|
||||
* Singular controller of a "remote" display change. When a display rotation or change is started,
|
||||
* WM freezes the screen. It will then call into this controller and wait for a response via the
|
||||
* callback.
|
||||
*
|
||||
* This needs to provide configuration changes because those changes need to be applied in sync
|
||||
@@ -36,17 +37,18 @@ import android.view.IDisplayWindowRotationCallback;
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IDisplayWindowRotationController {
|
||||
oneway interface IDisplayChangeWindowController {
|
||||
|
||||
/**
|
||||
* Called when WM needs to know how to update tasks in response to a display rotation.
|
||||
* If this isn't called, a timeout will continue the rotation in WM.
|
||||
* Called when WM needs to know how to update tasks in response to a display change.
|
||||
* If this isn't called, a timeout will continue the change in WM.
|
||||
*
|
||||
* @param displayId the display that is rotating.
|
||||
* @param fromRotation the rotation the display is rotating from.
|
||||
* @param toRotation the rotation the display is rotating to.
|
||||
* @param fromRotation the old rotation
|
||||
* @param newRotation the new rotation
|
||||
* @param newDisplayAreaInfo the new display area info after the change
|
||||
* @param callback A callback to be called when this has calculated updated configs.
|
||||
*/
|
||||
void onRotateDisplay(int displayId, int fromRotation, int toRotation,
|
||||
in IDisplayWindowRotationCallback callback);
|
||||
void onDisplayChange(int displayId, int fromRotation, int toRotation,
|
||||
in DisplayAreaInfo newDisplayAreaInfo, in IDisplayChangeWindowCallback callback);
|
||||
|
||||
}
|
||||
@@ -40,7 +40,7 @@ import android.view.ICrossWindowBlurEnabledListener;
|
||||
import android.view.IDisplayWindowInsetsController;
|
||||
import android.view.IDisplayWindowListener;
|
||||
import android.view.IDisplayFoldListener;
|
||||
import android.view.IDisplayWindowRotationController;
|
||||
import android.view.IDisplayChangeWindowController;
|
||||
import android.view.IOnKeyguardExitResult;
|
||||
import android.view.IPinnedTaskListener;
|
||||
import android.view.IScrollCaptureResponseListener;
|
||||
@@ -146,7 +146,7 @@ interface IWindowManager
|
||||
* controller is called after the display has "frozen" for a rotation and display rotation will
|
||||
* only continue once the controller has finished calculating associated configurations.
|
||||
*/
|
||||
void setDisplayWindowRotationController(IDisplayWindowRotationController controller);
|
||||
void setDisplayChangeWindowController(IDisplayChangeWindowController controller);
|
||||
|
||||
/**
|
||||
* Adds a root container that a client shell can populate with its own windows (usually via
|
||||
|
||||
@@ -469,6 +469,12 @@
|
||||
"group": "WM_DEBUG_ADD_REMOVE",
|
||||
"at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
|
||||
},
|
||||
"-1635750891": {
|
||||
"message": "Received remote change for Display[%d], applied: [%dx%d, rot = %d]",
|
||||
"level": "VERBOSE",
|
||||
"group": "WM_DEBUG_CONFIGURATION",
|
||||
"at": "com\/android\/server\/wm\/RemoteDisplayChangeController.java"
|
||||
},
|
||||
"-1633115609": {
|
||||
"message": "Key dispatch not paused for screen off",
|
||||
"level": "VERBOSE",
|
||||
@@ -3397,12 +3403,6 @@
|
||||
"group": "WM_DEBUG_BOOT",
|
||||
"at": "com\/android\/server\/wm\/WindowManagerService.java"
|
||||
},
|
||||
"1246035185": {
|
||||
"message": "stopFreezingDisplayLocked: Returning waitingForConfig=%b, waitingForRemoteRotation=%b, mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, mClientFreezingScreen=%b, mOpeningApps.size()=%d",
|
||||
"level": "DEBUG",
|
||||
"group": "WM_DEBUG_ORIENTATION",
|
||||
"at": "com\/android\/server\/wm\/WindowManagerService.java"
|
||||
},
|
||||
"1252594551": {
|
||||
"message": "Window types in WindowContext and LayoutParams.type should match! Type from LayoutParams is %d, but type from WindowContext is %d",
|
||||
"level": "WARN",
|
||||
@@ -3499,6 +3499,12 @@
|
||||
"group": "WM_DEBUG_ORIENTATION",
|
||||
"at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
|
||||
},
|
||||
"1360176455": {
|
||||
"message": "stopFreezingDisplayLocked: Returning waitingForConfig=%b, waitingForRemoteDisplayChange=%b, mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, mClientFreezingScreen=%b, mOpeningApps.size()=%d",
|
||||
"level": "DEBUG",
|
||||
"group": "WM_DEBUG_ORIENTATION",
|
||||
"at": "com\/android\/server\/wm\/WindowManagerService.java"
|
||||
},
|
||||
"1364126018": {
|
||||
"message": "Resumed activity; dropping state of: %s",
|
||||
"level": "INFO",
|
||||
@@ -3523,6 +3529,12 @@
|
||||
"group": "WM_DEBUG_ORIENTATION",
|
||||
"at": "com\/android\/server\/wm\/TaskDisplayArea.java"
|
||||
},
|
||||
"1393721079": {
|
||||
"message": "Starting remote display change: from [rot = %d], to [%dx%d, rot = %d]",
|
||||
"level": "VERBOSE",
|
||||
"group": "WM_DEBUG_CONFIGURATION",
|
||||
"at": "com\/android\/server\/wm\/RemoteDisplayChangeController.java"
|
||||
},
|
||||
"1396893178": {
|
||||
"message": "createRootTask unknown displayId=%d",
|
||||
"level": "ERROR",
|
||||
@@ -3865,6 +3877,12 @@
|
||||
"group": "WM_DEBUG_ORIENTATION",
|
||||
"at": "com\/android\/server\/wm\/WindowStateAnimator.java"
|
||||
},
|
||||
"1764619787": {
|
||||
"message": "Remote change for Display[%d]: timeout reached",
|
||||
"level": "VERBOSE",
|
||||
"group": "WM_DEBUG_CONFIGURATION",
|
||||
"at": "com\/android\/server\/wm\/RemoteDisplayChangeController.java"
|
||||
},
|
||||
"1774661765": {
|
||||
"message": "Devices still not ready after waiting %d milliseconds before attempting to detect safe mode.",
|
||||
"level": "WARN",
|
||||
|
||||
@@ -78,7 +78,6 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.WindowManager;
|
||||
import android.window.WindowContainerTransaction;
|
||||
|
||||
import androidx.annotation.MainThread;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -89,7 +88,6 @@ import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.TaskViewTransitions;
|
||||
import com.android.wm.shell.WindowManagerShellWrapper;
|
||||
import com.android.wm.shell.common.DisplayChangeController;
|
||||
import com.android.wm.shell.common.DisplayController;
|
||||
import com.android.wm.shell.common.FloatingContentCoordinator;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
@@ -423,17 +421,13 @@ public class BubbleController {
|
||||
});
|
||||
|
||||
mDisplayController.addDisplayChangingController(
|
||||
new DisplayChangeController.OnDisplayChangingListener() {
|
||||
@Override
|
||||
public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
|
||||
WindowContainerTransaction t) {
|
||||
// This is triggered right before the rotation is applied
|
||||
if (fromRotation != toRotation) {
|
||||
if (mStackView != null) {
|
||||
// Layout listener set on stackView will update the positioner
|
||||
// once the rotation is applied
|
||||
mStackView.onOrientationChanged();
|
||||
}
|
||||
(displayId, fromRotation, toRotation, newDisplayAreaInfo, t) -> {
|
||||
// This is triggered right before the rotation is applied
|
||||
if (fromRotation != toRotation) {
|
||||
if (mStackView != null) {
|
||||
// Layout listener set on stackView will update the positioner
|
||||
// once the rotation is applied
|
||||
mStackView.onOrientationChanged();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -16,11 +16,13 @@
|
||||
|
||||
package com.android.wm.shell.common;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Slog;
|
||||
import android.view.IDisplayWindowRotationCallback;
|
||||
import android.view.IDisplayWindowRotationController;
|
||||
import android.view.IDisplayChangeWindowCallback;
|
||||
import android.view.IDisplayChangeWindowController;
|
||||
import android.view.IWindowManager;
|
||||
import android.window.DisplayAreaInfo;
|
||||
import android.window.WindowContainerTransaction;
|
||||
|
||||
import androidx.annotation.BinderThread;
|
||||
@@ -40,17 +42,17 @@ public class DisplayChangeController {
|
||||
|
||||
private final ShellExecutor mMainExecutor;
|
||||
private final IWindowManager mWmService;
|
||||
private final IDisplayWindowRotationController mControllerImpl;
|
||||
private final IDisplayChangeWindowController mControllerImpl;
|
||||
|
||||
private final CopyOnWriteArrayList<OnDisplayChangingListener> mRotationListener =
|
||||
private final CopyOnWriteArrayList<OnDisplayChangingListener> mDisplayChangeListener =
|
||||
new CopyOnWriteArrayList<>();
|
||||
|
||||
public DisplayChangeController(IWindowManager wmService, ShellExecutor mainExecutor) {
|
||||
mMainExecutor = mainExecutor;
|
||||
mWmService = wmService;
|
||||
mControllerImpl = new DisplayWindowRotationControllerImpl();
|
||||
mControllerImpl = new DisplayChangeWindowControllerImpl();
|
||||
try {
|
||||
mWmService.setDisplayWindowRotationController(mControllerImpl);
|
||||
mWmService.setDisplayChangeWindowController(mControllerImpl);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException("Unable to register rotation controller");
|
||||
}
|
||||
@@ -59,63 +61,64 @@ public class DisplayChangeController {
|
||||
/**
|
||||
* Adds a display rotation controller.
|
||||
*/
|
||||
public void addRotationListener(OnDisplayChangingListener listener) {
|
||||
mRotationListener.add(listener);
|
||||
public void addDisplayChangeListener(OnDisplayChangingListener listener) {
|
||||
mDisplayChangeListener.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a display rotation controller.
|
||||
*/
|
||||
public void removeRotationListener(OnDisplayChangingListener listener) {
|
||||
mRotationListener.remove(listener);
|
||||
public void removeDisplayChangeListener(OnDisplayChangingListener listener) {
|
||||
mDisplayChangeListener.remove(listener);
|
||||
}
|
||||
|
||||
/** Query all listeners for changes that should happen on rotation. */
|
||||
public void dispatchOnRotateDisplay(WindowContainerTransaction outWct, int displayId,
|
||||
final int fromRotation, final int toRotation) {
|
||||
for (OnDisplayChangingListener c : mRotationListener) {
|
||||
c.onRotateDisplay(displayId, fromRotation, toRotation, outWct);
|
||||
/** Query all listeners for changes that should happen on display change. */
|
||||
public void dispatchOnDisplayChange(WindowContainerTransaction outWct, int displayId,
|
||||
int fromRotation, int toRotation, DisplayAreaInfo newDisplayAreaInfo) {
|
||||
for (OnDisplayChangingListener c : mDisplayChangeListener) {
|
||||
c.onDisplayChange(displayId, fromRotation, toRotation, newDisplayAreaInfo, outWct);
|
||||
}
|
||||
}
|
||||
|
||||
private void onRotateDisplay(int displayId, final int fromRotation, final int toRotation,
|
||||
IDisplayWindowRotationCallback callback) {
|
||||
private void onDisplayChange(int displayId, int fromRotation, int toRotation,
|
||||
DisplayAreaInfo newDisplayAreaInfo, IDisplayChangeWindowCallback callback) {
|
||||
WindowContainerTransaction t = new WindowContainerTransaction();
|
||||
dispatchOnRotateDisplay(t, displayId, fromRotation, toRotation);
|
||||
dispatchOnDisplayChange(t, displayId, fromRotation, toRotation, newDisplayAreaInfo);
|
||||
try {
|
||||
callback.continueRotateDisplay(toRotation, t);
|
||||
callback.continueDisplayChange(t);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to continue rotation", e);
|
||||
Slog.e(TAG, "Failed to continue handling display change", e);
|
||||
}
|
||||
}
|
||||
|
||||
@BinderThread
|
||||
private class DisplayWindowRotationControllerImpl
|
||||
extends IDisplayWindowRotationController.Stub {
|
||||
private class DisplayChangeWindowControllerImpl
|
||||
extends IDisplayChangeWindowController.Stub {
|
||||
@Override
|
||||
public void onRotateDisplay(int displayId, final int fromRotation,
|
||||
final int toRotation, IDisplayWindowRotationCallback callback) {
|
||||
mMainExecutor.execute(() -> {
|
||||
DisplayChangeController.this.onRotateDisplay(displayId, fromRotation, toRotation,
|
||||
callback);
|
||||
});
|
||||
public void onDisplayChange(int displayId, int fromRotation, int toRotation,
|
||||
DisplayAreaInfo newDisplayAreaInfo, IDisplayChangeWindowCallback callback) {
|
||||
mMainExecutor.execute(() -> DisplayChangeController.this
|
||||
.onDisplayChange(displayId, fromRotation, toRotation,
|
||||
newDisplayAreaInfo, callback));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Give a listener a chance to queue up configuration changes to execute as part of a
|
||||
* display rotation. The contents of {@link #onRotateDisplay} must run synchronously.
|
||||
* display rotation. The contents of {@link #onDisplayChange} must run synchronously.
|
||||
*/
|
||||
@ShellMainThread
|
||||
public interface OnDisplayChangingListener {
|
||||
/**
|
||||
* Called before the display is rotated. Contents of this method must run synchronously.
|
||||
* @param displayId Id of display that is rotating.
|
||||
* @param fromRotation starting rotation of the display.
|
||||
* @param toRotation target rotation of the display (after rotating).
|
||||
* Called before the display size has changed.
|
||||
* Contents of this method must run synchronously.
|
||||
* @param displayId display id of the display that is under the change
|
||||
* @param fromRotation rotation before the change
|
||||
* @param toRotation rotation after the change
|
||||
* @param newDisplayAreaInfo display area info after applying the update
|
||||
* @param t A task transaction to populate.
|
||||
*/
|
||||
void onRotateDisplay(int displayId, int fromRotation, int toRotation,
|
||||
WindowContainerTransaction t);
|
||||
void onDisplayChange(int displayId, int fromRotation, int toRotation,
|
||||
@Nullable DisplayAreaInfo newDisplayAreaInfo, WindowContainerTransaction t);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,14 +156,14 @@ public class DisplayController {
|
||||
* Adds a display rotation controller.
|
||||
*/
|
||||
public void addDisplayChangingController(OnDisplayChangingListener controller) {
|
||||
mChangeController.addRotationListener(controller);
|
||||
mChangeController.addDisplayChangeListener(controller);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a display rotation controller.
|
||||
*/
|
||||
public void removeDisplayChangingController(OnDisplayChangingListener controller) {
|
||||
mChangeController.removeRotationListener(controller);
|
||||
mChangeController.removeDisplayChangeListener(controller);
|
||||
}
|
||||
|
||||
private void onDisplayAdded(int displayId) {
|
||||
|
||||
@@ -39,6 +39,7 @@ import android.provider.Settings;
|
||||
import android.util.Slog;
|
||||
import android.view.WindowManager;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.window.DisplayAreaInfo;
|
||||
import android.window.WindowContainerTransaction;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -659,11 +660,11 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles rotation based on OnDisplayChangingListener callback
|
||||
* Handles display change based on OnDisplayChangingListener callback
|
||||
*/
|
||||
@Override
|
||||
public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
|
||||
WindowContainerTransaction wct) {
|
||||
public void onDisplayChange(int displayId, int fromRotation, int toRotation,
|
||||
DisplayAreaInfo newDisplayAreaInfo, WindowContainerTransaction wct) {
|
||||
if (!isInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
* Handler for display rotation changes.
|
||||
*/
|
||||
private final DisplayChangeController.OnDisplayChangingListener mRotationController = (
|
||||
int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) -> {
|
||||
displayId, fromRotation, toRotation, newDisplayAreaInfo, t) -> {
|
||||
if (mPipTransitionController.handleRotateDisplay(fromRotation, toRotation, t)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ import android.view.RemoteAnimationTarget;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.SurfaceSession;
|
||||
import android.view.WindowManager;
|
||||
import android.window.DisplayAreaInfo;
|
||||
import android.window.RemoteTransition;
|
||||
import android.window.TransitionInfo;
|
||||
import android.window.TransitionRequestInfo;
|
||||
@@ -1318,7 +1319,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
||||
if (displayId != DEFAULT_DISPLAY) {
|
||||
return;
|
||||
}
|
||||
mDisplayController.addDisplayChangingController(this::onRotateDisplay);
|
||||
mDisplayController.addDisplayChangingController(this::onDisplayChange);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1329,14 +1330,17 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
||||
mDisplayLayout.set(mDisplayController.getDisplayLayout(displayId));
|
||||
}
|
||||
|
||||
private void onRotateDisplay(int displayId, int fromRotation, int toRotation,
|
||||
WindowContainerTransaction wct) {
|
||||
private void onDisplayChange(int displayId, int fromRotation, int toRotation,
|
||||
@Nullable DisplayAreaInfo newDisplayAreaInfo, WindowContainerTransaction wct) {
|
||||
if (!mMainStage.isActive()) return;
|
||||
// Only do this when shell transition
|
||||
if (!ENABLE_SHELL_TRANSITIONS) return;
|
||||
|
||||
mDisplayLayout.rotateTo(mContext.getResources(), toRotation);
|
||||
mSplitLayout.rotateTo(toRotation, mDisplayLayout.stableInsets());
|
||||
if (newDisplayAreaInfo != null) {
|
||||
mSplitLayout.updateConfiguration(newDisplayAreaInfo.configuration);
|
||||
}
|
||||
updateWindowBounds(mSplitLayout, wct);
|
||||
updateUnfoldBounds();
|
||||
}
|
||||
|
||||
@@ -629,8 +629,9 @@ public class Transitions implements RemoteCallable<Transitions> {
|
||||
if (wct == null) {
|
||||
wct = new WindowContainerTransaction();
|
||||
}
|
||||
mDisplayController.getChangeController().dispatchOnRotateDisplay(wct,
|
||||
change.getDisplayId(), change.getStartRotation(), change.getEndRotation());
|
||||
mDisplayController.getChangeController().dispatchOnDisplayChange(wct,
|
||||
change.getDisplayId(), change.getStartRotation(), change.getEndRotation(),
|
||||
null /* newDisplayAreaInfo */);
|
||||
}
|
||||
}
|
||||
active.mToken = mOrganizer.startTransition(
|
||||
|
||||
@@ -127,7 +127,8 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene
|
||||
@Override
|
||||
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
|
||||
@NonNull TransitionRequestInfo request) {
|
||||
if (request.getType() == TRANSIT_CHANGE && request.getDisplayChange() != null) {
|
||||
if (request.getType() == TRANSIT_CHANGE && request.getDisplayChange() != null
|
||||
&& request.getDisplayChange().isPhysicalDisplayChanged()) {
|
||||
mTransition = transition;
|
||||
return new WindowContainerTransaction();
|
||||
}
|
||||
|
||||
@@ -345,8 +345,8 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
|
||||
false);
|
||||
final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
|
||||
mSpiedOneHandedController.onRotateDisplay(mDisplay.getDisplayId(), Surface.ROTATION_0,
|
||||
Surface.ROTATION_90, handlerWCT);
|
||||
mSpiedOneHandedController.onDisplayChange(mDisplay.getDisplayId(), Surface.ROTATION_0,
|
||||
Surface.ROTATION_90, null /* newDisplayAreaInfo */, handlerWCT);
|
||||
|
||||
verify(mMockDisplayAreaOrganizer, atLeastOnce()).onRotateDisplay(eq(mContext),
|
||||
eq(Surface.ROTATION_90), any(WindowContainerTransaction.class));
|
||||
@@ -358,8 +358,8 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
|
||||
false);
|
||||
final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
|
||||
mSpiedOneHandedController.onRotateDisplay(mDisplay.getDisplayId(), Surface.ROTATION_0,
|
||||
Surface.ROTATION_90, handlerWCT);
|
||||
mSpiedOneHandedController.onDisplayChange(mDisplay.getDisplayId(), Surface.ROTATION_0,
|
||||
Surface.ROTATION_90, null /* newDisplayAreaInfo */, handlerWCT);
|
||||
|
||||
verify(mMockDisplayAreaOrganizer, never()).onRotateDisplay(eq(mContext),
|
||||
eq(Surface.ROTATION_90), any(WindowContainerTransaction.class));
|
||||
@@ -371,8 +371,8 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
|
||||
true);
|
||||
final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
|
||||
mSpiedOneHandedController.onRotateDisplay(mDisplay.getDisplayId(), Surface.ROTATION_0,
|
||||
Surface.ROTATION_90, handlerWCT);
|
||||
mSpiedOneHandedController.onDisplayChange(mDisplay.getDisplayId(), Surface.ROTATION_0,
|
||||
Surface.ROTATION_90, null /* newDisplayAreaInfo */, handlerWCT);
|
||||
|
||||
verify(mMockDisplayAreaOrganizer, never()).onRotateDisplay(eq(mContext),
|
||||
eq(Surface.ROTATION_90), any(WindowContainerTransaction.class));
|
||||
@@ -384,8 +384,8 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
|
||||
false);
|
||||
final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
|
||||
mSpiedOneHandedController.onRotateDisplay(mDisplay.getDisplayId(), Surface.ROTATION_0,
|
||||
Surface.ROTATION_90, handlerWCT);
|
||||
mSpiedOneHandedController.onDisplayChange(mDisplay.getDisplayId(), Surface.ROTATION_0,
|
||||
Surface.ROTATION_90, null /* newDisplayAreaInfo */, handlerWCT);
|
||||
|
||||
verify(mMockDisplayAreaOrganizer, atLeastOnce()).onRotateDisplay(eq(mContext),
|
||||
eq(Surface.ROTATION_90), any(WindowContainerTransaction.class));
|
||||
|
||||
@@ -556,7 +556,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
||||
final FixedRotationTransitionListener mFixedRotationTransitionListener =
|
||||
new FixedRotationTransitionListener();
|
||||
|
||||
private PhysicalDisplaySwitchTransitionLauncher mDisplaySwitchTransitionLauncher;
|
||||
private final PhysicalDisplaySwitchTransitionLauncher mDisplaySwitchTransitionLauncher;
|
||||
final RemoteDisplayChangeController mRemoteDisplayChangeController;
|
||||
|
||||
/** Windows added since {@link #mCurrentFocus} was set to null. Used for ANR blaming. */
|
||||
final ArrayList<WindowState> mWinAddedSinceNullFocus = new ArrayList<>();
|
||||
@@ -1052,6 +1053,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
||||
mUnknownAppVisibilityController = new UnknownAppVisibilityController(mWmService, this);
|
||||
mDisplaySwitchTransitionLauncher = new PhysicalDisplaySwitchTransitionLauncher(this,
|
||||
mTransitionController);
|
||||
mRemoteDisplayChangeController = new RemoteDisplayChangeController(mWmService, mDisplayId);
|
||||
|
||||
final InputChannel inputChannel = mWmService.mInputManager.monitorInput(
|
||||
"PointerEventDispatcher" + mDisplayId, mDisplayId);
|
||||
@@ -1433,7 +1435,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
||||
if (!isReady()) {
|
||||
return;
|
||||
}
|
||||
if (mDisplayRotation.isWaitingForRemoteRotation()) {
|
||||
if (mRemoteDisplayChangeController.isWaitingForRemoteDisplayChange()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1533,8 +1535,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
||||
config = new Configuration();
|
||||
computeScreenConfiguration(config);
|
||||
} else if (!(mTransitionController.isCollecting(this)
|
||||
// If waiting for a remote rotation, don't prematurely update configuration.
|
||||
|| mDisplayRotation.isWaitingForRemoteRotation())) {
|
||||
// If waiting for a remote display change, don't prematurely update configuration.
|
||||
|| mRemoteDisplayChangeController.isWaitingForRemoteDisplayChange())) {
|
||||
// No obvious action we need to take, but if our current state mismatches the
|
||||
// activity manager's, update it, disregarding font scale, which should remain set
|
||||
// to the value of the previous configuration.
|
||||
@@ -1596,7 +1598,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
||||
boolean isSyncFinished() {
|
||||
// Do not consider children because if they are requested to be synced, they should be
|
||||
// added to sync group explicitly.
|
||||
return !mDisplayRotation.isWaitingForRemoteRotation();
|
||||
return !mRemoteDisplayChangeController.isWaitingForRemoteDisplayChange();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1829,8 +1831,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
||||
sendNewConfiguration();
|
||||
return;
|
||||
}
|
||||
if (mDisplayRotation.isWaitingForRemoteRotation()) {
|
||||
// There is pending rotation change to apply.
|
||||
if (mRemoteDisplayChangeController.isWaitingForRemoteDisplayChange()) {
|
||||
// There is pending display change to apply.
|
||||
return;
|
||||
}
|
||||
// The orientation of display is not changed.
|
||||
@@ -2758,6 +2760,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
||||
private void updateBaseDisplayMetricsIfNeeded() {
|
||||
// Get real display metrics without overrides from WM.
|
||||
mWmService.mDisplayManagerInternal.getNonOverrideDisplayInfo(mDisplayId, mDisplayInfo);
|
||||
final int currentRotation = getRotation();
|
||||
final int orientation = mDisplayInfo.rotation;
|
||||
final boolean rotated = (orientation == ROTATION_90 || orientation == ROTATION_270);
|
||||
final int newWidth = rotated ? mDisplayInfo.logicalHeight : mDisplayInfo.logicalWidth;
|
||||
@@ -2818,7 +2821,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
||||
reconfigureDisplayLocked();
|
||||
|
||||
if (physicalDisplayChanged) {
|
||||
mDisplaySwitchTransitionLauncher.onDisplayUpdated();
|
||||
mDisplaySwitchTransitionLauncher.onDisplayUpdated(currentRotation, getRotation(),
|
||||
getDisplayAreaInfo());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,14 +51,12 @@ import android.content.res.Resources;
|
||||
import android.database.ContentObserver;
|
||||
import android.hardware.power.Boost;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Slog;
|
||||
import android.util.TimeUtils;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
import android.view.IDisplayWindowRotationCallback;
|
||||
import android.view.IWindowManager;
|
||||
import android.view.Surface;
|
||||
import android.window.TransitionRequestInfo;
|
||||
@@ -67,7 +65,6 @@ import android.window.WindowContainerTransaction;
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.protolog.common.ProtoLog;
|
||||
import com.android.internal.util.function.pooled.PooledLambda;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.UiThread;
|
||||
import com.android.server.policy.WindowManagerPolicy;
|
||||
@@ -211,31 +208,6 @@ public class DisplayRotation {
|
||||
private boolean mDemoHdmiRotationLock;
|
||||
private boolean mDemoRotationLock;
|
||||
|
||||
private static final int REMOTE_ROTATION_TIMEOUT_MS = 800;
|
||||
|
||||
private boolean mIsWaitingForRemoteRotation = false;
|
||||
|
||||
private final Runnable mDisplayRotationHandlerTimeout =
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
continueRotation(mRotation, null /* transaction */);
|
||||
}
|
||||
};
|
||||
|
||||
private final IDisplayWindowRotationCallback mRemoteRotationCallback =
|
||||
new IDisplayWindowRotationCallback.Stub() {
|
||||
@Override
|
||||
public void continueRotateDisplay(int targetRotation,
|
||||
WindowContainerTransaction t) {
|
||||
synchronized (mService.getWindowManagerLock()) {
|
||||
mService.mH.sendMessage(PooledLambda.obtainMessage(
|
||||
DisplayRotation::continueRotation, DisplayRotation.this,
|
||||
targetRotation, t));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
DisplayRotation(WindowManagerService service, DisplayContent displayContent) {
|
||||
this(service, displayContent, displayContent.getDisplayPolicy(),
|
||||
service.mDisplayWindowSettings, service.mContext, service.getWindowManagerLock());
|
||||
@@ -511,6 +483,7 @@ public class DisplayRotation {
|
||||
final TransitionRequestInfo.DisplayChange change = wasCollecting ? null
|
||||
: new TransitionRequestInfo.DisplayChange(mDisplayContent.getDisplayId(),
|
||||
oldRotation, mRotation);
|
||||
|
||||
mDisplayContent.requestChangeTransitionIfNeeded(
|
||||
ActivityInfo.CONFIG_WINDOW_CONFIGURATION, change);
|
||||
if (wasCollecting) {
|
||||
@@ -554,61 +527,45 @@ public class DisplayRotation {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A Remote rotation is when we are waiting for some registered (remote)
|
||||
* {@link IDisplayWindowRotationController} to calculate and return some hierarchy operations
|
||||
* to perform in sync with the rotation.
|
||||
*/
|
||||
boolean isWaitingForRemoteRotation() {
|
||||
return mIsWaitingForRemoteRotation;
|
||||
}
|
||||
|
||||
private void startRemoteRotation(int fromRotation, int toRotation) {
|
||||
if (mService.mDisplayRotationController == null) {
|
||||
return;
|
||||
}
|
||||
mIsWaitingForRemoteRotation = true;
|
||||
try {
|
||||
mService.mDisplayRotationController.onRotateDisplay(mDisplayContent.getDisplayId(),
|
||||
fromRotation, toRotation, mRemoteRotationCallback);
|
||||
mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout);
|
||||
mService.mH.postDelayed(mDisplayRotationHandlerTimeout, REMOTE_ROTATION_TIMEOUT_MS);
|
||||
} catch (RemoteException e) {
|
||||
mIsWaitingForRemoteRotation = false;
|
||||
return;
|
||||
}
|
||||
mDisplayContent.mRemoteDisplayChangeController.performRemoteDisplayChange(
|
||||
fromRotation, toRotation, null /* newDisplayAreaInfo */,
|
||||
(appliedChange, transaction) -> {
|
||||
final int newRotation = appliedChange != null
|
||||
? appliedChange.toRotation
|
||||
// Timeout occurred, use old rotation
|
||||
: fromRotation;
|
||||
continueRotation(newRotation, transaction);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void continueRotation(int targetRotation, WindowContainerTransaction t) {
|
||||
synchronized (mService.mGlobalLock) {
|
||||
if (targetRotation != mRotation || !mIsWaitingForRemoteRotation) {
|
||||
// Drop it, this is either coming from an outdated remote rotation; or, we've
|
||||
// already moved on.
|
||||
return;
|
||||
}
|
||||
mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout);
|
||||
mIsWaitingForRemoteRotation = false;
|
||||
if (targetRotation != mRotation) {
|
||||
// Drop it, this is either coming from an outdated remote rotation; or, we've
|
||||
// already moved on.
|
||||
return;
|
||||
}
|
||||
|
||||
if (mDisplayContent.mTransitionController.isShellTransitionsEnabled()) {
|
||||
if (!mDisplayContent.mTransitionController.isCollecting()) {
|
||||
throw new IllegalStateException("Trying to rotate outside a transition");
|
||||
}
|
||||
mDisplayContent.mTransitionController.collect(mDisplayContent);
|
||||
// Go through all tasks and collect them before the rotation
|
||||
// TODO(shell-transitions): move collect() to onConfigurationChange once wallpaper
|
||||
// handling is synchronized.
|
||||
mDisplayContent.mTransitionController.collectForDisplayChange(mDisplayContent,
|
||||
null /* use collecting transition */);
|
||||
if (mDisplayContent.mTransitionController.isShellTransitionsEnabled()) {
|
||||
if (!mDisplayContent.mTransitionController.isCollecting()) {
|
||||
throw new IllegalStateException("Trying to rotate outside a transition");
|
||||
}
|
||||
mService.mAtmService.deferWindowLayout();
|
||||
try {
|
||||
mDisplayContent.sendNewConfiguration();
|
||||
if (t != null) {
|
||||
mService.mAtmService.mWindowOrganizerController.applyTransaction(t);
|
||||
}
|
||||
} finally {
|
||||
mService.mAtmService.continueWindowLayout();
|
||||
mDisplayContent.mTransitionController.collect(mDisplayContent);
|
||||
// Go through all tasks and collect them before the rotation
|
||||
// TODO(shell-transitions): move collect() to onConfigurationChange once wallpaper
|
||||
// handling is synchronized.
|
||||
mDisplayContent.mTransitionController.collectForDisplayChange(mDisplayContent,
|
||||
null /* use collecting transition */);
|
||||
}
|
||||
mService.mAtmService.deferWindowLayout();
|
||||
try {
|
||||
mDisplayContent.sendNewConfiguration();
|
||||
if (t != null) {
|
||||
mService.mAtmService.mWindowOrganizerController.applyTransaction(t);
|
||||
}
|
||||
} finally {
|
||||
mService.mAtmService.continueWindowLayout();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,17 +22,21 @@ import static com.android.internal.R.bool.config_unfoldTransitionEnabled;
|
||||
import static com.android.server.wm.ActivityTaskManagerService.POWER_MODE_REASON_CHANGE_DISPLAY;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.devicestate.DeviceStateManager;
|
||||
import android.os.HandlerExecutor;
|
||||
import android.window.DisplayAreaInfo;
|
||||
import android.window.TransitionRequestInfo;
|
||||
import android.window.WindowContainerTransaction;
|
||||
|
||||
public class PhysicalDisplaySwitchTransitionLauncher {
|
||||
|
||||
private final DisplayContent mDisplayContent;
|
||||
private final WindowManagerService mService;
|
||||
private final DeviceStateManager mDeviceStateManager;
|
||||
private final Context mContext;
|
||||
private final TransitionController mTransitionController;
|
||||
|
||||
private DeviceStateListener mDeviceStateListener;
|
||||
@@ -46,13 +50,13 @@ public class PhysicalDisplaySwitchTransitionLauncher {
|
||||
public PhysicalDisplaySwitchTransitionLauncher(DisplayContent displayContent,
|
||||
TransitionController transitionController) {
|
||||
mDisplayContent = displayContent;
|
||||
mContext = mDisplayContent.mWmService.mContext;
|
||||
mService = displayContent.mWmService;
|
||||
mTransitionController = transitionController;
|
||||
|
||||
mDeviceStateManager = mContext.getSystemService(DeviceStateManager.class);
|
||||
mDeviceStateManager = mService.mContext.getSystemService(DeviceStateManager.class);
|
||||
|
||||
if (mDeviceStateManager != null) {
|
||||
mDeviceStateListener = new DeviceStateListener(mContext);
|
||||
mDeviceStateListener = new DeviceStateListener(mService.mContext);
|
||||
mDeviceStateManager
|
||||
.registerCallback(new HandlerExecutor(mDisplayContent.mWmService.mH),
|
||||
mDeviceStateListener);
|
||||
@@ -74,7 +78,7 @@ public class PhysicalDisplaySwitchTransitionLauncher {
|
||||
if (!mDisplayContent.getLastHasContent()) return;
|
||||
|
||||
boolean shouldRequestUnfoldTransition = !mIsFolded
|
||||
&& mContext.getResources().getBoolean(config_unfoldTransitionEnabled)
|
||||
&& mService.mContext.getResources().getBoolean(config_unfoldTransitionEnabled)
|
||||
&& ValueAnimator.areAnimatorsEnabled();
|
||||
|
||||
if (!shouldRequestUnfoldTransition) {
|
||||
@@ -102,13 +106,44 @@ public class PhysicalDisplaySwitchTransitionLauncher {
|
||||
}
|
||||
}
|
||||
|
||||
public void onDisplayUpdated() {
|
||||
if (mTransition != null) {
|
||||
mTransition.setAllReady();
|
||||
mTransition = null;
|
||||
/**
|
||||
* Called when physical display is getting updated, this could happen e.g. on foldable
|
||||
* devices when the physical underlying display is replaced.
|
||||
*
|
||||
* @param fromRotation rotation before the display change
|
||||
* @param toRotation rotation after the display change
|
||||
* @param newDisplayAreaInfo display area info after the display change
|
||||
*/
|
||||
public void onDisplayUpdated(int fromRotation, int toRotation,
|
||||
@NonNull DisplayAreaInfo newDisplayAreaInfo) {
|
||||
if (mTransition == null) return;
|
||||
|
||||
final boolean started = mDisplayContent.mRemoteDisplayChangeController
|
||||
.performRemoteDisplayChange(fromRotation, toRotation, newDisplayAreaInfo,
|
||||
(appliedChange, transaction) -> continueDisplayUpdate(transaction));
|
||||
|
||||
if (!started) {
|
||||
markTransitionAsReady();
|
||||
}
|
||||
}
|
||||
|
||||
private void continueDisplayUpdate(@Nullable WindowContainerTransaction transaction) {
|
||||
if (mTransition == null) return;
|
||||
|
||||
if (transaction != null) {
|
||||
mService.mAtmService.mWindowOrganizerController.applyTransaction(transaction);
|
||||
}
|
||||
|
||||
markTransitionAsReady();
|
||||
}
|
||||
|
||||
private void markTransitionAsReady() {
|
||||
if (mTransition == null) return;
|
||||
|
||||
mTransition.setAllReady();
|
||||
mTransition = null;
|
||||
}
|
||||
|
||||
class DeviceStateListener extends DeviceStateManager.FoldStateListener {
|
||||
|
||||
DeviceStateListener(Context context) {
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.os.RemoteException;
|
||||
import android.view.IDisplayChangeWindowCallback;
|
||||
import android.window.DisplayAreaInfo;
|
||||
import android.window.WindowContainerTransaction;
|
||||
|
||||
import com.android.internal.protolog.common.ProtoLog;
|
||||
import com.android.internal.util.function.pooled.PooledLambda;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A helper class, a wrapper around {@link android.view.IDisplayChangeWindowController} to perform
|
||||
* a synchronous display change in other parts (e.g. in the Shell) and continue the process
|
||||
* in the system server. It handles timeouts and multiple requests.
|
||||
* We have an instance of this controller for each display.
|
||||
*/
|
||||
public class RemoteDisplayChangeController {
|
||||
|
||||
private static final int REMOTE_DISPLAY_CHANGE_TIMEOUT_MS = 800;
|
||||
|
||||
private final WindowManagerService mService;
|
||||
private final int mDisplayId;
|
||||
|
||||
private boolean mIsWaitingForRemoteDisplayChange;
|
||||
private final Runnable mTimeoutRunnable = () -> {
|
||||
continueDisplayChange(null /* appliedChange */, null /* transaction */);
|
||||
};
|
||||
|
||||
private final List<ContinueRemoteDisplayChangeCallback> mCallbacks = new ArrayList<>();
|
||||
|
||||
public RemoteDisplayChangeController(WindowManagerService service, int displayId) {
|
||||
mService = service;
|
||||
mDisplayId = displayId;
|
||||
}
|
||||
|
||||
/**
|
||||
* A Remote change is when we are waiting for some registered (remote)
|
||||
* {@link IDisplayChangeWindowController} to calculate and return some hierarchy operations
|
||||
* to perform in sync with the display change.
|
||||
*/
|
||||
public boolean isWaitingForRemoteDisplayChange() {
|
||||
return mIsWaitingForRemoteDisplayChange;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts remote display change
|
||||
* @param fromRotation rotation before the change
|
||||
* @param toRotation rotation after the change
|
||||
* @param newDisplayAreaInfo display area info after change
|
||||
* @param callback that will be called after completing remote display change
|
||||
* @return true if the change successfully started, false otherwise
|
||||
*/
|
||||
public boolean performRemoteDisplayChange(
|
||||
int fromRotation, int toRotation,
|
||||
@Nullable DisplayAreaInfo newDisplayAreaInfo,
|
||||
ContinueRemoteDisplayChangeCallback callback) {
|
||||
if (mService.mDisplayChangeController == null) {
|
||||
return false;
|
||||
}
|
||||
mIsWaitingForRemoteDisplayChange = true;
|
||||
mCallbacks.add(callback);
|
||||
|
||||
if (newDisplayAreaInfo != null) {
|
||||
ProtoLog.v(WM_DEBUG_CONFIGURATION,
|
||||
"Starting remote display change: "
|
||||
+ "from [rot = %d], "
|
||||
+ "to [%dx%d, rot = %d]",
|
||||
fromRotation,
|
||||
newDisplayAreaInfo.configuration.windowConfiguration
|
||||
.getMaxBounds().width(),
|
||||
newDisplayAreaInfo.configuration.windowConfiguration
|
||||
.getMaxBounds().height(),
|
||||
toRotation);
|
||||
}
|
||||
|
||||
final RemoteDisplayChange change = new RemoteDisplayChange(fromRotation, toRotation,
|
||||
newDisplayAreaInfo);
|
||||
final IDisplayChangeWindowCallback remoteCallback = createCallback(change);
|
||||
try {
|
||||
mService.mDisplayChangeController.onDisplayChange(mDisplayId, fromRotation, toRotation,
|
||||
newDisplayAreaInfo, remoteCallback);
|
||||
|
||||
mService.mH.removeCallbacks(mTimeoutRunnable);
|
||||
mService.mH.postDelayed(mTimeoutRunnable, REMOTE_DISPLAY_CHANGE_TIMEOUT_MS);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
mIsWaitingForRemoteDisplayChange = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void continueDisplayChange(@Nullable RemoteDisplayChange appliedChange,
|
||||
@Nullable WindowContainerTransaction transaction) {
|
||||
synchronized (mService.mGlobalLock) {
|
||||
if (appliedChange != null) {
|
||||
ProtoLog.v(WM_DEBUG_CONFIGURATION,
|
||||
"Received remote change for Display[%d], applied: [%dx%d, rot = %d]",
|
||||
mDisplayId,
|
||||
appliedChange.displayAreaInfo != null ? appliedChange.displayAreaInfo
|
||||
.configuration.windowConfiguration.getMaxBounds().width() : -1,
|
||||
appliedChange.displayAreaInfo != null ? appliedChange.displayAreaInfo
|
||||
.configuration.windowConfiguration.getMaxBounds().height() : -1,
|
||||
appliedChange.toRotation);
|
||||
} else {
|
||||
ProtoLog.v(WM_DEBUG_CONFIGURATION, "Remote change for Display[%d]: timeout reached",
|
||||
mDisplayId);
|
||||
}
|
||||
|
||||
mIsWaitingForRemoteDisplayChange = false;
|
||||
|
||||
for (int i = 0; i < mCallbacks.size(); i++) {
|
||||
ContinueRemoteDisplayChangeCallback callback = mCallbacks.get(i);
|
||||
callback.onContinueRemoteDisplayChange(appliedChange, transaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IDisplayChangeWindowCallback createCallback(RemoteDisplayChange originalChange) {
|
||||
return new IDisplayChangeWindowCallback.Stub() {
|
||||
@Override
|
||||
public void continueDisplayChange(WindowContainerTransaction t) {
|
||||
synchronized (mService.mGlobalLock) {
|
||||
mService.mH.removeCallbacks(mTimeoutRunnable);
|
||||
mService.mH.sendMessage(PooledLambda.obtainMessage(
|
||||
RemoteDisplayChangeController::continueDisplayChange,
|
||||
RemoteDisplayChangeController.this,
|
||||
originalChange, t));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Data class that contains information about a remote display change
|
||||
*/
|
||||
public static class RemoteDisplayChange {
|
||||
final int fromRotation;
|
||||
final int toRotation;
|
||||
@Nullable
|
||||
final DisplayAreaInfo displayAreaInfo;
|
||||
|
||||
public RemoteDisplayChange(int fromRotation, int toRotation,
|
||||
@Nullable DisplayAreaInfo displayAreaInfo) {
|
||||
this.fromRotation = fromRotation;
|
||||
this.toRotation = toRotation;
|
||||
this.displayAreaInfo = displayAreaInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface to handle continuation of the remote display change
|
||||
*/
|
||||
public interface ContinueRemoteDisplayChangeCallback {
|
||||
/**
|
||||
* This method is called when the remote display change has been applied
|
||||
* @param appliedChange the change that was applied or null if there was
|
||||
* an error during remote display change (e.g. timeout)
|
||||
* @param transaction window changes collected by the remote display change
|
||||
*/
|
||||
void onContinueRemoteDisplayChange(@Nullable RemoteDisplayChange appliedChange,
|
||||
@Nullable WindowContainerTransaction transaction);
|
||||
}
|
||||
}
|
||||
@@ -238,10 +238,10 @@ import android.view.DisplayInfo;
|
||||
import android.view.Gravity;
|
||||
import android.view.IAppTransitionAnimationSpecsFuture;
|
||||
import android.view.ICrossWindowBlurEnabledListener;
|
||||
import android.view.IDisplayChangeWindowController;
|
||||
import android.view.IDisplayFoldListener;
|
||||
import android.view.IDisplayWindowInsetsController;
|
||||
import android.view.IDisplayWindowListener;
|
||||
import android.view.IDisplayWindowRotationController;
|
||||
import android.view.IInputFilter;
|
||||
import android.view.IOnKeyguardExitResult;
|
||||
import android.view.IPinnedTaskListener;
|
||||
@@ -682,9 +682,9 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
final WallpaperVisibilityListeners mWallpaperVisibilityListeners =
|
||||
new WallpaperVisibilityListeners();
|
||||
|
||||
IDisplayWindowRotationController mDisplayRotationController = null;
|
||||
private final DeathRecipient mDisplayRotationControllerDeath =
|
||||
() -> mDisplayRotationController = null;
|
||||
IDisplayChangeWindowController mDisplayChangeController = null;
|
||||
private final DeathRecipient mDisplayChangeControllerDeath =
|
||||
() -> mDisplayChangeController = null;
|
||||
|
||||
final DisplayWindowListenerController mDisplayNotificationController;
|
||||
final TaskSystemBarsListenerController mTaskSystemBarsListenerController;
|
||||
@@ -4266,12 +4266,13 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
.notifyOnActivityRotation(displayContent.mDisplayId);
|
||||
}
|
||||
|
||||
final boolean pendingRemoteRotation = rotationChanged
|
||||
&& (displayContent.getDisplayRotation().isWaitingForRemoteRotation()
|
||||
final boolean pendingRemoteDisplayChange = rotationChanged
|
||||
&& (displayContent.mRemoteDisplayChangeController
|
||||
.isWaitingForRemoteDisplayChange()
|
||||
|| displayContent.mTransitionController.isCollecting());
|
||||
// Even if alwaysSend, we are waiting for a transition or remote to provide
|
||||
// rotated configuration, so we can't update configuration yet.
|
||||
if (!pendingRemoteRotation) {
|
||||
// updated configuration, so we can't update configuration yet.
|
||||
if (!pendingRemoteDisplayChange) {
|
||||
if (!rotationChanged || forceRelayout) {
|
||||
displayContent.setLayoutNeeded();
|
||||
layoutNeeded = true;
|
||||
@@ -4303,17 +4304,17 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayWindowRotationController(IDisplayWindowRotationController controller) {
|
||||
public void setDisplayChangeWindowController(IDisplayChangeWindowController controller) {
|
||||
mAtmService.enforceTaskPermission("setDisplayWindowRotationController");
|
||||
try {
|
||||
synchronized (mGlobalLock) {
|
||||
if (mDisplayRotationController != null) {
|
||||
mDisplayRotationController.asBinder().unlinkToDeath(
|
||||
mDisplayRotationControllerDeath, 0);
|
||||
mDisplayRotationController = null;
|
||||
if (mDisplayChangeController != null) {
|
||||
mDisplayChangeController.asBinder().unlinkToDeath(
|
||||
mDisplayChangeControllerDeath, 0);
|
||||
mDisplayChangeController = null;
|
||||
}
|
||||
controller.asBinder().linkToDeath(mDisplayRotationControllerDeath, 0);
|
||||
mDisplayRotationController = controller;
|
||||
controller.asBinder().linkToDeath(mDisplayChangeControllerDeath, 0);
|
||||
mDisplayChangeController = controller;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException("Unable to set rotation controller");
|
||||
@@ -6112,24 +6113,24 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
final DisplayContent displayContent = mRoot.getDisplayContent(mFrozenDisplayId);
|
||||
final int numOpeningApps;
|
||||
final boolean waitingForConfig;
|
||||
final boolean waitingForRemoteRotation;
|
||||
final boolean waitingForRemoteDisplayChange;
|
||||
if (displayContent != null) {
|
||||
numOpeningApps = displayContent.mOpeningApps.size();
|
||||
waitingForConfig = displayContent.mWaitingForConfig;
|
||||
waitingForRemoteRotation =
|
||||
displayContent.getDisplayRotation().isWaitingForRemoteRotation();
|
||||
waitingForRemoteDisplayChange = displayContent.mRemoteDisplayChangeController
|
||||
.isWaitingForRemoteDisplayChange();
|
||||
} else {
|
||||
waitingForConfig = waitingForRemoteRotation = false;
|
||||
waitingForConfig = waitingForRemoteDisplayChange = false;
|
||||
numOpeningApps = 0;
|
||||
}
|
||||
if (waitingForConfig || waitingForRemoteRotation || mAppsFreezingScreen > 0
|
||||
if (waitingForConfig || waitingForRemoteDisplayChange || mAppsFreezingScreen > 0
|
||||
|| mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_ACTIVE
|
||||
|| mClientFreezingScreen || numOpeningApps > 0) {
|
||||
ProtoLog.d(WM_DEBUG_ORIENTATION, "stopFreezingDisplayLocked: Returning "
|
||||
+ "waitingForConfig=%b, waitingForRemoteRotation=%b, "
|
||||
+ "waitingForConfig=%b, waitingForRemoteDisplayChange=%b, "
|
||||
+ "mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, "
|
||||
+ "mClientFreezingScreen=%b, mOpeningApps.size()=%d",
|
||||
waitingForConfig, waitingForRemoteRotation,
|
||||
waitingForConfig, waitingForRemoteDisplayChange,
|
||||
mAppsFreezingScreen, mWindowsFreezingScreen,
|
||||
mClientFreezingScreen, numOpeningApps);
|
||||
return;
|
||||
|
||||
@@ -1786,13 +1786,16 @@ public class ActivityRecordTests extends WindowTestsBase {
|
||||
public void testActivityOnCancelFixedRotationTransform() {
|
||||
final ActivityRecord activity = createActivityWithTask();
|
||||
final DisplayRotation displayRotation = activity.mDisplayContent.getDisplayRotation();
|
||||
final RemoteDisplayChangeController remoteDisplayChangeController = activity
|
||||
.mDisplayContent.mRemoteDisplayChangeController;
|
||||
spyOn(displayRotation);
|
||||
spyOn(remoteDisplayChangeController);
|
||||
|
||||
final DisplayContent display = activity.mDisplayContent;
|
||||
final int originalRotation = display.getRotation();
|
||||
|
||||
// Make {@link DisplayContent#sendNewConfiguration} not apply rotation immediately.
|
||||
doReturn(true).when(displayRotation).isWaitingForRemoteRotation();
|
||||
doReturn(true).when(remoteDisplayChangeController).isWaitingForRemoteDisplayChange();
|
||||
doReturn((originalRotation + 1) % 4).when(displayRotation).rotationForOrientation(
|
||||
anyInt() /* orientation */, anyInt() /* lastRotation */);
|
||||
// Set to visible so the activity can freeze the screen.
|
||||
@@ -1830,7 +1833,7 @@ public class ActivityRecordTests extends WindowTestsBase {
|
||||
// Simulate the remote rotation has completed and the configuration doesn't change, then
|
||||
// the rotated activity should also be restored by clearing the transform.
|
||||
displayRotation.updateRotationUnchecked(true /* forceUpdate */);
|
||||
doReturn(false).when(displayRotation).isWaitingForRemoteRotation();
|
||||
doReturn(false).when(remoteDisplayChangeController).isWaitingForRemoteDisplayChange();
|
||||
clearInvocations(activity);
|
||||
display.setFixedRotationLaunchingAppUnchecked(activity);
|
||||
display.sendNewConfiguration();
|
||||
|
||||
@@ -124,8 +124,8 @@ import android.view.ContentRecordingSession;
|
||||
import android.view.DisplayCutout;
|
||||
import android.view.DisplayInfo;
|
||||
import android.view.Gravity;
|
||||
import android.view.IDisplayWindowRotationCallback;
|
||||
import android.view.IDisplayWindowRotationController;
|
||||
import android.view.IDisplayChangeWindowCallback;
|
||||
import android.view.IDisplayChangeWindowController;
|
||||
import android.view.ISystemGestureExclusionListener;
|
||||
import android.view.IWindowManager;
|
||||
import android.view.InsetsState;
|
||||
@@ -136,6 +136,7 @@ import android.view.SurfaceControl;
|
||||
import android.view.SurfaceControl.Transaction;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.window.DisplayAreaInfo;
|
||||
import android.window.IDisplayAreaOrganizer;
|
||||
import android.window.WindowContainerToken;
|
||||
|
||||
@@ -1801,15 +1802,16 @@ public class DisplayContentTests extends WindowTestsBase {
|
||||
return true;
|
||||
}).when(dc).updateDisplayOverrideConfigurationLocked();
|
||||
final boolean[] called = new boolean[1];
|
||||
mWm.mDisplayRotationController =
|
||||
new IDisplayWindowRotationController.Stub() {
|
||||
mWm.mDisplayChangeController =
|
||||
new IDisplayChangeWindowController.Stub() {
|
||||
@Override
|
||||
public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
|
||||
IDisplayWindowRotationCallback callback) {
|
||||
public void onDisplayChange(int displayId, int fromRotation, int toRotation,
|
||||
DisplayAreaInfo newDisplayAreaInfo,
|
||||
IDisplayChangeWindowCallback callback) throws RemoteException {
|
||||
called[0] = true;
|
||||
|
||||
try {
|
||||
callback.continueRotateDisplay(toRotation, null);
|
||||
callback.continueDisplayChange(null);
|
||||
} catch (RemoteException e) {
|
||||
assertTrue(false);
|
||||
}
|
||||
@@ -1843,13 +1845,14 @@ public class DisplayContentTests extends WindowTestsBase {
|
||||
// Rotate 180 degree so the display doesn't have configuration change. This condition is
|
||||
// used for the later verification of stop-freezing (without setting mWaitingForConfig).
|
||||
doReturn((dr.getRotation() + 2) % 4).when(dr).rotationForOrientation(anyInt(), anyInt());
|
||||
mWm.mDisplayRotationController =
|
||||
new IDisplayWindowRotationController.Stub() {
|
||||
mWm.mDisplayChangeController =
|
||||
new IDisplayChangeWindowController.Stub() {
|
||||
@Override
|
||||
public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
|
||||
IDisplayWindowRotationCallback callback) {
|
||||
public void onDisplayChange(int displayId, int fromRotation, int toRotation,
|
||||
DisplayAreaInfo newDisplayAreaInfo,
|
||||
IDisplayChangeWindowCallback callback) throws RemoteException {
|
||||
try {
|
||||
callback.continueRotateDisplay(toRotation, null);
|
||||
callback.continueDisplayChange(null);
|
||||
} catch (RemoteException e) {
|
||||
assertTrue(false);
|
||||
}
|
||||
|
||||
@@ -821,8 +821,11 @@ public class TransitionTests extends WindowTestsBase {
|
||||
player.onTransactionReady(mDisplayContent.getSyncTransaction());
|
||||
|
||||
final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
|
||||
final RemoteDisplayChangeController displayChangeController = mDisplayContent
|
||||
.mRemoteDisplayChangeController;
|
||||
spyOn(displayRotation);
|
||||
doReturn(true).when(displayRotation).isWaitingForRemoteRotation();
|
||||
spyOn(displayChangeController);
|
||||
doReturn(true).when(displayChangeController).isWaitingForRemoteDisplayChange();
|
||||
doReturn(prevRotation + 1).when(displayRotation).rotationForOrientation(
|
||||
anyInt() /* orientation */, anyInt() /* lastRotation */);
|
||||
// Rotation update is skipped while the recents animation is running.
|
||||
|
||||
Reference in New Issue
Block a user