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

Commit 8997322e authored by Wale Ogunwale's avatar Wale Ogunwale
Browse files

Fixed transition animation from pipable activities

- Defer telling the client it is hidden if it can enter Pip and isn't
current stopped or stopping. This gives it a chance to enter Pip in
onPause().
- Once pause is complete set the visiblity to false to stop deferring
hiding client.
- Don't allow FLAG_RESUME_WHILE_PAUSING activity to resume until the
currently resumed activity is puased if the currently resumed activity
can enter Pip.
- Detach child surfaces added by the client process in
WindowState.sendAppVisibilityToClients() right before we notify the
client.

Test: manual
Change-Id: I3848f2b93f4f1d3ceec5a1ccd2e127c614f70fe4
Fixes: 37370508
Fixes: 37622341
parent 5c0f27a2
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -1568,17 +1568,21 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
    }

    void setVisibility(boolean visible) {
        mWindowContainerController.setVisibility(visible);
        mWindowContainerController.setVisibility(visible, false /* deferHidingClient */);
    }

    // TODO: Look into merging with #setVisibility()
    void setVisible(boolean newVisible) {
        setVisible(newVisible, false /* deferHidingClient */);
    }

    // TODO: Look into merging with #setVisibility()
    void setVisible(boolean newVisible, boolean deferHidingClient) {
        visible = newVisible;
        if (!visible && mUpdateTaskThumbnailWhenHidden) {
            updateThumbnailLocked(screenshotActivityLocked(), null /* description */);
            mUpdateTaskThumbnailWhenHidden = false;
        }
        mWindowContainerController.setVisibility(visible);
        mWindowContainerController.setVisibility(visible, deferHidingClient);
        final ArrayList<ActivityContainer> containers = mChildContainers;
        for (int containerNdx = containers.size() - 1; containerNdx >= 0; --containerNdx) {
            final ActivityContainer container = containers.get(containerNdx);
+20 −25
Original line number Diff line number Diff line
@@ -1402,7 +1402,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
                } else if ((!prev.visible && !hasVisibleBehindActivity())
                        || mService.isSleepingOrShuttingDownLocked()) {
                    // If we were visible then resumeTopActivities will release resources before
                    // stopping.
                    // stopping. Also, set visibility to false to flush any client hide that might have
                    // been deferred.
                    prev.setVisibility(false);
                    addToStopping(prev, true /* scheduleIdle */, false /* idleDelayed */);
                }
            } else {
@@ -2019,11 +2021,11 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        try {
            final boolean canEnterPictureInPicture = r.checkEnterPictureInPictureState(
                    "makeInvisible", true /* noThrow */, true /* beforeStopping */);
            // We don't want to call setVisible(false) to avoid notifying the client of this
            // intermittent invisible state if it can enter Pip and isn't stopped or stopping.
            if (!canEnterPictureInPicture || r.state == STOPPING || r.state == STOPPED) {
                r.setVisible(false);
            }
            // Defer telling the client it is hidden if it can enter Pip and isn't current stopped
            // or stopping. This gives it a chance to enter Pip in onPause().
            final boolean deferHidingClient = canEnterPictureInPicture
                    && r.state != STOPPING && r.state != STOPPED;
            r.setVisible(false, deferHidingClient);

            switch (r.state) {
                case STOPPING:
@@ -2048,15 +2050,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
                    if (visibleBehind == r) {
                        releaseBackgroundResources(r);
                    } else {
                        // If this activity is in a state where it can currently enter
                        // picture-in-picture, then don't immediately schedule the idle now in case
                        // the activity tries to enterPictureInPictureMode() later. Otherwise,
                        // we will try and stop the activity next time idle is processed.

                        if (canEnterPictureInPicture) {
                            // We set r.visible=false so that Stop will later call setVisible for us
                            r.visible = false;
                        }
                        addToStopping(r, true /* scheduleIdle */,
                                canEnterPictureInPicture /* idleDelayed */);
                    }
@@ -2338,20 +2331,22 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai

        mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid);

        final boolean prevCanPip = prev != null && prev.checkEnterPictureInPictureState(
        boolean lastResumedCanPip = false;
        final ActivityStack lastFocusedStack = mStackSupervisor.getLastStack();
        if (lastFocusedStack != null && lastFocusedStack != this) {
            // So, why aren't we using prev here??? See the param comment on the method. prev doesn't
            // represent the last resumed activity. However, the last focus stack does if it isn't null.
            final ActivityRecord lastResumed = lastFocusedStack.mResumedActivity;
            lastResumedCanPip = lastResumed != null && lastResumed.checkEnterPictureInPictureState(
                    "resumeTopActivity", true /* noThrow */, userLeaving /* beforeStopping */);
        }
        // If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous activity
        // to be paused, while at the same time resuming the new resume activity only if the
        // previous activity can't go into Pip since we want to give Pip activities a chance to
        // enter Pip before resuming the next activity.
        final boolean resumeWhilePausing = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
        // TODO: This would be go to have however, the various call points that pass in
        // prev need to be corrected first. In some cases the prev is equal to the next e.g. launch
        // an app from home. And, is come other cases it is null e.g. press home button after
        // launching an app. The doc on the method says prev. is null expect for the case we are
        // coming from pause. We need to see if that is a valid thing and also if all the code in
        // this method using prev. are setup to function like that.
        //&& !prevCanPip;
        final boolean resumeWhilePausing = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0
                && !lastResumedCanPip;

        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false);
        if (mResumedActivity != null) {
            if (DEBUG_STATES) Slog.d(TAG_STATES,
+8 −10
Original line number Diff line number Diff line
@@ -323,7 +323,7 @@ public class AppWindowContainerController
        }
    }

    public void setVisibility(boolean visible) {
    public void setVisibility(boolean visible, boolean deferHidingClient) {
        synchronized(mWindowMap) {
            if (mContainer == null) {
                Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
@@ -342,6 +342,7 @@ public class AppWindowContainerController
            mService.mClosingApps.remove(wtoken);
            wtoken.waitingToShow = false;
            wtoken.hiddenRequested = !visible;
            wtoken.mDeferHidingClient = deferHidingClient;

            if (!visible) {
                // If the app is dead while it was visible, we kept its dead window on screen.
@@ -368,15 +369,12 @@ public class AppWindowContainerController
                        wtoken.waitingToShow = true;
                    }

                    if (wtoken.clientHidden) {
                        // In the case where we are making an app visible
                        // but holding off for a transition, we still need
                        // to tell the client to make its windows visible so
                        // they get drawn.  Otherwise, we will wait on
                        // performing the transition until all windows have
                        // been drawn, they never will be, and we are sad.
                        wtoken.clientHidden = false;
                        wtoken.sendAppVisibilityToClients();
                    if (wtoken.isClientHidden()) {
                        // In the case where we are making an app visible but holding off for a
                        // transition, we still need to tell the client to make its windows visible
                        // so they get drawn. Otherwise, we will wait on performing the transition
                        // until all windows have been drawn, they never will be, and we are sad.
                        wtoken.setClientHidden(false);
                    }
                }
                wtoken.requestUpdateWallpaperIfNeeded();
+22 −13
Original line number Diff line number Diff line
@@ -126,7 +126,11 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
    boolean hiddenRequested;

    // Have we told the window clients to hide themselves?
    boolean clientHidden;
    private boolean mClientHidden;

    // If true we will defer setting mClientHidden to true and reporting to the client that it is
    // hidden.
    boolean mDeferHidingClient;

    // Last visibility state we reported to the app token.
    boolean reportedVisible;
@@ -307,16 +311,25 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
        }
    }

    boolean isClientHidden() {
        return mClientHidden;
    }

    void setClientHidden(boolean hideClient) {
        if (mClientHidden == hideClient || (hideClient && mDeferHidingClient)) {
            return;
        }
        mClientHidden = hideClient;
        sendAppVisibilityToClients();
    }

    boolean setVisibility(WindowManager.LayoutParams lp,
            boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) {

        boolean delayed = false;
        inPendingTransaction = false;

        if (clientHidden == visible) {
            clientHidden = !visible;
            sendAppVisibilityToClients();
        }
        setClientHidden(!visible);

        // Allow for state changes and animation to be applied if:
        // * token is transitioning visibility state
@@ -1143,10 +1156,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
                hidden = false;
                hiddenRequested = false;
            }
            if (clientHidden != fromToken.clientHidden) {
                clientHidden = fromToken.clientHidden;
                sendAppVisibilityToClients();
            }
            setClientHidden(fromToken.mClientHidden);
            fromToken.mAppAnimator.transferCurrentAnimation(
                    mAppAnimator, tStartingWindow.mWinAnimator);

@@ -1511,10 +1521,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
        pw.print(prefix); pw.print("task="); pw.println(getTask());
        pw.print(prefix); pw.print(" mFillsParent="); pw.print(mFillsParent);
                pw.print(" mOrientation="); pw.println(mOrientation);
        pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested);
                pw.print(" clientHidden="); pw.print(clientHidden);
                pw.print(" reportedDrawn="); pw.print(reportedDrawn);
                pw.print(" reportedVisible="); pw.println(reportedVisible);
        pw.println(prefix + "hiddenRequested=" + hiddenRequested + " mClientHidden=" + mClientHidden
            + ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "")
            + " reportedDrawn=" + reportedDrawn + " reportedVisible=" + reportedVisible);
        if (paused) {
            pw.print(prefix); pw.print("paused="); pw.println(paused);
        }
+1 −1
Original line number Diff line number Diff line
@@ -2245,7 +2245,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
                wsa.destroySurface();
                mService.mForceRemoves.add(w);
                mTmpWindow = w;
            } else if (w.mAppToken != null && w.mAppToken.clientHidden) {
            } else if (w.mAppToken != null && w.mAppToken.isClientHidden()) {
                Slog.w(TAG_WM, "LEAKED SURFACE (app token hidden): "
                        + w + " surface=" + wsa.mSurfaceController
                        + " token=" + w.mAppToken
Loading