diff options
7 files changed, 170 insertions, 44 deletions
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 8dfd5e842f3a..e65e7da57e58 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -869,6 +869,9 @@ which means to get a larger screen. --> <bool name="config_lidControlsDisplayFold">false</bool> + <!-- Indicate the display area rect for foldable devices in folded state. --> + <string name="config_foldedArea"></string> + <!-- Desk dock behavior --> <!-- The number of degrees to rotate the display when the device is in a desk dock. diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 16aed90ba2cd..7ef5e022c1c4 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3586,7 +3586,10 @@ <java-symbol type="integer" name="config_defaultRingVibrationIntensity" /> <java-symbol type="bool" name="config_maskMainBuiltInDisplayCutout" /> + + <!-- For Foldables --> <java-symbol type="bool" name="config_lidControlsDisplayFold" /> + <java-symbol type="string" name="config_foldedArea" /> <java-symbol type="array" name="config_disableApksUnlessMatchedSku_apk_list" /> <java-symbol type="array" name="config_disableApkUnlessMatchedSku_skus_list" /> diff --git a/services/core/java/com/android/server/policy/DisplayFoldController.java b/services/core/java/com/android/server/policy/DisplayFoldController.java index fdcafa77a378..0c6b773396c8 100644 --- a/services/core/java/com/android/server/policy/DisplayFoldController.java +++ b/services/core/java/com/android/server/policy/DisplayFoldController.java @@ -42,10 +42,12 @@ class DisplayFoldController { private final WindowManagerInternal mWindowManagerInternal; private final DisplayManagerInternal mDisplayManagerInternal; private final int mDisplayId; + private final Handler mHandler; /** The display area while device is folded. */ private final Rect mFoldedArea; - private final Handler mHandler; + /** The display area to override the original folded area. */ + private Rect mOverrideFoldedArea = new Rect(); private final DisplayInfo mNonOverrideDisplayInfo = new DisplayInfo(); private final RemoteCallbackList<IDisplayFoldListener> mListeners = new RemoteCallbackList<>(); @@ -70,14 +72,23 @@ class DisplayFoldController { return; } if (folded) { + Rect foldedArea; + if (!mOverrideFoldedArea.isEmpty()) { + foldedArea = mOverrideFoldedArea; + } else if (!mFoldedArea.isEmpty()) { + foldedArea = mFoldedArea; + } else { + return; + } + mDisplayManagerInternal.getNonOverrideDisplayInfo(mDisplayId, mNonOverrideDisplayInfo); - final int dx = (mNonOverrideDisplayInfo.logicalWidth - mFoldedArea.width()) / 2 - - mFoldedArea.left; - final int dy = (mNonOverrideDisplayInfo.logicalHeight - mFoldedArea.height()) / 2 - - mFoldedArea.top; + final int dx = (mNonOverrideDisplayInfo.logicalWidth - foldedArea.width()) / 2 + - foldedArea.left; + final int dy = (mNonOverrideDisplayInfo.logicalHeight - foldedArea.height()) / 2 + - foldedArea.top; - mWindowManagerInternal.setForcedDisplaySize(mDisplayId, mFoldedArea.width(), - mFoldedArea.height()); + mWindowManagerInternal.setForcedDisplaySize(mDisplayId, + foldedArea.width(), foldedArea.height()); mDisplayManagerInternal.setDisplayOffsets(mDisplayId, -dx, -dy); } else { mWindowManagerInternal.clearForcedDisplaySize(mDisplayId); @@ -114,6 +125,18 @@ class DisplayFoldController { mListeners.unregister(listener); } + void setOverrideFoldedArea(Rect area) { + mOverrideFoldedArea.set(area); + } + + Rect getFoldedArea() { + if (!mOverrideFoldedArea.isEmpty()) { + return mOverrideFoldedArea; + } else { + return mFoldedArea; + } + } + /** * Only used for the case that persist.debug.force_foldable is set. * This is using proximity sensor to simulate the fold state switch. @@ -125,7 +148,7 @@ class DisplayFoldController { return null; } - final DisplayFoldController result = create(displayId); + final DisplayFoldController result = create(context, displayId); sensorManager.registerListener(new SensorEventListener() { @Override public void onSensorChanged(SensorEvent event) { @@ -141,13 +164,17 @@ class DisplayFoldController { return result; } - static DisplayFoldController create(int displayId) { + static DisplayFoldController create(Context context, int displayId) { final DisplayManagerInternal displayService = LocalServices.getService(DisplayManagerInternal.class); - final DisplayInfo displayInfo = new DisplayInfo(); - displayService.getNonOverrideDisplayInfo(displayId, displayInfo); - final Rect foldedArea = new Rect(0, displayInfo.logicalHeight / 2, - displayInfo.logicalWidth, displayInfo.logicalHeight); + final String configFoldedArea = context.getResources().getString( + com.android.internal.R.string.config_foldedArea); + final Rect foldedArea; + if (configFoldedArea == null || configFoldedArea.isEmpty()) { + foldedArea = new Rect(); + } else { + foldedArea = Rect.unflattenFromString(configFoldedArea); + } return new DisplayFoldController(LocalServices.getService(WindowManagerInternal.class), displayService, displayId, foldedArea, DisplayThread.getHandler()); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 2e3e3e430839..c87a81db16e4 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -125,6 +125,7 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.database.ContentObserver; import android.graphics.PixelFormat; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.hardware.display.DisplayManager; import android.hardware.hdmi.HdmiAudioSystemClient; @@ -1858,7 +1859,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { readConfigurationDependentBehaviors(); if (mLidControlsDisplayFold) { - mDisplayFoldController = DisplayFoldController.create(DEFAULT_DISPLAY); + mDisplayFoldController = DisplayFoldController.create(context, DEFAULT_DISPLAY); } else if (SystemProperties.getBoolean("persist.debug.force_foldable", false)) { mDisplayFoldController = DisplayFoldController.createWithProxSensor(context, DEFAULT_DISPLAY); @@ -3221,6 +3222,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override + public void setOverrideFoldedArea(Rect area) { + if (mDisplayFoldController != null) { + mDisplayFoldController.setOverrideFoldedArea(area); + } + } + + @Override + public Rect getFoldedArea() { + if (mDisplayFoldController != null) { + return mDisplayFoldController.getFoldedArea(); + } + return new Rect(); + } + + @Override public void registerShortcutKey(long shortcutCode, IShortcutService shortcutService) throws RemoteException { synchronized (mLock) { diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 870d61b2ab90..d7e4b6cff4d8 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -64,6 +64,7 @@ import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType; import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.WindowConfiguration; import android.content.Context; @@ -1470,6 +1471,20 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { default void unregisterDisplayFoldListener(IDisplayFoldListener listener) {} /** + * Overrides the folded area. + * + * @param area the overriding folded area or an empty {@code Rect} to clear the override. + */ + default void setOverrideFoldedArea(@NonNull Rect area) {} + + /** + * Get the display folded area. + */ + default @NonNull Rect getFoldedArea() { + return new Rect(); + } + + /** * Updates the flag about whether AOD is showing. * * @return whether the value was changed. diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 899bf7c8fd39..7beee0e33355 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -22,6 +22,7 @@ import static android.Manifest.permission.MANAGE_APP_TOKENS; import static android.Manifest.permission.READ_FRAME_BUFFER; import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS; import static android.Manifest.permission.RESTRICTED_VR_ACCESS; +import static android.Manifest.permission.WRITE_SECURE_SETTINGS; import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY; import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; @@ -3759,6 +3760,41 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.unregisterDisplayFoldListener(listener); } + /** + * Overrides the folded area. + * + * @param area the overriding folded area or an empty {@code Rect} to clear the override. + */ + void setOverrideFoldedArea(@NonNull Rect area) { + if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS); + } + + long origId = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + mPolicy.setOverrideFoldedArea(area); + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + + /** + * Get the display folded area. + */ + @NonNull Rect getFoldedArea() { + long origId = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + return mPolicy.getFoldedArea(); + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + @Override public int getPreferredOptionsPanelGravity(int displayId) { synchronized (mGlobalLock) { @@ -4826,11 +4862,9 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setForcedDisplaySize(int displayId, int width, int height) { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.WRITE_SECURE_SETTINGS) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Must hold permission " + - android.Manifest.permission.WRITE_SECURE_SETTINGS); + if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS); } final long ident = Binder.clearCallingIdentity(); @@ -4848,11 +4882,9 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setForcedDisplayScalingMode(int displayId, int mode) { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.WRITE_SECURE_SETTINGS) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Must hold permission " + - android.Manifest.permission.WRITE_SECURE_SETTINGS); + if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS); } final long ident = Binder.clearCallingIdentity(); @@ -4917,11 +4949,9 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void clearForcedDisplaySize(int displayId) { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.WRITE_SECURE_SETTINGS) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Must hold permission " + - android.Manifest.permission.WRITE_SECURE_SETTINGS); + if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS); } final long ident = Binder.clearCallingIdentity(); @@ -4962,11 +4992,9 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setForcedDisplayDensityForUser(int displayId, int density, int userId) { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.WRITE_SECURE_SETTINGS) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Must hold permission " + - android.Manifest.permission.WRITE_SECURE_SETTINGS); + if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS); } final int targetUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), @@ -4987,11 +5015,9 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void clearForcedDisplayDensityForUser(int displayId, int userId) { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.WRITE_SECURE_SETTINGS) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Must hold permission " + - android.Manifest.permission.WRITE_SECURE_SETTINGS); + if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS); } final int callingUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), @@ -5056,11 +5082,9 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setOverscan(int displayId, int left, int top, int right, int bottom) { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.WRITE_SECURE_SETTINGS) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Must hold permission " + - android.Manifest.permission.WRITE_SECURE_SETTINGS); + if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS); } final long ident = Binder.clearCallingIdentity(); try { diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index 83e3c71cbee3..d13ee459c115 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -62,6 +62,8 @@ public class WindowManagerShellCommand extends ShellCommand { return runDisplaySize(pw); case "density": return runDisplayDensity(pw); + case "folded-area": + return runDisplayFoldedArea(pw); case "overscan": return runDisplayOverscan(pw); case "scaling": @@ -207,6 +209,40 @@ public class WindowManagerShellCommand extends ShellCommand { return 0; } + private void printFoldedArea(PrintWriter pw) { + final Rect foldedArea = mInternal.getFoldedArea(); + if (foldedArea.isEmpty()) { + pw.println("Folded area: none"); + } else { + pw.println("Folded area: " + foldedArea.left + "," + foldedArea.top + "," + + foldedArea.right + "," + foldedArea.bottom); + } + } + + private int runDisplayFoldedArea(PrintWriter pw) { + final String areaStr = getNextArg(); + final Rect rect = new Rect(); + if (areaStr == null) { + printFoldedArea(pw); + return 0; + } else if ("reset".equals(areaStr)) { + rect.setEmpty(); + } else { + final Pattern flattenedPattern = Pattern.compile( + "(-?\\d+),(-?\\d+),(-?\\d+),(-?\\d+)"); + final Matcher matcher = flattenedPattern.matcher(areaStr); + if (!matcher.matches()) { + getErrPrintWriter().println("Error: area should be LEFT,TOP,RIGHT,BOTTOM"); + return -1; + } + rect.set(Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)), + Integer.parseInt(matcher.group(3)), Integer.parseInt(matcher.group(4))); + } + + mInternal.setOverrideFoldedArea(rect); + return 0; + } + private int runDisplayOverscan(PrintWriter pw) throws RemoteException { String overscanStr = getNextArgRequired(); Rect rect = new Rect(); @@ -335,6 +371,8 @@ public class WindowManagerShellCommand extends ShellCommand { pw.println(" width and height in pixels unless suffixed with 'dp'."); pw.println(" density [reset|DENSITY] [-d DISPLAY_ID]"); pw.println(" Return or override display density."); + pw.println(" folded-area [reset|LEFT,TOP,RIGHT,BOTTOM]"); + pw.println(" Return or override folded area."); pw.println(" overscan [reset|LEFT,TOP,RIGHT,BOTTOM] [-d DISPLAY ID]"); pw.println(" Set overscan area for display."); pw.println(" scaling [off|auto] [-d DISPLAY_ID]"); |