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

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

Add shadow during resizing in docked mode

Bug: 27738239
Change-Id: I48c45bd97c2aa7f3d7bbb5b1ba650fbe408bd0bf
parent 771d0c2b
Loading
Loading
Loading
Loading
+24 −11
Original line number Diff line number Diff line
@@ -16,7 +16,8 @@

package android.view;

import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -96,8 +97,8 @@ import java.io.OutputStream;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.HashSet;
import java.util.concurrent.CountDownLatch;

/**
 * The top of a view hierarchy, implementing the needed protocol between View
@@ -146,9 +147,6 @@ public final class ViewRootImpl implements ViewParent,
     */
    static final int MAX_TRACKBALL_DELAY = 250;

    private static final int RESIZE_MODE_FREEFORM = 0;
    private static final int RESIZE_MODE_DOCKED_DIVIDER = 1;

    static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();

    static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList();
@@ -233,6 +231,7 @@ public final class ViewRootImpl implements ViewParent,
    boolean mIsAnimating;

    private boolean mDragResizing;
    private boolean mInvalidateRootRequested;
    private int mResizeMode;
    private int mCanvasOffsetX;
    private int mCanvasOffsetY;
@@ -1828,12 +1827,12 @@ public final class ViewRootImpl implements ViewParent,
                final boolean dragResizing = freeformResizing || dockedResizing;
                if (mDragResizing != dragResizing) {
                    if (dragResizing) {
                        startDragResizing(mPendingBackDropFrame,
                                mWinFrame.equals(mPendingBackDropFrame), mPendingVisibleInsets,
                                mPendingStableInsets);
                        mResizeMode = freeformResizing
                                ? RESIZE_MODE_FREEFORM
                                : RESIZE_MODE_DOCKED_DIVIDER;
                        startDragResizing(mPendingBackDropFrame,
                                mWinFrame.equals(mPendingBackDropFrame), mPendingVisibleInsets,
                                mPendingStableInsets, mResizeMode);
                    } else {
                        // We shouldn't come here, but if we come we should end the resize.
                        endDragResizing();
@@ -2438,6 +2437,11 @@ public final class ViewRootImpl implements ViewParent,
    @Override
    public void onHardwarePostDraw(DisplayListCanvas canvas) {
        drawAccessibilityFocusedDrawableIfNeeded(canvas);
        synchronized (mWindowCallbacks) {
            for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
                mWindowCallbacks.get(i).onPostDraw(canvas);
            }
        }
    }

    /**
@@ -2675,7 +2679,8 @@ public final class ViewRootImpl implements ViewParent,
        if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
            if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
                // If accessibility focus moved, always invalidate the root.
                boolean invalidateRoot = accessibilityFocusDirty;
                boolean invalidateRoot = accessibilityFocusDirty || mInvalidateRootRequested;
                mInvalidateRootRequested = false;

                // Draw with hardware renderer.
                mIsAnimating = false;
@@ -2908,6 +2913,14 @@ public final class ViewRootImpl implements ViewParent,
        return mAttachInfo.mAccessibilityFocusDrawable;
    }

    /**
     * Requests that the root render node is invalidated next time we perform a draw, such that
     * {@link WindowCallbacks#onPostDraw} gets called.
     */
    public void requestInvalidateRootRenderNode() {
        mInvalidateRootRequested = true;
    }

    boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
        final Rect ci = mAttachInfo.mContentInsets;
        final Rect vi = mAttachInfo.mVisibleInsets;
@@ -7090,13 +7103,13 @@ public final class ViewRootImpl implements ViewParent,
     * Start a drag resizing which will inform all listeners that a window resize is taking place.
     */
    private void startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets,
            Rect stableInsets) {
            Rect stableInsets, int resizeMode) {
        if (!mDragResizing) {
            mDragResizing = true;
            synchronized (mWindowCallbacks) {
                for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
                    mWindowCallbacks.get(i).onWindowDragResizeStart(initialBounds, fullscreen,
                            systemInsets, stableInsets);
                            systemInsets, stableInsets, resizeMode);
                }
            }
            mFullRedrawNeeded = true;
+15 −1
Original line number Diff line number Diff line
@@ -26,6 +26,11 @@ import android.graphics.Rect;
 * @hide
 */
public interface WindowCallbacks {

    public static final int RESIZE_MODE_INVALID = -1;
    public static final int RESIZE_MODE_FREEFORM = 0;
    public static final int RESIZE_MODE_DOCKED_DIVIDER = 1;

    /**
     * Called by the system when the window got changed by the user, before the layouter got called.
     * It also gets called when the insets changed, or when the window switched between a fullscreen
@@ -51,7 +56,7 @@ public interface WindowCallbacks {
     * @param stableInsets The stable insets for the window.
     */
    void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen, Rect systemInsets,
            Rect stableInsets);
            Rect stableInsets, int resizeMode);

    /**
     * Called when a drag resize ends.
@@ -69,4 +74,13 @@ public interface WindowCallbacks {
     * @param reportNextDraw Whether it should report when the requested draw finishes.
     */
    void onRequestDraw(boolean reportNextDraw);

    /**
     * Called after all the content has drawn and the callback now has the ability to draw something
     * on top of everything. Call {@link ViewRootImpl#requestInvalidateRootRenderNode} when this
     * content needs to be redrawn.
     *
     * @param canvas The canvas to draw on.
     */
    void onPostDraw(DisplayListCanvas canvas);
}
+15 −6
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.internal.policy;

import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;

import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -69,6 +71,7 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
    private ColorDrawable mNavigationBarColor;
    private boolean mOldFullscreen;
    private boolean mFullscreen;
    private final int mResizeMode;
    private final Rect mOldSystemInsets = new Rect();
    private final Rect mOldStableInsets = new Rect();
    private final Rect mSystemInsets = new Rect();
@@ -77,7 +80,7 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
    public BackdropFrameRenderer(DecorView decorView, ThreadedRenderer renderer, Rect initialBounds,
            Drawable resizingBackgroundDrawable, Drawable captionBackgroundDrawable,
            Drawable userCaptionBackgroundDrawable, int statusBarColor, int navigationBarColor,
            boolean fullscreen, Rect systemInsets, Rect stableInsets) {
            boolean fullscreen, Rect systemInsets, Rect stableInsets, int resizeMode) {
        setName("ResizeFrame");

        mRenderer = renderer;
@@ -98,6 +101,7 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
        mStableInsets.set(stableInsets);
        mOldSystemInsets.set(systemInsets);
        mOldStableInsets.set(stableInsets);
        mResizeMode = resizeMode;
        synchronized (this) {
            redrawLocked(initialBounds, fullscreen, mSystemInsets, mStableInsets);
        }
@@ -266,11 +270,16 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
            mLastXOffset = xOffset;
            mLastYOffset = yOffset;

            // Only clip the content to the bounds if we are not fullscreen. In the other case, we
            // actually need to draw outside these.
            if (mResizeMode == RESIZE_MODE_FREEFORM) {
                mRenderer.setContentDrawBounds(
                        mLastXOffset,
                        mLastYOffset,
                        mLastXOffset + mLastContentWidth,
                        mLastYOffset + mLastCaptionHeight + mLastContentHeight);
            }

            // If this was the first call and redrawLocked got already called prior
            // to us, we should re-issue a redrawLocked now.
            return firstCall
+59 −2
Original line number Diff line number Diff line
@@ -39,8 +39,11 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.RemoteException;
@@ -49,6 +52,7 @@ import android.util.Log;
import android.util.TypedValue;
import android.view.ActionMode;
import android.view.ContextThemeWrapper;
import android.view.DisplayListCanvas;
import android.view.Gravity;
import android.view.InputQueue;
import android.view.KeyEvent;
@@ -88,6 +92,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACK
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -211,6 +216,11 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
    private boolean mApplyFloatingVerticalInsets = false;
    private boolean mApplyFloatingHorizontalInsets = false;

    private int mResizeMode = RESIZE_MODE_INVALID;
    private final int mResizeShadowSize;
    private final Paint mVerticalResizeShadowPaint = new Paint();
    private final Paint mHorizontalResizeShadowPaint = new Paint();

    DecorView(Context context, int featureId, PhoneWindow window,
            WindowManager.LayoutParams params) {
        super(context);
@@ -233,6 +243,10 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
        setWindow(window);

        updateLogTag(params);

        mResizeShadowSize = context.getResources().getDimensionPixelSize(
                R.dimen.resize_shadow_size);
        initResizingPaints();
    }

    void setBackgroundFallback(int resId) {
@@ -699,6 +713,10 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
        // our shadow elevation.
        updateElevation();
        mAllowUpdateElevation = true;

        if (changed && mResizeMode == RESIZE_MODE_DOCKED_DIVIDER) {
            getViewRootImpl().requestInvalidateRootRenderNode();
        }
    }

    @Override
@@ -1907,7 +1925,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind

    @Override
    public void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen, Rect systemInsets,
            Rect stableInsets) {
            Rect stableInsets, int resizeMode) {
        if (mWindow.isDestroyed()) {
            // If the owner's window is gone, we should not be able to come here anymore.
            releaseThreadedRenderer();
@@ -1923,7 +1941,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
                    initialBounds, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
                    mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState),
                    getCurrentColor(mNavigationColorViewState), fullscreen, systemInsets,
                    stableInsets);
                    stableInsets, resizeMode);

            // Get rid of the shadow while we are resizing. Shadow drawing takes considerable time.
            // If we want to get the shadow shown while resizing, we would need to elevate a new
@@ -1932,12 +1950,16 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind

            updateColorViews(null /* insets */, false);
        }
        mResizeMode = resizeMode;
        getViewRootImpl().requestInvalidateRootRenderNode();
    }

    @Override
    public void onWindowDragResizeEnd() {
        releaseThreadedRenderer();
        updateColorViews(null /* insets */, false);
        mResizeMode = RESIZE_MODE_INVALID;
        getViewRootImpl().requestInvalidateRootRenderNode();
    }

    @Override
@@ -1960,6 +1982,41 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
        }
    }

    @Override
    public void onPostDraw(DisplayListCanvas canvas) {
        drawResizingShadowIfNeeded(canvas);
    }

    private void initResizingPaints() {
        final int startColor = mContext.getResources().getColor(
                R.color.resize_shadow_start_color, null);
        final int endColor = mContext.getResources().getColor(
                R.color.resize_shadow_end_color, null);
        final int middleColor = (startColor + endColor) / 2;
        mHorizontalResizeShadowPaint.setShader(new LinearGradient(
                0, 0, 0, mResizeShadowSize, new int[] { startColor, middleColor, endColor },
                new float[] { 0f, 0.3f, 1f }, Shader.TileMode.CLAMP));
        mVerticalResizeShadowPaint.setShader(new LinearGradient(
                0, 0, mResizeShadowSize, 0, new int[] { startColor, middleColor, endColor },
                new float[] { 0f, 0.3f, 1f }, Shader.TileMode.CLAMP));
    }

    private void drawResizingShadowIfNeeded(DisplayListCanvas canvas) {
        if (mResizeMode != RESIZE_MODE_DOCKED_DIVIDER || mWindow.mIsFloating
                || mWindow.isTranslucent()
                || (mWindow.getAttributes().flags & FLAG_SHOW_WALLPAPER) != 0) {
            return;
        }
        canvas.save();
        canvas.translate(0, getHeight() - mFrameOffsets.bottom);
        canvas.drawRect(0, 0, getWidth(), mResizeShadowSize, mHorizontalResizeShadowPaint);
        canvas.restore();
        canvas.save();
        canvas.translate(getWidth() - mFrameOffsets.right, 0);
        canvas.drawRect(0, 0, mResizeShadowSize, getHeight(), mVerticalResizeShadowPaint);
        canvas.restore();
    }

    /** Release the renderer thread which is usually done when the user stops resizing. */
    private void releaseThreadedRenderer() {
        if (mResizingBackgroundDrawable != null && mLastBackgroundDrawableCb != null) {
+7 −0
Original line number Diff line number Diff line
@@ -157,6 +157,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
    InputQueue.Callback mTakeInputQueueCallback;

    boolean mIsFloating;
    private boolean mIsTranslucent;

    private LayoutInflater mLayoutInflater;

@@ -490,6 +491,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
        return mIsFloating;
    }

    public boolean isTranslucent() {
        return mIsTranslucent;
    }

    /**
     * Return a LayoutInflater instance that can be used to inflate XML view layout
     * resources for use in this Window.
@@ -2400,6 +2405,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
            requestFeature(FEATURE_ACTIVITY_TRANSITIONS);
        }

        mIsTranslucent = a.getBoolean(R.styleable.Window_windowIsTranslucent, false);

        final Context context = getContext();
        final int targetSdk = context.getApplicationInfo().targetSdkVersion;
        final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB;
Loading