Loading packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt +14 −80 Original line number Diff line number Diff line Loading @@ -17,30 +17,20 @@ package com.android.systemui.biometrics.data.repository import android.content.Context import android.hardware.devicestate.DeviceStateManager import android.hardware.display.DisplayManager import android.hardware.display.DisplayManager.DisplayListener import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_CHANGED import android.os.Handler import android.util.Size import android.view.DisplayInfo import com.android.app.tracing.traceSection import com.android.internal.util.ArrayUtils import com.android.systemui.biometrics.shared.model.DisplayRotation import com.android.systemui.biometrics.shared.model.toDisplayRotation import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import java.util.concurrent.Executor import com.android.systemui.display.data.repository.DeviceStateRepository import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState.REAR_DISPLAY import com.android.systemui.display.data.repository.DisplayRepository import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn Loading @@ -65,52 +55,23 @@ interface DisplayStateRepository { val currentDisplaySize: StateFlow<Size> } // TODO(b/296211844): This class could directly use DeviceStateRepository and DisplayRepository // instead. @SysUISingleton class DisplayStateRepositoryImpl @Inject constructor( @Application applicationScope: CoroutineScope, @Background backgroundScope: CoroutineScope, @Application val context: Context, deviceStateManager: DeviceStateManager, displayManager: DisplayManager, @Background backgroundHandler: Handler, @Background backgroundExecutor: Executor, @Background backgroundDispatcher: CoroutineDispatcher, deviceStateRepository: DeviceStateRepository, displayRepository: DisplayRepository, ) : DisplayStateRepository { override val isReverseDefaultRotation = context.resources.getBoolean(com.android.internal.R.bool.config_reverseDefaultRotation) override val isInRearDisplayMode: StateFlow<Boolean> = conflatedCallbackFlow { val sendRearDisplayStateUpdate = { state: Boolean -> trySendWithFailureLogging( state, TAG, "Error sending rear display state update to $state" ) } val callback = DeviceStateManager.DeviceStateCallback { state -> val isInRearDisplayMode = ArrayUtils.contains( context.resources.getIntArray( com.android.internal.R.array.config_rearDisplayDeviceStates ), state ) sendRearDisplayStateUpdate(isInRearDisplayMode) } sendRearDisplayStateUpdate(false) deviceStateManager.registerCallback(backgroundExecutor, callback) awaitClose { deviceStateManager.unregisterCallback(callback) } } .flowOn(backgroundDispatcher) deviceStateRepository.state .map { it == REAR_DISPLAY } .stateIn( applicationScope, backgroundScope, started = SharingStarted.Eagerly, initialValue = false, ) Loading @@ -122,37 +83,10 @@ constructor( } private val currentDisplayInfo: StateFlow<DisplayInfo> = conflatedCallbackFlow { val callback = object : DisplayListener { override fun onDisplayRemoved(displayId: Int) {} override fun onDisplayAdded(displayId: Int) {} override fun onDisplayChanged(displayId: Int) { traceSection( "DisplayStateRepository" + ".currentRotationDisplayListener#onDisplayChanged" ) { val displayInfo = getDisplayInfo() trySendWithFailureLogging( displayInfo, TAG, "Error sending displayInfo to $displayInfo" ) } } } displayManager.registerDisplayListener( callback, backgroundHandler, EVENT_FLAG_DISPLAY_CHANGED ) awaitClose { displayManager.unregisterDisplayListener(callback) } } .flowOn(backgroundDispatcher) displayRepository.displayChangeEvent .map { getDisplayInfo() } .stateIn( applicationScope, backgroundScope, started = SharingStarted.Eagerly, initialValue = getDisplayInfo(), ) Loading @@ -169,7 +103,7 @@ constructor( currentDisplayInfo .map { rotationToDisplayRotation(it.rotation) } .stateIn( applicationScope, backgroundScope, started = SharingStarted.WhileSubscribed(), initialValue = rotationToDisplayRotation(currentDisplayInfo.value.rotation) ) Loading @@ -178,7 +112,7 @@ constructor( currentDisplayInfo .map { Size(it.naturalWidth, it.naturalHeight) } .stateIn( applicationScope, backgroundScope, started = SharingStarted.WhileSubscribed(), initialValue = Size( Loading packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/DisplayStateRepositoryTest.kt +19 −67 Original line number Diff line number Diff line Loading @@ -16,11 +16,9 @@ package com.android.systemui.keyguard.data.repository import android.hardware.devicestate.DeviceStateManager import android.hardware.display.DisplayManager import android.os.Handler import android.util.Size import android.view.Display import android.view.Display.DEFAULT_DISPLAY import android.view.DisplayInfo import android.view.Surface import androidx.test.filters.SmallTest Loading @@ -29,61 +27,37 @@ import com.android.systemui.biometrics.data.repository.DisplayStateRepository import com.android.systemui.biometrics.data.repository.DisplayStateRepositoryImpl import com.android.systemui.biometrics.shared.model.DisplayRotation import com.android.systemui.coroutines.collectLastValue import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState import com.android.systemui.display.data.repository.FakeDeviceStateRepository import com.android.systemui.display.data.repository.FakeDisplayRepository import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.withArgCaptor import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.same import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.spy import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoRule private const val NORMAL_DISPLAY_MODE_DEVICE_STATE = 2 private const val REAR_DISPLAY_MODE_DEVICE_STATE = 3 @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(JUnit4::class) class DisplayStateRepositoryTest : SysuiTestCase() { @JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule() @Mock private lateinit var deviceStateManager: DeviceStateManager @Mock private lateinit var displayManager: DisplayManager @Mock private lateinit var handler: Handler @Mock private lateinit var display: Display private lateinit var underTest: DisplayStateRepository private val display = mock<Display>() private val testScope = TestScope(StandardTestDispatcher()) private val fakeExecutor = FakeExecutor(FakeSystemClock()) private val fakeDeviceStateRepository = FakeDeviceStateRepository() private val fakeDisplayRepository = FakeDisplayRepository() @Captor private lateinit var displayListenerCaptor: ArgumentCaptor<DisplayManager.DisplayListener> private lateinit var underTest: DisplayStateRepository @Before fun setUp() { val rearDisplayDeviceStates = intArrayOf(REAR_DISPLAY_MODE_DEVICE_STATE) mContext.orCreateTestableResources.addOverride( com.android.internal.R.array.config_rearDisplayDeviceStates, rearDisplayDeviceStates ) mContext.orCreateTestableResources.addOverride( com.android.internal.R.bool.config_reverseDefaultRotation, false Loading @@ -96,11 +70,8 @@ class DisplayStateRepositoryTest : SysuiTestCase() { DisplayStateRepositoryImpl( testScope.backgroundScope, mContext, deviceStateManager, displayManager, handler, fakeExecutor, UnconfinedTestDispatcher(), fakeDeviceStateRepository, fakeDisplayRepository, ) } Loading @@ -110,12 +81,10 @@ class DisplayStateRepositoryTest : SysuiTestCase() { val isInRearDisplayMode by collectLastValue(underTest.isInRearDisplayMode) runCurrent() val callback = deviceStateManager.captureCallback() callback.onStateChanged(NORMAL_DISPLAY_MODE_DEVICE_STATE) fakeDeviceStateRepository.emit(DeviceState.FOLDED) assertThat(isInRearDisplayMode).isFalse() callback.onStateChanged(REAR_DISPLAY_MODE_DEVICE_STATE) fakeDeviceStateRepository.emit(DeviceState.REAR_DISPLAY) assertThat(isInRearDisplayMode).isTrue() } Loading @@ -125,19 +94,13 @@ class DisplayStateRepositoryTest : SysuiTestCase() { val currentRotation by collectLastValue(underTest.currentRotation) runCurrent() verify(displayManager) .registerDisplayListener( displayListenerCaptor.capture(), same(handler), eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) ) whenever(display.getDisplayInfo(any())).then { val info = it.getArgument<DisplayInfo>(0) info.rotation = Surface.ROTATION_90 return@then true } displayListenerCaptor.value.onDisplayChanged(Surface.ROTATION_90) fakeDisplayRepository.emitDisplayChangeEvent(DEFAULT_DISPLAY) assertThat(currentRotation).isEqualTo(DisplayRotation.ROTATION_90) whenever(display.getDisplayInfo(any())).then { Loading @@ -145,7 +108,8 @@ class DisplayStateRepositoryTest : SysuiTestCase() { info.rotation = Surface.ROTATION_180 return@then true } displayListenerCaptor.value.onDisplayChanged(Surface.ROTATION_180) fakeDisplayRepository.emitDisplayChangeEvent(DEFAULT_DISPLAY) assertThat(currentRotation).isEqualTo(DisplayRotation.ROTATION_180) } Loading @@ -155,13 +119,6 @@ class DisplayStateRepositoryTest : SysuiTestCase() { val currentSize by collectLastValue(underTest.currentDisplaySize) runCurrent() verify(displayManager) .registerDisplayListener( displayListenerCaptor.capture(), same(handler), eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) ) whenever(display.getDisplayInfo(any())).then { val info = it.getArgument<DisplayInfo>(0) info.rotation = Surface.ROTATION_0 Loading @@ -169,7 +126,7 @@ class DisplayStateRepositoryTest : SysuiTestCase() { info.logicalHeight = 200 return@then true } displayListenerCaptor.value.onDisplayChanged(Surface.ROTATION_0) fakeDisplayRepository.emitDisplayChangeEvent(DEFAULT_DISPLAY) assertThat(currentSize).isEqualTo(Size(100, 200)) whenever(display.getDisplayInfo(any())).then { Loading @@ -179,12 +136,7 @@ class DisplayStateRepositoryTest : SysuiTestCase() { info.logicalHeight = 200 return@then true } displayListenerCaptor.value.onDisplayChanged(Surface.ROTATION_180) fakeDisplayRepository.emitDisplayChangeEvent(DEFAULT_DISPLAY) assertThat(currentSize).isEqualTo(Size(200, 100)) } } private fun DeviceStateManager.captureCallback() = withArgCaptor<DeviceStateManager.DeviceStateCallback> { verify(this@captureCallback).registerCallback(any(), capture()) } Loading
packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt +14 −80 Original line number Diff line number Diff line Loading @@ -17,30 +17,20 @@ package com.android.systemui.biometrics.data.repository import android.content.Context import android.hardware.devicestate.DeviceStateManager import android.hardware.display.DisplayManager import android.hardware.display.DisplayManager.DisplayListener import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_CHANGED import android.os.Handler import android.util.Size import android.view.DisplayInfo import com.android.app.tracing.traceSection import com.android.internal.util.ArrayUtils import com.android.systemui.biometrics.shared.model.DisplayRotation import com.android.systemui.biometrics.shared.model.toDisplayRotation import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import java.util.concurrent.Executor import com.android.systemui.display.data.repository.DeviceStateRepository import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState.REAR_DISPLAY import com.android.systemui.display.data.repository.DisplayRepository import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn Loading @@ -65,52 +55,23 @@ interface DisplayStateRepository { val currentDisplaySize: StateFlow<Size> } // TODO(b/296211844): This class could directly use DeviceStateRepository and DisplayRepository // instead. @SysUISingleton class DisplayStateRepositoryImpl @Inject constructor( @Application applicationScope: CoroutineScope, @Background backgroundScope: CoroutineScope, @Application val context: Context, deviceStateManager: DeviceStateManager, displayManager: DisplayManager, @Background backgroundHandler: Handler, @Background backgroundExecutor: Executor, @Background backgroundDispatcher: CoroutineDispatcher, deviceStateRepository: DeviceStateRepository, displayRepository: DisplayRepository, ) : DisplayStateRepository { override val isReverseDefaultRotation = context.resources.getBoolean(com.android.internal.R.bool.config_reverseDefaultRotation) override val isInRearDisplayMode: StateFlow<Boolean> = conflatedCallbackFlow { val sendRearDisplayStateUpdate = { state: Boolean -> trySendWithFailureLogging( state, TAG, "Error sending rear display state update to $state" ) } val callback = DeviceStateManager.DeviceStateCallback { state -> val isInRearDisplayMode = ArrayUtils.contains( context.resources.getIntArray( com.android.internal.R.array.config_rearDisplayDeviceStates ), state ) sendRearDisplayStateUpdate(isInRearDisplayMode) } sendRearDisplayStateUpdate(false) deviceStateManager.registerCallback(backgroundExecutor, callback) awaitClose { deviceStateManager.unregisterCallback(callback) } } .flowOn(backgroundDispatcher) deviceStateRepository.state .map { it == REAR_DISPLAY } .stateIn( applicationScope, backgroundScope, started = SharingStarted.Eagerly, initialValue = false, ) Loading @@ -122,37 +83,10 @@ constructor( } private val currentDisplayInfo: StateFlow<DisplayInfo> = conflatedCallbackFlow { val callback = object : DisplayListener { override fun onDisplayRemoved(displayId: Int) {} override fun onDisplayAdded(displayId: Int) {} override fun onDisplayChanged(displayId: Int) { traceSection( "DisplayStateRepository" + ".currentRotationDisplayListener#onDisplayChanged" ) { val displayInfo = getDisplayInfo() trySendWithFailureLogging( displayInfo, TAG, "Error sending displayInfo to $displayInfo" ) } } } displayManager.registerDisplayListener( callback, backgroundHandler, EVENT_FLAG_DISPLAY_CHANGED ) awaitClose { displayManager.unregisterDisplayListener(callback) } } .flowOn(backgroundDispatcher) displayRepository.displayChangeEvent .map { getDisplayInfo() } .stateIn( applicationScope, backgroundScope, started = SharingStarted.Eagerly, initialValue = getDisplayInfo(), ) Loading @@ -169,7 +103,7 @@ constructor( currentDisplayInfo .map { rotationToDisplayRotation(it.rotation) } .stateIn( applicationScope, backgroundScope, started = SharingStarted.WhileSubscribed(), initialValue = rotationToDisplayRotation(currentDisplayInfo.value.rotation) ) Loading @@ -178,7 +112,7 @@ constructor( currentDisplayInfo .map { Size(it.naturalWidth, it.naturalHeight) } .stateIn( applicationScope, backgroundScope, started = SharingStarted.WhileSubscribed(), initialValue = Size( Loading
packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/DisplayStateRepositoryTest.kt +19 −67 Original line number Diff line number Diff line Loading @@ -16,11 +16,9 @@ package com.android.systemui.keyguard.data.repository import android.hardware.devicestate.DeviceStateManager import android.hardware.display.DisplayManager import android.os.Handler import android.util.Size import android.view.Display import android.view.Display.DEFAULT_DISPLAY import android.view.DisplayInfo import android.view.Surface import androidx.test.filters.SmallTest Loading @@ -29,61 +27,37 @@ import com.android.systemui.biometrics.data.repository.DisplayStateRepository import com.android.systemui.biometrics.data.repository.DisplayStateRepositoryImpl import com.android.systemui.biometrics.shared.model.DisplayRotation import com.android.systemui.coroutines.collectLastValue import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState import com.android.systemui.display.data.repository.FakeDeviceStateRepository import com.android.systemui.display.data.repository.FakeDisplayRepository import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.withArgCaptor import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.same import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.spy import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoRule private const val NORMAL_DISPLAY_MODE_DEVICE_STATE = 2 private const val REAR_DISPLAY_MODE_DEVICE_STATE = 3 @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(JUnit4::class) class DisplayStateRepositoryTest : SysuiTestCase() { @JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule() @Mock private lateinit var deviceStateManager: DeviceStateManager @Mock private lateinit var displayManager: DisplayManager @Mock private lateinit var handler: Handler @Mock private lateinit var display: Display private lateinit var underTest: DisplayStateRepository private val display = mock<Display>() private val testScope = TestScope(StandardTestDispatcher()) private val fakeExecutor = FakeExecutor(FakeSystemClock()) private val fakeDeviceStateRepository = FakeDeviceStateRepository() private val fakeDisplayRepository = FakeDisplayRepository() @Captor private lateinit var displayListenerCaptor: ArgumentCaptor<DisplayManager.DisplayListener> private lateinit var underTest: DisplayStateRepository @Before fun setUp() { val rearDisplayDeviceStates = intArrayOf(REAR_DISPLAY_MODE_DEVICE_STATE) mContext.orCreateTestableResources.addOverride( com.android.internal.R.array.config_rearDisplayDeviceStates, rearDisplayDeviceStates ) mContext.orCreateTestableResources.addOverride( com.android.internal.R.bool.config_reverseDefaultRotation, false Loading @@ -96,11 +70,8 @@ class DisplayStateRepositoryTest : SysuiTestCase() { DisplayStateRepositoryImpl( testScope.backgroundScope, mContext, deviceStateManager, displayManager, handler, fakeExecutor, UnconfinedTestDispatcher(), fakeDeviceStateRepository, fakeDisplayRepository, ) } Loading @@ -110,12 +81,10 @@ class DisplayStateRepositoryTest : SysuiTestCase() { val isInRearDisplayMode by collectLastValue(underTest.isInRearDisplayMode) runCurrent() val callback = deviceStateManager.captureCallback() callback.onStateChanged(NORMAL_DISPLAY_MODE_DEVICE_STATE) fakeDeviceStateRepository.emit(DeviceState.FOLDED) assertThat(isInRearDisplayMode).isFalse() callback.onStateChanged(REAR_DISPLAY_MODE_DEVICE_STATE) fakeDeviceStateRepository.emit(DeviceState.REAR_DISPLAY) assertThat(isInRearDisplayMode).isTrue() } Loading @@ -125,19 +94,13 @@ class DisplayStateRepositoryTest : SysuiTestCase() { val currentRotation by collectLastValue(underTest.currentRotation) runCurrent() verify(displayManager) .registerDisplayListener( displayListenerCaptor.capture(), same(handler), eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) ) whenever(display.getDisplayInfo(any())).then { val info = it.getArgument<DisplayInfo>(0) info.rotation = Surface.ROTATION_90 return@then true } displayListenerCaptor.value.onDisplayChanged(Surface.ROTATION_90) fakeDisplayRepository.emitDisplayChangeEvent(DEFAULT_DISPLAY) assertThat(currentRotation).isEqualTo(DisplayRotation.ROTATION_90) whenever(display.getDisplayInfo(any())).then { Loading @@ -145,7 +108,8 @@ class DisplayStateRepositoryTest : SysuiTestCase() { info.rotation = Surface.ROTATION_180 return@then true } displayListenerCaptor.value.onDisplayChanged(Surface.ROTATION_180) fakeDisplayRepository.emitDisplayChangeEvent(DEFAULT_DISPLAY) assertThat(currentRotation).isEqualTo(DisplayRotation.ROTATION_180) } Loading @@ -155,13 +119,6 @@ class DisplayStateRepositoryTest : SysuiTestCase() { val currentSize by collectLastValue(underTest.currentDisplaySize) runCurrent() verify(displayManager) .registerDisplayListener( displayListenerCaptor.capture(), same(handler), eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) ) whenever(display.getDisplayInfo(any())).then { val info = it.getArgument<DisplayInfo>(0) info.rotation = Surface.ROTATION_0 Loading @@ -169,7 +126,7 @@ class DisplayStateRepositoryTest : SysuiTestCase() { info.logicalHeight = 200 return@then true } displayListenerCaptor.value.onDisplayChanged(Surface.ROTATION_0) fakeDisplayRepository.emitDisplayChangeEvent(DEFAULT_DISPLAY) assertThat(currentSize).isEqualTo(Size(100, 200)) whenever(display.getDisplayInfo(any())).then { Loading @@ -179,12 +136,7 @@ class DisplayStateRepositoryTest : SysuiTestCase() { info.logicalHeight = 200 return@then true } displayListenerCaptor.value.onDisplayChanged(Surface.ROTATION_180) fakeDisplayRepository.emitDisplayChangeEvent(DEFAULT_DISPLAY) assertThat(currentSize).isEqualTo(Size(200, 100)) } } private fun DeviceStateManager.captureCallback() = withArgCaptor<DeviceStateManager.DeviceStateCallback> { verify(this@captureCallback).registerCallback(any(), capture()) }