Add udfpsTransitionProgress and qsExpansion to the ShadeRepository

Test: atest ShadeRepositoryImplTest
Bug: 278719514
Change-Id: I1662065f4ddf1de517df7b1af590b59eedcc535b
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
index ef14d1c..4012736 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -70,6 +70,7 @@
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.screenrecord.RecordingController;
+import com.android.systemui.shade.data.repository.ShadeRepository;
 import com.android.systemui.shade.transition.ShadeTransitionController;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
@@ -136,6 +137,7 @@
     private final KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor;
     private final FeatureFlags mFeatureFlags;
     private final InteractionJankMonitor mInteractionJankMonitor;
+    private final ShadeRepository mShadeRepository;
     private final FalsingManager mFalsingManager;
     private final AccessibilityManager mAccessibilityManager;
     private final MetricsLogger mMetricsLogger;
@@ -321,7 +323,8 @@
             FeatureFlags featureFlags,
             InteractionJankMonitor interactionJankMonitor,
             ShadeLogger shadeLog,
-            KeyguardFaceAuthInteractor keyguardFaceAuthInteractor
+            KeyguardFaceAuthInteractor keyguardFaceAuthInteractor,
+            ShadeRepository shadeRepository
     ) {
         mPanelViewControllerLazy = panelViewControllerLazy;
         mPanelView = panelView;
@@ -363,6 +366,7 @@
         mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor;
         mFeatureFlags = featureFlags;
         mInteractionJankMonitor = interactionJankMonitor;
+        mShadeRepository = shadeRepository;
 
         mLockscreenShadeTransitionController.addCallback(new LockscreenShadeTransitionCallback());
     }
@@ -1001,6 +1005,7 @@
 
         mDepthController.setQsPanelExpansion(qsExpansionFraction);
         mStatusBarKeyguardViewManager.setQsExpansion(qsExpansionFraction);
+        mShadeRepository.setQsExpansion(qsExpansionFraction);
 
         // TODO (b/265193930): remove dependency on NPVC
         float shadeExpandedFraction = mBarState == KEYGUARD
diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
index bf7a2be..44c8e48 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
@@ -25,11 +25,23 @@
 import javax.inject.Inject
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.distinctUntilChanged
 
 interface ShadeRepository {
     /** ShadeModel information regarding shade expansion events */
     val shadeModel: Flow<ShadeModel>
+
+    /** Amount qs has expanded. Quick Settings can be expanded without the full shade expansion. */
+    val qsExpansion: StateFlow<Float>
+
+    /** Amount shade has expanded with regard to the UDFPS location */
+    val udfpsTransitionToFullShadeProgress: StateFlow<Float>
+
+    fun setQsExpansion(qsExpansion: Float)
+    fun setUdfpsTransitionToFullShadeProgress(progress: Float)
 }
 
 /** Business logic for shade interactions */
@@ -62,6 +74,20 @@
             }
             .distinctUntilChanged()
 
+    private val _qsExpansion = MutableStateFlow(0f)
+    override val qsExpansion: StateFlow<Float> = _qsExpansion.asStateFlow()
+
+    private var _udfpsTransitionToFullShadeProgress = MutableStateFlow(0f)
+    override val udfpsTransitionToFullShadeProgress: StateFlow<Float> =
+        _udfpsTransitionToFullShadeProgress.asStateFlow()
+    override fun setQsExpansion(qsExpansion: Float) {
+        _qsExpansion.value = qsExpansion
+    }
+
+    override fun setUdfpsTransitionToFullShadeProgress(progress: Float) {
+        _udfpsTransitionToFullShadeProgress.value = progress
+    }
+
     companion object {
         private const val TAG = "ShadeRepository"
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index c5f64b0..7f016f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -32,6 +32,7 @@
 import com.android.systemui.plugins.qs.QS
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.shade.ShadeViewController
+import com.android.systemui.shade.data.repository.ShadeRepository
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.ExpandableView
@@ -74,6 +75,7 @@
     falsingManager: FalsingManager,
     dumpManager: DumpManager,
     qsTransitionControllerFactory: LockscreenShadeQsTransitionController.Factory,
+    private val shadeRepository: ShadeRepository,
 ) : Dumpable {
     private var pulseHeight: Float = 0f
     @get:VisibleForTesting
@@ -449,6 +451,7 @@
         }
 
         val udfpsProgress = MathUtils.saturate(dragDownAmount / udfpsTransitionDistance)
+        shadeRepository.setUdfpsTransitionToFullShadeProgress(udfpsProgress)
         udfpsKeyguardViewController?.setTransitionToFullShadeProgress(udfpsProgress)
 
         val statusBarProgress = MathUtils.saturate(dragDownAmount / statusBarTransitionDistance)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index f870631..1edc63c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -115,6 +115,7 @@
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.qs.QSFragment;
 import com.android.systemui.screenrecord.RecordingController;
+import com.android.systemui.shade.data.repository.ShadeRepository;
 import com.android.systemui.shade.transition.ShadeTransitionController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -304,6 +305,7 @@
             mEmptySpaceClickListenerCaptor;
     @Mock protected ActivityStarter mActivityStarter;
     @Mock protected KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor;
+    @Mock protected ShadeRepository mShadeRepository;
 
     protected final int mMaxUdfpsBurnInOffsetY = 5;
     protected KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
@@ -672,7 +674,8 @@
                 mFeatureFlags,
                 mInteractionJankMonitor,
                 mShadeLog,
-                mKeyguardFaceAuthInteractor
+                mKeyguardFaceAuthInteractor,
+                mShadeRepository
         );
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java
index 908f7cb..8a9161e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java
@@ -69,6 +69,7 @@
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.qs.QSFragment;
 import com.android.systemui.screenrecord.RecordingController;
+import com.android.systemui.shade.data.repository.ShadeRepository;
 import com.android.systemui.shade.transition.ShadeTransitionController;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -88,6 +89,8 @@
 import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
+import dagger.Lazy;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -98,8 +101,6 @@
 
 import java.util.List;
 
-import dagger.Lazy;
-
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -241,7 +242,8 @@
                 mFeatureFlags,
                 mInteractionJankMonitor,
                 mShadeLogger,
-                mock(KeyguardFaceAuthInteractor.class)
+                mock(KeyguardFaceAuthInteractor.class),
+                mock(ShadeRepository.class)
         );
 
         mFragmentListener = mQsController.getQsFragmentListener();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
new file mode 100644
index 0000000..8f2c93b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2023 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.shade.data.repository
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.RoboPilotTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.shade.ShadeExpansionChangeEvent
+import com.android.systemui.shade.ShadeExpansionStateManager
+import com.android.systemui.shade.domain.model.ShadeModel
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RoboPilotTest
+@RunWith(AndroidJUnit4::class)
+class ShadeRepositoryImplTest : SysuiTestCase() {
+
+    @Mock private lateinit var shadeExpansionStateManager: ShadeExpansionStateManager
+    private val testDispatcher = StandardTestDispatcher()
+    private val testScope = TestScope(testDispatcher)
+
+    private lateinit var underTest: ShadeRepositoryImpl
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        underTest = ShadeRepositoryImpl(shadeExpansionStateManager)
+    }
+
+    @Test
+    fun shadeExpansionChangeEvent() =
+        testScope.runTest {
+            var latest: ShadeModel? = null
+            val job = underTest.shadeModel.onEach { latest = it }.launchIn(this)
+            runCurrent()
+            assertThat(latest?.expansionAmount).isEqualTo(0f)
+            assertThat(latest?.isExpanded).isEqualTo(false)
+            assertThat(latest?.isUserDragging).isEqualTo(false)
+
+            val captor = withArgCaptor {
+                verify(shadeExpansionStateManager).addExpansionListener(capture())
+            }
+
+            captor.onPanelExpansionChanged(
+                ShadeExpansionChangeEvent(
+                    fraction = 1f,
+                    expanded = true,
+                    tracking = false,
+                    dragDownPxAmount = 0f,
+                )
+            )
+            runCurrent()
+            assertThat(latest?.expansionAmount).isEqualTo(1f)
+            assertThat(latest?.isExpanded).isEqualTo(true)
+            assertThat(latest?.isUserDragging).isEqualTo(false)
+
+            captor.onPanelExpansionChanged(
+                ShadeExpansionChangeEvent(
+                    fraction = .67f,
+                    expanded = false,
+                    tracking = true,
+                    dragDownPxAmount = 0f,
+                )
+            )
+            runCurrent()
+            assertThat(latest?.expansionAmount).isEqualTo(.67f)
+            assertThat(latest?.isExpanded).isEqualTo(false)
+            assertThat(latest?.isUserDragging).isEqualTo(true)
+
+            job.cancel()
+        }
+
+    @Test
+    fun updateQsExpansion() =
+        testScope.runTest {
+            assertThat(underTest.qsExpansion.value).isEqualTo(0f)
+
+            underTest.setQsExpansion(.5f)
+            assertThat(underTest.qsExpansion.value).isEqualTo(.5f)
+
+            underTest.setQsExpansion(.82f)
+            assertThat(underTest.qsExpansion.value).isEqualTo(.82f)
+
+            underTest.setQsExpansion(1f)
+            assertThat(underTest.qsExpansion.value).isEqualTo(1f)
+        }
+
+    @Test
+    fun updateUdfpsTransitionToFullShadeProgress() =
+        testScope.runTest {
+            assertThat(underTest.udfpsTransitionToFullShadeProgress.value).isEqualTo(0f)
+
+            underTest.setUdfpsTransitionToFullShadeProgress(.5f)
+            assertThat(underTest.udfpsTransitionToFullShadeProgress.value).isEqualTo(.5f)
+
+            underTest.setUdfpsTransitionToFullShadeProgress(.82f)
+            assertThat(underTest.udfpsTransitionToFullShadeProgress.value).isEqualTo(.82f)
+
+            underTest.setUdfpsTransitionToFullShadeProgress(1f)
+            assertThat(underTest.udfpsTransitionToFullShadeProgress.value).isEqualTo(1f)
+        }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index 2106da8..2351f760 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -15,6 +15,7 @@
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.plugins.qs.QS
 import com.android.systemui.shade.ShadeViewController
+import com.android.systemui.shade.data.repository.FakeShadeRepository
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper
 import com.android.systemui.statusbar.notification.stack.AmbientState
@@ -127,6 +128,7 @@
                 },
                 qsTransitionControllerFactory = { qsTransitionController },
                 activityStarter = activityStarter,
+                shadeRepository = FakeShadeRepository(),
             )
         transitionController.addCallback(transitionControllerCallback)
         whenever(nsslController.view).thenReturn(stackscroller)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
index 2c0a8fd..492e542 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
@@ -21,13 +21,27 @@
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 
-/** Fake implementation of [KeyguardRepository] */
+/** Fake implementation of [ShadeRepository] */
 class FakeShadeRepository : ShadeRepository {
 
     private val _shadeModel = MutableStateFlow(ShadeModel())
     override val shadeModel: Flow<ShadeModel> = _shadeModel
 
+    private val _qsExpansion = MutableStateFlow(0f)
+    override val qsExpansion = _qsExpansion
+
+    private val _udfpsTransitionToFullShadeProgress = MutableStateFlow(0f)
+    override val udfpsTransitionToFullShadeProgress = _udfpsTransitionToFullShadeProgress
+
     fun setShadeModel(model: ShadeModel) {
         _shadeModel.value = model
     }
+
+    override fun setQsExpansion(qsExpansion: Float) {
+        _qsExpansion.value = qsExpansion
+    }
+
+    override fun setUdfpsTransitionToFullShadeProgress(progress: Float) {
+        _udfpsTransitionToFullShadeProgress.value = progress
+    }
 }