diff options
8 files changed, 174 insertions, 5 deletions
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index c05795de4751..1db8135d31c7 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -861,6 +861,11 @@ The default is false. --> <bool name="config_lidControlsSleep">false</bool> + <!-- Indicate whether closing the lid causes the device to enter the folded state which means + to get a smaller screen and opening the lid causes the device to enter the unfolded state + which means to get a larger screen. --> + <bool name="config_lidControlsDisplayFold">false</bool> + <!-- 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 f79e22d1f94e..9f15321f1653 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3511,6 +3511,7 @@ <java-symbol type="integer" name="config_defaultRingVibrationIntensity" /> <java-symbol type="bool" name="config_maskMainBuiltInDisplayCutout" /> + <java-symbol type="bool" name="config_lidControlsDisplayFold" /> <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/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index 95665989cc34..7414e55ed94a 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -418,10 +418,15 @@ final class LogicalDisplay { // Now add back the offset for the masked area. mTempDisplayRect.offset(maskingInsets.left, maskingInsets.top); - mTempDisplayRect.left += mDisplayOffsetX; - mTempDisplayRect.right += mDisplayOffsetX; - mTempDisplayRect.top += mDisplayOffsetY; - mTempDisplayRect.bottom += mDisplayOffsetY; + if (orientation == Surface.ROTATION_0) { + mTempDisplayRect.offset(mDisplayOffsetX, mDisplayOffsetY); + } else if (orientation == Surface.ROTATION_90) { + mTempDisplayRect.offset(mDisplayOffsetY, -mDisplayOffsetX); + } else if (orientation == Surface.ROTATION_180) { + mTempDisplayRect.offset(-mDisplayOffsetX, -mDisplayOffsetY); + } else { // Surface.ROTATION_270 + mTempDisplayRect.offset(-mDisplayOffsetY, mDisplayOffsetX); + } device.setProjectionLocked(t, orientation, mTempLayerStackRect, mTempDisplayRect); } diff --git a/services/core/java/com/android/server/policy/DisplayFoldController.java b/services/core/java/com/android/server/policy/DisplayFoldController.java new file mode 100644 index 000000000000..71d6dfc9c598 --- /dev/null +++ b/services/core/java/com/android/server/policy/DisplayFoldController.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2019 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.policy; + +import android.content.Context; +import android.graphics.Rect; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.hardware.display.DisplayManagerInternal; +import android.view.DisplayInfo; + +import com.android.server.LocalServices; +import com.android.server.wm.WindowManagerInternal; + +/** + * Controls the behavior of foldable devices whose screen can literally bend and fold. + */ +class DisplayFoldController { + + private static final String TAG = "DisplayFoldController"; + private final WindowManagerInternal mWindowManagerInternal; + private final DisplayManagerInternal mDisplayManagerInternal; + private final int mDisplayId; + + /** The display area while device is folded. */ + private final Rect mFoldedArea; + + private final DisplayInfo mNonOverrideDisplayInfo = new DisplayInfo(); + private Boolean mFolded; + + DisplayFoldController(WindowManagerInternal windowManagerInternal, + DisplayManagerInternal displayManagerInternal, int displayId, Rect foldedArea) { + mWindowManagerInternal = windowManagerInternal; + mDisplayManagerInternal = displayManagerInternal; + mDisplayId = displayId; + mFoldedArea = new Rect(foldedArea); + } + + void setDeviceFolded(boolean folded) { + if (mFolded != null && mFolded == folded) { + return; + } + if (folded) { + mDisplayManagerInternal.getNonOverrideDisplayInfo(mDisplayId, mNonOverrideDisplayInfo); + final int dx = (mNonOverrideDisplayInfo.logicalWidth - mFoldedArea.width()) / 2 + - mFoldedArea.left; + final int dy = (mNonOverrideDisplayInfo.logicalHeight - mFoldedArea.height()) / 2 + - mFoldedArea.top; + + mWindowManagerInternal.setForcedDisplaySize(mDisplayId, mFoldedArea.width(), + mFoldedArea.height()); + mDisplayManagerInternal.setDisplayOffsets(mDisplayId, -dx, -dy); + } else { + mWindowManagerInternal.clearForcedDisplaySize(mDisplayId); + mDisplayManagerInternal.setDisplayOffsets(mDisplayId, 0, 0); + } + mFolded = folded; + } + + /** + * Only used for the case that persist.debug.force_foldable is set. + * This is using proximity sensor to simulate the fold state switch. + */ + static DisplayFoldController createWithProxSensor(Context context, int displayId) { + final SensorManager sensorManager = context.getSystemService(SensorManager.class); + final Sensor proxSensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); + if (proxSensor == null) { + return null; + } + + final DisplayFoldController result = create(displayId); + sensorManager.registerListener(new SensorEventListener() { + @Override + public void onSensorChanged(SensorEvent event) { + result.setDeviceFolded(event.values[0] < 1f); + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + // Ignore. + } + }, proxSensor, SensorManager.SENSOR_DELAY_NORMAL); + + return result; + } + + static DisplayFoldController create(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); + + return new DisplayFoldController(LocalServices.getService(WindowManagerInternal.class), + displayService, displayId, foldedArea); + } +} diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 13c4d886e7b1..25cfc7202bbb 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -374,6 +374,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { SearchManager mSearchManager; AccessibilityManager mAccessibilityManager; BurnInProtectionHelper mBurnInProtectionHelper; + private DisplayFoldController mDisplayFoldController; AppOpsManager mAppOpsManager; private ScreenshotHelper mScreenshotHelper; private boolean mHasFeatureWatch; @@ -471,6 +472,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mLidNavigationAccessibility; boolean mLidControlsScreenLock; boolean mLidControlsSleep; + private boolean mLidControlsDisplayFold; int mShortPressOnPowerBehavior; int mLongPressOnPowerBehavior; int mVeryLongPressOnPowerBehavior; @@ -1794,6 +1796,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.bool.config_lidControlsScreenLock); mLidControlsSleep = mContext.getResources().getBoolean( com.android.internal.R.bool.config_lidControlsSleep); + mLidControlsDisplayFold = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_lidControlsDisplayFold); mAllowTheaterModeWakeFromKey = mContext.getResources().getBoolean( com.android.internal.R.bool.config_allowTheaterModeWakeFromKey); @@ -1850,6 +1854,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { readConfigurationDependentBehaviors(); + if (mLidControlsDisplayFold) { + mDisplayFoldController = DisplayFoldController.create(DEFAULT_DISPLAY); + } else if (SystemProperties.getBoolean("persist.debug.force_foldable", false)) { + mDisplayFoldController = DisplayFoldController.createWithProxSensor(context, + DEFAULT_DISPLAY); + } + mAccessibilityManager = (AccessibilityManager) context.getSystemService( Context.ACCESSIBILITY_SERVICE); @@ -4972,7 +4983,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { private void applyLidSwitchState() { final int lidState = mDefaultDisplayPolicy.getLidState(); - if (lidState == LID_CLOSED && mLidControlsSleep) { + if (mLidControlsDisplayFold && mDisplayFoldController != null) { + mDisplayFoldController.setDeviceFolded(lidState == LID_CLOSED); + } else if (lidState == LID_CLOSED && mLidControlsSleep) { goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); } else if (lidState == LID_CLOSED && mLidControlsScreenLock) { diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index e204697e46cf..33e46f4af301 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -313,6 +313,22 @@ public abstract class WindowManagerInternal { public abstract void waitForAllWindowsDrawn(Runnable callback, long timeout); /** + * Overrides the display size. + * + * @param displayId The display to override the display size. + * @param width The width to override. + * @param height The height to override. + */ + public abstract void setForcedDisplaySize(int displayId, int width, int height); + + /** + * Recover the display size to real display size. + * + * @param displayId The display to recover the display size. + */ + public abstract void clearForcedDisplaySize(int displayId); + + /** * Adds a window token for a given window type. * * @param token The token to add. diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index e6581df233ef..12b858c81ca0 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -6937,6 +6937,16 @@ public class WindowManagerService extends IWindowManager.Stub } @Override + public void setForcedDisplaySize(int displayId, int width, int height) { + WindowManagerService.this.setForcedDisplaySize(displayId, width, height); + } + + @Override + public void clearForcedDisplaySize(int displayId) { + WindowManagerService.this.clearForcedDisplaySize(displayId); + } + + @Override public void addWindowToken(IBinder token, int type, int displayId) { WindowManagerService.this.addWindowToken(token, type, displayId); } diff --git a/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java b/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java index ea3f758fb209..98bad93e09e2 100644 --- a/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java +++ b/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java @@ -170,4 +170,9 @@ public class WmDisplayCutout { public int hashCode() { return Objects.hash(mInner, mFrameSize); } + + @Override + public String toString() { + return "WmDisplayCutout{" + mInner + ", mFrameSize=" + mFrameSize + '}'; + } } |