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

Commit 4d80678d authored by Beverly's avatar Beverly Committed by Beverly Tai
Browse files

DevicePostureControlller to use the device posture of the device display

Instead of using the CONCURRENT device state (multiple displays on the
device are being used), use the base (physical) device state.

Test: atest DevicePostureControllerImplTest
Test: manually set device state `adb shell cmd device_state state 4`,
then check sysui dumpsys, DozeSensors section and see posture is the
current display posture and not UNSUPPORTED/1000.
Fixes: 303543453
Flag: NONE

Change-Id: Id4cff55e197f3dc4c11d9e3bc4a2d0bccdcf516c
parent 3baabef4
Loading
Loading
Loading
Loading
+5 −1
Original line number Original line Diff line number Diff line
@@ -73,7 +73,11 @@ public interface DevicePostureController extends CallbackController<Callback> {


    /** Callback to be notified about device posture changes. */
    /** Callback to be notified about device posture changes. */
    interface Callback {
    interface Callback {
        /** Called when the posture changes. */
        /**
         * Called when the posture changes. If there are multiple active displays ("concurrent"),
         * this will report the physical posture of the device (also known as the base device
         * state).
         */
        void onPostureChanged(@DevicePostureInt int posture);
        void onPostureChanged(@DevicePostureInt int posture);
    }
    }
}
}
+30 −6
Original line number Original line Diff line number Diff line
@@ -36,8 +36,11 @@ import javax.inject.Inject;
/** Implementation of {@link DevicePostureController} using the DeviceStateManager. */
/** Implementation of {@link DevicePostureController} using the DeviceStateManager. */
@SysUISingleton
@SysUISingleton
public class DevicePostureControllerImpl implements DevicePostureController {
public class DevicePostureControllerImpl implements DevicePostureController {
    /** From androidx.window.common.COMMON_STATE_USE_BASE_STATE */
    private static final int COMMON_STATE_USE_BASE_STATE = 1000;
    private final List<Callback> mListeners = new ArrayList<>();
    private final List<Callback> mListeners = new ArrayList<>();
    private int mCurrentDevicePosture = DEVICE_POSTURE_UNKNOWN;
    private int mCurrentDevicePosture = DEVICE_POSTURE_UNKNOWN;
    private int mCurrentBasePosture = DEVICE_POSTURE_UNKNOWN;


    private final SparseIntArray mDeviceStateToPostureMap = new SparseIntArray();
    private final SparseIntArray mDeviceStateToPostureMap = new SparseIntArray();


@@ -70,12 +73,25 @@ public class DevicePostureControllerImpl implements DevicePostureController {
            mDeviceStateToPostureMap.put(deviceState, posture);
            mDeviceStateToPostureMap.put(deviceState, posture);
        }
        }


        deviceStateManager.registerCallback(executor, state -> {
        deviceStateManager.registerCallback(executor, new DeviceStateManager.DeviceStateCallback() {
            @Override
            public void onStateChanged(int state) {
                Assert.isMainThread();
                Assert.isMainThread();
                mCurrentDevicePosture =
                mCurrentDevicePosture =
                        mDeviceStateToPostureMap.get(state, DEVICE_POSTURE_UNKNOWN);
                        mDeviceStateToPostureMap.get(state, DEVICE_POSTURE_UNKNOWN);


            mListeners.forEach(l -> l.onPostureChanged(mCurrentDevicePosture));
                mListeners.forEach(l -> l.onPostureChanged(getDevicePosture()));
            }

            @Override
            public void onBaseStateChanged(int state) {
                Assert.isMainThread();
                mCurrentBasePosture = mDeviceStateToPostureMap.get(state, DEVICE_POSTURE_UNKNOWN);

                if (useBaseState()) {
                    mListeners.forEach(l -> l.onPostureChanged(getDevicePosture()));
                }
            }
        });
        });
    }
    }


@@ -93,6 +109,14 @@ public class DevicePostureControllerImpl implements DevicePostureController {


    @Override
    @Override
    public int getDevicePosture() {
    public int getDevicePosture() {
        if (useBaseState()) {
            return mCurrentBasePosture;
        } else {
            return mCurrentDevicePosture;
            return mCurrentDevicePosture;
        }
        }
    }
    }

    private boolean useBaseState() {
        return mCurrentDevicePosture == COMMON_STATE_USE_BASE_STATE;
    }
}
+143 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2021 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.statusbar.policy

import android.hardware.devicestate.DeviceStateManager
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.TestableResources
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_CLOSED
import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_FLIPPED
import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED
import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED
import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN
import com.android.systemui.statusbar.policy.DevicePostureController.SUPPORTED_POSTURES_SIZE
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations

@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class DevicePostureControllerImplTest : SysuiTestCase() {
    private val useBaseStateDeviceState = SUPPORTED_POSTURES_SIZE
    private val deviceStateToPostureMapping =
        arrayOf(
            "$DEVICE_POSTURE_UNKNOWN:$DEVICE_POSTURE_UNKNOWN",
            "$DEVICE_POSTURE_CLOSED:$DEVICE_POSTURE_CLOSED",
            "$DEVICE_POSTURE_HALF_OPENED:$DEVICE_POSTURE_HALF_OPENED",
            "$DEVICE_POSTURE_OPENED:$DEVICE_POSTURE_OPENED",
            "$DEVICE_POSTURE_FLIPPED:$DEVICE_POSTURE_FLIPPED",
            "$useBaseStateDeviceState:1000"
        )
    @Mock private lateinit var deviceStateManager: DeviceStateManager
    @Captor
    private lateinit var deviceStateCallback: ArgumentCaptor<DeviceStateManager.DeviceStateCallback>

    private lateinit var mainExecutor: FakeExecutor
    private lateinit var testableResources: TestableResources
    private lateinit var underTest: DevicePostureControllerImpl

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)
        mainExecutor = FakeExecutor(FakeSystemClock())
        testableResources = context.getOrCreateTestableResources()
        testableResources.addOverride(
            com.android.internal.R.array.config_device_state_postures,
            deviceStateToPostureMapping
        )
        underTest =
            DevicePostureControllerImpl(
                context,
                deviceStateManager,
                mainExecutor,
            )
        verifyRegistersForDeviceStateCallback()
    }

    @Test
    fun testPostureChanged_updates() {
        var posture = -1
        underTest.addCallback { posture = it }

        deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_UNKNOWN)
        assertThat(posture).isEqualTo(DEVICE_POSTURE_UNKNOWN)

        deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_CLOSED)
        assertThat(posture).isEqualTo(DEVICE_POSTURE_CLOSED)

        deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_HALF_OPENED)
        assertThat(posture).isEqualTo(DEVICE_POSTURE_HALF_OPENED)

        deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_OPENED)
        assertThat(posture).isEqualTo(DEVICE_POSTURE_OPENED)

        deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_FLIPPED)
        assertThat(posture).isEqualTo(DEVICE_POSTURE_FLIPPED)
    }

    @Test
    fun testPostureChanged_useBaseUpdate() {
        var posture = -1
        underTest.addCallback { posture = it }

        deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_HALF_OPENED)
        assertThat(posture).isEqualTo(DEVICE_POSTURE_HALF_OPENED)

        // base state change doesn't change the posture
        deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_CLOSED)
        assertThat(posture).isEqualTo(DEVICE_POSTURE_HALF_OPENED)

        // WHEN the display state maps to using the base state, then posture updates
        deviceStateCallback.value.onStateChanged(useBaseStateDeviceState)
        assertThat(posture).isEqualTo(DEVICE_POSTURE_CLOSED)
    }

    @Test
    fun baseStateChanges_doesNotUpdatePosture() {
        var numPostureChanges = 0
        underTest.addCallback { numPostureChanges++ }

        deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_HALF_OPENED)
        assertThat(numPostureChanges).isEqualTo(1)

        // base state changes doesn't send another posture update since the device state isn't
        // useBaseStateDeviceState
        deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_CLOSED)
        deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_HALF_OPENED)
        deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_FLIPPED)
        deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_OPENED)
        deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_UNKNOWN)
        assertThat(numPostureChanges).isEqualTo(1)
    }

    private fun verifyRegistersForDeviceStateCallback() {
        verify(deviceStateManager).registerCallback(eq(mainExecutor), deviceStateCallback.capture())
    }
}