Remove dependency on ShadeExpansionStateManager from KeyguardBypassController

Part of the effort to remove ShadeExpansionStateManager dependencies in preparation for Flexiglass.

Bug: 280887022
Test: manually verified qs expanded values using logs
Test: passes existing tests
Change-Id: If1f13ff24bd8dbe09465e9f59ea6c52173cba418
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index 430b0e9..63591d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -21,12 +21,14 @@
 import android.content.pm.PackageManager
 import android.hardware.biometrics.BiometricSourceType
 import android.provider.Settings
+import androidx.annotation.VisibleForTesting
 import com.android.systemui.Dumpable
-import com.android.systemui.res.R
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.shade.ShadeExpansionStateManager
+import com.android.systemui.res.R
+import com.android.systemui.shade.data.repository.ShadeRepository
 import com.android.systemui.statusbar.NotificationLockscreenUserManager
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm
@@ -35,6 +37,10 @@
 import com.android.systemui.statusbar.policy.DevicePostureController.DevicePostureInt
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.tuner.TunerService
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
 import java.io.PrintWriter
 import javax.inject.Inject
 
@@ -43,6 +49,7 @@
 
     private val mKeyguardStateController: KeyguardStateController
     private val statusBarStateController: StatusBarStateController
+    private val shadeRepository: ShadeRepository
     private val devicePostureController: DevicePostureController
     @BypassOverride private val bypassOverride: Int
     private var hasFaceFeature: Boolean
@@ -107,16 +114,18 @@
     @Inject
     constructor(
         context: Context,
+        @Application applicationScope: CoroutineScope,
         tunerService: TunerService,
         statusBarStateController: StatusBarStateController,
         lockscreenUserManager: NotificationLockscreenUserManager,
         keyguardStateController: KeyguardStateController,
-        shadeExpansionStateManager: ShadeExpansionStateManager,
+        shadeRepository: ShadeRepository,
         devicePostureController: DevicePostureController,
         dumpManager: DumpManager
     ) {
         this.mKeyguardStateController = keyguardStateController
         this.statusBarStateController = statusBarStateController
+        this.shadeRepository = shadeRepository
         this.devicePostureController = devicePostureController
 
         bypassOverride = context.resources.getInteger(R.integer.config_face_unlock_bypass_override)
@@ -128,6 +137,7 @@
             return
         }
 
+
         if (configFaceAuthSupportedPosture != DEVICE_POSTURE_UNKNOWN) {
             devicePostureController.addCallback { posture ->
                 if (postureState != posture) {
@@ -137,7 +147,7 @@
             }
         }
 
-        dumpManager.registerDumpable("KeyguardBypassController", this)
+        dumpManager.registerNormalDumpable("KeyguardBypassController", this)
         statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
             override fun onStateChanged(newState: Int) {
                 if (newState != StatusBarState.KEYGUARD) {
@@ -146,27 +156,36 @@
             }
         })
 
-        shadeExpansionStateManager.addQsExpansionListener { isQsExpanded ->
-            val changed = qsExpanded != isQsExpanded
-            qsExpanded = isQsExpanded
-            if (changed && !isQsExpanded) {
-                maybePerformPendingUnlock()
-            }
-        }
+        listenForQsExpandedChange(applicationScope)
 
         val dismissByDefault = if (context.resources.getBoolean(
-                        com.android.internal.R.bool.config_faceAuthDismissesKeyguard)) 1 else 0
+                com.android.internal.R.bool.config_faceAuthDismissesKeyguard)) 1 else 0
+
         tunerService.addTunable({ key, _ ->
             bypassEnabled = tunerService.getValue(key, dismissByDefault) != 0
         }, Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD)
+
         lockscreenUserManager.addUserChangedListener(
-                object : NotificationLockscreenUserManager.UserChangedListener {
-                    override fun onUserChanged(userId: Int) {
-                        pendingUnlock = null
-                    }
-                })
+            object : NotificationLockscreenUserManager.UserChangedListener {
+                override fun onUserChanged(userId: Int) {
+                    pendingUnlock = null
+                }
+            })
     }
 
+    @VisibleForTesting
+    fun listenForQsExpandedChange(scope: CoroutineScope) =
+        scope.launch {
+            shadeRepository.qsExpansion.map { it > 0f }.distinctUntilChanged()
+                .collect { isQsExpanded ->
+                    val changed = qsExpanded != isQsExpanded
+                    qsExpanded = isQsExpanded
+                    if (changed && !isQsExpanded) {
+                        maybePerformPendingUnlock()
+                    }
+                }
+        }
+
     private fun notifyListeners() = listeners.forEach { it.onBypassStateChanged(bypassEnabled) }
 
     /**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt
index ab441e3..6209f73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt
@@ -20,11 +20,14 @@
 import android.test.suitebuilder.annotation.SmallTest
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
-import com.android.systemui.res.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.shade.ShadeExpansionStateManager
+import com.android.systemui.res.R
+import com.android.systemui.scene.SceneTestUtils
+import com.android.systemui.shade.data.repository.FakeShadeRepository
 import com.android.systemui.statusbar.NotificationLockscreenUserManager
 import com.android.systemui.statusbar.policy.DevicePostureController
 import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_CLOSED
@@ -34,6 +37,9 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.tuner.TunerService
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
 import org.junit.After
 import org.junit.Before
 import org.junit.Rule
@@ -54,6 +60,10 @@
 @RunWith(AndroidTestingRunner::class)
 @TestableLooper.RunWithLooper
 class KeyguardBypassControllerTest : SysuiTestCase() {
+    private val utils = SceneTestUtils(this)
+    private val testScope = utils.testScope
+    private val featureFlags = FakeFeatureFlags()
+    private val shadeRepository = FakeShadeRepository()
 
     private lateinit var keyguardBypassController: KeyguardBypassController
     private lateinit var postureControllerCallback: DevicePostureController.Callback
@@ -61,10 +71,10 @@
     @Mock private lateinit var statusBarStateController: StatusBarStateController
     @Mock private lateinit var lockscreenUserManager: NotificationLockscreenUserManager
     @Mock private lateinit var keyguardStateController: KeyguardStateController
-    @Mock private lateinit var shadeExpansionStateManager: ShadeExpansionStateManager
     @Mock private lateinit var devicePostureController: DevicePostureController
     @Mock private lateinit var dumpManager: DumpManager
     @Mock private lateinit var packageManager: PackageManager
+
     @Captor
     private val postureCallbackCaptor =
         ArgumentCaptor.forClass(DevicePostureController.Callback::class.java)
@@ -73,6 +83,8 @@
     @Before
     fun setUp() {
         context.setMockPackageManager(packageManager)
+        featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
+
         whenever(packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true)
         whenever(keyguardStateController.isFaceAuthEnabled).thenReturn(true)
     }
@@ -126,11 +138,12 @@
         keyguardBypassController =
             KeyguardBypassController(
                 context,
+                testScope.backgroundScope,
                 tunerService,
                 statusBarStateController,
                 lockscreenUserManager,
                 keyguardStateController,
-                shadeExpansionStateManager,
+                shadeRepository,
                 devicePostureController,
                 dumpManager
             )
@@ -267,4 +280,25 @@
 
         assertThat(keyguardBypassController.bypassEnabled).isFalse()
     }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @Test
+    fun qsExpansion_updates() {
+        testScope.runTest {
+            initKeyguardBypassController()
+            assertThat(keyguardBypassController.qsExpanded).isFalse()
+            val job = keyguardBypassController.listenForQsExpandedChange(this)
+            shadeRepository.setQsExpansion(0.5f)
+            runCurrent()
+
+            assertThat(keyguardBypassController.qsExpanded).isTrue()
+
+            shadeRepository.setQsExpansion(0f)
+            runCurrent()
+
+            assertThat(keyguardBypassController.qsExpanded).isFalse()
+
+            job.cancel()
+        }
+    }
 }