Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6c3fc394 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Foldables: Implement emulation for folded screen"

parents f018cc9c 595416be
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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.
+1 −0
Original line number Diff line number Diff line
@@ -3532,6 +3532,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" />
+9 −4
Original line number Diff line number Diff line
@@ -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);
    }

+114 −0
Original line number Diff line number Diff line
/*
 * 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);
    }
}
+14 −1
Original line number Diff line number Diff line
@@ -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) {
Loading