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

Commit 5af42fc3 authored by Winson Chung's avatar Winson Chung
Browse files

Ensuring multi-window callbacks contain new configuration and are in order



- This CL has two main changes:
  1) It modifies the activity multi-window and picture-in-picture mode
     changed callbacks to provide the configuration of the activity with
     the mode applied.
  2) It modifies the order in which the multi-window and picture-in-picture
     mode callbacks are made, to ensure that when going in and out of
     picture-in-picture: first PiP, then MW, and then the config change.
- Previously, the ordering of the two callbacks was inconsistent.  When
  calling moveActivityToPinnedStack(), we reparent the task into the pinned
  stack (triggering the picture-in-picture mode change), followed by the
  resize animation (causes configuration changes).  Inversely, when we
  expand the task to fullscreen (and not just remove it), we run the
  animation first, which resizes the task to the final size (causes
  configuration changes) then reparent after the animation completes
  (triggering the picture-in-picture mode change).

  In this CL, we ensure that for both the transition in and out of PiP, we
  defer to the bounds animation to trigger the PiP mode change.  Normal
  calls to reparent or adding a new task are unchanged.  When the PiP
  mode change is called from the animation, it provides the final target
  bounds which we use to calculate the target configuration of the activity
  for the callback.  If the bounds animation is interrupted, an update will
  also be scheduled if we change the fullscreen state we are animating to.

  To work around the issue where we are scheduling MW/PiP mode changes in
  both the animation and the configuration change, we also now keep track
  of each state internally in the ActivityRecord.

Bug: 36099777
Test: android.server.cts.ActivityManagerPinnedStackTests
Test: #testConfigurationChangeOrderDuringTransition

Change-Id: I03513bc3a4d4a72c250983f22f079ce9d7a2cb40
Signed-off-by: default avatarWinson Chung <winsonc@google.com>
parent ddd95360
Loading
Loading
Loading
Loading
+12 −6
Original line number Diff line number Diff line
@@ -3675,7 +3675,8 @@ package android.app {
    method public boolean onMenuItemSelected(int, android.view.MenuItem);
    method public boolean onMenuOpened(int, android.view.Menu);
    method public void onMovedToDisplay(int, android.content.res.Configuration);
    method public void onMultiWindowModeChanged(boolean);
    method public void onMultiWindowModeChanged(boolean, android.content.res.Configuration);
    method public deprecated void onMultiWindowModeChanged(boolean);
    method public boolean onNavigateUp();
    method public boolean onNavigateUpFromChild(android.app.Activity);
    method protected void onNewIntent(android.content.Intent);
@@ -3683,7 +3684,8 @@ package android.app {
    method public void onOptionsMenuClosed(android.view.Menu);
    method public void onPanelClosed(int, android.view.Menu);
    method protected void onPause();
    method public void onPictureInPictureModeChanged(boolean);
    method public void onPictureInPictureModeChanged(boolean, android.content.res.Configuration);
    method public deprecated void onPictureInPictureModeChanged(boolean);
    method protected void onPostCreate(android.os.Bundle);
    method public void onPostCreate(android.os.Bundle, android.os.PersistableBundle);
    method protected void onPostResume();
@@ -4616,11 +4618,13 @@ package android.app {
    method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
    method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
    method public void onLowMemory();
    method public void onMultiWindowModeChanged(boolean);
    method public void onMultiWindowModeChanged(boolean, android.content.res.Configuration);
    method public deprecated void onMultiWindowModeChanged(boolean);
    method public boolean onOptionsItemSelected(android.view.MenuItem);
    method public void onOptionsMenuClosed(android.view.Menu);
    method public void onPause();
    method public void onPictureInPictureModeChanged(boolean);
    method public void onPictureInPictureModeChanged(boolean, android.content.res.Configuration);
    method public deprecated void onPictureInPictureModeChanged(boolean);
    method public void onPrepareOptionsMenu(android.view.Menu);
    method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
    method public void onResume();
@@ -4705,11 +4709,13 @@ package android.app {
    method public void dispatchDestroy();
    method public void dispatchDestroyView();
    method public void dispatchLowMemory();
    method public void dispatchMultiWindowModeChanged(boolean);
    method public deprecated void dispatchMultiWindowModeChanged(boolean);
    method public void dispatchMultiWindowModeChanged(boolean, android.content.res.Configuration);
    method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
    method public void dispatchOptionsMenuClosed(android.view.Menu);
    method public void dispatchPause();
    method public void dispatchPictureInPictureModeChanged(boolean);
    method public deprecated void dispatchPictureInPictureModeChanged(boolean);
    method public void dispatchPictureInPictureModeChanged(boolean, android.content.res.Configuration);
    method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
    method public void dispatchResume();
    method public void dispatchStart();
+12 −6
Original line number Diff line number Diff line
@@ -3801,7 +3801,8 @@ package android.app {
    method public boolean onMenuItemSelected(int, android.view.MenuItem);
    method public boolean onMenuOpened(int, android.view.Menu);
    method public void onMovedToDisplay(int, android.content.res.Configuration);
    method public void onMultiWindowModeChanged(boolean);
    method public void onMultiWindowModeChanged(boolean, android.content.res.Configuration);
    method public deprecated void onMultiWindowModeChanged(boolean);
    method public boolean onNavigateUp();
    method public boolean onNavigateUpFromChild(android.app.Activity);
    method protected void onNewIntent(android.content.Intent);
@@ -3809,7 +3810,8 @@ package android.app {
    method public void onOptionsMenuClosed(android.view.Menu);
    method public void onPanelClosed(int, android.view.Menu);
    method protected void onPause();
    method public void onPictureInPictureModeChanged(boolean);
    method public void onPictureInPictureModeChanged(boolean, android.content.res.Configuration);
    method public deprecated void onPictureInPictureModeChanged(boolean);
    method protected void onPostCreate(android.os.Bundle);
    method public void onPostCreate(android.os.Bundle, android.os.PersistableBundle);
    method protected void onPostResume();
@@ -4775,11 +4777,13 @@ package android.app {
    method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
    method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
    method public void onLowMemory();
    method public void onMultiWindowModeChanged(boolean);
    method public void onMultiWindowModeChanged(boolean, android.content.res.Configuration);
    method public deprecated void onMultiWindowModeChanged(boolean);
    method public boolean onOptionsItemSelected(android.view.MenuItem);
    method public void onOptionsMenuClosed(android.view.Menu);
    method public void onPause();
    method public void onPictureInPictureModeChanged(boolean);
    method public void onPictureInPictureModeChanged(boolean, android.content.res.Configuration);
    method public deprecated void onPictureInPictureModeChanged(boolean);
    method public void onPrepareOptionsMenu(android.view.Menu);
    method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
    method public void onResume();
@@ -4864,11 +4868,13 @@ package android.app {
    method public void dispatchDestroy();
    method public void dispatchDestroyView();
    method public void dispatchLowMemory();
    method public void dispatchMultiWindowModeChanged(boolean);
    method public deprecated void dispatchMultiWindowModeChanged(boolean);
    method public void dispatchMultiWindowModeChanged(boolean, android.content.res.Configuration);
    method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
    method public void dispatchOptionsMenuClosed(android.view.Menu);
    method public void dispatchPause();
    method public void dispatchPictureInPictureModeChanged(boolean);
    method public deprecated void dispatchPictureInPictureModeChanged(boolean);
    method public void dispatchPictureInPictureModeChanged(boolean, android.content.res.Configuration);
    method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
    method public void dispatchResume();
    method public void dispatchStart();
+12 −6
Original line number Diff line number Diff line
@@ -3677,7 +3677,8 @@ package android.app {
    method public boolean onMenuItemSelected(int, android.view.MenuItem);
    method public boolean onMenuOpened(int, android.view.Menu);
    method public void onMovedToDisplay(int, android.content.res.Configuration);
    method public void onMultiWindowModeChanged(boolean);
    method public void onMultiWindowModeChanged(boolean, android.content.res.Configuration);
    method public deprecated void onMultiWindowModeChanged(boolean);
    method public boolean onNavigateUp();
    method public boolean onNavigateUpFromChild(android.app.Activity);
    method protected void onNewIntent(android.content.Intent);
@@ -3685,7 +3686,8 @@ package android.app {
    method public void onOptionsMenuClosed(android.view.Menu);
    method public void onPanelClosed(int, android.view.Menu);
    method protected void onPause();
    method public void onPictureInPictureModeChanged(boolean);
    method public void onPictureInPictureModeChanged(boolean, android.content.res.Configuration);
    method public deprecated void onPictureInPictureModeChanged(boolean);
    method protected void onPostCreate(android.os.Bundle);
    method public void onPostCreate(android.os.Bundle, android.os.PersistableBundle);
    method protected void onPostResume();
@@ -4628,11 +4630,13 @@ package android.app {
    method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
    method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
    method public void onLowMemory();
    method public void onMultiWindowModeChanged(boolean);
    method public void onMultiWindowModeChanged(boolean, android.content.res.Configuration);
    method public deprecated void onMultiWindowModeChanged(boolean);
    method public boolean onOptionsItemSelected(android.view.MenuItem);
    method public void onOptionsMenuClosed(android.view.Menu);
    method public void onPause();
    method public void onPictureInPictureModeChanged(boolean);
    method public void onPictureInPictureModeChanged(boolean, android.content.res.Configuration);
    method public deprecated void onPictureInPictureModeChanged(boolean);
    method public void onPrepareOptionsMenu(android.view.Menu);
    method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
    method public void onResume();
@@ -4717,11 +4721,13 @@ package android.app {
    method public void dispatchDestroy();
    method public void dispatchDestroyView();
    method public void dispatchLowMemory();
    method public void dispatchMultiWindowModeChanged(boolean);
    method public deprecated void dispatchMultiWindowModeChanged(boolean);
    method public void dispatchMultiWindowModeChanged(boolean, android.content.res.Configuration);
    method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
    method public void dispatchOptionsMenuClosed(android.view.Menu);
    method public void dispatchPause();
    method public void dispatchPictureInPictureModeChanged(boolean);
    method public deprecated void dispatchPictureInPictureModeChanged(boolean);
    method public void dispatchPictureInPictureModeChanged(boolean, android.content.res.Configuration);
    method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
    method public void dispatchResume();
    method public void dispatchStart();
+55 −8
Original line number Diff line number Diff line
@@ -1887,13 +1887,34 @@ public class Activity extends ContextThemeWrapper
        }
    }

    /**
     * Called by the system when the activity changes from fullscreen mode to multi-window mode and
     * visa-versa. This method provides the same configuration that will be sent in the following
     * {@link #onConfigurationChanged(Configuration)} call after the activity enters this mode.
     *
     * @see android.R.attr#resizeableActivity
     *
     * @param isInMultiWindowMode True if the activity is in multi-window mode.
     * @param newConfig The new configuration of the activity with the state
     *                  {@param isInMultiWindowMode}.
     */
    public void onMultiWindowModeChanged(boolean isInMultiWindowMode, Configuration newConfig) {
        // Left deliberately empty. There should be no side effects if a direct
        // subclass of Activity does not call super.
        onMultiWindowModeChanged(isInMultiWindowMode);
    }

    /**
     * Called by the system when the activity changes from fullscreen mode to multi-window mode and
     * visa-versa.
     *
     * @see android.R.attr#resizeableActivity
     *
     * @param isInMultiWindowMode True if the activity is in multi-window mode.
     *
     * @deprecated Use {@link #onMultiWindowModeChanged(boolean, Configuration)} instead.
     */
    @Deprecated
    public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
        // Left deliberately empty. There should be no side effects if a direct
        // subclass of Activity does not call super.
@@ -1913,12 +1934,34 @@ public class Activity extends ContextThemeWrapper
        return false;
    }

    /**
     * Called by the system when the activity changes to and from picture-in-picture mode. This
     * method provides the same configuration that will be sent in the following
     * {@link #onConfigurationChanged(Configuration)} call after the activity enters this mode.
     *
     * @see android.R.attr#supportsPictureInPicture
     *
     * @param isInPictureInPictureMode True if the activity is in picture-in-picture mode.
     * @param newConfig The new configuration of the activity with the state
     *                  {@param isInPictureInPictureMode}.
     */
    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode,
            Configuration newConfig) {
        // Left deliberately empty. There should be no side effects if a direct
        // subclass of Activity does not call super.
        onPictureInPictureModeChanged(isInPictureInPictureMode);
    }

    /**
     * Called by the system when the activity changes to and from picture-in-picture mode.
     *
     * @see android.R.attr#supportsPictureInPicture
     *
     * @param isInPictureInPictureMode True if the activity is in picture-in-picture mode.
     *
     * @deprecated Use {@link #onPictureInPictureModeChanged(boolean, Configuration)} instead.
     */
    @Deprecated
    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
        // Left deliberately empty. There should be no side effects if a direct
        // subclass of Activity does not call super.
@@ -6993,21 +7036,25 @@ public class Activity extends ContextThemeWrapper
        }
    }

    final void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode) {
    final void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode,
            Configuration newConfig) {
        if (DEBUG_LIFECYCLE) Slog.v(TAG,
                "dispatchMultiWindowModeChanged " + this + ": " + isInMultiWindowMode);
        mFragments.dispatchMultiWindowModeChanged(isInMultiWindowMode);
                "dispatchMultiWindowModeChanged " + this + ": " + isInMultiWindowMode
                        + " " + newConfig);
        mFragments.dispatchMultiWindowModeChanged(isInMultiWindowMode, newConfig);
        if (mWindow != null) {
            mWindow.onMultiWindowModeChanged();
        }
        onMultiWindowModeChanged(isInMultiWindowMode);
        onMultiWindowModeChanged(isInMultiWindowMode, newConfig);
    }

    final void dispatchPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
    final void dispatchPictureInPictureModeChanged(boolean isInPictureInPictureMode,
            Configuration newConfig) {
        if (DEBUG_LIFECYCLE) Slog.v(TAG,
                "dispatchPictureInPictureModeChanged " + this + ": " + isInPictureInPictureMode);
        mFragments.dispatchPictureInPictureModeChanged(isInPictureInPictureMode);
        onPictureInPictureModeChanged(isInPictureInPictureMode);
                "dispatchPictureInPictureModeChanged " + this + ": " + isInPictureInPictureMode
                        + " " + newConfig);
        mFragments.dispatchPictureInPictureModeChanged(isInPictureInPictureMode, newConfig);
        onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig);
    }

    /**
+34 −12
Original line number Diff line number Diff line
@@ -1411,15 +1411,23 @@ public final class ActivityThread {
        }

        @Override
        public void scheduleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode)
                throws RemoteException {
            sendMessage(H.MULTI_WINDOW_MODE_CHANGED, token, isInMultiWindowMode ? 1 : 0);
        public void scheduleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode,
                Configuration overrideConfig) throws RemoteException {
            SomeArgs args = SomeArgs.obtain();
            args.arg1 = token;
            args.arg2 = overrideConfig;
            args.argi1 = isInMultiWindowMode ? 1 : 0;
            sendMessage(H.MULTI_WINDOW_MODE_CHANGED, args);
        }

        @Override
        public void schedulePictureInPictureModeChanged(IBinder token, boolean isInPipMode)
                throws RemoteException {
            sendMessage(H.PICTURE_IN_PICTURE_MODE_CHANGED, token, isInPipMode ? 1 : 0);
        public void schedulePictureInPictureModeChanged(IBinder token, boolean isInPipMode,
                Configuration overrideConfig) throws RemoteException {
            SomeArgs args = SomeArgs.obtain();
            args.arg1 = token;
            args.arg2 = overrideConfig;
            args.argi1 = isInPipMode ? 1 : 0;
            sendMessage(H.PICTURE_IN_PICTURE_MODE_CHANGED, args);
        }

        @Override
@@ -1816,10 +1824,14 @@ public final class ActivityThread {
                    handleStopBinderTrackingAndDump((ParcelFileDescriptor) msg.obj);
                    break;
                case MULTI_WINDOW_MODE_CHANGED:
                    handleMultiWindowModeChanged((IBinder) msg.obj, msg.arg1 == 1);
                    handleMultiWindowModeChanged((IBinder) ((SomeArgs) msg.obj).arg1,
                            ((SomeArgs) msg.obj).argi1 == 1,
                            (Configuration) ((SomeArgs) msg.obj).arg2);
                    break;
                case PICTURE_IN_PICTURE_MODE_CHANGED:
                    handlePictureInPictureModeChanged((IBinder) msg.obj, msg.arg1 == 1);
                    handlePictureInPictureModeChanged((IBinder) ((SomeArgs) msg.obj).arg1,
                            ((SomeArgs) msg.obj).argi1 == 1,
                            (Configuration) ((SomeArgs) msg.obj).arg2);
                    break;
                case LOCAL_VOICE_INTERACTION_STARTED:
                    handleLocalVoiceInteractionStarted((IBinder) ((SomeArgs) msg.obj).arg1,
@@ -3119,17 +3131,27 @@ public final class ActivityThread {
        }
    }

    private void handleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode) {
    private void handleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode,
            Configuration overrideConfig) {
        final ActivityClientRecord r = mActivities.get(token);
        if (r != null) {
            r.activity.dispatchMultiWindowModeChanged(isInMultiWindowMode);
            final Configuration newConfig = new Configuration(mConfiguration);
            if (overrideConfig != null) {
                newConfig.updateFrom(overrideConfig);
            }
            r.activity.dispatchMultiWindowModeChanged(isInMultiWindowMode, newConfig);
        }
    }

    private void handlePictureInPictureModeChanged(IBinder token, boolean isInPipMode) {
    private void handlePictureInPictureModeChanged(IBinder token, boolean isInPipMode,
            Configuration overrideConfig) {
        final ActivityClientRecord r = mActivities.get(token);
        if (r != null) {
            r.activity.dispatchPictureInPictureModeChanged(isInPipMode);
            final Configuration newConfig = new Configuration(mConfiguration);
            if (overrideConfig != null) {
                newConfig.updateFrom(overrideConfig);
            }
            r.activity.dispatchPictureInPictureModeChanged(isInPipMode, newConfig);
        }
    }

Loading