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

Commit 3a3cff40 authored by Christian Göllner's avatar Christian Göllner Committed by Automerger Merge Worker
Browse files

Merge "Foldable rotation settings: persist postures instead of device states"...

Merge "Foldable rotation settings: persist postures instead of device states" into tm-qpr-dev am: 16685036

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21798659



Change-Id: I1da8aec2141580dc99c3d05d4644e4fede487884
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 1065ad78 16685036
Loading
Loading
Loading
Loading
+30 −5
Original line number Diff line number Diff line
@@ -10997,21 +10997,46 @@ public final class Settings {
        public @interface DeviceStateRotationLockSetting {
        }
        /** @hide */
        public static final int DEVICE_STATE_ROTATION_KEY_UNKNOWN = -1;
        /** @hide */
        public static final int DEVICE_STATE_ROTATION_KEY_FOLDED = 0;
        /** @hide */
        public static final int DEVICE_STATE_ROTATION_KEY_HALF_FOLDED = 1;
        /** @hide */
        public static final int DEVICE_STATE_ROTATION_KEY_UNFOLDED = 2;
        /**
         * The different postures that can be used as keys with
         * {@link #DEVICE_STATE_ROTATION_LOCK}.
         * @hide
         */
        @IntDef(prefix = {"DEVICE_STATE_ROTATION_KEY_"}, value = {
                DEVICE_STATE_ROTATION_KEY_UNKNOWN,
                DEVICE_STATE_ROTATION_KEY_FOLDED,
                DEVICE_STATE_ROTATION_KEY_HALF_FOLDED,
                DEVICE_STATE_ROTATION_KEY_UNFOLDED,
        })
        @Retention(RetentionPolicy.SOURCE)
        public @interface DeviceStateRotationLockKey {
        }
        /**
         * Rotation lock setting keyed on device state.
         *
         * This holds a serialized map using int keys that represent Device States and value of
         * This holds a serialized map using int keys that represent postures in
         * {@link DeviceStateRotationLockKey} and value of
         * {@link DeviceStateRotationLockSetting} representing the rotation lock setting for that
         * device state.
         * posture.
         *
         * Serialized as key0:value0:key1:value1:...:keyN:valueN.
         *
         * Example: "0:1:1:2:2:1"
         * This example represents a map of:
         * <ul>
         *     <li>0 -> DEVICE_STATE_ROTATION_LOCK_LOCKED</li>
         *     <li>1 -> DEVICE_STATE_ROTATION_LOCK_UNLOCKED</li>
         *     <li>2 -> DEVICE_STATE_ROTATION_LOCK_IGNORED</li>
         *     <li>DEVICE_STATE_ROTATION_KEY_FOLDED -> DEVICE_STATE_ROTATION_LOCK_LOCKED</li>
         *     <li>DEVICE_STATE_ROTATION_KEY_HALF_FOLDED -> DEVICE_STATE_ROTATION_LOCK_UNLOCKED</li>
         *     <li>DEVICE_STATE_ROTATION_KEY_UNFOLDED -> DEVICE_STATE_ROTATION_LOCK_IGNORED</li>
         * </ul>
         *
         * @hide
+7 −8
Original line number Diff line number Diff line
@@ -720,14 +720,13 @@
         display is powered on at the same time. -->
    <bool name="config_supportsConcurrentInternalDisplays">true</bool>

    <!-- Map of DeviceState to rotation lock setting. Each entry must be in the format
         "key:value", for example: "0:1".
          The keys are device states, and the values are one of
    <!-- Map of device posture to rotation lock setting. Each entry must be in the format
         "key:value", or "key:value:fallback_key" for example: "0:1" or "2:0:1". The keys are one of
         Settings.Secure.DeviceStateRotationLockKey, and the values are one of
         Settings.Secure.DeviceStateRotationLockSetting.
          Any device state that doesn't have a default set here will be treated as
          DEVICE_STATE_ROTATION_LOCK_IGNORED meaning it will not have its own rotation lock setting.
          If this map is missing, the feature is disabled and only one global rotation lock setting
           will apply, regardless of device state. -->
         The fallback is a key to a device posture that can be specified when the value is
         Settings.Secure.DEVICE_STATE_ROTATION_LOCK_IGNORED.
     -->
    <string-array name="config_perDeviceStateRotationLockDefaults" />

    <!-- Dock behavior -->
+4 −1
Original line number Diff line number Diff line
@@ -10,7 +10,10 @@ package {
android_library {
    name: "SettingsLibDeviceStateRotationLock",

    srcs: ["src/**/*.java"],
    srcs: [
        "src/**/*.java",
        "src/**/*.kt",
    ],

    min_sdk_version: "21",
}
+58 −53
Original line number Diff line number Diff line
@@ -57,17 +57,19 @@ public final class DeviceStateRotationLockSettingsManager {
    private final Handler mMainHandler = new Handler(Looper.getMainLooper());
    private final Set<DeviceStateRotationLockSettingsListener> mListeners = new HashSet<>();
    private final SecureSettings mSecureSettings;
    private String[] mDeviceStateRotationLockDefaults;
    private SparseIntArray mDeviceStateRotationLockSettings;
    private SparseIntArray mDeviceStateDefaultRotationLockSettings;
    private SparseIntArray mDeviceStateRotationLockFallbackSettings;
    private final PosturesHelper mPosturesHelper;
    private String[] mPostureRotationLockDefaults;
    private SparseIntArray mPostureRotationLockSettings;
    private SparseIntArray mPostureDefaultRotationLockSettings;
    private SparseIntArray mPostureRotationLockFallbackSettings;
    private String mLastSettingValue;
    private List<SettableDeviceState> mSettableDeviceStates;

    @VisibleForTesting
    DeviceStateRotationLockSettingsManager(Context context, SecureSettings secureSettings) {
        this.mSecureSettings = secureSettings;
        mDeviceStateRotationLockDefaults =
        mSecureSettings = secureSettings;
        mPosturesHelper = new PosturesHelper(context);
        mPostureRotationLockDefaults =
                context.getResources()
                        .getStringArray(R.array.config_perDeviceStateRotationLockDefaults);
        loadDefaults();
@@ -134,13 +136,14 @@ public final class DeviceStateRotationLockSettingsManager {

    /** Updates the rotation lock setting for a specified device state. */
    public void updateSetting(int deviceState, boolean rotationLocked) {
        if (mDeviceStateRotationLockFallbackSettings.indexOfKey(deviceState) >= 0) {
            // The setting for this device state is IGNORED, and has a fallback device state.
            // The setting for that fallback device state should be the changed in this case.
            deviceState = mDeviceStateRotationLockFallbackSettings.get(deviceState);
        }
        mDeviceStateRotationLockSettings.put(
                deviceState,
        int posture = mPosturesHelper.deviceStateToPosture(deviceState);
        if (mPostureRotationLockFallbackSettings.indexOfKey(posture) >= 0) {
            // The setting for this device posture is IGNORED, and has a fallback posture.
            // The setting for that fallback posture should be the changed in this case.
            posture = mPostureRotationLockFallbackSettings.get(posture);
        }
        mPostureRotationLockSettings.put(
                posture,
                rotationLocked
                        ? DEVICE_STATE_ROTATION_LOCK_LOCKED
                        : DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
@@ -159,22 +162,23 @@ public final class DeviceStateRotationLockSettingsManager {
     */
    @Settings.Secure.DeviceStateRotationLockSetting
    public int getRotationLockSetting(int deviceState) {
        int rotationLockSetting = mDeviceStateRotationLockSettings.get(
                deviceState, /* valueIfKeyNotFound= */ DEVICE_STATE_ROTATION_LOCK_IGNORED);
        int devicePosture = mPosturesHelper.deviceStateToPosture(deviceState);
        int rotationLockSetting = mPostureRotationLockSettings.get(
                devicePosture, /* valueIfKeyNotFound= */ DEVICE_STATE_ROTATION_LOCK_IGNORED);
        if (rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_IGNORED) {
            rotationLockSetting = getFallbackRotationLockSetting(deviceState);
            rotationLockSetting = getFallbackRotationLockSetting(devicePosture);
        }
        return rotationLockSetting;
    }

    private int getFallbackRotationLockSetting(int deviceState) {
        int indexOfFallbackState = mDeviceStateRotationLockFallbackSettings.indexOfKey(deviceState);
        if (indexOfFallbackState < 0) {
    private int getFallbackRotationLockSetting(int devicePosture) {
        int indexOfFallback = mPostureRotationLockFallbackSettings.indexOfKey(devicePosture);
        if (indexOfFallback < 0) {
            Log.w(TAG, "Setting is ignored, but no fallback was specified.");
            return DEVICE_STATE_ROTATION_LOCK_IGNORED;
        }
        int fallbackState = mDeviceStateRotationLockFallbackSettings.valueAt(indexOfFallbackState);
        return mDeviceStateRotationLockSettings.get(fallbackState,
        int fallbackPosture = mPostureRotationLockFallbackSettings.valueAt(indexOfFallback);
        return mPostureRotationLockSettings.get(fallbackPosture,
                /* valueIfKeyNotFound= */ DEVICE_STATE_ROTATION_LOCK_IGNORED);
    }

@@ -189,8 +193,8 @@ public final class DeviceStateRotationLockSettingsManager {
     * DEVICE_STATE_ROTATION_LOCK_UNLOCKED}.
     */
    public boolean isRotationLockedForAllStates() {
        for (int i = 0; i < mDeviceStateRotationLockSettings.size(); i++) {
            if (mDeviceStateRotationLockSettings.valueAt(i)
        for (int i = 0; i < mPostureRotationLockSettings.size(); i++) {
            if (mPostureRotationLockSettings.valueAt(i)
                    == DEVICE_STATE_ROTATION_LOCK_UNLOCKED) {
                return false;
            }
@@ -221,7 +225,7 @@ public final class DeviceStateRotationLockSettingsManager {
            fallbackOnDefaults();
            return;
        }
        mDeviceStateRotationLockSettings = new SparseIntArray(values.length / 2);
        mPostureRotationLockSettings = new SparseIntArray(values.length / 2);
        int key;
        int value;

@@ -230,7 +234,7 @@ public final class DeviceStateRotationLockSettingsManager {
                key = Integer.parseInt(values[i++]);
                value = Integer.parseInt(values[i++]);
                boolean isPersistedValueIgnored = value == DEVICE_STATE_ROTATION_LOCK_IGNORED;
                boolean isDefaultValueIgnored = mDeviceStateDefaultRotationLockSettings.get(key)
                boolean isDefaultValueIgnored = mPostureDefaultRotationLockSettings.get(key)
                        == DEVICE_STATE_ROTATION_LOCK_IGNORED;
                if (isPersistedValueIgnored != isDefaultValueIgnored) {
                    Log.w(TAG, "Conflict for ignored device state " + key
@@ -238,7 +242,7 @@ public final class DeviceStateRotationLockSettingsManager {
                    fallbackOnDefaults();
                    return;
                }
                mDeviceStateRotationLockSettings.put(key, value);
                mPostureRotationLockSettings.put(key, value);
            } catch (NumberFormatException e) {
                Log.wtf(TAG, "Error deserializing one of the saved settings", e);
                fallbackOnDefaults();
@@ -253,7 +257,7 @@ public final class DeviceStateRotationLockSettingsManager {
     */
    @VisibleForTesting
    public void resetStateForTesting(Resources resources) {
        mDeviceStateRotationLockDefaults =
        mPostureRotationLockDefaults =
                resources.getStringArray(R.array.config_perDeviceStateRotationLockDefaults);
        fallbackOnDefaults();
    }
@@ -264,23 +268,23 @@ public final class DeviceStateRotationLockSettingsManager {
    }

    private void persistSettings() {
        if (mDeviceStateRotationLockSettings.size() == 0) {
        if (mPostureRotationLockSettings.size() == 0) {
            persistSettingIfChanged(/* newSettingValue= */ "");
            return;
        }

        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder
                .append(mDeviceStateRotationLockSettings.keyAt(0))
                .append(mPostureRotationLockSettings.keyAt(0))
                .append(SEPARATOR_REGEX)
                .append(mDeviceStateRotationLockSettings.valueAt(0));
                .append(mPostureRotationLockSettings.valueAt(0));

        for (int i = 1; i < mDeviceStateRotationLockSettings.size(); i++) {
        for (int i = 1; i < mPostureRotationLockSettings.size(); i++) {
            stringBuilder
                    .append(SEPARATOR_REGEX)
                    .append(mDeviceStateRotationLockSettings.keyAt(i))
                    .append(mPostureRotationLockSettings.keyAt(i))
                    .append(SEPARATOR_REGEX)
                    .append(mDeviceStateRotationLockSettings.valueAt(i));
                    .append(mPostureRotationLockSettings.valueAt(i));
        }
        persistSettingIfChanged(stringBuilder.toString());
    }
@@ -300,22 +304,20 @@ public final class DeviceStateRotationLockSettingsManager {
    }

    private void loadDefaults() {
        mSettableDeviceStates = new ArrayList<>(mDeviceStateRotationLockDefaults.length);
        mDeviceStateDefaultRotationLockSettings = new SparseIntArray(
                mDeviceStateRotationLockDefaults.length);
        mDeviceStateRotationLockSettings = new SparseIntArray(
                mDeviceStateRotationLockDefaults.length);
        mDeviceStateRotationLockFallbackSettings = new SparseIntArray(1);
        for (String entry : mDeviceStateRotationLockDefaults) {
        mSettableDeviceStates = new ArrayList<>(mPostureRotationLockDefaults.length);
        mPostureDefaultRotationLockSettings = new SparseIntArray(
                mPostureRotationLockDefaults.length);
        mPostureRotationLockSettings = new SparseIntArray(mPostureRotationLockDefaults.length);
        mPostureRotationLockFallbackSettings = new SparseIntArray(1);
        for (String entry : mPostureRotationLockDefaults) {
            String[] values = entry.split(SEPARATOR_REGEX);
            try {
                int deviceState = Integer.parseInt(values[0]);
                int posture = Integer.parseInt(values[0]);
                int rotationLockSetting = Integer.parseInt(values[1]);
                if (rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_IGNORED) {
                    if (values.length == 3) {
                        int fallbackDeviceState = Integer.parseInt(values[2]);
                        mDeviceStateRotationLockFallbackSettings.put(deviceState,
                                fallbackDeviceState);
                        int fallbackPosture = Integer.parseInt(values[2]);
                        mPostureRotationLockFallbackSettings.put(posture, fallbackPosture);
                    } else {
                        Log.w(TAG,
                                "Rotation lock setting is IGNORED, but values have unexpected "
@@ -324,9 +326,14 @@ public final class DeviceStateRotationLockSettingsManager {
                    }
                }
                boolean isSettable = rotationLockSetting != DEVICE_STATE_ROTATION_LOCK_IGNORED;
                Integer deviceState = mPosturesHelper.postureToDeviceState(posture);
                if (deviceState != null) {
                    mSettableDeviceStates.add(new SettableDeviceState(deviceState, isSettable));
                mDeviceStateRotationLockSettings.put(deviceState, rotationLockSetting);
                mDeviceStateDefaultRotationLockSettings.put(deviceState, rotationLockSetting);
                } else {
                    Log.wtf(TAG, "No matching device state for posture: " + posture);
                }
                mPostureRotationLockSettings.put(posture, rotationLockSetting);
                mPostureDefaultRotationLockSettings.put(posture, rotationLockSetting);
            } catch (NumberFormatException e) {
                Log.wtf(TAG, "Error parsing settings entry. Entry was: " + entry, e);
                return;
@@ -338,13 +345,11 @@ public final class DeviceStateRotationLockSettingsManager {
    public void dump(IndentingPrintWriter pw) {
        pw.println("DeviceStateRotationLockSettingsManager");
        pw.increaseIndent();
        pw.println("mDeviceStateRotationLockDefaults: " + Arrays.toString(
                mDeviceStateRotationLockDefaults));
        pw.println("mDeviceStateDefaultRotationLockSettings: "
                + mDeviceStateDefaultRotationLockSettings);
        pw.println("mDeviceStateRotationLockSettings: " + mDeviceStateRotationLockSettings);
        pw.println("mDeviceStateRotationLockFallbackSettings: "
                + mDeviceStateRotationLockFallbackSettings);
        pw.println("mPostureRotationLockDefaults: "
                + Arrays.toString(mPostureRotationLockDefaults));
        pw.println("mPostureDefaultRotationLockSettings: " + mPostureDefaultRotationLockSettings);
        pw.println("mDeviceStateRotationLockSettings: " + mPostureRotationLockSettings);
        pw.println("mPostureRotationLockFallbackSettings: " + mPostureRotationLockFallbackSettings);
        pw.println("mSettableDeviceStates: " + mSettableDeviceStates);
        pw.println("mLastSettingValue: " + mLastSettingValue);
        pw.decreaseIndent();
+55 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.settingslib.devicestate

import android.content.Context
import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_FOLDED
import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_HALF_FOLDED
import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_UNFOLDED
import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_KEY_UNKNOWN
import android.provider.Settings.Secure.DeviceStateRotationLockKey
import com.android.internal.R

/** Helps to convert between device state and posture. */
class PosturesHelper(context: Context) {

    private val foldedDeviceStates =
        context.resources.getIntArray(R.array.config_foldedDeviceStates)
    private val halfFoldedDeviceStates =
        context.resources.getIntArray(R.array.config_halfFoldedDeviceStates)
    private val unfoldedDeviceStates =
        context.resources.getIntArray(R.array.config_openDeviceStates)

    @DeviceStateRotationLockKey
    fun deviceStateToPosture(deviceState: Int): Int {
        return when (deviceState) {
            in foldedDeviceStates -> DEVICE_STATE_ROTATION_KEY_FOLDED
            in halfFoldedDeviceStates -> DEVICE_STATE_ROTATION_KEY_HALF_FOLDED
            in unfoldedDeviceStates -> DEVICE_STATE_ROTATION_KEY_UNFOLDED
            else -> DEVICE_STATE_ROTATION_KEY_UNKNOWN
        }
    }

    fun postureToDeviceState(@DeviceStateRotationLockKey posture: Int): Int? {
        return when (posture) {
            DEVICE_STATE_ROTATION_KEY_FOLDED -> foldedDeviceStates.firstOrNull()
            DEVICE_STATE_ROTATION_KEY_HALF_FOLDED -> halfFoldedDeviceStates.firstOrNull()
            DEVICE_STATE_ROTATION_KEY_UNFOLDED -> unfoldedDeviceStates.firstOrNull()
            else -> null
        }
    }
}
Loading