Merge "Check 'DeviceFoldStateProvider' is already started" into udc-qpr-dev
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractor.kt
index 86940ca..863ba8d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractor.kt
@@ -82,7 +82,9 @@
) : LogContextInteractor {
init {
- foldProvider.start()
+ applicationScope.launch {
+ foldProvider.start()
+ }
}
override val displayState =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
index bf54d42..aa49287 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
@@ -20,6 +20,7 @@
import android.content.res.Configuration
import android.content.res.Resources
import android.os.Handler
+import android.os.Looper
import android.testing.AndroidTestingRunner
import androidx.core.util.Consumer
import androidx.test.filters.SmallTest
@@ -38,6 +39,7 @@
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
+import junit.framework.Assert.fail
import java.util.concurrent.Executor
import org.junit.Before
import org.junit.Test
@@ -55,16 +57,20 @@
@Mock private lateinit var activityTypeProvider: ActivityManagerActivityTypeProvider
- @Mock private lateinit var handler: Handler
-
@Mock private lateinit var rotationChangeProvider: RotationChangeProvider
@Mock private lateinit var unfoldKeyguardVisibilityProvider: UnfoldKeyguardVisibilityProvider
@Mock private lateinit var resources: Resources
+ @Mock private lateinit var handler: Handler
+
+ @Mock private lateinit var mainLooper: Looper
+
@Mock private lateinit var context: Context
+ @Mock private lateinit var thread: Thread
+
@Captor private lateinit var rotationListener: ArgumentCaptor<RotationListener>
private val foldProvider = TestFoldProvider()
@@ -89,6 +95,11 @@
override val halfFoldedTimeoutMillis: Int
get() = HALF_OPENED_TIMEOUT_MILLIS.toInt()
}
+ whenever(mainLooper.isCurrentThread).thenReturn(true)
+ whenever(handler.looper).thenReturn(mainLooper)
+ whenever(mainLooper.isCurrentThread).thenReturn(true)
+ whenever(mainLooper.thread).thenReturn(thread)
+ whenever(thread.name).thenReturn("backgroundThread")
whenever(context.resources).thenReturn(resources)
whenever(context.mainExecutor).thenReturn(mContext.mainExecutor)
@@ -435,6 +446,26 @@
}
@Test
+ fun startOnlyOnce_whenStartTriggeredThrice_startOnlyOnce() {
+ foldStateProvider.start()
+ foldStateProvider.start()
+ foldStateProvider.start()
+
+ assertThat(foldProvider.getNumberOfCallbacks()).isEqualTo(1)
+ }
+
+ @Test(expected = AssertionError::class)
+ fun startMethod_whileNotOnMainThread_throwsException() {
+ whenever(mainLooper.isCurrentThread).thenReturn(true)
+ try {
+ foldStateProvider.start()
+ fail("Should have thrown AssertionError: should be called from the main thread.")
+ } catch (e: AssertionError) {
+ assertThat(e.message).contains("backgroundThread")
+ }
+ }
+
+ @Test
fun startClosingEvent_whileNotOnKeyguard_triggersAfterThreshold() {
setKeyguardVisibility(visible = false)
setInitialHingeAngle(START_CLOSING_ON_APPS_THRESHOLD_DEGREES)
@@ -658,6 +689,10 @@
fun notifyFolded(isFolded: Boolean) {
callbacks.forEach { it.onFoldUpdated(isFolded) }
}
+
+ fun getNumberOfCallbacks(): Int{
+ return callbacks.size
+ }
}
private class TestScreenOnStatusProvider : ScreenStatusProvider {
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index 8c5244e..6743515 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
@@ -62,6 +62,7 @@
private val hingeAngleListener = HingeAngleListener()
private val screenListener = ScreenStatusListener()
private val foldStateListener = FoldStateListener()
+ private val mainLooper = handler.looper
private val timeoutRunnable = Runnable { cancelAnimation() }
private val rotationListener = RotationListener {
if (isTransitionInProgress) cancelAnimation()
@@ -77,22 +78,28 @@
private var isFolded = false
private var isScreenOn = false
private var isUnfoldHandled = true
+ private var isStarted = false
override fun start() {
+ assertMainThread()
+ if (isStarted) return
foldProvider.registerCallback(foldStateListener, mainExecutor)
screenStatusProvider.addCallback(screenListener)
hingeAngleProvider.addCallback(hingeAngleListener)
rotationChangeProvider.addCallback(rotationListener)
activityTypeProvider.init()
+ isStarted = true
}
override fun stop() {
+ assertMainThread()
screenStatusProvider.removeCallback(screenListener)
foldProvider.unregisterCallback(foldStateListener)
hingeAngleProvider.removeCallback(hingeAngleListener)
hingeAngleProvider.stop()
rotationChangeProvider.removeCallback(rotationListener)
activityTypeProvider.uninit()
+ isStarted = false
}
override fun addCallback(listener: FoldUpdatesListener) {
@@ -292,6 +299,14 @@
onHingeAngle(angle)
}
}
+
+ private fun assertMainThread() {
+ check(mainLooper.isCurrentThread) {
+ ("should be called from the main thread." +
+ " sMainLooper.threadName=" + mainLooper.thread.name +
+ " Thread.currentThread()=" + Thread.currentThread().name)
+ }
+ }
}
fun @receiver:FoldUpdate Int.name() =