diff options
12 files changed, 247 insertions, 21 deletions
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl index 28c273ec50a6..f6056bd39005 100644 --- a/core/java/android/app/IWallpaperManager.aidl +++ b/core/java/android/app/IWallpaperManager.aidl @@ -206,6 +206,20 @@ interface IWallpaperManager { void notifyGoingToSleep(int x, int y, in Bundle extras); /** + * Called when the screen has been fully turned on and is visible. + * + * @hide + */ + void notifyScreenTurnedOn(int displayId); + + /** + * Called when the screen starts turning on. + * + * @hide + */ + void notifyScreenTurningOn(int displayId); + + /** * Sets the wallpaper dim amount between [0f, 1f] which would be blended with the system default * dimming. 0f doesn't add any additional dimming and 1f makes the wallpaper fully black. * diff --git a/core/java/android/service/wallpaper/IWallpaperEngine.aidl b/core/java/android/service/wallpaper/IWallpaperEngine.aidl index 1a00acf475e3..15a8502a2e7f 100644 --- a/core/java/android/service/wallpaper/IWallpaperEngine.aidl +++ b/core/java/android/service/wallpaper/IWallpaperEngine.aidl @@ -32,6 +32,8 @@ interface IWallpaperEngine { oneway void setDisplayPadding(in Rect padding); @UnsupportedAppUsage oneway void setVisibility(boolean visible); + oneway void onScreenTurningOn(); + oneway void onScreenTurnedOn(); oneway void setInAmbientMode(boolean inAmbientDisplay, long animationDuration); @UnsupportedAppUsage oneway void dispatchPointer(in MotionEvent event); diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 2887d1f85d21..8f1fc1b9348e 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -168,6 +168,7 @@ public abstract class WallpaperService extends Service { private static final int MSG_ZOOM = 10100; private static final int MSG_RESIZE_PREVIEW = 10110; private static final int MSG_REPORT_SHOWN = 10150; + private static final int MSG_UPDATE_SCREEN_TURNING_ON = 10170; private static final int MSG_UPDATE_DIMMING = 10200; /** limit calls to {@link Engine#onComputeColors} to at most once per second */ @@ -213,6 +214,16 @@ public abstract class WallpaperService extends Service { boolean mInitializing = true; boolean mVisible; + /** + * Whether the screen is turning on. + * After the display is powered on, brightness is initially off. It is turned on only after + * all windows have been drawn, and sysui notifies that it's ready (See + * {@link com.android.internal.policy.IKeyguardDrawnCallback}). + * As some wallpapers use visibility as a signal to start animations, this makes sure + * {@link Engine#onVisibilityChanged} is invoked only when the display is both on and + * visible (with brightness on). + */ + private boolean mIsScreenTurningOn; boolean mReportedVisible; boolean mDestroyed; // Set to true after receiving WallpaperManager#COMMAND_FREEZE. It's reset back to false @@ -988,6 +999,7 @@ public abstract class WallpaperService extends Service { out.print(" mDestroyed="); out.println(mDestroyed); out.print(prefix); out.print("mVisible="); out.print(mVisible); out.print(" mReportedVisible="); out.println(mReportedVisible); + out.print(" mIsScreenTurningOn="); out.println(mIsScreenTurningOn); out.print(prefix); out.print("mDisplay="); out.println(mDisplay); out.print(prefix); out.print("mCreated="); out.print(mCreated); out.print(" mSurfaceCreated="); out.print(mSurfaceCreated); @@ -1522,6 +1534,13 @@ public abstract class WallpaperService extends Service { } } + void onScreenTurningOnChanged(boolean isScreenTurningOn) { + if (!mDestroyed) { + mIsScreenTurningOn = isScreenTurningOn; + reportVisibility(); + } + } + void doVisibilityChanged(boolean visible) { if (!mDestroyed) { mVisible = visible; @@ -1538,9 +1557,10 @@ public abstract class WallpaperService extends Service { return; } if (!mDestroyed) { - mDisplayState = mDisplay == null ? Display.STATE_UNKNOWN : - mDisplay.getCommittedState(); - boolean visible = mVisible && mDisplayState != Display.STATE_OFF; + mDisplayState = + mDisplay == null ? Display.STATE_UNKNOWN : mDisplay.getCommittedState(); + boolean displayVisible = Display.isOnState(mDisplayState) && !mIsScreenTurningOn; + boolean visible = mVisible && displayVisible; if (mReportedVisible != visible) { mReportedVisible = visible; if (DEBUG) Log.v(TAG, "onVisibilityChanged(" + visible @@ -2414,6 +2434,20 @@ public abstract class WallpaperService extends Service { } } + public void updateScreenTurningOn(boolean isScreenTurningOn) { + Message msg = mCaller.obtainMessageBO(MSG_UPDATE_SCREEN_TURNING_ON, isScreenTurningOn, + null); + mCaller.sendMessage(msg); + } + + public void onScreenTurningOn() throws RemoteException { + updateScreenTurningOn(true); + } + + public void onScreenTurnedOn() throws RemoteException { + updateScreenTurningOn(false); + } + @Override public void executeMessage(Message message) { if (mDetached.get()) { @@ -2464,6 +2498,13 @@ public abstract class WallpaperService extends Service { + ": " + message.arg1); mEngine.doVisibilityChanged(message.arg1 != 0); break; + case MSG_UPDATE_SCREEN_TURNING_ON: + if (DEBUG) { + Log.v(TAG, + message.arg1 != 0 ? "Screen turning on" : "Screen turned on"); + } + mEngine.onScreenTurningOnChanged(/* isScreenTurningOn= */ message.arg1 != 0); + break; case MSG_WALLPAPER_OFFSETS: { mEngine.doOffsetsChanged(true); } break; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt index 82bd45ce2279..6322edf5a1b4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt @@ -24,6 +24,10 @@ import androidx.annotation.VisibleForTesting import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.keyguard.data.repository.KeyguardRepository +import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.expansionChanges @@ -40,22 +44,26 @@ import com.android.systemui.statusbar.policy.HeadsUpManager import com.android.systemui.statusbar.policy.headsUpEvents import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.settings.SettingsProxyExt.observerFlow -import javax.inject.Inject -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.conflate +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.emitAll import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.transformLatest import kotlinx.coroutines.launch +import kotlinx.coroutines.yield +import javax.inject.Inject +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds /** * Filters low priority and privacy-sensitive notifications from the lockscreen, and hides section @@ -69,6 +77,7 @@ constructor( private val headsUpManager: HeadsUpManager, private val keyguardNotificationVisibilityProvider: KeyguardNotificationVisibilityProvider, private val keyguardRepository: KeyguardRepository, + private val keyguardTransitionRepository: KeyguardTransitionRepository, private val notifPipelineFlags: NotifPipelineFlags, @Application private val scope: CoroutineScope, private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider, @@ -99,21 +108,46 @@ constructor( } private suspend fun trackUnseenNotificationsWhileUnlocked() { + // Whether or not we're actively tracking unseen notifications to mark them as seen when + // appropriate. + val isTrackingUnseen: Flow<Boolean> = + keyguardRepository.isKeyguardShowing + // transformLatest so that we can cancel listening to keyguard transitions once + // isKeyguardShowing changes (after a successful transition to the keyguard). + .transformLatest { isShowing -> + if (isShowing) { + // If the keyguard is showing, we're not tracking unseen. + emit(false) + } else { + // If the keyguard stops showing, then start tracking unseen notifications. + emit(true) + // If the screen is turning off, stop tracking, but if that transition is + // cancelled, then start again. + emitAll( + keyguardTransitionRepository.transitions + .map { step -> !step.isScreenTurningOff } + ) + } + } + // Prevent double emit of `false` caused by transition to AOD, followed by keyguard + // showing + .distinctUntilChanged() + // Use collectLatest so that trackUnseenNotifications() is cancelled when the keyguard is // showing again - var clearUnseenOnUnlock = false - keyguardRepository.isKeyguardShowing.collectLatest { isKeyguardShowing -> - if (isKeyguardShowing) { + var clearUnseenOnBeginTracking = false + isTrackingUnseen.collectLatest { trackingUnseen -> + if (!trackingUnseen) { // Wait for the user to spend enough time on the lock screen before clearing unseen // set when unlocked awaitTimeSpentNotDozing(SEEN_TIMEOUT) - clearUnseenOnUnlock = true + clearUnseenOnBeginTracking = true } else { - unseenNotifFilter.invalidateList("keyguard no longer showing") - if (clearUnseenOnUnlock) { - clearUnseenOnUnlock = false + if (clearUnseenOnBeginTracking) { + clearUnseenOnBeginTracking = false unseenNotifications.clear() } + unseenNotifFilter.invalidateList("keyguard no longer showing") trackUnseenNotifications() } } @@ -142,7 +176,10 @@ constructor( } private suspend fun clearUnseenNotificationsWhenShadeIsExpanded() { - statusBarStateController.expansionChanges.collect { isExpanded -> + statusBarStateController.expansionChanges.collectLatest { isExpanded -> + // Give keyguard events time to propagate, in case this expansion is part of the + // keyguard transition and not the user expanding the shade + yield() if (isExpanded) { unseenNotifications.clear() } @@ -276,3 +313,6 @@ constructor( private val SEEN_TIMEOUT = 5.seconds } } + +private val TransitionStep.isScreenTurningOff: Boolean get() = + transitionState == TransitionState.STARTED && to != KeyguardState.GONE
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt index 8109e24a1e52..c2a2a40b7e5d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt @@ -25,6 +25,10 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.advanceTimeBy import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository +import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.notification.NotifPipelineFlags @@ -69,6 +73,7 @@ class KeyguardCoordinatorTest : SysuiTestCase() { private val headsUpManager: HeadsUpManager = mock() private val keyguardNotifVisibilityProvider: KeyguardNotificationVisibilityProvider = mock() private val keyguardRepository = FakeKeyguardRepository() + private val keyguardTransitionRepository = FakeKeyguardTransitionRepository() private val notifPipelineFlags: NotifPipelineFlags = mock() private val notifPipeline: NotifPipeline = mock() private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider = mock() @@ -118,6 +123,33 @@ class KeyguardCoordinatorTest : SysuiTestCase() { } @Test + fun unseenFilterStopsMarkingSeenNotifWhenTransitionToAod() { + whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true) + + // GIVEN: Keyguard is not showing, shade is not expanded, and a notification is present + keyguardRepository.setKeyguardShowing(false) + whenever(statusBarStateController.isExpanded).thenReturn(false) + runKeyguardCoordinatorTest { + val fakeEntry = NotificationEntryBuilder().build() + collectionListener.onEntryAdded(fakeEntry) + + // WHEN: The device transitions to AOD + keyguardTransitionRepository.sendTransitionStep( + TransitionStep(to = KeyguardState.AOD, transitionState = TransitionState.STARTED), + ) + testScheduler.runCurrent() + + // WHEN: The shade is expanded + whenever(statusBarStateController.isExpanded).thenReturn(true) + statusBarStateListener.onExpandedChanged(true) + testScheduler.runCurrent() + + // THEN: The notification is still treated as "unseen" and is not filtered out. + assertThat(unseenFilter.shouldFilterOut(fakeEntry, 0L)).isFalse() + } + } + + @Test fun unseenFilter_headsUpMarkedAsSeen() { whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true) @@ -373,6 +405,7 @@ class KeyguardCoordinatorTest : SysuiTestCase() { headsUpManager, keyguardNotifVisibilityProvider, keyguardRepository, + keyguardTransitionRepository, notifPipelineFlags, testScope.backgroundScope, sectionHeaderVisibilityProvider, diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/UnfoldRemoteFilter.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/UnfoldRemoteFilter.kt index 0b019d1285e3..30418883eaf8 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/UnfoldRemoteFilter.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/UnfoldRemoteFilter.kt @@ -35,7 +35,7 @@ class UnfoldRemoteFilter( private var inProgress = false - private var processedProgress: Float = 0.0f + private var processedProgress: Float = 1.0f set(newProgress) { if (inProgress) { logCounter({ "$TAG#filtered_progress" }, newProgress) diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index be4fe09d593c..f064f83393c0 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -212,6 +212,7 @@ import com.android.server.policy.keyguard.KeyguardServiceDelegate.DrawnListener; import com.android.server.policy.keyguard.KeyguardStateMonitor.StateCallback; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.vr.VrManagerInternal; +import com.android.server.wallpaper.WallpaperManagerInternal; import com.android.server.wm.ActivityTaskManagerInternal; import com.android.server.wm.DisplayPolicy; import com.android.server.wm.DisplayRotation; @@ -398,6 +399,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { AudioManagerInternal mAudioManagerInternal; DisplayManager mDisplayManager; DisplayManagerInternal mDisplayManagerInternal; + + private WallpaperManagerInternal mWallpaperManagerInternal; + boolean mPreloadedRecentApps; final Object mServiceAcquireLock = new Object(); Vibrator mVibrator; // Vibrator for giving feedback of orientation changes @@ -4776,11 +4780,34 @@ public class PhoneWindowManager implements WindowManagerPolicy { return bootCompleted ? mKeyguardDrawnTimeout : 5000; } + @Nullable + private WallpaperManagerInternal getWallpaperManagerInternal() { + if (mWallpaperManagerInternal == null) { + mWallpaperManagerInternal = LocalServices.getService(WallpaperManagerInternal.class); + } + return mWallpaperManagerInternal; + } + + private void reportScreenTurningOnToWallpaper(int displayId) { + WallpaperManagerInternal wallpaperManagerInternal = getWallpaperManagerInternal(); + if (wallpaperManagerInternal != null) { + wallpaperManagerInternal.onScreenTurningOn(displayId); + } + } + + private void reportScreenTurnedOnToWallpaper(int displayId) { + WallpaperManagerInternal wallpaperManagerInternal = getWallpaperManagerInternal(); + if (wallpaperManagerInternal != null) { + wallpaperManagerInternal.onScreenTurnedOn(displayId); + } + } + // Called on the DisplayManager's DisplayPowerController thread. @Override public void screenTurningOn(int displayId, final ScreenOnListener screenOnListener) { if (DEBUG_WAKEUP) Slog.i(TAG, "Display " + displayId + " turning on..."); + reportScreenTurningOnToWallpaper(displayId); if (displayId == DEFAULT_DISPLAY) { Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn", 0 /* cookie */); @@ -4821,6 +4848,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void screenTurnedOn(int displayId) { if (DEBUG_WAKEUP) Slog.i(TAG, "Display " + displayId + " turned on..."); + reportScreenTurnedOnToWallpaper(displayId); + if (displayId != DEFAULT_DISPLAY) { return; } diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerInternal.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerInternal.java index 584fbddee478..3699557706fd 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerInternal.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerInternal.java @@ -27,4 +27,10 @@ public abstract class WallpaperManagerInternal { * Notifies the display is ready for adding wallpaper on it. */ public abstract void onDisplayReady(int displayId); + + /** Notifies when the screen finished turning on and is visible to the user. */ + public abstract void onScreenTurnedOn(int displayId); + + /** Notifies when the screen starts turning on and is not yet visible to the user. */ + public abstract void onScreenTurningOn(int displayId); } diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 79a4acf55fef..1574ff554fb1 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -1762,6 +1762,15 @@ public class WallpaperManagerService extends IWallpaperManager.Stub public void onDisplayReady(int displayId) { onDisplayReadyInternal(displayId); } + + @Override + public void onScreenTurnedOn(int displayId) { + notifyScreenTurnedOn(displayId); + } + @Override + public void onScreenTurningOn(int displayId) { + notifyScreenTurningOn(displayId); + } } void initialize() { @@ -2575,6 +2584,54 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } + /** + * Propagates screen turned on event to wallpaper engine. + */ + @Override + public void notifyScreenTurnedOn(int displayId) { + synchronized (mLock) { + final WallpaperData data = mWallpaperMap.get(mCurrentUserId); + if (data != null + && data.connection != null + && data.connection.containsDisplay(displayId)) { + final IWallpaperEngine engine = data.connection + .getDisplayConnectorOrCreate(displayId).mEngine; + if (engine != null) { + try { + engine.onScreenTurnedOn(); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + } + } + } + + + + /** + * Propagate screen turning on event to wallpaper engine. + */ + @Override + public void notifyScreenTurningOn(int displayId) { + synchronized (mLock) { + final WallpaperData data = mWallpaperMap.get(mCurrentUserId); + if (data != null + && data.connection != null + && data.connection.containsDisplay(displayId)) { + final IWallpaperEngine engine = data.connection + .getDisplayConnectorOrCreate(displayId).mEngine; + if (engine != null) { + try { + engine.onScreenTurningOn(); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + } + } + } + @Override public boolean setLockWallpaperCallback(IWallpaperManagerCallback cb) { checkPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW); diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 2507a8d5af3a..a4e08dfb1e3b 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2282,11 +2282,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent> resumedOnDisplay[0] |= curResult; return; } - if (rootTask.getDisplayArea().isTopRootTask(rootTask) - && topRunningActivity.isState(RESUMED)) { - // Kick off any lingering app transitions form the MoveTaskToFront - // operation, but only consider the top task and root-task on that - // display. + if (topRunningActivity.isState(RESUMED) + && topRunningActivity == rootTask.getDisplayArea().topRunningActivity()) { + // Kick off any lingering app transitions form the MoveTaskToFront operation, + // but only consider the top activity on that display. rootTask.executeAppTransition(targetOptions); } else { resumedOnDisplay[0] |= topRunningActivity.makeActiveIfNeeded(target); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 8f1702c1b0fa..78ed43658dd5 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -913,6 +913,11 @@ public class WindowManagerService extends IWindowManager.Stub mMaximumObscuringOpacityForTouch = Settings.Global.getFloat(resolver, Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH, InputManager.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH); + if (mMaximumObscuringOpacityForTouch < 0.0f + || mMaximumObscuringOpacityForTouch > 1.0f) { + mMaximumObscuringOpacityForTouch = + InputManager.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH; + } } void updateSystemUiSettings(boolean handleChange) { diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java index b89643cba116..42dafe226abd 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java @@ -761,7 +761,7 @@ public class RootWindowContainerTests extends WindowTestsBase { // Assume the task is at the topmost position assertFalse(rootTask.isTopRootTaskInDisplayArea()); - doReturn(rootTask).when(mRootWindowContainer).getTopDisplayFocusedRootTask(); + doReturn(taskDisplayArea.getHomeActivity()).when(taskDisplayArea).topRunningActivity(); // Use the task as target to resume. mRootWindowContainer.resumeFocusedTasksTopActivities(); |