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

Commit d5e5c502 authored by Kenneth Ford's avatar Kenneth Ford
Browse files

Adds SystemUI DeviceStateManager utilities

Adds a DeviceStateManager kosmo that provides helper state
information that can be used in tests.

Also updates the Utils#isFoldable method to use the
updated DeviceState#hasProperty method, to be used by
clients within SystemUI.

Test: UtilsTest
Bug: 336640888
Flag: android.hardware.devicestate.feature.flags.device_state_property_migration
Change-Id: I777f7702df01e34546afb147cf2adda2dd39e0f7
parent 4ba1a4de
Loading
Loading
Loading
Loading
+126 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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.systemui.util

import android.hardware.devicestate.DeviceState
import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY
import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY
import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED
import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN
import android.hardware.devicestate.feature.flags.Flags
import android.platform.test.annotations.RequiresFlagsDisabled
import android.platform.test.annotations.RequiresFlagsEnabled
import android.testing.TestableResources
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.deviceStateManager
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.whenever

@SmallTest
@RunWith(AndroidJUnit4::class)
class UtilsTest : SysuiTestCase() {

    private val kosmos = Kosmos()
    private val deviceStateManager = kosmos.deviceStateManager
    private lateinit var testableResources: TestableResources


    @Before
    fun setUp() {
        testableResources = context.orCreateTestableResources
    }

    @Test
    @RequiresFlagsDisabled(Flags.FLAG_DEVICE_STATE_PROPERTY_MIGRATION)
    fun isFoldableReturnsFalse_overlayConfigurationValues() {
        testableResources.addOverride(
            com.android.internal.R.array.config_foldedDeviceStates,
            intArrayOf() // empty array <=> device is not foldable
        )
        whenever(deviceStateManager.supportedDeviceStates).thenReturn(listOf(DEFAULT_DEVICE_STATE))
        assertFalse(Utils.isDeviceFoldable(testableResources.resources, deviceStateManager))
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_DEVICE_STATE_PROPERTY_MIGRATION)
    fun isFoldableReturnsFalse_deviceStateManager() {
        testableResources.addOverride(
            com.android.internal.R.array.config_foldedDeviceStates,
            intArrayOf() // empty array <=> device is not foldable
        )
        whenever(deviceStateManager.supportedDeviceStates).thenReturn(listOf(DEFAULT_DEVICE_STATE))
        assertFalse(Utils.isDeviceFoldable(testableResources.resources, deviceStateManager))
    }

    @Test
    @RequiresFlagsDisabled(Flags.FLAG_DEVICE_STATE_PROPERTY_MIGRATION)
    fun isFoldableReturnsTrue_overlayConfigurationValues() {
        testableResources.addOverride(
            com.android.internal.R.array.config_foldedDeviceStates,
            intArrayOf(FOLDED_DEVICE_STATE.identifier)
        )
        whenever(deviceStateManager.supportedDeviceStates).thenReturn(
            listOf(
                FOLDED_DEVICE_STATE,
                UNFOLDED_DEVICE_STATE
            )
        )
        assertTrue(Utils.isDeviceFoldable(testableResources.resources, deviceStateManager))
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_DEVICE_STATE_PROPERTY_MIGRATION)
    fun isFoldableReturnsTrue_deviceStateManager() {
        testableResources.addOverride(
            com.android.internal.R.array.config_foldedDeviceStates,
            intArrayOf(FOLDED_DEVICE_STATE.identifier)
        )
        whenever(deviceStateManager.supportedDeviceStates).thenReturn(
            listOf(
                FOLDED_DEVICE_STATE,
                UNFOLDED_DEVICE_STATE
            )
        )
        assertTrue(Utils.isDeviceFoldable(testableResources.resources, deviceStateManager))
    }

    companion object {
        private val DEFAULT_DEVICE_STATE = DeviceState(
            DeviceState.Configuration.Builder(
                0 /* identifier */, "DEFAULT"
            ).build()
        )
        private val FOLDED_DEVICE_STATE = DeviceState(
            DeviceState.Configuration.Builder(1 /* identifier */, "FOLDED")
                .setSystemProperties(setOf(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY))
                .setPhysicalProperties(
                    setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED)
                ).build()
        )
        private val UNFOLDED_DEVICE_STATE = DeviceState(
            DeviceState.Configuration.Builder(2 /* identifier */, "UNFOLDED")
                .setSystemProperties(setOf(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY))
                .setPhysicalProperties(setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN))
                .build()
        )
    }
}
 No newline at end of file
+23 −3
Original line number Diff line number Diff line
@@ -14,11 +14,17 @@

package com.android.systemui.util;

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 android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.feature.flags.Flags;
import android.provider.Settings;
import android.view.DisplayCutout;

@@ -84,9 +90,23 @@ public class Utils {
    /**
     * Returns {@code true} if the device is a foldable device
     */
    public static boolean isDeviceFoldable(Context context) {
        return context.getResources()
                .getIntArray(com.android.internal.R.array.config_foldedDeviceStates).length != 0;
    public static boolean isDeviceFoldable(Resources resources,
            DeviceStateManager deviceStateManager) {
        if (Flags.deviceStatePropertyMigration()) {
            List<DeviceState> deviceStates = deviceStateManager.getSupportedDeviceStates();
            for (int i = 0; i < deviceStates.size(); i++) {
                DeviceState state = deviceStates.get(i);
                if (state.hasProperty(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY)
                        || state.hasProperty(
                        PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY)) {
                    return true;
                }
            }
            return false;
        } else {
            return resources.getIntArray(
                    com.android.internal.R.array.config_foldedDeviceStates).length != 0;
        }
    }

    /**
+136 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.systemui

import android.hardware.devicestate.DeviceState
import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY
import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY
import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY
import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED
import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN
import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN
import android.hardware.devicestate.DeviceState.PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP
import android.hardware.devicestate.DeviceState.PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE
import android.hardware.devicestate.DeviceStateManager
import com.android.systemui.kosmos.Kosmos
import org.mockito.kotlin.mock

val Kosmos.deviceStateManager by Kosmos.Fixture { mock<DeviceStateManager>() }

val Kosmos.defaultDeviceState by Kosmos.Fixture {
    DeviceState(
        DeviceState.Configuration.Builder(
            0 /* identifier */,
            "DEFAULT"
        ).build()
    )
}

val Kosmos.foldedDeviceStateList by Kosmos.Fixture {
    listOf(
        DeviceState(
            DeviceState.Configuration.Builder(0, "FOLDED_0")
                .setSystemProperties(
                    setOf(
                        PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY,
                        PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP
                    )
                )
                .setPhysicalProperties(
                    setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED)
                )
                .build()
        ),
        DeviceState(
            DeviceState.Configuration.Builder(1, "FOLDED_1")
                .setSystemProperties(
                    setOf(
                        PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY,
                        PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP
                    )
                )
                .setPhysicalProperties(
                    setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED)
                )
                .build()
        ),
        DeviceState(
            DeviceState.Configuration.Builder(2, "FOLDED_2")
                .setSystemProperties(
                    setOf(
                        PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY,
                        PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP
                    )
                )
                .setPhysicalProperties(
                    setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED)
                )
                .build()
        )
    )
}

val Kosmos.halfFoldedDeviceState by Kosmos.Fixture {
    DeviceState(
        DeviceState.Configuration.Builder(3 /* identifier */, "HALF_FOLDED")
            .setSystemProperties(
                setOf(
                    PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY,
                    PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE
                )
            )
            .setPhysicalProperties(
                setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN)
            )
            .build()
    )
}

val Kosmos.unfoldedDeviceState by Kosmos.Fixture {
    DeviceState(
        DeviceState.Configuration.Builder(4 /* identifier */, "UNFOLDED")
            .setSystemProperties(
                setOf(
                    PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY,
                    PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE
                )
            )
            .setPhysicalProperties(
                setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN)
            )
            .build()
    )
}

val Kosmos.rearDisplayDeviceState by Kosmos.Fixture {
    DeviceState(
        DeviceState.Configuration.Builder(5 /* identifier */, "REAR_DISPLAY")
            .setSystemProperties(
                setOf(
                    PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY,
                    PROPERTY_FEATURE_REAR_DISPLAY
                )
            )
            .build()
    )
}

val Kosmos.unknownDeviceState by Kosmos.Fixture {
    DeviceState(
        DeviceState.Configuration.Builder(8 /* identifier */, "UNKNOWN").build()
    )
}