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

Commit aea6b74e authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

Handle case when snapshot dimensions don't match

If the snapshot starting window has different dimensions than the
snapshots we have taken, we do the following:

- Create a child Surface that has exactly the dimensions of the
snapshot.
- We fill the parent surface with the app background color, as well
as all screen background decorations (status bar background,
navigation bar background).
- We also clip of the status bar/navigation bar background in some
cases, as it looks ugly if it's not behind the system bars.
- Furthermore, we inherit all layout flags on the window and all
layout relevant SystemUI flags on the window such that it's very
likely that the size will match, and the system bars are drawn
correctly.
- In order to make the transition from the snapshot to the real
window a bit more predictable/less messy, we enforce a minimum
duration the snapshot is visible, which is slightly more than our
app transitions.

Test: TaskSnapshotSurfaceTest
Test: Open app, go home, go landscape, open app again
Test: Go to multi-window, open app from recents with a snapshot
taken in fullscreen.

Fixes: 36703868
Change-Id: Ia2d4add6971a18ab7aa2942d2b644d6e87a402af
parent 91232840
Loading
Loading
Loading
Loading
+18 −7
Original line number Diff line number Diff line
@@ -4116,14 +4116,25 @@ public class Activity extends ContextThemeWrapper
                mTaskDescription.setPrimaryColor(colorPrimary);
            }
        }
        // For dev-preview only.
        if (mTaskDescription.getBackgroundColor() == 0) {

        int colorBackground = a.getColor(
                com.android.internal.R.styleable.ActivityTaskDescription_colorBackground, 0);
        if (colorBackground != 0 && Color.alpha(colorBackground) == 0xFF) {
            mTaskDescription.setBackgroundColor(colorBackground);
        }

        final int statusBarColor = a.getColor(
                com.android.internal.R.styleable.ActivityTaskDescription_statusBarColor, 0);
        if (statusBarColor != 0) {
            mTaskDescription.setStatusBarColor(statusBarColor);
        }

        final int navigationBarColor = a.getColor(
                com.android.internal.R.styleable.ActivityTaskDescription_navigationBarColor, 0);
        if (navigationBarColor != 0) {
            mTaskDescription.setNavigationBarColor(navigationBarColor);
        }

        a.recycle();
        setTaskDescription(mTaskDescription);
    }
+46 −6
Original line number Diff line number Diff line
@@ -1145,6 +1145,8 @@ public class ActivityManager {
        private String mIconFilename;
        private int mColorPrimary;
        private int mColorBackground;
        private int mStatusBarColor;
        private int mNavigationBarColor;

        /**
         * Creates the TaskDescription to the specified values.
@@ -1155,7 +1157,7 @@ public class ActivityManager {
         *                     opaque.
         */
        public TaskDescription(String label, Bitmap icon, int colorPrimary) {
            this(label, icon, null, colorPrimary, 0);
            this(label, icon, null, colorPrimary, 0, 0, 0);
            if ((colorPrimary != 0) && (Color.alpha(colorPrimary) != 255)) {
                throw new RuntimeException("A TaskDescription's primary color should be opaque");
            }
@@ -1168,7 +1170,7 @@ public class ActivityManager {
         * @param icon An icon that represents the current state of this activity.
         */
        public TaskDescription(String label, Bitmap icon) {
            this(label, icon, null, 0, 0);
            this(label, icon, null, 0, 0, 0, 0);
        }

        /**
@@ -1177,24 +1179,26 @@ public class ActivityManager {
         * @param label A label and description of the current state of this activity.
         */
        public TaskDescription(String label) {
            this(label, null, null, 0, 0);
            this(label, null, null, 0, 0, 0, 0);
        }

        /**
         * Creates an empty TaskDescription.
         */
        public TaskDescription() {
            this(null, null, null, 0, 0);
            this(null, null, null, 0, 0, 0, 0);
        }

        /** @hide */
        public TaskDescription(String label, Bitmap icon, String iconFilename, int colorPrimary,
                int colorBackground) {
                int colorBackground, int statusBarColor, int navigationBarColor) {
            mLabel = label;
            mIcon = icon;
            mIconFilename = iconFilename;
            mColorPrimary = colorPrimary;
            mColorBackground = colorBackground;
            mStatusBarColor = statusBarColor;
            mNavigationBarColor = navigationBarColor;
        }

        /**
@@ -1214,6 +1218,8 @@ public class ActivityManager {
            mIconFilename = other.mIconFilename;
            mColorPrimary = other.mColorPrimary;
            mColorBackground = other.mColorBackground;
            mStatusBarColor = other.mStatusBarColor;
            mNavigationBarColor = other.mNavigationBarColor;
        }

        private TaskDescription(Parcel source) {
@@ -1252,6 +1258,20 @@ public class ActivityManager {
            mColorBackground = backgroundColor;
        }

        /**
         * @hide
         */
        public void setStatusBarColor(int statusBarColor) {
            mStatusBarColor = statusBarColor;
        }

        /**
         * @hide
         */
        public void setNavigationBarColor(int navigationBarColor) {
            mNavigationBarColor = navigationBarColor;
        }

        /**
         * Sets the icon for this task description.
         * @hide
@@ -1325,6 +1345,20 @@ public class ActivityManager {
            return mColorBackground;
        }

        /**
         * @hide
         */
        public int getStatusBarColor() {
            return mStatusBarColor;
        }

        /**
         * @hide
         */
        public int getNavigationBarColor() {
            return mNavigationBarColor;
        }

        /** @hide */
        public void saveToXml(XmlSerializer out) throws IOException {
            if (mLabel != null) {
@@ -1377,6 +1411,8 @@ public class ActivityManager {
            }
            dest.writeInt(mColorPrimary);
            dest.writeInt(mColorBackground);
            dest.writeInt(mStatusBarColor);
            dest.writeInt(mNavigationBarColor);
            if (mIconFilename == null) {
                dest.writeInt(0);
            } else {
@@ -1390,6 +1426,8 @@ public class ActivityManager {
            mIcon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null;
            mColorPrimary = source.readInt();
            mColorBackground = source.readInt();
            mStatusBarColor = source.readInt();
            mNavigationBarColor = source.readInt();
            mIconFilename = source.readInt() > 0 ? source.readString() : null;
        }

@@ -1407,7 +1445,9 @@ public class ActivityManager {
        public String toString() {
            return "TaskDescription Label: " + mLabel + " Icon: " + mIcon +
                    " IconFilename: " + mIconFilename + " colorPrimary: " + mColorPrimary +
                    " colorBackground: " + mColorBackground;
                    " colorBackground: " + mColorBackground +
                    " statusBarColor: " + mColorBackground +
                    " navigationBarColor: " + mNavigationBarColor;
        }
    }

+3 −14
Original line number Diff line number Diff line
@@ -74,6 +74,7 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
    private final Rect mOldStableInsets = new Rect();
    private final Rect mSystemInsets = new Rect();
    private final Rect mStableInsets = new Rect();
    private final Rect mTmpRect = new Rect();

    public BackdropFrameRenderer(DecorView decorView, ThreadedRenderer renderer, Rect initialBounds,
            Drawable resizingBackgroundDrawable, Drawable captionBackgroundDrawable,
@@ -370,12 +371,6 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
        DisplayListCanvas canvas = mSystemBarBackgroundNode.start(width, height);
        mSystemBarBackgroundNode.setLeftTopRightBottom(left, top, left + width, top + height);
        final int topInset = DecorView.getColorViewTopInset(mStableInsets.top, mSystemInsets.top);
        final int bottomInset = DecorView.getColorViewBottomInset(stableInsets.bottom,
                systemInsets.bottom);
        final int rightInset = DecorView.getColorViewRightInset(stableInsets.right,
                systemInsets.right);
        final int leftInset = DecorView.getColorViewLeftInset(stableInsets.left,
                systemInsets.left);
        if (mStatusBarColor != null) {
            mStatusBarColor.setBounds(0, 0, left + width, topInset);
            mStatusBarColor.draw(canvas);
@@ -385,14 +380,8 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
        // don't want the navigation bar background be moving around when resizing in docked mode.
        // However, we need it for the transitions into/out of docked mode.
        if (mNavigationBarColor != null && fullscreen) {
            final int size = DecorView.getNavBarSize(bottomInset, rightInset, leftInset);
            if (DecorView.isNavBarToRightEdge(bottomInset, rightInset)) {
                mNavigationBarColor.setBounds(width - size, 0, width, height);
            } else if (DecorView.isNavBarToLeftEdge(bottomInset, leftInset)) {
                mNavigationBarColor.setBounds(0, 0, size, height);
            } else {
                mNavigationBarColor.setBounds(0, height - size, width, height);
            }
            DecorView.getNavigationBarRect(width, height, stableInsets, systemInsets, mTmpRect);
            mNavigationBarColor.setBounds(mTmpRect);
            mNavigationBarColor.draw(canvas);
        }
        mSystemBarBackgroundNode.end(canvas);
+86 −36
Original line number Diff line number Diff line
@@ -119,6 +119,21 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
    // The height of a window which has not in DIP.
    private final static int DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP = 5;

    public static final ColorViewAttributes STATUS_BAR_COLOR_VIEW_ATTRIBUTES =
            new ColorViewAttributes(SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
                    Gravity.TOP, Gravity.LEFT, Gravity.RIGHT,
                    Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME,
                    com.android.internal.R.id.statusBarBackground,
                    FLAG_FULLSCREEN);

    public static final ColorViewAttributes NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES =
            new ColorViewAttributes(
                    SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION,
                    Gravity.BOTTOM, Gravity.RIGHT, Gravity.LEFT,
                    Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME,
                    com.android.internal.R.id.navigationBarBackground,
                    0 /* hideWindowFlag */);

    // Cludge to address b/22668382: Set the shadow size to the maximum so that the layer
    // size calculation takes the shadow size into account. We set the elevation currently
    // to max until the first layout command has been executed.
@@ -162,18 +177,10 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
    // View added at runtime to draw under the navigation bar area
    private View mNavigationGuard;

    private final ColorViewState mStatusColorViewState = new ColorViewState(
            SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
            Gravity.TOP, Gravity.LEFT, Gravity.RIGHT,
            Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME,
            com.android.internal.R.id.statusBarBackground,
            FLAG_FULLSCREEN);
    private final ColorViewState mNavigationColorViewState = new ColorViewState(
            SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION,
            Gravity.BOTTOM, Gravity.RIGHT, Gravity.LEFT,
            Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME,
            com.android.internal.R.id.navigationBarBackground,
            0 /* hideWindowFlag */);
    private final ColorViewState mStatusColorViewState =
            new ColorViewState(STATUS_BAR_COLOR_VIEW_ATTRIBUTES);
    private final ColorViewState mNavigationColorViewState =
            new ColorViewState(NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES);

    private final Interpolator mShowInterpolator;
    private final Interpolator mHideInterpolator;
@@ -983,35 +990,50 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
        return false;
    }

    static int getColorViewTopInset(int stableTop, int systemTop) {
    public static int getColorViewTopInset(int stableTop, int systemTop) {
        return Math.min(stableTop, systemTop);
    }

    static int getColorViewBottomInset(int stableBottom, int systemBottom) {
    public static int getColorViewBottomInset(int stableBottom, int systemBottom) {
        return Math.min(stableBottom, systemBottom);
    }

    static int getColorViewRightInset(int stableRight, int systemRight) {
    public static int getColorViewRightInset(int stableRight, int systemRight) {
        return Math.min(stableRight, systemRight);
    }

    static int getColorViewLeftInset(int stableLeft, int systemLeft) {
    public static int getColorViewLeftInset(int stableLeft, int systemLeft) {
        return Math.min(stableLeft, systemLeft);
    }

    static boolean isNavBarToRightEdge(int bottomInset, int rightInset) {
    public static boolean isNavBarToRightEdge(int bottomInset, int rightInset) {
        return bottomInset == 0 && rightInset > 0;
    }

    static boolean isNavBarToLeftEdge(int bottomInset, int leftInset) {
    public static boolean isNavBarToLeftEdge(int bottomInset, int leftInset) {
        return bottomInset == 0 && leftInset > 0;
    }

    static int getNavBarSize(int bottomInset, int rightInset, int leftInset) {
    public static int getNavBarSize(int bottomInset, int rightInset, int leftInset) {
        return isNavBarToRightEdge(bottomInset, rightInset) ? rightInset
                : isNavBarToLeftEdge(bottomInset, leftInset) ? leftInset : bottomInset;
    }

    public static void getNavigationBarRect(int canvasWidth, int canvasHeight, Rect stableInsets,
            Rect contentInsets, Rect outRect) {
        final int bottomInset = getColorViewBottomInset(stableInsets.bottom, contentInsets.bottom);
        final int leftInset = getColorViewLeftInset(stableInsets.left, contentInsets.left);
        final int rightInset = getColorViewLeftInset(stableInsets.right, contentInsets.right);
        final int size = getNavBarSize(bottomInset, rightInset, leftInset);
        if (isNavBarToRightEdge(bottomInset, rightInset)) {
            outRect.set(canvasWidth - size, 0, canvasWidth, canvasHeight);
        } else if (isNavBarToLeftEdge(bottomInset, leftInset)) {
            outRect.set(0, 0, size, canvasHeight);
        } else {
            outRect.set(0, canvasHeight - size, canvasWidth, canvasHeight);
        }
    }

    WindowInsets updateColorViews(WindowInsets insets, boolean animate) {
        WindowManager.LayoutParams attrs = mWindow.getAttributes();
        int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility();
@@ -1131,9 +1153,14 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
    }

    private int calculateStatusBarColor() {
        int flags = mWindow.getAttributes().flags;
        return (flags & FLAG_TRANSLUCENT_STATUS) != 0 ? mSemiTransparentStatusBarColor
                : (flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 ? mWindow.mStatusBarColor
        return calculateStatusBarColor(mWindow.getAttributes().flags,
                mSemiTransparentStatusBarColor, mWindow.mStatusBarColor);
    }

    public static int calculateStatusBarColor(int flags, int semiTransparentStatusBarColor,
            int statusBarColor) {
        return (flags & FLAG_TRANSLUCENT_STATUS) != 0 ? semiTransparentStatusBarColor
                : (flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 ? statusBarColor
                : Color.BLACK;
    }

@@ -1160,13 +1187,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
    private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color,
            int size, boolean verticalBar, boolean seascape, int sideMargin,
            boolean animate, boolean force) {
        state.present = (sysUiVis & state.systemUiHideFlag) == 0
                && (mWindow.getAttributes().flags & state.hideWindowFlag) == 0
                && ((mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
                        || force);
        boolean show = state.present
                && (color & Color.BLACK) != 0
                && ((mWindow.getAttributes().flags & state.translucentFlag) == 0  || force);
        state.present = state.attributes.isPresent(sysUiVis, mWindow.getAttributes().flags, force);
        boolean show = state.attributes.isVisible(state.present, color,
                mWindow.getAttributes().flags, force);
        boolean showView = show && !isResizing() && size > 0;

        boolean visibilityChanged = false;
@@ -1175,15 +1198,15 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
        int resolvedHeight = verticalBar ? LayoutParams.MATCH_PARENT : size;
        int resolvedWidth = verticalBar ? size : LayoutParams.MATCH_PARENT;
        int resolvedGravity = verticalBar
                ? (seascape ? state.seascapeGravity : state.horizontalGravity)
                : state.verticalGravity;
                ? (seascape ? state.attributes.seascapeGravity : state.attributes.horizontalGravity)
                : state.attributes.verticalGravity;

        if (view == null) {
            if (showView) {
                state.view = view = new View(mContext);
                view.setBackgroundColor(color);
                view.setTransitionName(state.transitionName);
                view.setId(state.id);
                view.setTransitionName(state.attributes.transitionName);
                view.setId(state.attributes.id);
                visibilityChanged = true;
                view.setVisibility(INVISIBLE);
                state.targetVisibility = VISIBLE;
@@ -2269,6 +2292,15 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
        boolean visible;
        int color;

        final ColorViewAttributes attributes;

        ColorViewState(ColorViewAttributes attributes) {
            this.attributes = attributes;
        }
    }

    public static class ColorViewAttributes {

        final int id;
        final int systemUiHideFlag;
        final int translucentFlag;
@@ -2278,9 +2310,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
        final String transitionName;
        final int hideWindowFlag;

        ColorViewState(int systemUiHideFlag,
                int translucentFlag, int verticalGravity, int horizontalGravity,
                int seascapeGravity, String transitionName, int id, int hideWindowFlag) {
        private ColorViewAttributes(int systemUiHideFlag, int translucentFlag, int verticalGravity,
                int horizontalGravity, int seascapeGravity, String transitionName, int id,
                int hideWindowFlag) {
            this.id = id;
            this.systemUiHideFlag = systemUiHideFlag;
            this.translucentFlag = translucentFlag;
@@ -2290,6 +2322,24 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
            this.transitionName = transitionName;
            this.hideWindowFlag = hideWindowFlag;
        }

        public boolean isPresent(int sysUiVis, int windowFlags, boolean force) {
            return (sysUiVis & systemUiHideFlag) == 0
                    && (windowFlags & hideWindowFlag) == 0
                    && ((windowFlags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
                    || force);
        }

        public boolean isVisible(boolean present, int color, int windowFlags, boolean force) {
            return present
                    && (color & Color.BLACK) != 0
                    && ((windowFlags & translucentFlag) == 0  || force);
        }

        public boolean isVisible(int sysUiVis, int color, int windowFlags, boolean force) {
            final boolean present = isPresent(sysUiVis, windowFlags, force);
            return isVisible(present, color, windowFlags, force);
        }
    }

    /**
+5 −0
Original line number Diff line number Diff line
@@ -8566,6 +8566,11 @@
        <!-- @hide From Theme.colorBackground, used for the TaskDescription background
                   color. -->
        <attr name="colorBackground" />
        <!-- @hide From Theme.statusBarColor, used for the TaskDescription status bar color. -->
        <attr name="statusBarColor"/>
        <!-- @hide From Theme.navigationBarColor, used for the TaskDescription navigation bar
                   color. -->
        <attr name="navigationBarColor"/>
    </declare-styleable>

    <declare-styleable name="Shortcut">
Loading