Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit de35559c authored by wilsonshih's avatar wilsonshih
Browse files

Prevent the splashscreenview be replaced after transfer starting window

The splashscreenview can be replaced if starting window was transferred
and the first starting window didn't added success.
There should verify the appToken before setViewSynchronized set the
splashscreenview back to the container.

Issue sequence:
- Start first activity A, core request to add a starting window for it.
- Start second activity B, core try to transfer starting window from A
to B but since the window haven't added back,  there will trigger to
add a new starting window for B.
- SystemUI add starting window to A but added fail because there was
transferred.
- SystemUI add starting window to B, success.
- Choreographer post setViewSynchronized to add view for A and B to the
container, because we only verify by taskId, so the SplashscreenView was
overwrite by A.
- After reveal animation finish, SplashScreenView#post will not be
executed because this view was not on screen.

Fixes: 188540606
Test: atest StartingSurfaceDrawerTests
Test: Open twitter from notification.
Change-Id: I894da75827556d3c1bc8bb0656196102de5a6847
parent 4d225a0e
Loading
Loading
Loading
Loading
+24 −17
Original line number Diff line number Diff line
@@ -277,8 +277,9 @@ public class StartingSurfaceDrawer {
            // waiting for setContentView before relayoutWindow
            SplashScreenView contentView = viewSupplier.get();
            final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
            // if record == null, either the starting window added fail or removed already.
            if (record != null) {
            // If record == null, either the starting window added fail or removed already.
            // Do not add this view if the token is mismatch.
            if (record != null && appToken == record.mAppToken) {
                // if view == null then creation of content view was failed.
                if (contentView != null) {
                    try {
@@ -297,15 +298,16 @@ public class StartingSurfaceDrawer {

        try {
            final WindowManager wm = context.getSystemService(WindowManager.class);
            postAddWindow(taskId, appToken, rootLayout, wm, params);

            // We use the splash screen worker thread to create SplashScreenView while adding the
            // window, as otherwise Choreographer#doFrame might be delayed on this thread.
            // And since Choreographer#doFrame won't happen immediately after adding the window, if
            // the view is not added to the PhoneWindow on the first #doFrame, the view will not be
            // rendered on the first frame. So here we need to synchronize the view on the window
            // before first round relayoutWindow, which will happen after insets animation.
            if (postAddWindow(taskId, appToken, rootLayout, wm, params)) {
                // We use the splash screen worker thread to create SplashScreenView while adding
                // the window, as otherwise Choreographer#doFrame might be delayed on this thread.
                // And since Choreographer#doFrame won't happen immediately after adding the window,
                // if the view is not added to the PhoneWindow on the first #doFrame, the view will
                // not be rendered on the first frame. So here we need to synchronize the view on
                // the window before first round relayoutWindow, which will happen after insets
                // animation.
                mChoreographer.postCallback(CALLBACK_INSETS_ANIMATION, setViewSynchronized, null);
            }
        } catch (RuntimeException e) {
            // don't crash if something else bad happens, for example a
            // failure loading resources because we are loading from an app
@@ -347,7 +349,8 @@ public class StartingSurfaceDrawer {
        final int taskId = startingWindowInfo.taskInfo.taskId;
        final TaskSnapshotWindow surface = TaskSnapshotWindow.create(startingWindowInfo, appToken,
                snapshot, mSplashScreenExecutor, () -> removeWindowNoAnimate(taskId));
        final StartingWindowRecord tView = new StartingWindowRecord(null/* decorView */, surface);
        final StartingWindowRecord tView = new StartingWindowRecord(appToken,
                null/* decorView */, surface);
        mStartingWindowRecords.put(taskId, tView);
    }

@@ -382,7 +385,7 @@ public class StartingSurfaceDrawer {
        ActivityTaskManager.getInstance().onSplashScreenViewCopyFinished(taskId, parcelable);
    }

    protected void postAddWindow(int taskId, IBinder appToken, View view, WindowManager wm,
    protected boolean postAddWindow(int taskId, IBinder appToken, View view, WindowManager wm,
            WindowManager.LayoutParams params) {
        boolean shouldSaveView = true;
        try {
@@ -401,12 +404,13 @@ public class StartingSurfaceDrawer {
        }
        if (shouldSaveView) {
            removeWindowNoAnimate(taskId);
            saveSplashScreenRecord(taskId, view);
            saveSplashScreenRecord(appToken, taskId, view);
        }
        return shouldSaveView;
    }

    private void saveSplashScreenRecord(int taskId, View view) {
        final StartingWindowRecord tView = new StartingWindowRecord(view,
    private void saveSplashScreenRecord(IBinder appToken, int taskId, View view) {
        final StartingWindowRecord tView = new StartingWindowRecord(appToken, view,
                null/* TaskSnapshotWindow */);
        mStartingWindowRecords.put(taskId, tView);
    }
@@ -468,12 +472,15 @@ public class StartingSurfaceDrawer {
     * Record the view or surface for a starting window.
     */
    private static class StartingWindowRecord {
        private final IBinder mAppToken;
        private final View mDecorView;
        private final TaskSnapshotWindow mTaskSnapshotWindow;
        private SplashScreenView mContentView;
        private boolean mSetSplashScreen;

        StartingWindowRecord(View decorView, TaskSnapshotWindow taskSnapshotWindow) {
        StartingWindowRecord(IBinder appToken, View decorView,
                TaskSnapshotWindow taskSnapshotWindow) {
            mAppToken = appToken;
            mDecorView = decorView;
            mTaskSnapshotWindow = taskSnapshotWindow;
        }
+2 −1
Original line number Diff line number Diff line
@@ -83,11 +83,12 @@ public class StartingSurfaceDrawerTests {
        }

        @Override
        protected void postAddWindow(int taskId, IBinder appToken,
        protected boolean postAddWindow(int taskId, IBinder appToken,
                View view, WindowManager wm, WindowManager.LayoutParams params) {
            // listen for addView
            mAddWindowForTask = taskId;
            mViewThemeResId = view.getContext().getThemeResId();
            return true;
        }

        @Override