diff options
9 files changed, 112 insertions, 0 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 44a6c6b2803b..8134dab1768b 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -20355,6 +20355,7 @@ package android.hardware.display { method public android.view.Surface getSurface(); method public void release(); method public void resize(int, int, int); + method @FlaggedApi("android.companion.virtualdevice.flags.virtual_display_rotation_api") public void setRotation(int); method public void setSurface(android.view.Surface); } diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig index cd8082c1e27d..3865e9b23e9a 100644 --- a/core/java/android/companion/virtual/flags/flags.aconfig +++ b/core/java/android/companion/virtual/flags/flags.aconfig @@ -82,3 +82,10 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + namespace: "virtual_devices" + name: "virtual_display_rotation_api" + description: "API for on-demand rotation of virtual displays" + bug: "291748430" +} diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index 85197221e651..3dbc3d213d4f 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -812,6 +812,14 @@ public final class DisplayManagerGlobal { } } + void setVirtualDisplayRotation(IVirtualDisplayCallback token, @Surface.Rotation int rotation) { + try { + mDm.setVirtualDisplayRotation(token, rotation); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + /** * Gets the stable device display size, in pixels. */ diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl index b7c02b0d0720..9f33f3b8f36e 100644 --- a/core/java/android/hardware/display/IDisplayManager.aidl +++ b/core/java/android/hardware/display/IDisplayManager.aidl @@ -117,6 +117,9 @@ interface IDisplayManager { // No permissions required but must be same Uid as the creator. void setVirtualDisplayState(in IVirtualDisplayCallback token, boolean isOn); + // No permissions required but must be same Uid as the creator. + void setVirtualDisplayRotation(in IVirtualDisplayCallback token, int rotation); + // Get a stable metric for the device's display size. No permissions required. Point getStableDisplaySize(); diff --git a/core/java/android/hardware/display/VirtualDisplay.java b/core/java/android/hardware/display/VirtualDisplay.java index 051ce636484c..6cc938f5e6f8 100644 --- a/core/java/android/hardware/display/VirtualDisplay.java +++ b/core/java/android/hardware/display/VirtualDisplay.java @@ -15,6 +15,7 @@ */ package android.hardware.display; +import android.annotation.FlaggedApi; import android.view.Display; import android.view.Surface; @@ -122,6 +123,28 @@ public final class VirtualDisplay { } } + /** + * Sets the rotation of the virtual display. + * + * @param rotation the new rotation of the display. May be one of {@link Surface#ROTATION_0}, + * {@link Surface#ROTATION_90}, {@link Surface#ROTATION_180}, {@link Surface#ROTATION_270}. + * Upon creation, the rotation of the virtual display is always {@link Surface#ROTATION_0}. + */ + @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_VIRTUAL_DISPLAY_ROTATION_API) + public void setRotation(@Surface.Rotation int rotation) { + if (!android.companion.virtualdevice.flags.Flags.virtualDisplayRotationApi()) { + return; + } + if (rotation != Surface.ROTATION_0 && rotation != Surface.ROTATION_90 + && rotation != Surface.ROTATION_180 && rotation != Surface.ROTATION_270) { + throw new IllegalArgumentException( + "Invalid virtual display rotation value: " + rotation); + } + if (mToken != null && mDisplay.getRotation() != rotation) { + mGlobal.setVirtualDisplayRotation(mToken, rotation); + } + } + @Override public String toString() { return "VirtualDisplay{display=" + mDisplay + ", token=" + mToken diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index e686779e4ccd..2064ba0ce4d1 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -1939,6 +1939,27 @@ public final class DisplayManagerService extends SystemService { } } + private void setVirtualDisplayRotationInternal(IBinder appToken, + @Surface.Rotation int rotation) { + int displayId; + synchronized (mSyncRoot) { + if (mVirtualDisplayAdapter == null) { + return; + } + DisplayDevice device = mVirtualDisplayAdapter.getDisplayDevice(appToken); + if (device == null) { + return; + } + LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device); + if (display == null) { + return; + } + displayId = display.getDisplayIdLocked(); + } + mWindowManagerInternal.setNonDefaultDisplayRotation( + displayId, rotation, /* caller= */ "Virtual Display"); + } + private void registerDefaultDisplayAdapters() { // Register default display adapters. synchronized (mSyncRoot) { @@ -4179,6 +4200,20 @@ public final class DisplayManagerService extends SystemService { } @Override // Binder call + public void setVirtualDisplayRotation(IVirtualDisplayCallback callback, + @Surface.Rotation int rotation) { + if (!android.companion.virtualdevice.flags.Flags.virtualDisplayRotationApi()) { + return; + } + final long token = Binder.clearCallingIdentity(); + try { + setVirtualDisplayRotationInternal(callback.asBinder(), rotation); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override // Binder call public void dump(@NonNull FileDescriptor fd, @NonNull final PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index 1a5c79fada55..962acc701878 100644 --- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -213,6 +213,10 @@ public class VirtualDisplayAdapter extends DisplayAdapter { } } + DisplayDevice getDisplayDevice(IBinder appToken) { + return mVirtualDisplayDevices.get(appToken); + } + /** * Generates a virtual display's unique identifier. * diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index a42cb09f5500..2ea1cf88447a 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -44,6 +44,7 @@ import android.view.IWindow; import android.view.InputChannel; import android.view.MagnificationSpec; import android.view.RemoteAnimationTarget; +import android.view.Surface; import android.view.SurfaceControl; import android.view.SurfaceControlViewHost; import android.view.WindowInfo; @@ -817,6 +818,16 @@ public abstract class WindowManagerInternal { public abstract Context getTopFocusedDisplayUiContext(); /** + * Sets the rotation of a non-default display. + * + * @param displayId The id of the display + * @param rotation The new rotation value. + * @param caller The requester of the rotation change, used for bookkeeping. + */ + public abstract void setNonDefaultDisplayRotation(int displayId, @Surface.Rotation int rotation, + @NonNull String caller); + + /** * Sets whether the relevant display content can host the relevant home activity and wallpaper. * * @param displayUniqueId The unique ID of the display. Note that the display may not yet be diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 72ec05847973..a6d0b63b26ad 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -8357,6 +8357,26 @@ public class WindowManagerService extends IWindowManager.Stub } @Override + public void setNonDefaultDisplayRotation(int displayId, @Surface.Rotation int rotation, + @NonNull String caller) { + if (displayId == Display.DEFAULT_DISPLAY || displayId == Display.INVALID_DISPLAY) { + Slog.w(TAG, "Cannot set rotation for display with id: " + displayId); + return; + } + synchronized (mGlobalLock) { + final DisplayContent displayContent = mRoot.getDisplayContent(displayId); + if (displayContent == null) { + Slog.w(TAG, "Cannot set rotation for display " + displayId + + " due to missing DisplayContent"); + return; + } + displayContent.getDisplayRotation().setUserRotation( + displayContent.getDisplayRotation().getUserRotationMode(), rotation, + caller); + } + } + + @Override public void setHomeSupportedOnDisplay(String displayUniqueId, int displayType, boolean supported) { final long origId = Binder.clearCallingIdentity(); |