summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRiddle Hsu <riddlehsu@google.com>2023-11-21 18:15:46 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-12-15 07:19:47 +0000
commit19f6b2f62c8865130b028a1a9258fd548a34e152 (patch)
tree44fd0c8e23556fdf473727940720dfba65e2ef06
parent7f17bb5c5a6e33e3891ae3ba38a0aa21f889b550 (diff)
downloadbase-19f6b2f62c8865130b028a1a9258fd548a34e152.tar.gz
Update surface visibility state when forcing visible
Since surface visibility recovery always applies for visible request even for sleeping case, when finishing an activity while sleeping, the next activity will enter onVisibleWithoutCollectingTransition because there won't be a transition for invisible finishing activity. And then because the device is sleeping, the next activity will be stopped and invisible directly right after resuming. But its surface visibility is only forced to be visible. Then after the device is awake and the "invisible-visible" activity doesn't have visibility change, home will be untouchable because the surface layer of home task is always at bottom, which is under the ActivityRecordInputSink of the problematic activity. The surface hierarchy and visibility will be: [Top]Task T (visible) > Activity X (visible) > Window (invisible) > ActivityRecordInputSink (follow parent, so visible) [Bottom]Task Home (visible) > Activity (visible) > Window (visible) Even if X is stopped and mVisible/mVisibleRequested are false. So this change updates mLastSurfaceShowing when forcing visible. Then when executing ActivityRecord/Task#prepareSurface, it can follow the current state of hierarchy to refresh the visibility. Also narrow down the scope of surface visibility recovery while display is sleeping, which is for show-when-locked case. Fix: 311221846 Fix: 311379188 Fix: 309908645 Test: atest ActivityRecordTests# \ testFinishActivityIfPossible_nonVisibleNoAppTransition Test: Launch app A. Launch app B. Turn off screen. B calls finish. Launch app C (so A doesn't have visibility change later). Unlock device. Press home key. Home can still scroll. (App A,B,C have different uids so InputSink will block touch) (cherry picked from commit 1c18c583b6b057ed72cd41b30a7a644f3047fa06) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:450cb0f9e4f1efa98578028910d1494cf2317935) Merged-In: I1d6c2e5a0dad831a9a7043d390037ca15a8b14bd Change-Id: I1d6c2e5a0dad831a9a7043d390037ca15a8b14bd
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java12
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecordInputSink.java2
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java16
4 files changed, 30 insertions, 8 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index d570c9e1acab..add27078b00f 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -700,7 +700,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private boolean mCurrentLaunchCanTurnScreenOn = true;
/** Whether our surface was set to be showing in the last call to {@link #prepareSurfaces} */
- private boolean mLastSurfaceShowing;
+ boolean mLastSurfaceShowing;
/**
* The activity is opaque and fills the entire space of this task.
@@ -5345,11 +5345,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Finish should only ever commit visibility=false, so we can check full containment
// rather than just direct membership.
inFinishingTransition = mTransitionController.inFinishingTransition(this);
- if (!inFinishingTransition && (visible || !mDisplayContent.isSleeping())) {
+ if (!inFinishingTransition) {
if (visible) {
- mTransitionController.onVisibleWithoutCollectingTransition(this,
- Debug.getCallers(1, 1));
- } else {
+ if (!mDisplayContent.isSleeping() || canShowWhenLocked()) {
+ mTransitionController.onVisibleWithoutCollectingTransition(this,
+ Debug.getCallers(1, 1));
+ }
+ } else if (!mDisplayContent.isSleeping()) {
Slog.w(TAG, "Set invisible without transition " + this);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
index be7d9b63f779..15a3f9349007 100644
--- a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
+++ b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
@@ -87,9 +87,11 @@ class ActivityRecordInputSink {
activityBelowInTask.mAllowedTouchUid == mActivityRecord.getUid()
|| activityBelowInTask.isUid(mActivityRecord.getUid()));
if (allowPassthrough || !mIsCompatEnabled || mActivityRecord.isInTransition()) {
+ // Set to non-touchable, so the touch events can pass through.
mInputWindowHandleWrapper.setInputConfigMasked(InputConfig.NOT_TOUCHABLE,
InputConfig.NOT_TOUCHABLE);
} else {
+ // Set to touchable, so it can block by intercepting the touch events.
mInputWindowHandleWrapper.setInputConfigMasked(0, InputConfig.NOT_TOUCHABLE);
}
mInputWindowHandleWrapper.setDisplayId(mActivityRecord.getDisplayId());
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 577e755c310c..3ad42328a2df 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -971,11 +971,19 @@ class TransitionController {
private void enforceSurfaceVisible(WindowContainer<?> wc) {
if (wc.mSurfaceControl == null) return;
wc.getSyncTransaction().show(wc.mSurfaceControl);
+ final ActivityRecord ar = wc.asActivityRecord();
+ if (ar != null) {
+ ar.mLastSurfaceShowing = true;
+ }
// Force showing the parents because they may be hidden by previous transition.
for (WindowContainer<?> p = wc.getParent(); p != null && p != wc.mDisplayContent;
p = p.getParent()) {
if (p.mSurfaceControl != null) {
p.getSyncTransaction().show(p.mSurfaceControl);
+ final Task task = p.asTask();
+ if (task != null) {
+ task.mLastSurfaceShowing = true;
+ }
}
}
wc.scheduleAnimation();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 3eed0b72e0bb..185f5ba9316e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1179,10 +1179,12 @@ public class ActivityRecordTests extends WindowTestsBase {
@Test
public void testFinishActivityIfPossible_nonVisibleNoAppTransition() {
registerTestTransitionPlayer();
+ spyOn(mRootWindowContainer.mTransitionController);
+ final ActivityRecord bottomActivity = createActivityWithTask();
+ bottomActivity.setVisibility(false);
+ bottomActivity.setState(STOPPED, "test");
+ bottomActivity.mLastSurfaceShowing = false;
final ActivityRecord activity = createActivityWithTask();
- // Put an activity on top of test activity to make it invisible and prevent us from
- // accidentally resuming the topmost one again.
- new ActivityBuilder(mAtm).build();
activity.setVisibleRequested(false);
activity.setState(STOPPED, "test");
@@ -1190,6 +1192,14 @@ public class ActivityRecordTests extends WindowTestsBase {
verify(activity.mDisplayContent, never()).prepareAppTransition(eq(TRANSIT_CLOSE));
assertFalse(activity.inTransition());
+
+ // finishIfPossible -> completeFinishing -> addToFinishingAndWaitForIdle
+ // -> resumeFocusedTasksTopActivities
+ assertTrue(bottomActivity.isState(RESUMED));
+ assertTrue(bottomActivity.isVisible());
+ verify(mRootWindowContainer.mTransitionController).onVisibleWithoutCollectingTransition(
+ eq(bottomActivity), any());
+ assertTrue(bottomActivity.mLastSurfaceShowing);
}
/**