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

Commit 000885e7 authored by Chong Zhang's avatar Chong Zhang Committed by Android (Google) Code Review
Browse files

Merge "Save window when an app died while it's visible"

parents c737c937 112eb8c1
Loading
Loading
Loading
Loading
+36 −23
Original line number Diff line number Diff line
@@ -1456,6 +1456,12 @@ final class ActivityStack {
                    }

                    if (r.app == null || r.app.thread == null) {
                        // We need to make sure the app is running if it's the top, or it is
                        // just made visible from invisible.
                        // If the app is already visible, it must have died while it was visible.
                        // In this case, we'll show the dead window but will not restart the app.
                        // Otherwise we could end up thrashing.
                        if (r == top || !r.visible) {
                            // This activity needs to be visible, but isn't even running...
                            // get it started and resume if no other stack in this stack is resumed.
                            if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
@@ -1478,7 +1484,7 @@ final class ActivityStack {
                                    noStackActivityResumed = false;
                                }
                            }

                        }
                    } else if (r.visible) {
                        // If this activity is already visible, then there is nothing
                        // else to do here.
@@ -3731,10 +3737,13 @@ final class ActivityStack {
                        // Don't currently have state for the activity, or
                        // it is finishing -- always remove it.
                        remove = true;
                    } else if (r.launchCount > 2 &&
                    } else if (!r.visible && r.launchCount > 2 &&
                            r.lastLaunchTime > (SystemClock.uptimeMillis() - 60000)) {
                        // We have launched this activity too many times since it was
                        // able to run, so give up and remove it.
                        // (Note if the activity is visible, we don't remove the record.
                        // We leave the dead window on the screen but the process will
                        // not be restarted unless user explicitly tap on it.)
                        remove = true;
                    } else {
                        // The process may be gone, but the activity lives on!
@@ -3764,7 +3773,11 @@ final class ActivityStack {
                        if (DEBUG_APP) Slog.v(TAG_APP,
                                "Clearing app during removeHistory for activity " + r);
                        r.app = null;
                        r.nowVisible = false;
                        // Set nowVisible to previous visible state. If the app was visible while
                        // it died, we leave the dead window on screen so it's basically visible.
                        // This is needed when user later tap on the dead window, we need to stop
                        // other apps when user transfers focus to the restarted activity.
                        r.nowVisible = r.visible;
                        if (!r.haveState) {
                            if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE,
                                    "App died, clearing saved state of " + r);
+9 −9
Original line number Diff line number Diff line
@@ -2886,24 +2886,24 @@ public final class ActivityStackSupervisor implements DisplayListener {
            return;
        }

        int stackId = task.stack.mStackId;
        if (task.mResizeable && options != null) {
            ActivityOptions opts = new ActivityOptions(options);
            if (opts.hasBounds()) {
                Rect bounds = opts.getBounds();
                task.updateOverrideConfiguration(bounds);
                mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig,
                        false /*relayout*/, false /*forced*/);
                stackId = task.getLaunchStackId();
            }
        }

                final int stackId = task.getLaunchStackId();
                if (stackId != task.stack.mStackId) {
                    moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, reason);

                    // moveTaskToStackUncheckedLocked() should already placed the task on top,
                    // still need moveTaskToFrontLocked() below for any transition settings.
                }
                // WM resizeTask must be done after the task is moved to the correct stack,
                // because Task's setBounds() also updates dim layer's bounds, but that has
                // dependency on the stack.
                mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig,
                        false /*relayout*/, false /*forced*/);
            }
        }

        final ActivityRecord r = task.getTopActivity();
        task.stack.moveTaskToFrontLocked(task, false /* noAnimation */, options,
+21 −0
Original line number Diff line number Diff line
@@ -102,6 +102,7 @@ class AppWindowToken extends WindowToken {
    // Set to true when the token has been removed from the window mgr.
    boolean removed;

    boolean appDied;
    // Information about an application starting window if displayed.
    StartingData startingData;
    WindowState startingWindow;
@@ -365,6 +366,26 @@ class AppWindowToken extends WindowToken {
        windows.clear();
    }

    void removeAllDeadWindows() {
        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0;
                // removeWindowLocked at bottom of loop may remove multiple entries from
                // allAppWindows if the window to be removed has child windows. It also may
                // not remove any windows from allAppWindows at all if win is exiting and
                // currently animating away. This ensures that winNdx is monotonically decreasing
                // and never beyond allAppWindows bounds.
                winNdx = Math.min(winNdx - 1, allAppWindows.size() - 1)) {
            WindowState win = allAppWindows.get(winNdx);
            if (win.mAppDied) {
                if (WindowManagerService.DEBUG_WINDOW_MOVEMENT) {
                    Slog.w(WindowManagerService.TAG, "removeAllDeadWindows: " + win);
                }
                // Set mDestroying, we don't want any animation or delayed removal here.
                win.mDestroying = true;
                service.removeWindowLocked(win);
            }
        }
    }

    @Override
    void dump(PrintWriter pw, String prefix) {
        super.dump(pw, prefix);
+59 −31
Original line number Diff line number Diff line
package com.android.server.wm;

import static com.android.server.wm.WindowManagerService.DEBUG_DIM_LAYER;
import static com.android.server.wm.WindowManagerService.LAYER_OFFSET_DIM;

import android.graphics.Rect;
import android.util.ArrayMap;
@@ -11,32 +12,38 @@ import java.io.PrintWriter;

/**
 * Centralizes the control of dim layers used for
 * {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND}.
 * {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND}
 * as well as other use cases (such as dimming above a dead window).
 */
class DimBehindController {
    private static final String TAG = "DimBehindController";
class DimLayerController {
    private static final String TAG = "DimLayerController";

    /** Amount of time in milliseconds to animate the dim surface from one value to another,
     * when no window animation is driving it. */
    private static final int DEFAULT_DIM_DURATION = 200;

    // Shared dim layer for fullscreen users. {@link DimBehindState#dimLayer} will point to this
    /**
     * The default amount of dim applied over a dead window
     */
    private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f;

    // Shared dim layer for fullscreen users. {@link DimLayerState#dimLayer} will point to this
    // instead of creating a new object per fullscreen task on a display.
    private DimLayer mSharedFullScreenDimLayer;

    private ArrayMap<DimLayer.DimLayerUser, DimBehindState> mState = new ArrayMap<>();
    private ArrayMap<DimLayer.DimLayerUser, DimLayerState> mState = new ArrayMap<>();

    private DisplayContent mDisplayContent;

    private Rect mTmpBounds = new Rect();

    DimBehindController(DisplayContent displayContent) {
    DimLayerController(DisplayContent displayContent) {
        mDisplayContent = displayContent;
    }

    /** Updates the dim layer bounds, recreating it if needed. */
    void updateDimLayer(DimLayer.DimLayerUser dimLayerUser) {
        DimBehindState state = getOrCreateDimBehindState(dimLayerUser);
        DimLayerState state = getOrCreateDimLayerState(dimLayerUser, false);
        final boolean previousFullscreen = state.dimLayer != null
                && state.dimLayer == mSharedFullScreenDimLayer;
        DimLayer newDimLayer;
@@ -72,19 +79,21 @@ class DimBehindController {
        state.dimLayer = newDimLayer;
    }

    private DimBehindState getOrCreateDimBehindState(DimLayer.DimLayerUser dimLayerUser) {
        if (DEBUG_DIM_LAYER) Slog.v(TAG, "getDimBehindState, dimLayerUser="
    private DimLayerState getOrCreateDimLayerState(
            DimLayer.DimLayerUser dimLayerUser, boolean aboveApp) {
        if (DEBUG_DIM_LAYER) Slog.v(TAG, "getOrCreateDimLayerState, dimLayerUser="
                + dimLayerUser.toShortString());
        DimBehindState state = mState.get(dimLayerUser);
        DimLayerState state = mState.get(dimLayerUser);
        if (state == null) {
            state = new DimBehindState();
            state = new DimLayerState();
            mState.put(dimLayerUser, state);
        }
        state.dimAbove = aboveApp;
        return state;
    }

    private void setContinueDimming(DimLayer.DimLayerUser dimLayerUser) {
        DimBehindState state = mState.get(dimLayerUser);
        DimLayerState state = mState.get(dimLayerUser);
        if (state == null) {
            if (DEBUG_DIM_LAYER) Slog.w(TAG, "setContinueDimming, no state for: "
                    + dimLayerUser.toShortString());
@@ -95,7 +104,7 @@ class DimBehindController {

    boolean isDimming() {
        for (int i = mState.size() - 1; i >= 0; i--) {
            DimBehindState state = mState.valueAt(i);
            DimLayerState state = mState.valueAt(i);
            if (state.dimLayer != null && state.dimLayer.isDimming()) {
                return true;
            }
@@ -110,15 +119,15 @@ class DimBehindController {
    }

    private boolean getContinueDimming(DimLayer.DimLayerUser dimLayerUser) {
        DimBehindState state = mState.get(dimLayerUser);
        DimLayerState state = mState.get(dimLayerUser);
        return state != null && state.continueDimming;
    }

    void startDimmingIfNeeded(DimLayer.DimLayerUser dimLayerUser,
            WindowStateAnimator newWinAnimator) {
            WindowStateAnimator newWinAnimator, boolean aboveApp) {
        // Only set dim params on the highest dimmed layer.
        // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer.
        DimBehindState state = getOrCreateDimBehindState(dimLayerUser);
        DimLayerState state = getOrCreateDimLayerState(dimLayerUser, aboveApp);
        if (DEBUG_DIM_LAYER) Slog.v(TAG, "startDimmingIfNeeded,"
                + " dimLayerUser=" + dimLayerUser.toShortString()
                + " newWinAnimator=" + newWinAnimator
@@ -145,7 +154,7 @@ class DimBehindController {

    private void stopDimmingIfNeeded(DimLayer.DimLayerUser dimLayerUser) {
        // No need to check if state is null, we know the key has a value.
        DimBehindState state = mState.get(dimLayerUser);
        DimLayerState state = mState.get(dimLayerUser);
        if (DEBUG_DIM_LAYER) Slog.v(TAG, "stopDimmingIfNeeded,"
                + " dimLayerUser=" + dimLayerUser.toShortString()
                + " state.continueDimming=" + state.continueDimming
@@ -188,7 +197,7 @@ class DimBehindController {
    }

    private boolean animateDimLayers(DimLayer.DimLayerUser dimLayerUser) {
        DimBehindState state = mState.get(dimLayerUser);
        DimLayerState state = mState.get(dimLayerUser);
        if (DEBUG_DIM_LAYER) Slog.v(TAG, "animateDimLayers,"
                + " dimLayerUser=" + dimLayerUser.toShortString()
                + " state.animator=" + state.animator
@@ -199,9 +208,14 @@ class DimBehindController {
            dimLayer = state.dimLayer.getLayer();
            dimAmount = 0;
        } else {
            dimLayer = state.animator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM;
            if (state.dimAbove) {
                dimLayer = state.animator.mAnimLayer + LAYER_OFFSET_DIM;
                dimAmount = DEFAULT_DIM_AMOUNT_DEAD_WINDOW;
            } else {
                dimLayer = state.animator.mAnimLayer - LAYER_OFFSET_DIM;
                dimAmount = state.animator.mWin.mAttrs.dimAmount;
            }
        }
        final float targetAlpha = state.dimLayer.getTargetAlpha();
        if (targetAlpha != dimAmount) {
            if (state.animator == null) {
@@ -211,7 +225,7 @@ class DimBehindController {
                        ? state.animator.mAnimation.computeDurationHint()
                        : DEFAULT_DIM_DURATION;
                if (targetAlpha > dimAmount) {
                    duration = getDimBehindFadeDuration(duration);
                    duration = getDimLayerFadeDuration(duration);
                }
                state.dimLayer.show(dimLayer, dimAmount, duration);
            }
@@ -230,11 +244,11 @@ class DimBehindController {
    }

    boolean isDimming(DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator winAnimator) {
        DimBehindState state = mState.get(dimLayerUser);
        DimLayerState state = mState.get(dimLayerUser);
        return state != null && state.animator == winAnimator && state.dimLayer.isDimming();
    }

    private long getDimBehindFadeDuration(long duration) {
    private long getDimLayerFadeDuration(long duration) {
        TypedValue tv = new TypedValue();
        mDisplayContent.mService.mContext.getResources().getValue(
                com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true);
@@ -248,7 +262,7 @@ class DimBehindController {

    void close() {
        for (int i = mState.size() - 1; i >= 0; i--) {
            DimBehindState state = mState.valueAt(i);
            DimLayerState state = mState.valueAt(i);
            state.dimLayer.destroySurface();
        }
        mState.clear();
@@ -256,10 +270,23 @@ class DimBehindController {
    }

    void removeDimLayerUser(DimLayer.DimLayerUser dimLayerUser) {
        DimLayerState state = mState.get(dimLayerUser);
        if (state != null) {
            state.dimLayer.destroySurface();
            mState.remove(dimLayerUser);
        }
    }

    void applyDimBehind(DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator animator) {
        applyDim(dimLayerUser, animator, false /* aboveApp */);
    }

    void applyDimAbove(DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator animator) {
        applyDim(dimLayerUser, animator, true /* aboveApp */);
    }

    private void applyDim(
            DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator animator, boolean aboveApp) {
        if (dimLayerUser == null) {
            Slog.e(TAG, "Trying to apply dim layer for: " + this
                    + ", but no dim layer user found.");
@@ -269,26 +296,27 @@ class DimBehindController {
            setContinueDimming(dimLayerUser);
            if (!isDimming(dimLayerUser, animator)) {
                if (DEBUG_DIM_LAYER) Slog.v(TAG, "Win " + this + " start dimming.");
                startDimmingIfNeeded(dimLayerUser, animator);
                startDimmingIfNeeded(dimLayerUser, animator, aboveApp);
            }
        }
    }

    private static class DimBehindState {
        // The particular window with FLAG_DIM_BEHIND set. If null, hide dimLayer.
    private static class DimLayerState {
        // The particular window requesting a dim layer. If null, hide dimLayer.
        WindowStateAnimator animator;
        // Set to false at the start of performLayoutAndPlaceSurfaces. If it is still false by the
        // end then stop any dimming.
        boolean continueDimming;
        DimLayer dimLayer;
        boolean dimAbove;
    }

    void dump(String prefix, PrintWriter pw) {
        pw.println(prefix + "DimBehindController");
        pw.println(prefix + "DimLayerController");
        for (int i = 0, n = mState.size(); i < n; i++) {
            pw.println(prefix + "  " + mState.keyAt(i).toShortString());
            pw.print(prefix + "    ");
            DimBehindState state = mState.valueAt(i);
            DimLayerState state = mState.valueAt(i);
            pw.print("dimLayer=" + (state.dimLayer == mSharedFullScreenDimLayer ? "shared" :
                    state.dimLayer));
            pw.print(", animator=" + state.animator);
+9 −9
Original line number Diff line number Diff line
@@ -116,7 +116,7 @@ class DisplayContent {

    final DockedStackDividerController mDividerControllerLocked;

    final DimBehindController mDimBehindController;
    final DimLayerController mDimLayerController;

    /**
     * @param display May not be null.
@@ -131,7 +131,7 @@ class DisplayContent {
        mService = service;
        initializeDisplayBaseInfo();
        mDividerControllerLocked = new DockedStackDividerController(service.mContext, this);
        mDimBehindController = new DimBehindController(this);
        mDimLayerController = new DimLayerController(this);
    }

    int getDisplayId() {
@@ -271,7 +271,7 @@ class DisplayContent {
    }

    void detachStack(TaskStack stack) {
        mDimBehindController.removeDimLayerUser(stack);
        mDimLayerController.removeDimLayerUser(stack);
        mStacks.remove(stack);
    }

@@ -415,23 +415,23 @@ class DisplayContent {
    }

    boolean animateDimLayers() {
        return mDimBehindController.animateDimLayers();
        return mDimLayerController.animateDimLayers();
    }

    void resetDimming() {
        mDimBehindController.resetDimming();
        mDimLayerController.resetDimming();
    }

    boolean isDimming() {
        return mDimBehindController.isDimming();
        return mDimLayerController.isDimming();
    }

    void stopDimmingIfNeeded() {
        mDimBehindController.stopDimmingIfNeeded();
        mDimLayerController.stopDimmingIfNeeded();
    }

    void close() {
        mDimBehindController.close();
        mDimLayerController.close();
        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
            mStacks.get(stackNdx).close();
        }
@@ -578,7 +578,7 @@ class DisplayContent {
            }
        }
        pw.println();
        mDimBehindController.dump(prefix + "  ", pw);
        mDimLayerController.dump(prefix + "  ", pw);
    }

    @Override
Loading