Merge "Add shadow during resizing in docked mode" into nyc-dev

This commit is contained in:
Jorim Jaggi
2016-03-25 21:12:10 +00:00
committed by Android (Google) Code Review
8 changed files with 128 additions and 20 deletions

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;
mRenderer.setContentDrawBounds(
mLastXOffset,
mLastYOffset,
mLastXOffset + mLastContentWidth,
mLastYOffset + mLastCaptionHeight + mLastContentHeight);
// 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

View File

@@ -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) {

View File

@@ -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;

View File

@@ -180,4 +180,7 @@
<!-- Status bar color for semi transparent mode. -->
<color name="system_bar_background_semi_transparent">#66000000</color> <!-- 40% black -->
<color name="resize_shadow_start_color">#2a000000</color>
<color name="resize_shadow_end_color">#00000000</color>
</resources>

View File

@@ -452,4 +452,6 @@
<item type="dimen" name="aerr_padding_list_top">15dp</item>
<item type="fraction" name="docked_stack_divider_fixed_ratio">34.15%</item>
<dimen name="resize_shadow_size">5dp</dimen>
</resources>

View File

@@ -1512,6 +1512,9 @@
<java-symbol type="integer" name="config_dockedStackDividerSnapMode" />
<java-symbol type="fraction" name="docked_stack_divider_fixed_ratio" />
<java-symbol type="fraction" name="thumbnail_fullscreen_scale" />
<java-symbol type="dimen" name="resize_shadow_size" />
<java-symbol type="color" name="resize_shadow_start_color" />
<java-symbol type="color" name="resize_shadow_end_color" />
<java-symbol type="dimen" name="navigation_bar_height" />
<java-symbol type="dimen" name="navigation_bar_height_landscape" />
<java-symbol type="dimen" name="navigation_bar_width" />