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

Commit 07126b4e authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "WM: correctly draw the rounded corner / cutout overlay during rotation"

parents 41dcc4ea 83537a70
Loading
Loading
Loading
Loading
+52 −5
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ import android.view.View;
import android.view.View.OnLayoutChangeListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -97,6 +98,7 @@ public class ScreenDecorations extends SystemUI implements Tunable {
    private DisplayCutoutView mCutoutTop;
    private DisplayCutoutView mCutoutBottom;
    private SecureSetting mColorInversionSetting;
    private boolean mPendingRotationChange;

    @Override
    public void start() {
@@ -130,6 +132,21 @@ public class ScreenDecorations extends SystemUI implements Tunable {

            @Override
            public void onDisplayChanged(int displayId) {
                if ((hasRoundedCorners() || shouldDrawCutout()) &&
                        mRotation != RotationUtils.getExactRotation(mContext)) {
                    // We cannot immediately update the orientation. Otherwise
                    // WindowManager is still deferring layout until it has finished dispatching
                    // the config changes, which may cause divergence between what we draw
                    // (new orientation), and where we are placed on the screen (old orientation).
                    // Instead we wait until either:
                    // - we are trying to redraw. This because WM resized our window and told us to.
                    // - the config change has been dispatched, so WM is no longer deferring layout.
                    mPendingRotationChange = true;
                    mOverlay.getViewTreeObserver().addOnPreDrawListener(
                            new RestartingPreDrawListener(mOverlay));
                    mBottomOverlay.getViewTreeObserver().addOnPreDrawListener(
                            new RestartingPreDrawListener(mBottomOverlay));
                }
                updateOrientation();
            }
        };
@@ -144,12 +161,12 @@ public class ScreenDecorations extends SystemUI implements Tunable {
        mOverlay = LayoutInflater.from(mContext)
                .inflate(R.layout.rounded_corners, null);
        mCutoutTop = new DisplayCutoutView(mContext, true,
                this::updateWindowVisibilities);
                this::updateWindowVisibilities, this);
        ((ViewGroup)mOverlay).addView(mCutoutTop);
        mBottomOverlay = LayoutInflater.from(mContext)
                .inflate(R.layout.rounded_corners, null);
        mCutoutBottom = new DisplayCutoutView(mContext, false,
                this::updateWindowVisibilities);
                this::updateWindowVisibilities, this);
        ((ViewGroup)mBottomOverlay).addView(mCutoutBottom);

        mOverlay.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
@@ -229,6 +246,7 @@ public class ScreenDecorations extends SystemUI implements Tunable {

    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        mPendingRotationChange = false;
        updateOrientation();
        if (shouldDrawCutout() && mOverlay == null) {
            setupDecorations();
@@ -236,6 +254,9 @@ public class ScreenDecorations extends SystemUI implements Tunable {
    }

    protected void updateOrientation() {
        if (mPendingRotationChange) {
            return;
        }
        int newRotation = RotationUtils.getExactRotation(mContext);
        if (newRotation != mRotation) {
            mRotation = newRotation;
@@ -451,15 +472,17 @@ public class ScreenDecorations extends SystemUI implements Tunable {
        private final int[] mLocation = new int[2];
        private final boolean mInitialStart;
        private final Runnable mVisibilityChangedListener;
        private final ScreenDecorations mDecorations;
        private int mColor = Color.BLACK;
        private boolean mStart;
        private int mRotation;

        public DisplayCutoutView(Context context, boolean start,
                Runnable visibilityChangedListener) {
                Runnable visibilityChangedListener, ScreenDecorations decorations) {
            super(context);
            mInitialStart = start;
            mVisibilityChangedListener = visibilityChangedListener;
            mDecorations = decorations;
            setId(R.id.display_cutout);
        }

@@ -522,10 +545,10 @@ public class ScreenDecorations extends SystemUI implements Tunable {
        }

        private void update() {
            mStart = isStart();
            if (!isAttachedToWindow()) {
            if (!isAttachedToWindow() || mDecorations.mPendingRotationChange) {
                return;
            }
            mStart = isStart();
            requestLayout();
            getDisplay().getDisplayInfo(mInfo);
            mBounds.setEmpty();
@@ -688,4 +711,28 @@ public class ScreenDecorations extends SystemUI implements Tunable {
        return rotation == RotationUtils.ROTATION_LANDSCAPE || rotation ==
                RotationUtils.ROTATION_SEASCAPE;
    }

    /**
     * A pre-draw listener, that cancels the draw and restarts the traversal with the updated
     * window attributes.
     */
    private class RestartingPreDrawListener implements ViewTreeObserver.OnPreDrawListener {

        private final View mView;

        private RestartingPreDrawListener(View view) {
            mView = view;
        }

        @Override
        public boolean onPreDraw() {
            mPendingRotationChange = false;
            mView.getViewTreeObserver().removeOnPreDrawListener(this);
            // This changes the window attributes - we need to restart the traversal for them to
            // take effect.
            updateOrientation();
            mView.invalidate();
            return false;
        }
    }
}
+2 −1
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import android.view.SurfaceSession;
import libcore.io.Streams;

import com.android.server.LocalServices;
import com.android.server.policy.WindowManagerPolicy;

/**
 * <p>
@@ -63,7 +64,7 @@ final class ColorFade {

    // The layer for the electron beam surface.
    // This is currently hardcoded to be one layer above the boot animation.
    private static final int COLOR_FADE_LAYER = 0x40000001;
    private static final int COLOR_FADE_LAYER = WindowManagerPolicy.COLOR_FADE_LAYER;

    // The number of frames to draw when preparing the animation so that it will
    // be ready to run smoothly.  We use 3 frames because we are triple-buffered.
+2 −0
Original line number Diff line number Diff line
@@ -157,6 +157,8 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
    int FINISH_LAYOUT_REDO_WALLPAPER = 0x0004;
    /** Need to recompute animations */
    int FINISH_LAYOUT_REDO_ANIM = 0x0008;
    /** Layer for the screen off animation */
    int COLOR_FADE_LAYER = 0x40000001;

    /**
     * Register shortcuts for window manager to dispatch.
+22 −0
Original line number Diff line number Diff line
@@ -1136,6 +1136,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
            }
        }

        forAllWindows(w -> {
            w.forceSeamlesslyRotateIfAllowed(oldRotation, rotation);
        }, true /* traverseTopToBottom */);

        // TODO(b/111504081): Consolidate seamless rotation logic.
        if (rotateSeamlessly) {
            seamlesslyRotate(getPendingTransaction(), oldRotation, rotation);
        }
@@ -3766,6 +3771,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
            super(name, service);
        }

        @Override
        SurfaceControl.Builder makeChildSurface(WindowContainer child) {
            final SurfaceControl.Builder builder = super.makeChildSurface(child);
            if (child instanceof WindowToken && ((WindowToken) child).mRoundedCornerOverlay) {
                // To draw above the ColorFade layer during the screen off transition, the
                // rounded corner overlays need to be at the root of the surface hierarchy.
                // TODO: move the ColorLayer into the display overlay layer such that this is not
                // necessary anymore.
                builder.setParent(null);
            }
            return builder;
        }

        @Override
        void assignChildLayers(SurfaceControl.Transaction t) {
            assignChildLayers(t, null /* imeContainer */);
@@ -3782,6 +3800,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
                    wt.assignRelativeLayer(t, mTaskStackContainers.getSplitScreenDividerAnchor(), 1);
                    continue;
                }
                if (wt.mRoundedCornerOverlay) {
                    wt.assignLayer(t, WindowManagerPolicy.COLOR_FADE_LAYER + 1);
                    continue;
                }
                wt.assignLayer(t, j);
                wt.assignChildLayers(t);

+78 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.wm;

import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;

import android.graphics.Matrix;
import android.view.DisplayInfo;

import com.android.server.wm.utils.CoordinateTransforms;

/**
 * Helper class for forced seamless rotation.
 *
 * Works by transforming the window token back into the old display rotation.
 *
 * Uses deferTransactionUntil instead of latching on the buffer size to allow for seamless 180
 * degree rotations.
 * TODO(b/111504081): Consolidate seamless rotation logic.
 */
public class ForcedSeamlessRotator {

    private final Matrix mTransform = new Matrix();
    private final float[] mFloat9 = new float[9];

    public ForcedSeamlessRotator(int oldRotation, int newRotation, DisplayInfo info) {
        final boolean flipped = info.rotation == ROTATION_90 || info.rotation == ROTATION_270;
        final int h = flipped ? info.logicalWidth : info.logicalHeight;
        final int w = flipped ? info.logicalHeight : info.logicalWidth;

        final Matrix tmp = new Matrix();
        CoordinateTransforms.transformLogicalToPhysicalCoordinates(oldRotation, w, h, mTransform);
        CoordinateTransforms.transformPhysicalToLogicalCoordinates(newRotation, w, h, tmp);
        mTransform.postConcat(tmp);
    }

    /**
     * Applies a transform to the window token's surface that undoes the effect of the global
     * display rotation.
     */
    public void unrotate(WindowToken token) {
        token.getPendingTransaction().setMatrix(token.getSurfaceControl(), mTransform, mFloat9);
    }

    /**
     * Removes the transform to the window token's surface that undoes the effect of the global
     * display rotation.
     *
     * Removing the transform and the result of the WindowState's layout are both tied to the
     * WindowState's next frame, such that they apply at the same time the client draws the
     * window in the new orientation.
     */
    public void finish(WindowToken token, WindowState win) {
        mTransform.reset();
        token.getPendingTransaction().setMatrix(token.mSurfaceControl, mTransform, mFloat9);
        token.getPendingTransaction().deferTransactionUntil(token.mSurfaceControl,
                win.mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(),
                win.getFrameNumber());
        win.getPendingTransaction().deferTransactionUntil(win.mSurfaceControl,
                win.mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(),
                win.getFrameNumber());
    }
}
Loading