diff options
| -rw-r--r-- | packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt | 68 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt | 4 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.kt | 65 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerImpl.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java) | 38 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt | 73 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt | 21 | ||||
| -rw-r--r-- | packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/AutoHideKosmos.kt | 31 |
7 files changed, 278 insertions, 22 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt new file mode 100644 index 000000000000..0b0b1e45d604 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt @@ -0,0 +1,68 @@ +/* + * 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.phone + +import android.platform.test.annotations.EnableFlags +import android.view.Display.DEFAULT_DISPLAY +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.display.data.repository.displayRepository +import com.android.systemui.kosmos.testScope +import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.statusbar.core.StatusBarConnectedDisplays +import com.android.systemui.testKosmos +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.never +import org.mockito.kotlin.verify + +@SmallTest +@RunWith(AndroidJUnit4::class) +@EnableFlags(StatusBarConnectedDisplays.FLAG_NAME) +class MultiDisplayAutoHideControllerStoreTest : SysuiTestCase() { + + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + private val testScope = kosmos.testScope + private val fakeDisplayRepository = kosmos.displayRepository + + // Lazy so that @EnableFlags has time to run before underTest is instantiated. + private val underTest by lazy { kosmos.multiDisplayAutoHideControllerStore } + + @Before fun addDisplays() = runBlocking { fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY) } + + @Test + fun beforeDisplayRemoved_doesNotStopInstances() = + testScope.runTest { + val instance = underTest.forDisplay(DEFAULT_DISPLAY) + + verify(instance, never()).stop() + } + + @Test + fun displayRemoved_stopsInstance() = + testScope.runTest { + val instance = underTest.forDisplay(DEFAULT_DISPLAY) + + fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY) + + verify(instance).stop() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt index d3d2c5872a01..45933e5549f5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt @@ -27,6 +27,8 @@ import com.android.systemui.log.LogBufferFactory import com.android.systemui.statusbar.core.StatusBarConnectedDisplays import com.android.systemui.statusbar.data.StatusBarDataLayerModule import com.android.systemui.statusbar.data.repository.LightBarControllerStore +import com.android.systemui.statusbar.phone.AutoHideController +import com.android.systemui.statusbar.phone.AutoHideControllerImpl import com.android.systemui.statusbar.phone.LightBarController import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider import com.android.systemui.statusbar.phone.StatusBarContentInsetsProviderImpl @@ -79,6 +81,8 @@ interface StatusBarModule { implFactory: StatusBarWindowControllerImpl.Factory ): StatusBarWindowController.Factory + @Binds @SysUISingleton fun autoHideController(impl: AutoHideControllerImpl): AutoHideController + companion object { @Provides diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.kt new file mode 100644 index 000000000000..636e1c45bc81 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.kt @@ -0,0 +1,65 @@ +/* + * 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.phone + +import android.content.Context +import android.view.MotionEvent +import com.android.systemui.statusbar.AutoHideUiElement +import java.io.PrintWriter + +/** + * Controls the auto-hide behavior of system bars (status bar, navigation bar). + * + * This interface provides methods to manage the auto-hide schedule of system bars, allowing them to + * be shown or hidden. + */ +interface AutoHideController { + /** + * Sets a [AutoHideUiElement] status bar that should be controlled by the [AutoHideController]. + */ + fun setStatusBar(element: AutoHideUiElement) + + /** + * Sets a [AutoHideUiElement] navigation bar that should be controlled by the + * [AutoHideController]. + */ + fun setNavigationBar(element: AutoHideUiElement) + + /** Resumes the auto-hide behavior that was previously suspended. */ + fun resumeSuspendedAutoHide() + + /** Suspends the auto-hide behavior. */ + fun suspendAutoHide() + + /** Schedules or cancels auto hide behavior based on current system bar state. */ + fun touchAutoHide() + + /** Hides system bars on user touch if the interaction requires them to be hidden. */ + fun checkUserAutoHide(event: MotionEvent) + + /** Called when work should stop and resources should be released. */ + fun stop() + + /** Dumps the current state of the [AutoHideController] */ + fun dump(pw: PrintWriter) + + /** Injectable factory for creating a [AutoHideController]. */ + interface Factory { + /** Create an [AutoHideController] */ + fun create(context: Context): AutoHideController + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerImpl.java index 1358cfd3e8da..4fbfbb254064 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * 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. @@ -28,7 +28,6 @@ import android.view.accessibility.AccessibilityManager; import androidx.annotation.NonNull; -import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.statusbar.AutoHideUiElement; @@ -36,9 +35,7 @@ import java.io.PrintWriter; import javax.inject.Inject; -/** A controller to control all auto-hide things. Also see {@link AutoHideUiElement}. */ -@SysUISingleton -public class AutoHideController { +public class AutoHideControllerImpl implements AutoHideController { private static final String TAG = "AutoHideController"; private static final int AUTO_HIDE_TIMEOUT_MS = 2250; private static final int USER_AUTO_HIDE_TIMEOUT_MS = 350; @@ -61,7 +58,7 @@ public class AutoHideController { }; @Inject - public AutoHideController(Context context, + public AutoHideControllerImpl(Context context, @Main Handler handler, IWindowManager iWindowManager) { mAccessibilityManager = context.getSystemService(AccessibilityManager.class); @@ -70,18 +67,12 @@ public class AutoHideController { mDisplayId = context.getDisplayId(); } - /** - * Sets a {@link AutoHideUiElement} status bar that should be controlled by the - * {@link AutoHideController}. - */ + @Override public void setStatusBar(AutoHideUiElement element) { mStatusBar = element; } - /** - * Sets a {@link AutoHideUiElement} navigation bar that should be controlled by the - * {@link AutoHideController}. - */ + @Override public void setNavigationBar(AutoHideUiElement element) { mNavigationBar = element; } @@ -102,6 +93,7 @@ public class AutoHideController { } } + @Override public void resumeSuspendedAutoHide() { if (mAutoHideSuspended) { scheduleAutoHide(); @@ -112,6 +104,7 @@ public class AutoHideController { } } + @Override public void suspendAutoHide() { mHandler.removeCallbacks(mAutoHide); Runnable checkBarModesRunnable = getCheckBarModesRunnable(); @@ -121,7 +114,7 @@ public class AutoHideController { mAutoHideSuspended = isAnyTransientBarShown(); } - /** Schedules or cancels auto hide behavior based on current system bar state. */ + @Override public void touchAutoHide() { // update transient bar auto hide if (isAnyTransientBarShown()) { @@ -156,6 +149,7 @@ public class AutoHideController { FLAG_CONTENT_CONTROLS); } + @Override public void checkUserAutoHide(MotionEvent event) { boolean shouldHide = isAnyTransientBarShown() && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar. @@ -196,6 +190,12 @@ public class AutoHideController { return false; } + @Override + public void stop() { + mHandler.removeCallbacks(mAutoHide); + } + + @Override public void dump(@NonNull PrintWriter pw) { pw.println("AutoHideController:"); pw.println("\tmAutoHideSuspended=" + mAutoHideSuspended); @@ -205,10 +205,7 @@ public class AutoHideController { pw.println("\tgetUserAutoHideTimeout=" + getUserAutoHideTimeout()); } - /** - * Injectable factory for creating a {@link AutoHideController}. - */ - public static class Factory { + public static class Factory implements AutoHideController.Factory { private final Handler mHandler; private final IWindowManager mIWindowManager; @@ -219,8 +216,9 @@ public class AutoHideController { } /** Create an {@link AutoHideController} */ + @Override public AutoHideController create(Context context) { - return new AutoHideController(context, mHandler, mIWindowManager); + return new AutoHideControllerImpl(context, mHandler, mIWindowManager); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt new file mode 100644 index 000000000000..744f96918eef --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt @@ -0,0 +1,73 @@ +/* + * 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.phone + +import android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.display.data.repository.DisplayRepository +import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository +import com.android.systemui.display.data.repository.PerDisplayStore +import com.android.systemui.display.data.repository.PerDisplayStoreImpl +import com.android.systemui.display.data.repository.SingleDisplayStore +import com.android.systemui.statusbar.core.StatusBarConnectedDisplays +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope + +/** Provides per display instances of [AutoHideController] */ +interface AutoHideControllerStore : PerDisplayStore<AutoHideController> + +@SysUISingleton +class MultiDisplayAutoHideControllerStore +@Inject +constructor( + @Background backgroundApplicationScope: CoroutineScope, + displayRepository: DisplayRepository, + private val displayWindowPropertiesRepository: DisplayWindowPropertiesRepository, + private val autoHideControllerFactory: AutoHideControllerImpl.Factory, +) : + AutoHideControllerStore, + PerDisplayStoreImpl<AutoHideController>(backgroundApplicationScope, displayRepository) { + + init { + StatusBarConnectedDisplays.assertInNewMode() + } + + override fun createInstanceForDisplay(displayId: Int): AutoHideController { + val displayWindowProperties = + displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR) + return autoHideControllerFactory.create(displayWindowProperties.context) + } + + override suspend fun onDisplayRemovalAction(instance: AutoHideController) { + instance.stop() + } + + override val instanceClass = AutoHideController::class.java +} + +@SysUISingleton +class SingleDisplayAutoHideControllerStore +@Inject +constructor(defaultController: AutoHideController) : + AutoHideControllerStore, + PerDisplayStore<AutoHideController> by SingleDisplayStore(defaultController) { + + init { + StatusBarConnectedDisplays.assertInLegacyMode() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt index e1cdc58de8ad..a62776c03bb8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt @@ -35,7 +35,12 @@ import com.android.systemui.statusbar.data.repository.PrivacyDotViewControllerSt import com.android.systemui.statusbar.data.repository.PrivacyDotWindowControllerStoreModule import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore import com.android.systemui.statusbar.events.PrivacyDotViewControllerModule +import com.android.systemui.statusbar.phone.AutoHideController +import com.android.systemui.statusbar.phone.AutoHideControllerImpl +import com.android.systemui.statusbar.phone.AutoHideControllerStore import com.android.systemui.statusbar.phone.CentralSurfacesCommandQueueCallbacks +import com.android.systemui.statusbar.phone.MultiDisplayAutoHideControllerStore +import com.android.systemui.statusbar.phone.SingleDisplayAutoHideControllerStore import com.android.systemui.statusbar.window.StatusBarWindowControllerStore import com.android.systemui.statusbar.window.data.repository.StatusBarWindowStateRepositoryStore import com.android.systemui.statusbar.window.data.repository.StatusBarWindowStateRepositoryStoreImpl @@ -75,6 +80,9 @@ interface StatusBarPhoneModule { @Binds fun statusBarInitializer(@Default impl: StatusBarInitializerImpl): StatusBarInitializer + @Binds + fun autoHideControllerFactory(impl: AutoHideControllerImpl.Factory): AutoHideController.Factory + companion object { /** Binds {@link StatusBarInitializer} as a {@link CoreStartable}. */ @Provides @@ -172,5 +180,18 @@ interface StatusBarPhoneModule { singleDisplayStoreLazy.get() } } + + @Provides + @SysUISingleton + fun autoHideStore( + singleDisplayLazy: Lazy<SingleDisplayAutoHideControllerStore>, + multiDisplayLazy: Lazy<MultiDisplayAutoHideControllerStore>, + ): AutoHideControllerStore { + return if (StatusBarConnectedDisplays.isEnabled) { + multiDisplayLazy.get() + } else { + singleDisplayLazy.get() + } + } } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/AutoHideKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/AutoHideKosmos.kt index 090ce31bd43c..951ae59ebcf1 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/AutoHideKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/AutoHideKosmos.kt @@ -16,9 +16,36 @@ package com.android.systemui.statusbar.phone +import android.content.Context +import android.os.Handler +import android.view.IWindowManager +import com.android.systemui.display.data.repository.displayRepository +import com.android.systemui.display.data.repository.fakeDisplayWindowPropertiesRepository import com.android.systemui.kosmos.Kosmos -import com.android.systemui.util.mockito.mock +import com.android.systemui.kosmos.applicationCoroutineScope +import org.mockito.Mockito.mock -val Kosmos.mockAutoHideController by Kosmos.Fixture { mock<AutoHideController>() } +val Kosmos.mockAutoHideController: AutoHideController by + Kosmos.Fixture { mock(AutoHideController::class.java) } var Kosmos.autoHideController by Kosmos.Fixture { mockAutoHideController } + +val Kosmos.fakeAutoHideControllerFactory by Kosmos.Fixture { FakeAutoHideControllerFactory() } + +val Kosmos.multiDisplayAutoHideControllerStore by + Kosmos.Fixture { + MultiDisplayAutoHideControllerStore( + applicationCoroutineScope, + displayRepository, + fakeDisplayWindowPropertiesRepository, + fakeAutoHideControllerFactory, + ) + } + +class FakeAutoHideControllerFactory : + AutoHideControllerImpl.Factory(mock(Handler::class.java), mock(IWindowManager::class.java)) { + + override fun create(context: Context): AutoHideControllerImpl { + return mock(AutoHideControllerImpl::class.java) + } +} |