summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepository.kt86
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/window/shared/model/StatusBarWindowState.kt27
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryTest.kt112
4 files changed, 243 insertions, 14 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt
index 8f424b2e251e..fa9c6b2c8151 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt
@@ -17,9 +17,9 @@
package com.android.systemui.statusbar.window
import android.app.StatusBarManager
-import android.app.StatusBarManager.WindowVisibleState
import android.app.StatusBarManager.WINDOW_STATE_SHOWING
import android.app.StatusBarManager.WINDOW_STATUS_BAR
+import android.app.StatusBarManager.WindowVisibleState
import android.app.StatusBarManager.windowStateToString
import android.util.Log
import com.android.systemui.dagger.SysUISingleton
@@ -31,23 +31,27 @@ import javax.inject.Inject
/**
* A centralized class maintaining the state of the status bar window.
*
+ * @deprecated use
+ * [com.android.systemui.statusbar.window.data.repository.StatusBarWindowStateRepository] instead.
+ *
* Classes that want to get updates about the status bar window state should subscribe to this class
* via [addListener] and should NOT add their own callback on [CommandQueue].
*/
@SysUISingleton
-class StatusBarWindowStateController @Inject constructor(
- @DisplayId private val thisDisplayId: Int,
- commandQueue: CommandQueue
-) {
- private val commandQueueCallback = object : CommandQueue.Callbacks {
- override fun setWindowState(
- displayId: Int,
- @StatusBarManager.WindowType window: Int,
- @WindowVisibleState state: Int
- ) {
- this@StatusBarWindowStateController.setWindowState(displayId, window, state)
+@Deprecated("Use StatusBarWindowRepository instead")
+class StatusBarWindowStateController
+@Inject
+constructor(@DisplayId private val thisDisplayId: Int, commandQueue: CommandQueue) {
+ private val commandQueueCallback =
+ object : CommandQueue.Callbacks {
+ override fun setWindowState(
+ displayId: Int,
+ @StatusBarManager.WindowType window: Int,
+ @WindowVisibleState state: Int,
+ ) {
+ this@StatusBarWindowStateController.setWindowState(displayId, window, state)
+ }
}
- }
private val listeners: MutableSet<StatusBarWindowStateListener> = HashSet()
@WindowVisibleState private var windowState: Int = WINDOW_STATE_SHOWING
@@ -71,7 +75,7 @@ class StatusBarWindowStateController @Inject constructor(
private fun setWindowState(
displayId: Int,
@StatusBarManager.WindowType window: Int,
- @WindowVisibleState state: Int
+ @WindowVisibleState state: Int,
) {
if (displayId != thisDisplayId) {
return
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepository.kt
new file mode 100644
index 000000000000..678576d1b450
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepository.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 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.window.data.repository
+
+import android.app.StatusBarManager
+import android.app.StatusBarManager.WINDOW_STATE_HIDDEN
+import android.app.StatusBarManager.WINDOW_STATE_HIDING
+import android.app.StatusBarManager.WINDOW_STATE_SHOWING
+import android.app.StatusBarManager.WINDOW_STATUS_BAR
+import android.app.StatusBarManager.WindowVisibleState
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.DisplayId
+import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.window.data.model.StatusBarWindowState
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * A centralized class maintaining the state of the status bar window.
+ *
+ * Classes that want to get updates about the status bar window state should subscribe to
+ * [windowState] and should NOT add their own callback on [CommandQueue].
+ */
+@SysUISingleton
+class StatusBarWindowStateRepository
+@Inject
+constructor(
+ private val commandQueue: CommandQueue,
+ @DisplayId private val thisDisplayId: Int,
+ @Application private val scope: CoroutineScope,
+) {
+ val windowState: StateFlow<StatusBarWindowState> =
+ conflatedCallbackFlow {
+ val callback =
+ object : CommandQueue.Callbacks {
+ override fun setWindowState(
+ displayId: Int,
+ @StatusBarManager.WindowType window: Int,
+ @WindowVisibleState state: Int,
+ ) {
+ // TODO(b/364360986): Log the window state changes.
+ if (displayId != thisDisplayId) {
+ return
+ }
+ if (window != WINDOW_STATUS_BAR) {
+ return
+ }
+ trySend(state.toWindowState())
+ }
+ }
+ commandQueue.addCallback(callback)
+ awaitClose { commandQueue.removeCallback(callback) }
+ }
+ // Use Eagerly because we always need to know about the status bar window state
+ .stateIn(scope, SharingStarted.Eagerly, StatusBarWindowState.Hidden)
+
+ @WindowVisibleState
+ private fun Int.toWindowState(): StatusBarWindowState {
+ return when (this) {
+ WINDOW_STATE_SHOWING -> StatusBarWindowState.Showing
+ WINDOW_STATE_HIDING -> StatusBarWindowState.Hiding
+ WINDOW_STATE_HIDDEN -> StatusBarWindowState.Hidden
+ else -> StatusBarWindowState.Hidden
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/shared/model/StatusBarWindowState.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/shared/model/StatusBarWindowState.kt
new file mode 100644
index 000000000000..a99046ee05e9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/shared/model/StatusBarWindowState.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.window.data.model
+
+/**
+ * Represents the state of the status bar *window* as a whole (as opposed to individual views within
+ * the status bar).
+ */
+enum class StatusBarWindowState {
+ Showing,
+ Hiding,
+ Hidden,
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryTest.kt
new file mode 100644
index 000000000000..38e04bb1d00f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/data/repository/StatusBarWindowStateRepositoryTest.kt
@@ -0,0 +1,112 @@
+/*
+ * 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.window.data.repository
+
+import android.app.StatusBarManager.WINDOW_NAVIGATION_BAR
+import android.app.StatusBarManager.WINDOW_STATE_HIDDEN
+import android.app.StatusBarManager.WINDOW_STATE_HIDING
+import android.app.StatusBarManager.WINDOW_STATE_SHOWING
+import android.app.StatusBarManager.WINDOW_STATUS_BAR
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.commandQueue
+import com.android.systemui.statusbar.window.data.model.StatusBarWindowState
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.argumentCaptor
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+class StatusBarWindowStateRepositoryTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val commandQueue = kosmos.commandQueue
+ private val underTest =
+ StatusBarWindowStateRepository(commandQueue, DISPLAY_ID, testScope.backgroundScope)
+
+ private val callback: CommandQueue.Callbacks
+ get() {
+ testScope.runCurrent()
+ val callbackCaptor = argumentCaptor<CommandQueue.Callbacks>()
+ verify(commandQueue).addCallback(callbackCaptor.capture())
+ return callbackCaptor.firstValue
+ }
+
+ @Test
+ fun windowState_notSameDisplayId_notUpdated() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.windowState)
+ assertThat(latest).isEqualTo(StatusBarWindowState.Hidden)
+
+ callback.setWindowState(DISPLAY_ID + 1, WINDOW_STATUS_BAR, WINDOW_STATE_SHOWING)
+
+ assertThat(latest).isEqualTo(StatusBarWindowState.Hidden)
+ }
+
+ @Test
+ fun windowState_notStatusBarWindow_notUpdated() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.windowState)
+ assertThat(latest).isEqualTo(StatusBarWindowState.Hidden)
+
+ callback.setWindowState(DISPLAY_ID, WINDOW_NAVIGATION_BAR, WINDOW_STATE_SHOWING)
+
+ assertThat(latest).isEqualTo(StatusBarWindowState.Hidden)
+ }
+
+ @Test
+ fun windowState_showing_updated() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.windowState)
+
+ callback.setWindowState(DISPLAY_ID, WINDOW_STATUS_BAR, WINDOW_STATE_SHOWING)
+
+ assertThat(latest).isEqualTo(StatusBarWindowState.Showing)
+ }
+
+ @Test
+ fun windowState_hiding_updated() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.windowState)
+
+ callback.setWindowState(DISPLAY_ID, WINDOW_STATUS_BAR, WINDOW_STATE_HIDING)
+
+ assertThat(latest).isEqualTo(StatusBarWindowState.Hiding)
+ }
+
+ @Test
+ fun windowState_hidden_updated() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.windowState)
+ callback.setWindowState(DISPLAY_ID, WINDOW_STATUS_BAR, WINDOW_STATE_SHOWING)
+ assertThat(latest).isEqualTo(StatusBarWindowState.Showing)
+
+ callback.setWindowState(DISPLAY_ID, WINDOW_STATUS_BAR, WINDOW_STATE_HIDDEN)
+
+ assertThat(latest).isEqualTo(StatusBarWindowState.Hidden)
+ }
+}
+
+private const val DISPLAY_ID = 10