Merge "Add shadow during resizing in docked mode" into nyc-dev
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
Reference in New Issue
Block a user