Loading packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt +12 −12 Original line number Diff line number Diff line Loading @@ -64,35 +64,35 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { } @Test fun onStatusBarTouched_called_updatesDisplayId() = fun onStatusBarOrLauncherTouched_called_updatesDisplayId() = testScope.runTest { val displayId by collectLastValue(underTest.displayId) displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL)) underTest.onStatusBarTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH) underTest.onStatusBarOrLauncherTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH) assertThat(displayId).isEqualTo(2) } @Test fun onStatusBarTouched_notExistentDisplay_displayIdNotUpdated() = fun onStatusBarOrLauncherTouched_notExistentDisplay_displayIdNotUpdated() = testScope.runTest { val displayIds by collectValues(underTest.displayId) assertThat(displayIds).isEqualTo(listOf(Display.DEFAULT_DISPLAY)) underTest.onStatusBarTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH) underTest.onStatusBarOrLauncherTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH) // Never set, as 2 was not a display according to the repository. assertThat(displayIds).isEqualTo(listOf(Display.DEFAULT_DISPLAY)) } @Test fun onStatusBarTouched_afterDisplayRemoved_goesBackToDefaultDisplay() = fun onStatusBarOrLauncherTouched_afterDisplayRemoved_goesBackToDefaultDisplay() = testScope.runTest { val displayId by collectLastValue(underTest.displayId) displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL)) underTest.onStatusBarTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH) underTest.onStatusBarOrLauncherTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH) assertThat(displayId).isEqualTo(2) Loading @@ -102,9 +102,9 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { } @Test fun onStatusBarTouched_leftSide_intentSetToNotifications() = fun onStatusBarOrLauncherTouched_leftSide_intentSetToNotifications() = testScope.runTest { underTest.onStatusBarTouched( underTest.onStatusBarOrLauncherTouched( createMotionEventForDisplay(2, STATUS_BAR_WIDTH * 0.1f), STATUS_BAR_WIDTH, ) Loading @@ -113,9 +113,9 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { } @Test fun onStatusBarTouched_rightSide_intentSetToQs() = fun onStatusBarOrLauncherTouched_rightSide_intentSetToQs() = testScope.runTest { underTest.onStatusBarTouched( underTest.onStatusBarOrLauncherTouched( createMotionEventForDisplay(2, STATUS_BAR_WIDTH * 0.95f), STATUS_BAR_WIDTH, ) Loading @@ -124,9 +124,9 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { } @Test fun onStatusBarTouched_nullAfterConsumed() = fun onStatusBarOrLauncherTouched_nullAfterConsumed() = testScope.runTest { underTest.onStatusBarTouched( underTest.onStatusBarOrLauncherTouched( createMotionEventForDisplay(2, STATUS_BAR_WIDTH * 0.1f), STATUS_BAR_WIDTH, ) Loading packages/SystemUI/src/com/android/systemui/recents/LauncherProxyService.java +39 −2 Original line number Diff line number Diff line Loading @@ -63,10 +63,12 @@ import android.os.Looper; import android.os.PatternMatcher; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.util.Log; import android.view.Display; import android.view.DisplayInfo; import android.view.InputDevice; import android.view.KeyCharacterMap; import android.view.KeyEvent; Loading Loading @@ -110,6 +112,7 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag; import com.android.systemui.settings.DisplayTracker; import com.android.systemui.settings.UserTracker; import com.android.systemui.shade.ShadeViewController; import com.android.systemui.shade.display.StatusBarTouchShadeDisplayPolicy; import com.android.systemui.shade.domain.interactor.ShadeInteractor; import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround; import com.android.systemui.shared.recents.ILauncherProxy; Loading @@ -126,6 +129,8 @@ import com.android.wm.shell.back.BackAnimation; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; import com.android.wm.shell.sysui.ShellInterface; import dagger.Lazy; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; Loading @@ -137,8 +142,6 @@ import java.util.function.Supplier; import javax.inject.Inject; import javax.inject.Provider; import dagger.Lazy; /** * Class to send information from SysUI to Launcher with a binder. */ Loading Loading @@ -168,6 +171,7 @@ public class LauncherProxyService implements CallbackController<LauncherProxyLis private final NotificationShadeWindowController mStatusBarWinController; private final Provider<SceneInteractor> mSceneInteractor; private final Provider<ShadeInteractor> mShadeInteractor; private final StatusBarTouchShadeDisplayPolicy mShadeDisplayPolicy; private final Runnable mConnectionRunnable = () -> internalConnectToCurrentUser("runnable: startConnectionToCurrentUser"); Loading Loading @@ -224,6 +228,12 @@ public class LauncherProxyService implements CallbackController<LauncherProxyLis // TODO: change the method signature to use (boolean inputFocusTransferStarted) @Override public void onStatusBarTouchEvent(MotionEvent event) { moveShadeWindowIfNeeded(event); if (shouldIgnoreEvent(event)) { Log.d(TAG_OPS, "Ignoring launcher swipe event for legacy shade due to touch event" + " on display without notification shade"); return; } verifyCallerAndClearCallingIdentity("onStatusBarTouchEvent", () -> { if (SceneContainerFlag.isEnabled()) { //TODO(b/329863123) implement latency tracking for shade scene Loading Loading @@ -269,6 +279,31 @@ public class LauncherProxyService implements CallbackController<LauncherProxyLis }); } @VisibleForTesting public void moveShadeWindowIfNeeded(MotionEvent event) { if (ShadeWindowGoesAround.isEnabled() && SceneContainerFlag.isEnabled()) { Trace.beginSection("LauncherProxyService#moveShadeWindowIfNeeded"); // TODO: b/407496148 - Refactor to use DisplayMetricsRepository instead final DisplayInfo displayInfo = new DisplayInfo(); mDisplayTracker.getDisplay(event.getDisplayId()).getDisplayInfo(displayInfo); int displayWidth = displayInfo.logicalWidth; mShadeDisplayPolicy.onStatusBarOrLauncherTouched(event, displayWidth); Trace.endSection(); } } @VisibleForTesting public boolean shouldIgnoreEvent(MotionEvent event) { if (ShadeWindowGoesAround.isEnabled() && !SceneContainerFlag.isEnabled()) { // For legacy shade case, don't attempt to handle touch events on display that // doesn't have the shade. They're handled with SceneContainerFlag enabled. boolean touchingDisplayWithoutShade = event.getDisplayId() != mShadeDisplayPolicy.getDisplayId().getValue(); return touchingDisplayWithoutShade; } return false; } @Override public void onStatusBarTrackpadEvent(MotionEvent event) { verifyCallerAndClearCallingIdentityPostMain("onStatusBarTrackpadEvent", () -> { Loading Loading @@ -694,6 +729,7 @@ public class LauncherProxyService implements CallbackController<LauncherProxyLis PerDisplayRepository<SysUiState> perDisplaySysUiStateRepository, Provider<SceneInteractor> sceneInteractor, Provider<ShadeInteractor> shadeInteractor, StatusBarTouchShadeDisplayPolicy shadeDisplayPolicy, UserTracker userTracker, UserManager userManager, WakefulnessLifecycle wakefulnessLifecycle, Loading Loading @@ -733,6 +769,7 @@ public class LauncherProxyService implements CallbackController<LauncherProxyLis mStatusBarWinController = statusBarWinController; mSceneInteractor = sceneInteractor; mShadeInteractor = shadeInteractor; mShadeDisplayPolicy = shadeDisplayPolicy; mUserTracker = userTracker; mConnectionBackoffAttempts = 0; mRecentsComponentName = ComponentName.unflattenFromString(context.getString( Loading packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt +2 −2 Original line number Diff line number Diff line Loading @@ -67,8 +67,8 @@ constructor( private var removalListener: Job? = null /** Called when the status bar on the given display is touched. */ fun onStatusBarTouched(event: MotionEvent, statusBarWidth: Int) { /** Called when the status bar or launcher homescreen on the given display is touched. */ fun onStatusBarOrLauncherTouched(event: MotionEvent, statusBarWidth: Int) { ShadeWindowGoesAround.isUnexpectedlyInLegacyMode() updateShadeDisplayIfNeeded(event) updateExpansionIntent(event, statusBarWidth) Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt +1 −1 Original line number Diff line number Diff line Loading @@ -119,7 +119,7 @@ private constructor( // Notify the shade display policy that the status bar was touched. This may cause // the shade to change display if the touch was in a display different than the shade // one. lazyStatusBarShadeDisplayPolicy.get().onStatusBarTouched(event, mView.width) lazyStatusBarShadeDisplayPolicy.get().onStatusBarOrLauncherTouched(event, mView.width) } } Loading packages/SystemUI/tests/src/com/android/systemui/recents/LauncherProxyServiceTest.kt +100 −12 Original line number Diff line number Diff line Loading @@ -22,10 +22,11 @@ import android.content.pm.PackageManager import android.content.pm.ResolveInfo import android.os.PowerManager import android.os.UserManager import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.testing.TestableContext import android.testing.TestableLooper import android.view.Display import android.view.MotionEvent import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.app.AssistUtils Loading @@ -49,9 +50,11 @@ import com.android.systemui.navigationbar.NavigationModeController import com.android.systemui.navigationbar.views.NavigationBar import com.android.systemui.process.ProcessWrapper import com.android.systemui.recents.LauncherProxyService.ACTION_QUICKSTEP import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.settings.FakeDisplayTracker import com.android.systemui.settings.UserTracker import com.android.systemui.shade.ShadeViewController import com.android.systemui.shade.display.StatusBarTouchShadeDisplayPolicy import com.android.systemui.shared.recents.ILauncherProxy import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_WAKEFULNESS_MASK import com.android.systemui.shared.system.QuickStepContract.WAKEFULNESS_ASLEEP Loading @@ -69,6 +72,7 @@ import com.android.wm.shell.sysui.ShellInterface import com.google.common.util.concurrent.MoreExecutors import java.util.Optional import java.util.concurrent.Executor import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runTest import org.junit.After Loading @@ -77,6 +81,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers import org.mockito.ArgumentMatchers.anyLong import org.mockito.ArgumentMatchers.anyString import org.mockito.ArgumentMatchers.eq import org.mockito.Mock import org.mockito.Mockito.any Loading @@ -90,6 +95,9 @@ import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations import org.mockito.kotlin.argThat import org.mockito.kotlin.doNothing import org.mockito.kotlin.never import org.mockito.kotlin.whenever @SmallTest Loading Loading @@ -119,6 +127,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { @Mock private lateinit var shellInterface: ShellInterface @Mock private lateinit var navBarController: NavigationBarController @Mock private lateinit var shadeViewController: ShadeViewController @Mock private lateinit var sceneInteractor: SceneInteractor @Mock private lateinit var screenPinningRequest: ScreenPinningRequest @Mock private lateinit var navModeController: NavigationModeController @Mock private lateinit var statusBarWinController: NotificationShadeWindowController Loading @@ -134,6 +143,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { private lateinit var unfoldTransitionProgressForwarder: Optional<UnfoldTransitionProgressForwarder> @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher @Mock private lateinit var statusBarShadeDisplayPolicy: StatusBarTouchShadeDisplayPolicy @Mock private lateinit var backAnimation: Optional<BackAnimation> @Before Loading @@ -142,14 +152,14 @@ class LauncherProxyServiceTest : SysuiTestCase() { val serviceComponent = ComponentName("test_package", "service_provider") context.addMockService(serviceComponent, launcherProxy) context.addMockServiceResolver( TestableContext.MockServiceResolver { context.addMockServiceResolver { if (it.action == ACTION_QUICKSTEP) serviceComponent else null } ) whenever(launcherProxy.queryLocalInterface(ArgumentMatchers.anyString())) .thenReturn(launcherProxy) whenever(launcherProxy.asBinder()).thenReturn(launcherProxy) doNothing().whenever(sceneInteractor).onRemoteUserInputStarted(anyString()) doNothing().whenever(shadeViewController).startInputFocusTransfer() // packageManager.resolveServiceAsUser has to return non-null for // LauncherProxyService#isEnabled to become true. Loading @@ -157,8 +167,6 @@ class LauncherProxyServiceTest : SysuiTestCase() { whenever(packageManager.resolveServiceAsUser(any(), anyInt(), anyInt())) .thenReturn(mock(ResolveInfo::class.java)) mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) // return isSystemUser as true by default. `when`(processWrapper.isSystemUser).thenReturn(true) sysuiStatePerDisplayRepository.add(Display.DEFAULT_DISPLAY, sysUiState) Loading @@ -172,6 +180,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun wakefulnessLifecycle_dispatchFinishedWakingUpSetsSysUIflagToAWAKE() { // WakefulnessLifecycle is initialized to AWAKE initially, and won't emit a noop. wakefulnessLifecycle.dispatchFinishedGoingToSleep() Loading @@ -187,6 +196,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun wakefulnessLifecycle_dispatchStartedWakingUpSetsSysUIflagToWAKING() { wakefulnessLifecycle.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN) Loading @@ -198,6 +208,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun wakefulnessLifecycle_dispatchFinishedGoingToSleepSetsSysUIflagToASLEEP() { wakefulnessLifecycle.dispatchFinishedGoingToSleep() Loading @@ -209,6 +220,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun wakefulnessLifecycle_dispatchStartedGoingToSleepSetsSysUIflagToGOING_TO_SLEEP() { wakefulnessLifecycle.dispatchStartedGoingToSleep( PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON Loading @@ -222,6 +234,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun connectToLauncherService_primaryUserNoVisibleBgUsersSupported_expectBindService() { `when`(processWrapper.isSystemUser).thenReturn(true) `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(false) Loading @@ -232,6 +245,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun connectToLauncherService_nonPrimaryUserNoVisibleBgUsersSupported_expectNoBindService() { `when`(processWrapper.isSystemUser).thenReturn(false) `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(false) Loading @@ -242,6 +256,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun connectToLauncherService_nonPrimaryBgUserVisibleBgUsersSupported_expectBindService() { `when`(processWrapper.isSystemUser).thenReturn(false) `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(true) Loading @@ -253,6 +268,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun connectToLauncherService_nonPrimaryFgUserVisibleBgUsersSupported_expectNoBindService() { `when`(processWrapper.isSystemUser).thenReturn(false) `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(true) Loading @@ -264,6 +280,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun notifySysUiStateFlagsForAllDisplays_triggersUpdateInAllDisplays() = kosmos.testScope.runTest { kosmos.displayRepository.apply { Loading @@ -285,15 +302,14 @@ class LauncherProxyServiceTest : SysuiTestCase() { @Test @EnableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND) @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun updateSystemUiStateFlags_updatesAllNavBars() = kosmos.testScope.runTest { kosmos.displayRepository.apply { addDisplay(0) addDisplay(1) } kosmos.fakeSysUIStatePerDisplayRepository.apply { add(1, sysUiStateFactory.create(1)) } kosmos.fakeSysUIStatePerDisplayRepository.apply { add(1, sysUiStateFactory.create(1)) } val navBar0 = mock<NavigationBar>() val navBar1 = mock<NavigationBar>() whenever(navBarController.getNavigationBar(eq(0))).thenReturn(navBar0) Loading @@ -305,6 +321,77 @@ class LauncherProxyServiceTest : SysuiTestCase() { verify(navBar1).updateSystemUiStateFlags() } @Test @EnableFlags( Flags.FLAG_SHADE_WINDOW_GOES_AROUND, Flags.FLAG_SCENE_CONTAINER, Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR, ) fun onStatusBarTouchEvent_withSceneFlag_callsOnLauncherDrag() = kosmos.testScope.runTest { val shadeDisplayId = 1 whenever(statusBarShadeDisplayPolicy.displayId) .thenReturn(MutableStateFlow(shadeDisplayId)) val event = MotionEvent.obtain(500, 500, MotionEvent.ACTION_MOVE, 500f, 500f, 0).apply { displayId = 0 } subject.mSysUiProxy.onStatusBarTouchEvent(event) verify(statusBarShadeDisplayPolicy) .onStatusBarOrLauncherTouched( argThat<MotionEvent> { displayId == event.displayId }, anyInt(), ) } @Test @EnableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND) @DisableFlags(Flags.FLAG_SCENE_CONTAINER, Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun onStatusBarTouchEvent_withoutSceneFlag_onDifferentDisplayTouch_ignoresInput() = kosmos.testScope.runTest { val shadeDisplayId = 1 whenever(statusBarShadeDisplayPolicy.displayId) .thenReturn(MutableStateFlow(shadeDisplayId)) val event = MotionEvent.obtain(500, 500, MotionEvent.ACTION_DOWN, 500f, 500f, 0).apply { displayId = 0 } subject.mSysUiProxy.onStatusBarTouchEvent(event) verify(statusBarShadeDisplayPolicy, never()) .onStatusBarOrLauncherTouched( argThat<MotionEvent> { displayId == event.displayId }, anyInt(), ) verify(shadeViewController, never()).startExpandLatencyTracking() } @Test @EnableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND) @DisableFlags(Flags.FLAG_SCENE_CONTAINER, Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun onStatusBarTouchEvent_withoutSceneFlag_onSameDisplayTouch_handlesInput() = kosmos.testScope.runTest { val shadeDisplayId = 0 whenever(statusBarShadeDisplayPolicy.displayId) .thenReturn(MutableStateFlow(shadeDisplayId)) val event = MotionEvent.obtain(500, 500, MotionEvent.ACTION_DOWN, 500f, 500f, 0).apply { displayId = shadeDisplayId } subject.mSysUiProxy.onStatusBarTouchEvent(event) verify(statusBarShadeDisplayPolicy, never()) .onStatusBarOrLauncherTouched( argThat<MotionEvent> { displayId == shadeDisplayId }, anyInt(), ) verify(shadeViewController).startExpandLatencyTracking() } private fun createLauncherProxyService(ctx: Context): LauncherProxyService { return LauncherProxyService( ctx, Loading @@ -317,8 +404,9 @@ class LauncherProxyServiceTest : SysuiTestCase() { navModeController, statusBarWinController, kosmos.fakeSysUIStatePerDisplayRepository, { sceneInteractor }, mock(), mock(), statusBarShadeDisplayPolicy, userTracker, userManager, wakefulnessLifecycle, Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt +12 −12 Original line number Diff line number Diff line Loading @@ -64,35 +64,35 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { } @Test fun onStatusBarTouched_called_updatesDisplayId() = fun onStatusBarOrLauncherTouched_called_updatesDisplayId() = testScope.runTest { val displayId by collectLastValue(underTest.displayId) displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL)) underTest.onStatusBarTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH) underTest.onStatusBarOrLauncherTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH) assertThat(displayId).isEqualTo(2) } @Test fun onStatusBarTouched_notExistentDisplay_displayIdNotUpdated() = fun onStatusBarOrLauncherTouched_notExistentDisplay_displayIdNotUpdated() = testScope.runTest { val displayIds by collectValues(underTest.displayId) assertThat(displayIds).isEqualTo(listOf(Display.DEFAULT_DISPLAY)) underTest.onStatusBarTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH) underTest.onStatusBarOrLauncherTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH) // Never set, as 2 was not a display according to the repository. assertThat(displayIds).isEqualTo(listOf(Display.DEFAULT_DISPLAY)) } @Test fun onStatusBarTouched_afterDisplayRemoved_goesBackToDefaultDisplay() = fun onStatusBarOrLauncherTouched_afterDisplayRemoved_goesBackToDefaultDisplay() = testScope.runTest { val displayId by collectLastValue(underTest.displayId) displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL)) underTest.onStatusBarTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH) underTest.onStatusBarOrLauncherTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH) assertThat(displayId).isEqualTo(2) Loading @@ -102,9 +102,9 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { } @Test fun onStatusBarTouched_leftSide_intentSetToNotifications() = fun onStatusBarOrLauncherTouched_leftSide_intentSetToNotifications() = testScope.runTest { underTest.onStatusBarTouched( underTest.onStatusBarOrLauncherTouched( createMotionEventForDisplay(2, STATUS_BAR_WIDTH * 0.1f), STATUS_BAR_WIDTH, ) Loading @@ -113,9 +113,9 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { } @Test fun onStatusBarTouched_rightSide_intentSetToQs() = fun onStatusBarOrLauncherTouched_rightSide_intentSetToQs() = testScope.runTest { underTest.onStatusBarTouched( underTest.onStatusBarOrLauncherTouched( createMotionEventForDisplay(2, STATUS_BAR_WIDTH * 0.95f), STATUS_BAR_WIDTH, ) Loading @@ -124,9 +124,9 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { } @Test fun onStatusBarTouched_nullAfterConsumed() = fun onStatusBarOrLauncherTouched_nullAfterConsumed() = testScope.runTest { underTest.onStatusBarTouched( underTest.onStatusBarOrLauncherTouched( createMotionEventForDisplay(2, STATUS_BAR_WIDTH * 0.1f), STATUS_BAR_WIDTH, ) Loading
packages/SystemUI/src/com/android/systemui/recents/LauncherProxyService.java +39 −2 Original line number Diff line number Diff line Loading @@ -63,10 +63,12 @@ import android.os.Looper; import android.os.PatternMatcher; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.util.Log; import android.view.Display; import android.view.DisplayInfo; import android.view.InputDevice; import android.view.KeyCharacterMap; import android.view.KeyEvent; Loading Loading @@ -110,6 +112,7 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag; import com.android.systemui.settings.DisplayTracker; import com.android.systemui.settings.UserTracker; import com.android.systemui.shade.ShadeViewController; import com.android.systemui.shade.display.StatusBarTouchShadeDisplayPolicy; import com.android.systemui.shade.domain.interactor.ShadeInteractor; import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround; import com.android.systemui.shared.recents.ILauncherProxy; Loading @@ -126,6 +129,8 @@ import com.android.wm.shell.back.BackAnimation; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; import com.android.wm.shell.sysui.ShellInterface; import dagger.Lazy; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; Loading @@ -137,8 +142,6 @@ import java.util.function.Supplier; import javax.inject.Inject; import javax.inject.Provider; import dagger.Lazy; /** * Class to send information from SysUI to Launcher with a binder. */ Loading Loading @@ -168,6 +171,7 @@ public class LauncherProxyService implements CallbackController<LauncherProxyLis private final NotificationShadeWindowController mStatusBarWinController; private final Provider<SceneInteractor> mSceneInteractor; private final Provider<ShadeInteractor> mShadeInteractor; private final StatusBarTouchShadeDisplayPolicy mShadeDisplayPolicy; private final Runnable mConnectionRunnable = () -> internalConnectToCurrentUser("runnable: startConnectionToCurrentUser"); Loading Loading @@ -224,6 +228,12 @@ public class LauncherProxyService implements CallbackController<LauncherProxyLis // TODO: change the method signature to use (boolean inputFocusTransferStarted) @Override public void onStatusBarTouchEvent(MotionEvent event) { moveShadeWindowIfNeeded(event); if (shouldIgnoreEvent(event)) { Log.d(TAG_OPS, "Ignoring launcher swipe event for legacy shade due to touch event" + " on display without notification shade"); return; } verifyCallerAndClearCallingIdentity("onStatusBarTouchEvent", () -> { if (SceneContainerFlag.isEnabled()) { //TODO(b/329863123) implement latency tracking for shade scene Loading Loading @@ -269,6 +279,31 @@ public class LauncherProxyService implements CallbackController<LauncherProxyLis }); } @VisibleForTesting public void moveShadeWindowIfNeeded(MotionEvent event) { if (ShadeWindowGoesAround.isEnabled() && SceneContainerFlag.isEnabled()) { Trace.beginSection("LauncherProxyService#moveShadeWindowIfNeeded"); // TODO: b/407496148 - Refactor to use DisplayMetricsRepository instead final DisplayInfo displayInfo = new DisplayInfo(); mDisplayTracker.getDisplay(event.getDisplayId()).getDisplayInfo(displayInfo); int displayWidth = displayInfo.logicalWidth; mShadeDisplayPolicy.onStatusBarOrLauncherTouched(event, displayWidth); Trace.endSection(); } } @VisibleForTesting public boolean shouldIgnoreEvent(MotionEvent event) { if (ShadeWindowGoesAround.isEnabled() && !SceneContainerFlag.isEnabled()) { // For legacy shade case, don't attempt to handle touch events on display that // doesn't have the shade. They're handled with SceneContainerFlag enabled. boolean touchingDisplayWithoutShade = event.getDisplayId() != mShadeDisplayPolicy.getDisplayId().getValue(); return touchingDisplayWithoutShade; } return false; } @Override public void onStatusBarTrackpadEvent(MotionEvent event) { verifyCallerAndClearCallingIdentityPostMain("onStatusBarTrackpadEvent", () -> { Loading Loading @@ -694,6 +729,7 @@ public class LauncherProxyService implements CallbackController<LauncherProxyLis PerDisplayRepository<SysUiState> perDisplaySysUiStateRepository, Provider<SceneInteractor> sceneInteractor, Provider<ShadeInteractor> shadeInteractor, StatusBarTouchShadeDisplayPolicy shadeDisplayPolicy, UserTracker userTracker, UserManager userManager, WakefulnessLifecycle wakefulnessLifecycle, Loading Loading @@ -733,6 +769,7 @@ public class LauncherProxyService implements CallbackController<LauncherProxyLis mStatusBarWinController = statusBarWinController; mSceneInteractor = sceneInteractor; mShadeInteractor = shadeInteractor; mShadeDisplayPolicy = shadeDisplayPolicy; mUserTracker = userTracker; mConnectionBackoffAttempts = 0; mRecentsComponentName = ComponentName.unflattenFromString(context.getString( Loading
packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt +2 −2 Original line number Diff line number Diff line Loading @@ -67,8 +67,8 @@ constructor( private var removalListener: Job? = null /** Called when the status bar on the given display is touched. */ fun onStatusBarTouched(event: MotionEvent, statusBarWidth: Int) { /** Called when the status bar or launcher homescreen on the given display is touched. */ fun onStatusBarOrLauncherTouched(event: MotionEvent, statusBarWidth: Int) { ShadeWindowGoesAround.isUnexpectedlyInLegacyMode() updateShadeDisplayIfNeeded(event) updateExpansionIntent(event, statusBarWidth) Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt +1 −1 Original line number Diff line number Diff line Loading @@ -119,7 +119,7 @@ private constructor( // Notify the shade display policy that the status bar was touched. This may cause // the shade to change display if the touch was in a display different than the shade // one. lazyStatusBarShadeDisplayPolicy.get().onStatusBarTouched(event, mView.width) lazyStatusBarShadeDisplayPolicy.get().onStatusBarOrLauncherTouched(event, mView.width) } } Loading
packages/SystemUI/tests/src/com/android/systemui/recents/LauncherProxyServiceTest.kt +100 −12 Original line number Diff line number Diff line Loading @@ -22,10 +22,11 @@ import android.content.pm.PackageManager import android.content.pm.ResolveInfo import android.os.PowerManager import android.os.UserManager import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.testing.TestableContext import android.testing.TestableLooper import android.view.Display import android.view.MotionEvent import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.app.AssistUtils Loading @@ -49,9 +50,11 @@ import com.android.systemui.navigationbar.NavigationModeController import com.android.systemui.navigationbar.views.NavigationBar import com.android.systemui.process.ProcessWrapper import com.android.systemui.recents.LauncherProxyService.ACTION_QUICKSTEP import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.settings.FakeDisplayTracker import com.android.systemui.settings.UserTracker import com.android.systemui.shade.ShadeViewController import com.android.systemui.shade.display.StatusBarTouchShadeDisplayPolicy import com.android.systemui.shared.recents.ILauncherProxy import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_WAKEFULNESS_MASK import com.android.systemui.shared.system.QuickStepContract.WAKEFULNESS_ASLEEP Loading @@ -69,6 +72,7 @@ import com.android.wm.shell.sysui.ShellInterface import com.google.common.util.concurrent.MoreExecutors import java.util.Optional import java.util.concurrent.Executor import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runTest import org.junit.After Loading @@ -77,6 +81,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers import org.mockito.ArgumentMatchers.anyLong import org.mockito.ArgumentMatchers.anyString import org.mockito.ArgumentMatchers.eq import org.mockito.Mock import org.mockito.Mockito.any Loading @@ -90,6 +95,9 @@ import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations import org.mockito.kotlin.argThat import org.mockito.kotlin.doNothing import org.mockito.kotlin.never import org.mockito.kotlin.whenever @SmallTest Loading Loading @@ -119,6 +127,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { @Mock private lateinit var shellInterface: ShellInterface @Mock private lateinit var navBarController: NavigationBarController @Mock private lateinit var shadeViewController: ShadeViewController @Mock private lateinit var sceneInteractor: SceneInteractor @Mock private lateinit var screenPinningRequest: ScreenPinningRequest @Mock private lateinit var navModeController: NavigationModeController @Mock private lateinit var statusBarWinController: NotificationShadeWindowController Loading @@ -134,6 +143,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { private lateinit var unfoldTransitionProgressForwarder: Optional<UnfoldTransitionProgressForwarder> @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher @Mock private lateinit var statusBarShadeDisplayPolicy: StatusBarTouchShadeDisplayPolicy @Mock private lateinit var backAnimation: Optional<BackAnimation> @Before Loading @@ -142,14 +152,14 @@ class LauncherProxyServiceTest : SysuiTestCase() { val serviceComponent = ComponentName("test_package", "service_provider") context.addMockService(serviceComponent, launcherProxy) context.addMockServiceResolver( TestableContext.MockServiceResolver { context.addMockServiceResolver { if (it.action == ACTION_QUICKSTEP) serviceComponent else null } ) whenever(launcherProxy.queryLocalInterface(ArgumentMatchers.anyString())) .thenReturn(launcherProxy) whenever(launcherProxy.asBinder()).thenReturn(launcherProxy) doNothing().whenever(sceneInteractor).onRemoteUserInputStarted(anyString()) doNothing().whenever(shadeViewController).startInputFocusTransfer() // packageManager.resolveServiceAsUser has to return non-null for // LauncherProxyService#isEnabled to become true. Loading @@ -157,8 +167,6 @@ class LauncherProxyServiceTest : SysuiTestCase() { whenever(packageManager.resolveServiceAsUser(any(), anyInt(), anyInt())) .thenReturn(mock(ResolveInfo::class.java)) mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) // return isSystemUser as true by default. `when`(processWrapper.isSystemUser).thenReturn(true) sysuiStatePerDisplayRepository.add(Display.DEFAULT_DISPLAY, sysUiState) Loading @@ -172,6 +180,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun wakefulnessLifecycle_dispatchFinishedWakingUpSetsSysUIflagToAWAKE() { // WakefulnessLifecycle is initialized to AWAKE initially, and won't emit a noop. wakefulnessLifecycle.dispatchFinishedGoingToSleep() Loading @@ -187,6 +196,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun wakefulnessLifecycle_dispatchStartedWakingUpSetsSysUIflagToWAKING() { wakefulnessLifecycle.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN) Loading @@ -198,6 +208,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun wakefulnessLifecycle_dispatchFinishedGoingToSleepSetsSysUIflagToASLEEP() { wakefulnessLifecycle.dispatchFinishedGoingToSleep() Loading @@ -209,6 +220,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun wakefulnessLifecycle_dispatchStartedGoingToSleepSetsSysUIflagToGOING_TO_SLEEP() { wakefulnessLifecycle.dispatchStartedGoingToSleep( PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON Loading @@ -222,6 +234,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun connectToLauncherService_primaryUserNoVisibleBgUsersSupported_expectBindService() { `when`(processWrapper.isSystemUser).thenReturn(true) `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(false) Loading @@ -232,6 +245,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun connectToLauncherService_nonPrimaryUserNoVisibleBgUsersSupported_expectNoBindService() { `when`(processWrapper.isSystemUser).thenReturn(false) `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(false) Loading @@ -242,6 +256,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun connectToLauncherService_nonPrimaryBgUserVisibleBgUsersSupported_expectBindService() { `when`(processWrapper.isSystemUser).thenReturn(false) `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(true) Loading @@ -253,6 +268,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun connectToLauncherService_nonPrimaryFgUserVisibleBgUsersSupported_expectNoBindService() { `when`(processWrapper.isSystemUser).thenReturn(false) `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(true) Loading @@ -264,6 +280,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { } @Test @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun notifySysUiStateFlagsForAllDisplays_triggersUpdateInAllDisplays() = kosmos.testScope.runTest { kosmos.displayRepository.apply { Loading @@ -285,15 +302,14 @@ class LauncherProxyServiceTest : SysuiTestCase() { @Test @EnableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND) @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun updateSystemUiStateFlags_updatesAllNavBars() = kosmos.testScope.runTest { kosmos.displayRepository.apply { addDisplay(0) addDisplay(1) } kosmos.fakeSysUIStatePerDisplayRepository.apply { add(1, sysUiStateFactory.create(1)) } kosmos.fakeSysUIStatePerDisplayRepository.apply { add(1, sysUiStateFactory.create(1)) } val navBar0 = mock<NavigationBar>() val navBar1 = mock<NavigationBar>() whenever(navBarController.getNavigationBar(eq(0))).thenReturn(navBar0) Loading @@ -305,6 +321,77 @@ class LauncherProxyServiceTest : SysuiTestCase() { verify(navBar1).updateSystemUiStateFlags() } @Test @EnableFlags( Flags.FLAG_SHADE_WINDOW_GOES_AROUND, Flags.FLAG_SCENE_CONTAINER, Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR, ) fun onStatusBarTouchEvent_withSceneFlag_callsOnLauncherDrag() = kosmos.testScope.runTest { val shadeDisplayId = 1 whenever(statusBarShadeDisplayPolicy.displayId) .thenReturn(MutableStateFlow(shadeDisplayId)) val event = MotionEvent.obtain(500, 500, MotionEvent.ACTION_MOVE, 500f, 500f, 0).apply { displayId = 0 } subject.mSysUiProxy.onStatusBarTouchEvent(event) verify(statusBarShadeDisplayPolicy) .onStatusBarOrLauncherTouched( argThat<MotionEvent> { displayId == event.displayId }, anyInt(), ) } @Test @EnableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND) @DisableFlags(Flags.FLAG_SCENE_CONTAINER, Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun onStatusBarTouchEvent_withoutSceneFlag_onDifferentDisplayTouch_ignoresInput() = kosmos.testScope.runTest { val shadeDisplayId = 1 whenever(statusBarShadeDisplayPolicy.displayId) .thenReturn(MutableStateFlow(shadeDisplayId)) val event = MotionEvent.obtain(500, 500, MotionEvent.ACTION_DOWN, 500f, 500f, 0).apply { displayId = 0 } subject.mSysUiProxy.onStatusBarTouchEvent(event) verify(statusBarShadeDisplayPolicy, never()) .onStatusBarOrLauncherTouched( argThat<MotionEvent> { displayId == event.displayId }, anyInt(), ) verify(shadeViewController, never()).startExpandLatencyTracking() } @Test @EnableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND) @DisableFlags(Flags.FLAG_SCENE_CONTAINER, Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) fun onStatusBarTouchEvent_withoutSceneFlag_onSameDisplayTouch_handlesInput() = kosmos.testScope.runTest { val shadeDisplayId = 0 whenever(statusBarShadeDisplayPolicy.displayId) .thenReturn(MutableStateFlow(shadeDisplayId)) val event = MotionEvent.obtain(500, 500, MotionEvent.ACTION_DOWN, 500f, 500f, 0).apply { displayId = shadeDisplayId } subject.mSysUiProxy.onStatusBarTouchEvent(event) verify(statusBarShadeDisplayPolicy, never()) .onStatusBarOrLauncherTouched( argThat<MotionEvent> { displayId == shadeDisplayId }, anyInt(), ) verify(shadeViewController).startExpandLatencyTracking() } private fun createLauncherProxyService(ctx: Context): LauncherProxyService { return LauncherProxyService( ctx, Loading @@ -317,8 +404,9 @@ class LauncherProxyServiceTest : SysuiTestCase() { navModeController, statusBarWinController, kosmos.fakeSysUIStatePerDisplayRepository, { sceneInteractor }, mock(), mock(), statusBarShadeDisplayPolicy, userTracker, userManager, wakefulnessLifecycle, Loading