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

Commit f9519def authored by Kevin Chyn's avatar Kevin Chyn Committed by Android (Google) Code Review
Browse files

Merge "Update DeviceStateController to use new DSM API's" into main

parents 1a3a2f96 fa5f10e0
Loading
Loading
Loading
Loading
+80 −20
Original line number Diff line number Diff line
@@ -16,9 +16,19 @@

package com.android.server.wm;

import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT;
import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY;
import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY;
import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY;
import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN;

import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.feature.flags.FeatureFlags;
import android.hardware.devicestate.feature.flags.FeatureFlagsImpl;
import android.util.ArrayMap;
import android.util.Pair;

@@ -28,6 +38,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
@@ -43,16 +54,16 @@ final class DeviceStateController {
    @NonNull
    private final WindowManagerGlobalLock mWmLock;
    @NonNull
    private final int[] mOpenDeviceStates;
    private final List<Integer> mOpenDeviceStates;
    @NonNull
    private final int[] mHalfFoldedDeviceStates;
    private final List<Integer> mHalfFoldedDeviceStates;
    @NonNull
    private final int[] mFoldedDeviceStates;
    private final List<Integer> mFoldedDeviceStates;
    @NonNull
    private final int[] mRearDisplayDeviceStates;
    private final int mConcurrentDisplayDeviceState;
    private final List<Integer> mRearDisplayDeviceStates;
    private final List<Integer> mConcurrentDisplayDeviceStates;
    @NonNull
    private final int[] mReverseRotationAroundZAxisStates;
    private final List<Integer> mReverseRotationAroundZAxisStates;
    @GuardedBy("mWmLock")
    @NonNull
    @VisibleForTesting
@@ -76,18 +87,55 @@ final class DeviceStateController {
    DeviceStateController(@NonNull Context context, @NonNull WindowManagerGlobalLock wmLock) {
        mWmLock = wmLock;

        mOpenDeviceStates = context.getResources()
                .getIntArray(R.array.config_openDeviceStates);
        mHalfFoldedDeviceStates = context.getResources()
                .getIntArray(R.array.config_halfFoldedDeviceStates);
        mFoldedDeviceStates = context.getResources()
                .getIntArray(R.array.config_foldedDeviceStates);
        mRearDisplayDeviceStates = context.getResources()
                .getIntArray(R.array.config_rearDisplayDeviceStates);
        mConcurrentDisplayDeviceState = context.getResources()
                .getInteger(R.integer.config_deviceStateConcurrentRearDisplay);
        mReverseRotationAroundZAxisStates = context.getResources()
                .getIntArray(R.array.config_deviceStatesToReverseDefaultDisplayRotationAroundZAxis);
        final FeatureFlags deviceStateManagerFlags = new FeatureFlagsImpl();
        if (deviceStateManagerFlags.deviceStatePropertyMigration()) {
            mOpenDeviceStates = new ArrayList<>();
            mHalfFoldedDeviceStates = new ArrayList<>();
            mFoldedDeviceStates = new ArrayList<>();
            mRearDisplayDeviceStates = new ArrayList<>();
            mConcurrentDisplayDeviceStates = new ArrayList<>();

            final DeviceStateManager deviceStateManager =
                    context.getSystemService(DeviceStateManager.class);
            final List<android.hardware.devicestate.DeviceState> deviceStates =
                    deviceStateManager.getSupportedDeviceStates();

            for (int i = 0; i < deviceStates.size(); i++) {
                final android.hardware.devicestate.DeviceState state = deviceStates.get(i);
                if (state.hasProperty(
                        PROPERTY_FEATURE_REAR_DISPLAY)) {
                    mRearDisplayDeviceStates.add(state.getIdentifier());
                } else if (state.hasProperty(
                        PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT)) {
                    mConcurrentDisplayDeviceStates.add(state.getIdentifier());
                } else if (state.hasProperty(
                        PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY)) {
                    mFoldedDeviceStates.add(state.getIdentifier());
                } else if (state.hasProperty(
                        PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY)) {
                    if (state.hasProperty(
                            PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN)) {
                        mHalfFoldedDeviceStates.add(state.getIdentifier());
                    } else {
                        mOpenDeviceStates.add(state.getIdentifier());
                    }
                }
            }
        } else {
            mOpenDeviceStates = copyIntArrayToList(context.getResources()
                    .getIntArray(R.array.config_openDeviceStates));
            mHalfFoldedDeviceStates = copyIntArrayToList(context.getResources()
                    .getIntArray(R.array.config_halfFoldedDeviceStates));
            mFoldedDeviceStates = copyIntArrayToList(context.getResources()
                    .getIntArray(R.array.config_foldedDeviceStates));
            mRearDisplayDeviceStates = copyIntArrayToList(context.getResources()
                    .getIntArray(R.array.config_rearDisplayDeviceStates));
            mConcurrentDisplayDeviceStates = new ArrayList<>(List.of(context.getResources()
                    .getInteger(R.integer.config_deviceStateConcurrentRearDisplay)));
        }

        mReverseRotationAroundZAxisStates = copyIntArrayToList(context.getResources().getIntArray(
                R.array.config_deviceStatesToReverseDefaultDisplayRotationAroundZAxis));
        mMatchBuiltInDisplayOrientationToDefaultDisplay = context.getResources()
                .getBoolean(R.bool
                        .config_matchSecondaryInternalDisplaysOrientationToReverseDefaultDisplay);
@@ -145,7 +193,6 @@ final class DeviceStateController {
     */
    public void onDeviceStateReceivedByDisplayManager(int state) {
        mCurrentState = state;

        final DeviceState deviceState;
        if (ArrayUtils.contains(mHalfFoldedDeviceStates, state)) {
            deviceState = DeviceState.HALF_FOLDED;
@@ -155,9 +202,10 @@ final class DeviceStateController {
            deviceState = DeviceState.REAR;
        } else if (ArrayUtils.contains(mOpenDeviceStates, state)) {
            deviceState = DeviceState.OPEN;
        } else if (state == mConcurrentDisplayDeviceState) {
        } else if (ArrayUtils.contains(mConcurrentDisplayDeviceStates, state)) {
            deviceState = DeviceState.CONCURRENT;
        } else {

            deviceState = DeviceState.UNKNOWN;
        }

@@ -190,4 +238,16 @@ final class DeviceStateController {
        }
        return entries;
    }

    @NonNull
    private List<Integer> copyIntArrayToList(@Nullable int[] values) {
        if (values == null) {
            return Collections.emptyList();
        }
        final List<Integer> valueList = new ArrayList<>();
        for (int i = 0; i < values.length; i++) {
            valueList.add(values[i]);
        }
        return valueList;
    }
}
+118 −25
Original line number Diff line number Diff line
@@ -16,6 +16,15 @@

package com.android.server.wm;

import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT;
import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY;
import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY;
import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY;
import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED;
import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN;
import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN;
import static android.hardware.devicestate.feature.flags.Flags.FLAG_DEVICE_STATE_PROPERTY_MIGRATION;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;

@@ -24,8 +33,11 @@ import static org.junit.Assert.assertTrue;

import android.content.Context;
import android.content.res.Resources;
import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.util.Pair;

import androidx.test.filters.SmallTest;
@@ -37,6 +49,8 @@ import com.google.common.util.concurrent.MoreExecutors;
import org.junit.Before;
import org.junit.Test;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -79,39 +93,67 @@ public class DeviceStateControllerTests {
    @Test
    public void testInitialization() {
        initialize(true /* supportFold */, true /* supportHalfFolded */);
        mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates[0]);
        mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates.get(0).getIdentifier());
        assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
    }

    @Test
    public void testInitializationWithNoFoldSupport() {
        initialize(false /* supportFold */, false /* supportHalfFolded */);
        mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates[0]);
        mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates.get(0).getIdentifier());
        // Note that the folded state is ignored.
        assertEquals(DeviceStateController.DeviceState.UNKNOWN, mCurrentState);
    }

    @Test
    public void testWithFoldSupported() {
    @RequiresFlagsDisabled(FLAG_DEVICE_STATE_PROPERTY_MIGRATION)
    public void testWithFoldSupported_withOverlayConfigValues() {
        initialize(true /* supportFold */, false /* supportHalfFolded */);
        mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates[0]);
        mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates.get(0).getIdentifier());
        assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
        mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates[0]);
        mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates.get(0).getIdentifier());
        assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState);
        mTarget.onDeviceStateReceivedByDisplayManager(mHalfFoldedStates[0]);
        mTarget.onDeviceStateReceivedByDisplayManager(mHalfFoldedStates.get(0).getIdentifier());
        assertEquals(DeviceStateController.DeviceState.UNKNOWN, mCurrentState); // Ignored
    }

    @Test
    public void testWithHalfFoldSupported() {
    @RequiresFlagsEnabled(FLAG_DEVICE_STATE_PROPERTY_MIGRATION)
    public void testWithFoldSupported_withDeviceStateManagerPropertyAPI() {
        initialize(true /* supportFold */, false /* supportHalfFolded */);
        mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates.get(0).getIdentifier());
        assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
        mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates.get(0).getIdentifier());
        assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState);
        mTarget.onDeviceStateReceivedByDisplayManager(mHalfFoldedStates.get(0).getIdentifier());
        assertEquals(DeviceStateController.DeviceState.UNKNOWN, mCurrentState); // Ignored
    }

    @Test
    @RequiresFlagsDisabled(FLAG_DEVICE_STATE_PROPERTY_MIGRATION)
    public void testWithHalfFoldSupported_withOverlayConfigValue() {
        initialize(true /* supportFold */, true /* supportHalfFolded */);
        mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates.get(0).getIdentifier());
        assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
        mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates.get(0).getIdentifier());
        assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState);
        mTarget.onDeviceStateReceivedByDisplayManager(mHalfFoldedStates.get(0).getIdentifier());
        assertEquals(DeviceStateController.DeviceState.HALF_FOLDED, mCurrentState);
        mTarget.onDeviceStateReceivedByDisplayManager(mConcurrentDisplayState.getIdentifier());
        assertEquals(DeviceStateController.DeviceState.CONCURRENT, mCurrentState);
    }

    @Test
    @RequiresFlagsEnabled(FLAG_DEVICE_STATE_PROPERTY_MIGRATION)
    public void testWithHalfFoldSupported_withDeviceStateManagerPropertyApi() {
        initialize(true /* supportFold */, true /* supportHalfFolded */);
        mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates[0]);
        mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates.get(0).getIdentifier());
        assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
        mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates[0]);
        mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates.get(0).getIdentifier());
        assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState);
        mTarget.onDeviceStateReceivedByDisplayManager(mHalfFoldedStates[0]);
        mTarget.onDeviceStateReceivedByDisplayManager(mHalfFoldedStates.get(0).getIdentifier());
        assertEquals(DeviceStateController.DeviceState.HALF_FOLDED, mCurrentState);
        mTarget.onDeviceStateReceivedByDisplayManager(mConcurrentDisplayState);
        mTarget.onDeviceStateReceivedByDisplayManager(mConcurrentDisplayState.getIdentifier());
        assertEquals(DeviceStateController.DeviceState.CONCURRENT, mCurrentState);
    }

@@ -121,16 +163,18 @@ public class DeviceStateControllerTests {
        assertEquals(1, mTarget.mDeviceStateCallbacks.size());
        assertTrue(mTarget.mDeviceStateCallbacks.containsKey(mDelegate));

        mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates[0]);
        mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates.get(0).getIdentifier());
        assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
        mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates[0]);
        mTarget.onDeviceStateReceivedByDisplayManager(mFoldedStates.get(0).getIdentifier());
        assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState);

        // The callback should not receive state change when it is unregistered.
        mTarget.unregisterDeviceStateCallback(mDelegate);
        assertTrue(mTarget.mDeviceStateCallbacks.isEmpty());
        mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates[0]);
        assertEquals(DeviceStateController.DeviceState.FOLDED /* unchanged */, mCurrentState);

        mTarget.onDeviceStateReceivedByDisplayManager(mOpenDeviceStates.get(0).getIdentifier());
        assertEquals(DeviceStateController.DeviceState.FOLDED /* unchanged */,
                mCurrentState);
    }

    @Test
@@ -151,16 +195,50 @@ public class DeviceStateControllerTests {
        assertEquals(mExecutor, entries.get(0).second);
    }

    private final int[] mFoldedStates = {0};
    private final int[] mOpenDeviceStates = {1};
    private final int[] mHalfFoldedStates = {2};
    private final int[] mRearDisplayStates = {3};
    private final int mConcurrentDisplayState = 4;
    private final List<DeviceState> mFoldedStates = new ArrayList<>(
            List.of(new DeviceState(new DeviceState.Configuration.Builder(0,
                    "folded").setSystemProperties(new HashSet<>(
                    List.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY)))
                    .setPhysicalProperties(new HashSet<>(
                            List.of(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED)))
                    .build())));
    private final List<DeviceState> mOpenDeviceStates = new ArrayList<>(
            List.of(new DeviceState(new DeviceState.Configuration.Builder(1,
                    "open").setSystemProperties(new HashSet<>(
                            List.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY)))
                    .setPhysicalProperties(new HashSet<>(
                            List.of(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN)))
                    .build())));
    private final List<DeviceState> mHalfFoldedStates = new ArrayList<>(
            List.of(new DeviceState(new DeviceState.Configuration.Builder(2,
                    "half_folded").setSystemProperties(new HashSet<>(
                            List.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY)))
                    .setPhysicalProperties(new HashSet<>(
                            List.of(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN)))
                    .build())));
    private final List<DeviceState> mRearDisplayStates = new ArrayList<>(
            List.of(new DeviceState(new DeviceState.Configuration.Builder(3,
                    "rear_display").setSystemProperties(new HashSet<>(
                            List.of(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY,
                                    PROPERTY_FEATURE_REAR_DISPLAY)))
                    .setPhysicalProperties(new HashSet<>(
                            List.of(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN)))
                    .build())));
    private final DeviceState mConcurrentDisplayState = new DeviceState(
            new DeviceState.Configuration.Builder(4, "concurrent_display")
                    .setSystemProperties(new HashSet<>(List.of(
                            PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY,
                            PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT)))
                    .setPhysicalProperties(new HashSet<>(List.of(
                            PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN)))
                    .build());

    private class DeviceStateControllerBuilder {
        private boolean mSupportFold = false;
        private boolean mSupportHalfFold = false;

        private Consumer<DeviceStateController.DeviceState> mDelegate;
        private final List<DeviceState> mDeviceStateList = new ArrayList<>();

        DeviceStateControllerBuilder setSupportFold(
                boolean supportFold, boolean supportHalfFold) {
@@ -179,13 +257,17 @@ public class DeviceStateControllerTests {
            if (enableFold || enableHalfFold) {
                when(mMockContext.getResources()
                        .getIntArray(R.array.config_openDeviceStates))
                        .thenReturn(mOpenDeviceStates);
                        .thenReturn(mapDeviceStateListToIdentifierArray(mOpenDeviceStates));
                when(mMockContext.getResources()
                        .getIntArray(R.array.config_rearDisplayDeviceStates))
                        .thenReturn(mRearDisplayStates);
                        .thenReturn(mapDeviceStateListToIdentifierArray(mRearDisplayStates));
                when(mMockContext.getResources()
                        .getInteger(R.integer.config_deviceStateConcurrentRearDisplay))
                        .thenReturn(mConcurrentDisplayState);
                        .thenReturn(mConcurrentDisplayState.getIdentifier());

                mDeviceStateList.addAll(mOpenDeviceStates);
                mDeviceStateList.addAll(mRearDisplayStates);
                mDeviceStateList.add(mConcurrentDisplayState);
            } else {
                // Match the default value in framework resources
                when(mMockContext.getResources()
@@ -196,12 +278,14 @@ public class DeviceStateControllerTests {
            if (enableFold) {
                when(mMockContext.getResources()
                        .getIntArray(R.array.config_foldedDeviceStates))
                        .thenReturn(mFoldedStates);
                        .thenReturn(mapDeviceStateListToIdentifierArray(mFoldedStates));
                mDeviceStateList.addAll(mFoldedStates);
            }
            if (enableHalfFold) {
                when(mMockContext.getResources()
                        .getIntArray(R.array.config_halfFoldedDeviceStates))
                        .thenReturn(mHalfFoldedStates);
                        .thenReturn(mapDeviceStateListToIdentifierArray(mHalfFoldedStates));
                mDeviceStateList.addAll(mHalfFoldedStates);
            }
        }

@@ -210,11 +294,20 @@ public class DeviceStateControllerTests {
            mMockDeviceStateManager = mock(DeviceStateManager.class);
            when(mMockContext.getSystemService(DeviceStateManager.class))
                    .thenReturn(mMockDeviceStateManager);
            when(mMockDeviceStateManager.getSupportedDeviceStates()).thenReturn(mDeviceStateList);
            Resources mockRes = mock(Resources.class);
            when(mMockContext.getResources()).thenReturn((mockRes));
            mockFold(mSupportFold, mSupportHalfFold);
            mTarget = new DeviceStateController(mMockContext, new WindowManagerGlobalLock());
            mTarget.registerDeviceStateCallback(mDelegate, mExecutor);
        }

        private int[] mapDeviceStateListToIdentifierArray(List<DeviceState> deviceStates) {
            int[] identifiers = new int[deviceStates.size()];
            for (int i = 0; i < deviceStates.size(); i++) {
                identifiers[i] = deviceStates.get(i).getIdentifier();
            }
            return identifiers;
        }
    }
}