diff options
29 files changed, 669 insertions, 154 deletions
diff --git a/api/current.xml b/api/current.xml index b3f03a6..3bcac93 100644 --- a/api/current.xml +++ b/api/current.xml @@ -215899,8 +215899,6 @@ deprecated="not deprecated" visibility="public" > -<parameter name="visibility" type="int"> -</parameter> </method> <method name="getTag" return="java.lang.Object" diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java index e405df5..f13d940 100644 --- a/core/java/android/animation/LayoutTransition.java +++ b/core/java/android/animation/LayoutTransition.java @@ -34,15 +34,16 @@ import java.util.List; * custom animations, use the {@link LayoutTransition#setAnimator(int, Animator) * setAnimator()} method. * - * <p>One of the core concepts of these transition animations is that there are two core + * <p>One of the core concepts of these transition animations is that there are two types of * changes that cause the transition and four different animations that run because of * those changes. The changes that trigger the transition are items being added to a container * (referred to as an "appearing" transition) or removed from a container (also known as - * "disappearing"). The animations that run due to those events are one that animates + * "disappearing"). Setting the visibility of views (between GONE and VISIBLE) will trigger + * the same add/remove logic. The animations that run due to those events are one that animates * items being added, one that animates items being removed, and two that animate the other * items in the container that change due to the add/remove occurrence. Users of * the transition may want different animations for the changing items depending on whether - * they are changing due to anappearing or disappearing event, so there is one animation for + * they are changing due to an appearing or disappearing event, so there is one animation for * each of these variations of the changing event. Most of the API of this class is concerned * with setting up the basic properties of the animations used in these four situations, * or with setting up custom animations for any or all of the four.</p> @@ -62,6 +63,18 @@ import java.util.List; * values when the transition begins. Custom animations will be similarly populated with * the target and values being animated, assuming they use ObjectAnimator objects with * property names that are known on the target object.</p> + * + * <p>This class, and the associated XML flag for containers, animateLayoutChanges="true", + * provides a simple utility meant for automating changes in straightforward situations. + * Using LayoutTransition at multiple levels of a nested view hierarchy may not work due to the + * interrelationship of the various levels of layout. Also, a container that is being scrolled + * at the same time as items are being added or removed is probably not a good candidate for + * this utility, because the before/after locations calculated by LayoutTransition + * may not match the actual locations when the animations finish due to the container + * being scrolled as the animations are running. You can work around that + * particular issue by disabling the 'changing' animations by setting the CHANGE_APPEARING + * and CHANGE_DISAPPEARING animations to null, and setting the startDelay of the + * other animations appropriately.</p> */ public class LayoutTransition { diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java index 959fae4..4484d59 100644 --- a/core/java/android/view/DisplayList.java +++ b/core/java/android/view/DisplayList.java @@ -21,9 +21,11 @@ package android.view; * them later. Display lists are usually built by recording operations on a * {@link android.graphics.Canvas}. Replaying the operations from a display list * avoids executing views drawing code on every frame, and is thus much more - * efficient. + * efficient. + * + * @hide */ -abstract class DisplayList { +public abstract class DisplayList { /** * Starts recording the display list. All operations performed on the * returned canvas are recorded and stored in this display list. diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index f6c5e0b..dce1a6c 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -220,6 +220,13 @@ class GLES20Canvas extends HardwareCanvas { private native void nAcquireContext(int renderer); @Override + public boolean callDrawGLFunction(int drawGLFunction) { + return nCallDrawGLFunction(mRenderer, drawGLFunction); + } + + private native boolean nCallDrawGLFunction(int renderer, int drawGLFunction); + + @Override public void releaseContext() { if (mContextLocked) { nReleaseContext(mRenderer); @@ -246,11 +253,11 @@ class GLES20Canvas extends HardwareCanvas { private static native void nDestroyDisplayList(int displayList); @Override - public void drawDisplayList(DisplayList displayList) { - nDrawDisplayList(mRenderer, ((GLES20DisplayList) displayList).mNativeDisplayList); + public boolean drawDisplayList(DisplayList displayList) { + return nDrawDisplayList(mRenderer, ((GLES20DisplayList) displayList).mNativeDisplayList); } - private native void nDrawDisplayList(int renderer, int displayList); + private native boolean nDrawDisplayList(int renderer, int displayList); /////////////////////////////////////////////////////////////////////////// // Hardware layer @@ -306,7 +313,7 @@ class GLES20Canvas extends HardwareCanvas { @Override public boolean clipRect(int left, int top, int right, int bottom) { - return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt); + return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt); } private native boolean nClipRect(int renderer, int left, int top, int right, int bottom, int op); diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java index e813bc9..262eb81 100644 --- a/core/java/android/view/GLES20DisplayList.java +++ b/core/java/android/view/GLES20DisplayList.java @@ -16,6 +16,8 @@ package android.view; +import java.lang.ref.WeakReference; + /** * An implementation of display list for OpenGL ES 2.0. */ @@ -27,12 +29,24 @@ class GLES20DisplayList extends DisplayList { private boolean mValid = false; int mNativeDisplayList; + WeakReference<View> hostView; // The native display list will be destroyed when this object dies. // DO NOT overwrite this reference once it is set. @SuppressWarnings("unused") private DisplayListFinalizer mFinalizer; + public GLES20DisplayList(View view) { + hostView = new WeakReference<View>(view); + } + + public void invalidateView() { + View v = hostView.get(); + if (v != null) { + v.invalidate(); + } + } + @Override HardwareCanvas start() { if (mStarted) { diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java index 2273238..a4d36b7 100644 --- a/core/java/android/view/HardwareCanvas.java +++ b/core/java/android/view/HardwareCanvas.java @@ -21,9 +21,11 @@ import android.graphics.Canvas; import android.graphics.Paint; /** - * Hardware accelerated canvas. + * Hardware accelerated canvas. + * + * @hide */ -abstract class HardwareCanvas extends Canvas { +public abstract class HardwareCanvas extends Canvas { @Override public boolean isHardwareAccelerated() { return true; @@ -49,7 +51,7 @@ abstract class HardwareCanvas extends Canvas { * * @param displayList The display list to replay. */ - abstract void drawDisplayList(DisplayList displayList); + abstract boolean drawDisplayList(DisplayList displayList); /** * Draws the specified layer onto this canvas. @@ -59,5 +61,18 @@ abstract class HardwareCanvas extends Canvas { * @param y The top coordinate of the layer * @param paint The paint used to draw the layer */ - abstract void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint); + abstract void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint); + + /** + * Calls the function specified with the drawGLFunction function pointer. This is + * functionality used by webkit for calling into their renderer from our display lists. + * This function may return true if an invalidation is needed after the call. + * + * @param drawGLFunction A native function pointer + * @return true if an invalidate is needed after the call, false otherwise + */ + public boolean callDrawGLFunction(int drawGLFunction) { + // Noop - this is done in the display list recorder subclass + return false; + } } diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index addd1b3..c82184a 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -120,7 +120,7 @@ public abstract class HardwareRenderer { * * @return A new display list. */ - abstract DisplayList createDisplayList(); + abstract DisplayList createDisplayList(View v); /** * Creates a new hardware layer. @@ -506,19 +506,32 @@ public abstract class HardwareRenderer { if (checkCurrent()) { onPreDraw(); - Canvas canvas = mCanvas; + HardwareCanvas canvas = mCanvas; + attachInfo.mHardwareCanvas = canvas; int saveCount = canvas.save(); callbacks.onHardwarePreDraw(canvas); - + try { - view.draw(canvas); + view.mRecreateDisplayList = + (view.mPrivateFlags & View.INVALIDATED) == View.INVALIDATED; + view.mPrivateFlags &= ~View.INVALIDATED; + DisplayList displayList = view.getDisplayList(); + if (displayList != null) { + if (canvas.drawDisplayList(displayList)) { + view.invalidate(); + } + } else { + // Shouldn't reach here + view.draw(canvas); + } } finally { callbacks.onHardwarePostDraw(canvas); canvas.restoreToCount(saveCount); + view.mRecreateDisplayList = false; } - + onPostDraw(); - + if (ViewDebug.DEBUG_PROFILE_DRAWING) { EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime); } @@ -704,8 +717,8 @@ public abstract class HardwareRenderer { } @Override - DisplayList createDisplayList() { - return new GLES20DisplayList(); + DisplayList createDisplayList(View v) { + return new GLES20DisplayList(v); } @Override diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 6d5fd2c..8af2549 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -1509,6 +1509,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility /*package*/ int mMeasuredHeight; /** + * Flag to indicate that this view was marked INVALIDATED, or had its display list + * invalidated, prior to the current drawing iteration. If true, the view must re-draw + * its display list. This flag, used only when hw accelerated, allows us to clear the + * flag while retaining this information until it's needed (at getDisplayList() time and + * in drawChild(), when we decide to draw a view's children's display lists into our own). + * + * {@hide} + */ + boolean mRecreateDisplayList = false; + + /** * The view's identifier. * {@hide} * @@ -1672,6 +1683,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility static final int ACTIVATED = 0x40000000; /** + * Indicates that this view was specifically invalidated, not just dirtied because some + * child view was invalidated. The flag is used to determine when we need to recreate + * a view's display list (as opposed to just returning a reference to its existing + * display list). + * + * @hide + */ + static final int INVALIDATED = 0x80000000; + + /** * Always allow a user to over-scroll this view, provided it is a * view that can scroll. * @@ -5295,6 +5316,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility if ((changed & VISIBILITY_MASK) != 0) { if (mParent instanceof ViewGroup) { ((ViewGroup)mParent).onChildVisibilityChanged(this, (flags & VISIBILITY_MASK)); + ((View) mParent).invalidate(); } dispatchVisibilityChanged(this, (flags & VISIBILITY_MASK)); } @@ -5306,6 +5328,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility if ((changed & DRAWING_CACHE_ENABLED) != 0) { destroyDrawingCache(); mPrivateFlags &= ~DRAWING_CACHE_VALID; + invalidateParentIfAccelerated(); } if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { @@ -5666,6 +5689,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility mMatrixDirty = true; mPrivateFlags |= DRAWN; // force another invalidation with the new orientation invalidate(false); + invalidateParentIfAccelerated(); } } @@ -5699,6 +5723,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility mMatrixDirty = true; mPrivateFlags |= DRAWN; // force another invalidation with the new orientation invalidate(false); + invalidateParentIfAccelerated(); } } @@ -5732,6 +5757,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility mMatrixDirty = true; mPrivateFlags |= DRAWN; // force another invalidation with the new orientation invalidate(false); + invalidateParentIfAccelerated(); } } @@ -5767,6 +5793,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility mMatrixDirty = true; mPrivateFlags |= DRAWN; // force another invalidation with the new orientation invalidate(false); + invalidateParentIfAccelerated(); } } @@ -5802,6 +5829,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility mMatrixDirty = true; mPrivateFlags |= DRAWN; // force another invalidation with the new orientation invalidate(false); + invalidateParentIfAccelerated(); } } @@ -5843,6 +5871,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility mMatrixDirty = true; mPrivateFlags |= DRAWN; // force another invalidation with the new orientation invalidate(false); + invalidateParentIfAccelerated(); } } @@ -5883,6 +5912,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility mMatrixDirty = true; mPrivateFlags |= DRAWN; // force another invalidation with the new orientation invalidate(false); + invalidateParentIfAccelerated(); } } @@ -5922,6 +5952,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility mPrivateFlags &= ~ALPHA_SET; invalidate(false); } + invalidateParentIfAccelerated(); } /** @@ -6241,6 +6272,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility mMatrixDirty = true; mPrivateFlags |= DRAWN; // force another invalidation with the new orientation invalidate(false); + invalidateParentIfAccelerated(); } } @@ -6274,6 +6306,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility mMatrixDirty = true; mPrivateFlags |= DRAWN; // force another invalidation with the new orientation invalidate(false); + invalidateParentIfAccelerated(); } } @@ -6490,6 +6523,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility int oldY = mScrollY; mScrollX = x; mScrollY = y; + invalidateParentIfAccelerated(); onScrollChanged(mScrollX, mScrollY, oldX, oldY); if (!awakenScrollBars()) { invalidate(); @@ -6690,8 +6724,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) || - (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) { + (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID || + (mPrivateFlags & INVALIDATED) != INVALIDATED) { mPrivateFlags &= ~DRAWING_CACHE_VALID; + mPrivateFlags |= INVALIDATED; final ViewParent p = mParent; final AttachInfo ai = mAttachInfo; if (p != null && ai != null && ai.mHardwareAccelerated) { @@ -6728,8 +6764,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) || - (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) { + (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID || + (mPrivateFlags & INVALIDATED) != INVALIDATED) { mPrivateFlags &= ~DRAWING_CACHE_VALID; + mPrivateFlags |= INVALIDATED; final ViewParent p = mParent; final AttachInfo ai = mAttachInfo; if (p != null && ai != null && ai.mHardwareAccelerated) { @@ -6776,10 +6814,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility boolean opaque = isOpaque(); if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) || (invalidateCache && (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) || - opaque != mLastIsOpaque) { + opaque != mLastIsOpaque || (mPrivateFlags & INVALIDATED) != INVALIDATED) { mLastIsOpaque = opaque; mPrivateFlags &= ~DRAWN; if (invalidateCache) { + mPrivateFlags |= INVALIDATED; mPrivateFlags &= ~DRAWING_CACHE_VALID; } final AttachInfo ai = mAttachInfo; @@ -6802,6 +6841,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } /** + * Used to indicate that the parent of this view should be invalidated. This functionality + * is used to force the parent to rebuild its display list (when hardware-accelerated), + * which is necessary when various parent-managed properties of the view change, such as + * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. + * + * @hide + */ + protected void invalidateParentIfAccelerated() { + if (isHardwareAccelerated() && mParent instanceof View) { + ((View) mParent).invalidate(); + } + } + + /** * Indicates whether this View is opaque. An opaque View guarantees that it will * draw all the pixels overlapping its bounds using a fully opaque color. * @@ -7630,6 +7683,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility mHardwareLayer = null; } + if (mDisplayList != null) { + mDisplayList.invalidate(); + } + if (mAttachInfo != null) { mAttachInfo.mHandler.removeMessages(AttachInfo.INVALIDATE_MSG, this); mAttachInfo.mHandler.removeMessages(AttachInfo.INVALIDATE_RECT_MSG, this); @@ -7953,7 +8010,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); } - + if (layerType == mLayerType) { if (layerType != LAYER_TYPE_NONE && paint != mLayerPaint) { mLayerPaint = paint == null ? new Paint() : paint; @@ -8041,7 +8098,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility mHardwareLayer.resize(width, height); } - final HardwareCanvas canvas = mHardwareLayer.start(currentCanvas); + final HardwareCanvas canvas = mHardwareLayer.start(mAttachInfo.mHardwareCanvas); try { canvas.setViewport(width, height); canvas.onPreDraw(); @@ -8064,7 +8121,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility canvas.restoreToCount(restoreCount); } finally { canvas.onPostDraw(); - mHardwareLayer.end(currentCanvas); + mHardwareLayer.end(mAttachInfo.mHardwareCanvas); } } @@ -8081,9 +8138,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility * * <p>Enabling the drawing cache is similar to * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware - * acceleration is turned off. When hardware acceleration is turned on enabling the - * drawing cache has either no effect or the cache used at drawing time is not a bitmap. - * This API can however be used to manually generate a bitmap copy of this view.</p> + * acceleration is turned off. When hardware acceleration is turned on, enabling the + * drawing cache has no effect on rendering because the system uses a different mechanism + * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even + * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} + * for information on how to enable software and hardware layers.</p> + * + * <p>This API can be used to manually generate + * a bitmap copy of this view, by setting the flag to <code>true</code> and calling + * {@link #getDrawingCache()}.</p> * * @param enabled true to enable the drawing cache, false otherwise * @@ -8110,25 +8173,76 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } /** + * Debugging utility which recursively outputs the dirty state of a view and its + * descendants. + * + * @hide + */ + public void outputDirtyFlags(String indent, boolean clear, int clearMask) { + Log.d("View", indent + this + " DIRTY(" + (mPrivateFlags & View.DIRTY_MASK) + + ") DRAWN(" + (mPrivateFlags & DRAWN) + ")" + " CACHE_VALID(" + + (mPrivateFlags & View.DRAWING_CACHE_VALID) + + ") INVALIDATED(" + (mPrivateFlags & INVALIDATED) + ")"); + if (clear) { + mPrivateFlags &= clearMask; + } + if (this instanceof ViewGroup) { + ViewGroup parent = (ViewGroup) this; + final int count = parent.getChildCount(); + for (int i = 0; i < count; i++) { + final View child = (View) parent.getChildAt(i); + child.outputDirtyFlags(indent + " ", clear, clearMask); + } + } + } + + /** + * This method is used by ViewGroup to cause its children to restore or recreate their + * display lists. It is called by getDisplayList() when the parent ViewGroup does not need + * to recreate its own display list, which would happen if it went through the normal + * draw/dispatchDraw mechanisms. + * + * @hide + */ + protected void dispatchGetDisplayList() {} + + /** * <p>Returns a display list that can be used to draw this view again * without executing its draw method.</p> * * @return A DisplayList ready to replay, or null if caching is not enabled. + * + * @hide */ - DisplayList getDisplayList() { - if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { - return null; - } + public DisplayList getDisplayList() { if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) { return null; } - if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED && - ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || - mDisplayList == null || !mDisplayList.isValid())) { + if (((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || + mDisplayList == null || !mDisplayList.isValid() || + mRecreateDisplayList)) { + // Don't need to recreate the display list, just need to tell our + // children to restore/recreate theirs + if (mDisplayList != null && mDisplayList.isValid() && + !mRecreateDisplayList) { + mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID; + mPrivateFlags &= ~DIRTY_MASK; + dispatchGetDisplayList(); + + return mDisplayList; + } + + // If we got here, we're recreating it. Mark it as such to ensure that + // we copy in child display lists into ours in drawChild() + mRecreateDisplayList = true; if (mDisplayList == null) { - mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList(); + mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList(this); + // If we're creating a new display list, make sure our parent gets invalidated + // since they will need to recreate their display list to account for this + // new child display list. + invalidateParentIfAccelerated(); } final HardwareCanvas canvas = mDisplayList.start(); @@ -8141,6 +8255,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility final int restoreCount = canvas.save(); + computeScroll(); + canvas.translate(-mScrollX, -mScrollY); mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID; // Fast path for layouts with no backgrounds @@ -8229,9 +8345,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility mUnscaledDrawingCache.recycle(); mUnscaledDrawingCache = null; } - if (mDisplayList != null) { - mDisplayList.invalidate(); - } } /** @@ -10480,6 +10593,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility animation.setStartTime(Animation.START_ON_FIRST_FRAME); setAnimation(animation); invalidate(); + invalidateParentIfAccelerated(); } /** @@ -10490,6 +10604,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility mCurrentAnimation.detach(); } mCurrentAnimation = null; + invalidateParentIfAccelerated(); } /** @@ -10660,7 +10775,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility /** * Returns the status bar visibility that this view has requested. */ - public int getSystemUiVisibility(int visibility) { + public int getSystemUiVisibility() { return mSystemUiVisibility; } @@ -11495,6 +11610,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility final Callbacks mRootCallbacks; + Canvas mHardwareCanvas; + /** * The top view of the hierarchy. */ diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java index d5c440c..c19a107 100644 --- a/core/java/android/view/ViewDebug.java +++ b/core/java/android/view/ViewDebug.java @@ -998,22 +998,27 @@ public class ViewDebug { new ViewOperation<Object>() { public Object[] pre() { final DisplayMetrics metrics = - view.getResources().getDisplayMetrics(); - final Bitmap bitmap = + (view != null && view.getResources() != null) ? + view.getResources().getDisplayMetrics() : null; + final Bitmap bitmap = metrics != null ? Bitmap.createBitmap(metrics.widthPixels, - metrics.heightPixels, Bitmap.Config.RGB_565); - final Canvas canvas = new Canvas(bitmap); + metrics.heightPixels, Bitmap.Config.RGB_565) : null; + final Canvas canvas = bitmap != null ? new Canvas(bitmap) : null; return new Object[] { bitmap, canvas }; } public void run(Object... data) { - view.draw((Canvas) data[1]); + if (data[1] != null) { + view.draw((Canvas) data[1]); + } } public void post(Object... data) { - ((Bitmap) data[0]).recycle(); + if (data[0] != null) { + ((Bitmap) data[0]).recycle(); + } } }) : 0; out.write(String.valueOf(durationMeasure)); diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index d6c8ad6..c73cbe6 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -2206,6 +2206,27 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } /** + * This method is used to cause children of this ViewGroup to restore or recreate their + * display lists. It is called by getDisplayList() when the parent ViewGroup does not need + * to recreate its own display list, which would happen if it went through the normal + * draw/dispatchDraw mechanisms. + * + * @hide + */ + @Override + protected void dispatchGetDisplayList() { + final int count = mChildrenCount; + final View[] children = mChildren; + for (int i = 0; i < count; i++) { + final View child = children[i]; + child.mRecreateDisplayList = (child.mPrivateFlags & INVALIDATED) == INVALIDATED; + child.mPrivateFlags &= ~INVALIDATED; + child.getDisplayList(); + child.mRecreateDisplayList = false; + } + } + + /** * Draw one child of this View Group. This method is responsible for getting * the canvas in the right state. This includes clipping, translating so * that the child's scrolled origin is at 0, 0, and applying any animation @@ -2247,7 +2268,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager caching = true; if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired; } else { - caching = layerType != LAYER_TYPE_NONE; + caching = (layerType != LAYER_TYPE_NONE) || canvas.isHardwareAccelerated(); } if (a != null) { @@ -2329,6 +2350,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return more; } + if (canvas.isHardwareAccelerated()) { + // Clear INVALIDATED flag to allow invalidation to occur during rendering, but + // retain the flag's value temporarily in the mRecreateDisplayList flag + child.mRecreateDisplayList = (child.mPrivateFlags & INVALIDATED) == INVALIDATED; + child.mPrivateFlags &= ~INVALIDATED; + } + child.computeScroll(); final int sx = child.mScrollX; @@ -2347,7 +2375,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (layerType == LAYER_TYPE_SOFTWARE) { child.buildDrawingCache(true); cache = child.getDrawingCache(true); - } else { + } else if (layerType == LAYER_TYPE_NONE) { displayList = child.getDisplayList(); } } @@ -2357,7 +2385,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final boolean hasNoCache = cache == null || hasDisplayList; final int restoreTo = canvas.save(); - if (hasNoCache) { + if (cache == null && !hasDisplayList) { canvas.translate(cl - sx, ct - sy); } else { canvas.translate(cl, ct); @@ -2375,7 +2403,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager int transX = 0; int transY = 0; - if (hasNoCache) { + if (cache == null && !hasDisplayList) { transX = -sx; transY = -sy; } @@ -2435,10 +2463,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) { - if (hasNoCache) { + if (cache == null && !hasDisplayList) { canvas.clipRect(sx, sy, sx + (cr - cl), sy + (cb - ct)); } else { - if (!scalingRequired) { + if (!scalingRequired || cache == null) { canvas.clipRect(0, 0, cr - cl, cb - ct); } else { canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); @@ -2473,7 +2501,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } } else { child.mPrivateFlags &= ~DIRTY_MASK; - ((HardwareCanvas) canvas).drawDisplayList(displayList); + // Skip drawing the display list into ours if we were just refreshing + // it's content; we already have a reference to it in our display list + if (mRecreateDisplayList || mLayerType != LAYER_TYPE_NONE) { + ((HardwareCanvas) canvas).drawDisplayList(displayList); + } } } } else if (cache != null) { @@ -2503,6 +2535,15 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager finishAnimatingView(child, a); } + if (more && canvas.isHardwareAccelerated()) { + // invalidation is the trigger to recreate display lists, so if we're using + // display lists to render, force an invalidate to allow the animation to + // continue drawing another frame + invalidate(); + } + + child.mRecreateDisplayList = false; + return more; } @@ -2743,7 +2784,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // addViewInner() will call child.requestLayout() when setting the new LayoutParams // therefore, we call requestLayout() on ourselves before, so that the child's request // will be blocked at our level - child.mPrivateFlags &= ~DIRTY_MASK; requestLayout(); invalidate(); addViewInner(child, index, params, false); @@ -3425,10 +3465,20 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION; if (dirty == null) { + if (child.mLayerType != LAYER_TYPE_NONE) { + mPrivateFlags |= INVALIDATED; + mPrivateFlags &= ~DRAWING_CACHE_VALID; + } do { View view = null; if (parent instanceof View) { view = (View) parent; + if (view.mLayerType != LAYER_TYPE_NONE && + view.getParent() instanceof View) { + final View grandParent = (View) view.getParent(); + grandParent.mPrivateFlags |= INVALIDATED; + grandParent.mPrivateFlags &= ~DRAWING_CACHE_VALID; + } if ((view.mPrivateFlags & DIRTY_MASK) != 0) { // already marked dirty - we're done break; diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index d932141..ba671c0 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -597,7 +597,7 @@ public final class ViewRoot extends Handler implements ViewParent, dirty.inset(-1, -1); } } - if (!mDirty.isEmpty()) { + if (!mDirty.isEmpty() && !mDirty.contains(dirty)) { mAttachInfo.mIgnoreDirtyState = true; } mDirty.union(dirty); diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 3102ee9..83061ec 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -16,6 +16,7 @@ package android.webkit; +import android.view.HardwareCanvas; import com.android.internal.R; import android.annotation.Widget; @@ -353,7 +354,7 @@ public class WebView extends AbsoluteLayout private ZoomManager mZoomManager; - private Rect mGLRectViewport; + private Rect mGLRectViewport = new Rect(); /** * Transportation object for returning WebView across thread boundaries. @@ -4079,20 +4080,8 @@ public class WebView extends AbsoluteLayout } if (canvas.isHardwareAccelerated()) { - try { - if (canvas.acquireContext()) { - Rect rect = new Rect(mGLRectViewport.left, - mGLRectViewport.top, - mGLRectViewport.right, - mGLRectViewport.bottom - - getVisibleTitleHeight()); - if (nativeDrawGL(rect, getScale(), extras)) { - invalidate(); - } - } - } finally { - canvas.releaseContext(); - } + int functor = nativeGetDrawGLFunction(mGLRectViewport, getScale(), extras); + ((HardwareCanvas) canvas).callDrawGLFunction(functor); } else { DrawFilter df = null; if (mZoomManager.isZoomAnimating() || UIAnimationsRunning) { @@ -5163,7 +5152,6 @@ public class WebView extends AbsoluteLayout if (mNativeClass != 0) { nativeRecordButtons(false, false, true); } - setFocusControllerActive(false); } mGotKeyDown = false; } @@ -5173,18 +5161,16 @@ public class WebView extends AbsoluteLayout void setGLRectViewport() { // Use the getGlobalVisibleRect() to get the intersection among the parents - Rect webViewRect = new Rect(); - boolean visible = getGlobalVisibleRect(webViewRect); + getGlobalVisibleRect(mGLRectViewport); // Then need to invert the Y axis, just for GL View rootView = getRootView(); int rootViewHeight = rootView.getHeight(); - int savedWebViewBottom = webViewRect.bottom; - webViewRect.bottom = rootViewHeight - webViewRect.top; - webViewRect.top = rootViewHeight - savedWebViewBottom; + int savedWebViewBottom = mGLRectViewport.bottom; + mGLRectViewport.bottom = rootViewHeight - mGLRectViewport.top - getVisibleTitleHeight(); + mGLRectViewport.top = rootViewHeight - savedWebViewBottom; - // Store the viewport - mGLRectViewport = webViewRect; + nativeUpdateDrawGLFunction(mGLRectViewport); } /** @@ -8239,6 +8225,8 @@ public class WebView extends AbsoluteLayout boolean splitIfNeeded); private native void nativeDumpDisplayTree(String urlOrNull); private native boolean nativeEvaluateLayersAnimations(); + private native int nativeGetDrawGLFunction(Rect rect, float scale, int extras); + private native void nativeUpdateDrawGLFunction(Rect rect); private native boolean nativeDrawGL(Rect rect, float scale, int extras); private native void nativeExtendSelection(int x, int y); private native int nativeFindAll(String findLower, String findUpper, diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 665f9e7..fc5c893 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -2357,6 +2357,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } if (mScrollY != 0) { mScrollY = 0; + invalidateParentIfAccelerated(); finishGlows(); invalidate(); } @@ -2733,6 +2734,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (mScrollY != 0) { mScrollY = 0; + invalidateParentIfAccelerated(); finishGlows(); invalidate(); } @@ -2951,6 +2953,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te // Coming back to 'real' list scrolling incrementalDeltaY = -newScroll; mScrollY = 0; + invalidateParentIfAccelerated(); // No need to do all this work if we're not going to move anyway if (incrementalDeltaY != 0) { @@ -3244,6 +3247,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) { mScrollY = scrollY; + invalidateParentIfAccelerated(); if (clampedY) { // Velocity is broken by hitting the limit; don't start a fling off of this. diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java index 707b92d..e8ce4e9 100644 --- a/core/java/android/widget/AutoCompleteTextView.java +++ b/core/java/android/widget/AutoCompleteTextView.java @@ -116,6 +116,10 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe // Set to true when text is set directly and no filtering shall be performed private boolean mBlockCompletion; + // When set, an update in the underlying adapter will update the result list popup. + // Set to false when the list is hidden to prevent asynchronous updates to popup the list again. + private boolean mPopupCanBeUpdated = true; + private PassThroughClickListener mPassThroughClickListener; private PopupDataSetObserver mObserver; @@ -722,21 +726,20 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe return; } - updateList(); - } - - private void updateList() { // the drop down is shown only when a minimum number of characters // was typed in the text view if (enoughToFilter()) { if (mFilter != null) { + mPopupCanBeUpdated = true; performFiltering(getText(), mLastKeyCode); buildImeCompletions(); } } else { // drop down is automatically dismissed when enough characters // are deleted from the text view - if (!mPopup.isDropDownAlwaysVisible()) dismissDropDown(); + if (!mPopup.isDropDownAlwaysVisible()) { + dismissDropDown(); + } if (mFilter != null) { mFilter.filter(null); } @@ -908,10 +911,10 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe /** {@inheritDoc} */ public void onFilterComplete(int count) { - updateDropDownForFilter(count, true); + updateDropDownForFilter(count); } - private void updateDropDownForFilter(int count, boolean forceShow) { + private void updateDropDownForFilter(int count) { // Not attached to window, don't update drop-down if (getWindowVisibility() == View.GONE) return; @@ -924,11 +927,15 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe final boolean dropDownAlwaysVisible = mPopup.isDropDownAlwaysVisible(); if ((count > 0 || dropDownAlwaysVisible) && enoughToFilter()) { - if (hasFocus() && hasWindowFocus() && (forceShow || isPopupShowing())) { + if (hasFocus() && hasWindowFocus() && mPopupCanBeUpdated) { showDropDown(); } - } else if (!dropDownAlwaysVisible) { + } else if (!dropDownAlwaysVisible && isPopupShowing()) { dismissDropDown(); + // When the filter text is changed, the first update from the adapter may show an empty + // count (when the query is being performed on the network). Future updates when some + // content has been retrieved should still be able to update the list. + mPopupCanBeUpdated = true; } } @@ -984,6 +991,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe imm.displayCompletions(this, null); } mPopup.dismiss(); + mPopupCanBeUpdated = false; } @Override @@ -1194,7 +1202,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe if (adapter != null) { // This will re-layout, thus resetting mDataChanged, so that the // listView click listener stays responsive - updateDropDownForFilter(adapter.getCount(), false); + updateDropDownForFilter(adapter.getCount()); } } }); diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java index db22a0c..ff6677f 100644 --- a/core/java/android/widget/HorizontalScrollView.java +++ b/core/java/android/widget/HorizontalScrollView.java @@ -647,6 +647,7 @@ public class HorizontalScrollView extends FrameLayout { if (!mScroller.isFinished()) { mScrollX = scrollX; mScrollY = scrollY; + invalidateParentIfAccelerated(); if (clampedX) { mScroller.springBack(mScrollX, mScrollY, 0, getScrollRange(), 0, 0); } diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index ce6da72..fc049cc 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -644,6 +644,7 @@ public class ScrollView extends FrameLayout { if (!mScroller.isFinished()) { mScrollX = scrollX; mScrollY = scrollY; + invalidateParentIfAccelerated(); if (clampedY) { mScroller.springBack(mScrollX, mScrollY, 0, 0, 0, getScrollRange()); } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index aac57ed..a0a615a 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -6272,6 +6272,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mScroller.computeScrollOffset()) { mScrollX = mScroller.getCurrX(); mScrollY = mScroller.getCurrY(); + invalidateParentIfAccelerated(); postInvalidate(); // So we draw again } } diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index 8d074af..e4a89d7 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -117,6 +117,11 @@ static void android_view_GLES20Canvas_acquireContext(JNIEnv* env, jobject canvas renderer->acquireContext(); } +static bool android_view_GLES20Canvas_callDrawGLFunction(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, Functor *functor) { + return renderer->callDrawGLFunction(functor); +} + static void android_view_GLES20Canvas_releaseContext(JNIEnv* env, jobject canvas, OpenGLRenderer* renderer) { renderer->releaseContext(); @@ -482,9 +487,9 @@ static void android_view_GLES20Canvas_destroyDisplayList(JNIEnv* env, delete displayList; } -static void android_view_GLES20Canvas_drawDisplayList(JNIEnv* env, +static bool android_view_GLES20Canvas_drawDisplayList(JNIEnv* env, jobject canvas, OpenGLRenderer* renderer, DisplayList* displayList) { - renderer->drawDisplayList(displayList); + return renderer->drawDisplayList(displayList); } // ---------------------------------------------------------------------------- @@ -577,6 +582,8 @@ static JNINativeMethod gMethods[] = { { "nPrepare", "(IZ)V", (void*) android_view_GLES20Canvas_prepare }, { "nFinish", "(I)V", (void*) android_view_GLES20Canvas_finish }, { "nAcquireContext", "(I)V", (void*) android_view_GLES20Canvas_acquireContext }, + { "nCallDrawGLFunction", "(II)Z", + (void*) android_view_GLES20Canvas_callDrawGLFunction }, { "nReleaseContext", "(I)V", (void*) android_view_GLES20Canvas_releaseContext }, { "nSave", "(II)I", (void*) android_view_GLES20Canvas_save }, @@ -639,7 +646,7 @@ static JNINativeMethod gMethods[] = { { "nGetDisplayList", "(I)I", (void*) android_view_GLES20Canvas_getDisplayList }, { "nDestroyDisplayList", "(I)V", (void*) android_view_GLES20Canvas_destroyDisplayList }, { "nGetDisplayListRenderer", "(I)I", (void*) android_view_GLES20Canvas_getDisplayListRenderer }, - { "nDrawDisplayList", "(II)V", (void*) android_view_GLES20Canvas_drawDisplayList }, + { "nDrawDisplayList", "(II)Z", (void*) android_view_GLES20Canvas_drawDisplayList }, { "nInterrupt", "(I)V", (void*) android_view_GLES20Canvas_interrupt }, { "nResume", "(I)V", (void*) android_view_GLES20Canvas_resume }, diff --git a/include/utils/Functor.h b/include/utils/Functor.h new file mode 100644 index 0000000..3955bc3 --- /dev/null +++ b/include/utils/Functor.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef ANDROID_FUNCTOR_H +#define ANDROID_FUNCTOR_H + +#include <utils/Errors.h> + +namespace android { + +class Functor { +public: + Functor() {} + virtual ~Functor() {} + virtual status_t operator ()() { return true; } +}; + +}; // namespace android + +#endif // ANDROID_FUNCTOR_H diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index ffd3be4..a768efe 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -117,7 +117,8 @@ const char* DisplayList::OP_NAMES[] = { "ResetColorFilter", "SetupColorFilter", "ResetShadow", - "SetupShadow" + "SetupShadow", + "DrawGLFunction" }; DisplayList::DisplayList(const DisplayListRenderer& recorder) { @@ -212,7 +213,8 @@ void DisplayList::init() { mPathHeap = NULL; } -void DisplayList::replay(OpenGLRenderer& renderer, uint32_t level) { +bool DisplayList::replay(OpenGLRenderer& renderer, uint32_t level) { + bool needsInvalidate = false; TextContainer text; mReader.rewind(); @@ -229,87 +231,165 @@ void DisplayList::replay(OpenGLRenderer& renderer, uint32_t level) { int saveCount = renderer.getSaveCount() - 1; while (!mReader.eof()) { int op = mReader.readInt(); - DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); switch (op) { + case DrawGLFunction: { + Functor *functor = (Functor *) getInt(); + DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], functor); + needsInvalidate |= renderer.callDrawGLFunction(functor); + } + break; case AcquireContext: { + DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.acquireContext(); } break; case ReleaseContext: { + DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.releaseContext(); } break; case Save: { - renderer.save(getInt()); + int rendererNum = getInt(); + DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], rendererNum); + renderer.save(rendererNum); } break; case Restore: { + DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.restore(); } break; case RestoreToCount: { - renderer.restoreToCount(saveCount + getInt()); + int restoreCount = saveCount + getInt(); + DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], restoreCount); + renderer.restoreToCount(restoreCount); } break; case SaveLayer: { - renderer.saveLayer(getFloat(), getFloat(), getFloat(), getFloat(), - getPaint(), getInt()); + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + SkPaint* paint = getPaint(); + int flags = getInt(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent, + OP_NAMES[op], f1, f2, f3, f4, paint, flags); + renderer.saveLayer(f1, f2, f3, f4, paint, flags); } break; case SaveLayerAlpha: { - renderer.saveLayerAlpha(getFloat(), getFloat(), getFloat(), getFloat(), - getInt(), getInt()); + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + int alpha = getInt(); + int flags = getInt(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent, + OP_NAMES[op], f1, f2, f3, f4, alpha, flags); + renderer.saveLayerAlpha(f1, f2, f3, f4, alpha, flags); } break; case Translate: { - renderer.translate(getFloat(), getFloat()); + float f1 = getFloat(); + float f2 = getFloat(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], f1, f2); + renderer.translate(f1, f2); } break; case Rotate: { - renderer.rotate(getFloat()); + float rotation = getFloat(); + DISPLAY_LIST_LOGD("%s%s %.2f", (char*) indent, OP_NAMES[op], rotation); + renderer.rotate(rotation); } break; case Scale: { - renderer.scale(getFloat(), getFloat()); + float sx = getFloat(); + float sy = getFloat(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy); + renderer.scale(sx, sy); } break; case Skew: { - renderer.skew(getFloat(), getFloat()); + float sx = getFloat(); + float sy = getFloat(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy); + renderer.skew(sx, sy); } break; case SetMatrix: { - renderer.setMatrix(getMatrix()); + SkMatrix* matrix = getMatrix(); + DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix); + renderer.setMatrix(matrix); } break; case ConcatMatrix: { - renderer.concatMatrix(getMatrix()); + SkMatrix* matrix = getMatrix(); + DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix); + renderer.concatMatrix(matrix); } break; case ClipRect: { - renderer.clipRect(getFloat(), getFloat(), getFloat(), getFloat(), - (SkRegion::Op) getInt()); + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + int regionOp = getInt(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op], + f1, f2, f3, f4, regionOp); + renderer.clipRect(f1, f2, f3, f4, (SkRegion::Op) regionOp); } break; case DrawDisplayList: { - renderer.drawDisplayList(getDisplayList(), level + 1); + DisplayList* displayList = getDisplayList(); + DISPLAY_LIST_LOGD("%s%s %p, %d", (char*) indent, OP_NAMES[op], + displayList, level + 1); + needsInvalidate |= renderer.drawDisplayList(displayList, level + 1); } break; case DrawLayer: { - renderer.drawLayer((Layer*) getInt(), getFloat(), getFloat(), getPaint()); + Layer* layer = (Layer*) getInt(); + float x = getFloat(); + float y = getFloat(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], + layer, x, y, paint); + renderer.drawLayer(layer, x, y, paint); } break; case DrawBitmap: { - renderer.drawBitmap(getBitmap(), getFloat(), getFloat(), getPaint()); + SkBitmap* bitmap = getBitmap(); + float x = getFloat(); + float y = getFloat(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], + bitmap, x, y, paint); + renderer.drawBitmap(bitmap, x, y, paint); } break; case DrawBitmapMatrix: { - renderer.drawBitmap(getBitmap(), getMatrix(), getPaint()); + SkBitmap* bitmap = getBitmap(); + SkMatrix* matrix = getMatrix(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %p, %p, %p", (char*) indent, OP_NAMES[op], + bitmap, matrix, paint); + renderer.drawBitmap(bitmap, matrix, paint); } break; case DrawBitmapRect: { - renderer.drawBitmap(getBitmap(), getFloat(), getFloat(), getFloat(), getFloat(), - getFloat(), getFloat(), getFloat(), getFloat(), getPaint()); + SkBitmap* bitmap = getBitmap(); + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + float f5 = getFloat(); + float f6 = getFloat(); + float f7 = getFloat(); + float f8 = getFloat(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p", + (char*) indent, OP_NAMES[op], bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint); + renderer.drawBitmap(bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint); } break; case DrawBitmapMesh: { @@ -323,6 +403,7 @@ void DisplayList::replay(OpenGLRenderer& renderer, uint32_t level) { bool hasColors = getInt(); int* colors = hasColors ? getInts(colorsCount) : NULL; + DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.drawBitmapMesh(bitmap, meshWidth, meshHeight, vertices, colors, getPaint()); } break; @@ -340,80 +421,148 @@ void DisplayList::replay(OpenGLRenderer& renderer, uint32_t level) { yDivs = getInts(yDivsCount); colors = getUInts(numColors); + DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.drawPatch(bitmap, xDivs, yDivs, colors, xDivsCount, yDivsCount, numColors, getFloat(), getFloat(), getFloat(), getFloat(), getPaint()); } break; case DrawColor: { - renderer.drawColor(getInt(), (SkXfermode::Mode) getInt()); + int color = getInt(); + int xferMode = getInt(); + DISPLAY_LIST_LOGD("%s%s 0x%x %d", (char*) indent, OP_NAMES[op], color, xferMode); + renderer.drawColor(color, (SkXfermode::Mode) xferMode); } break; case DrawRect: { - renderer.drawRect(getFloat(), getFloat(), getFloat(), getFloat(), getPaint()); + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], + f1, f2, f3, f4, paint); + renderer.drawRect(f1, f2, f3, f4, paint); } break; case DrawRoundRect: { - renderer.drawRoundRect(getFloat(), getFloat(), getFloat(), getFloat(), - getFloat(), getFloat(), getPaint()); + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + float f5 = getFloat(); + float f6 = getFloat(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p", + (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint); + renderer.drawRoundRect(f1, f2, f3, f4, f5, f6, paint); } break; case DrawCircle: { - renderer.drawCircle(getFloat(), getFloat(), getFloat(), getPaint()); + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %p", + (char*) indent, OP_NAMES[op], f1, f2, f3, paint); + renderer.drawCircle(f1, f2, f3, paint); } break; case DrawOval: { - renderer.drawOval(getFloat(), getFloat(), getFloat(), getFloat(), getPaint()); + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", + (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint); + renderer.drawOval(f1, f2, f3, f4, paint); } break; case DrawArc: { - renderer.drawArc(getFloat(), getFloat(), getFloat(), getFloat(), - getFloat(), getFloat(), getInt() == 1, getPaint()); + float f1 = getFloat(); + float f2 = getFloat(); + float f3 = getFloat(); + float f4 = getFloat(); + float f5 = getFloat(); + float f6 = getFloat(); + int i1 = getInt(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p", + (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint); + renderer.drawArc(f1, f2, f3, f4, f5, f6, i1 == 1, paint); } break; case DrawPath: { - renderer.drawPath(getPath(), getPaint()); + SkPath* path = getPath(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %p, %p", (char*) indent, OP_NAMES[op], path, paint); + renderer.drawPath(path, paint); } break; case DrawLines: { int count = 0; float* points = getFloats(count); + DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.drawLines(points, count, getPaint()); } break; case DrawText: { getText(&text); - renderer.drawText(text.text(), text.length(), getInt(), - getFloat(), getFloat(), getPaint()); + int count = getInt(); + float x = getFloat(); + float y = getFloat(); + SkPaint* paint = getPaint(); + DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], + text.text(), text.length(), count, x, y, paint); + renderer.drawText(text.text(), text.length(), count, x, y, paint); } break; case ResetShader: { + DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.resetShader(); } break; case SetupShader: { - renderer.setupShader(getShader()); + SkiaShader* shader = getShader(); + DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], shader); + renderer.setupShader(shader); } break; case ResetColorFilter: { + DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.resetColorFilter(); } break; case SetupColorFilter: { - renderer.setupColorFilter(getColorFilter()); + SkiaColorFilter *colorFilter = getColorFilter(); + DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], colorFilter); + renderer.setupColorFilter(colorFilter); } break; case ResetShadow: { + DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); renderer.resetShadow(); } break; case SetupShadow: { - renderer.setupShadow(getFloat(), getFloat(), getFloat(), getInt()); - } - break; + float radius = getFloat(); + float dx = getFloat(); + float dy = getFloat(); + int color = getInt(); + DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op], + radius, dx, dy, color); + renderer.setupShadow(radius, dx, dy, color); + } + break; + default: + DISPLAY_LIST_LOGD("Display List error: op not handled: %s%s", + (char*) indent, OP_NAMES[op]); + break; } } - DISPLAY_LIST_LOGD("%sDone", (char*) indent + 2); + DISPLAY_LIST_LOGD("%sDone, returning %d", (char*) indent + 2, needsInvalidate); + return needsInvalidate; } /////////////////////////////////////////////////////////////////////////////// @@ -493,12 +642,26 @@ void DisplayListRenderer::finish() { OpenGLRenderer::finish(); } +void DisplayListRenderer::interrupt() { + +} +void DisplayListRenderer::resume() { + +} void DisplayListRenderer::acquireContext() { + // TODO: probably noop instead of calling super addOp(DisplayList::AcquireContext); OpenGLRenderer::acquireContext(); } +bool DisplayListRenderer::callDrawGLFunction(Functor *functor) { + addOp(DisplayList::DrawGLFunction); + addInt((int) functor); + return false; // No invalidate needed at record-time +} + void DisplayListRenderer::releaseContext() { + // TODO: probably noop instead of calling super addOp(DisplayList::ReleaseContext); OpenGLRenderer::releaseContext(); } @@ -581,9 +744,10 @@ bool DisplayListRenderer::clipRect(float left, float top, float right, float bot return OpenGLRenderer::clipRect(left, top, right, bottom, op); } -void DisplayListRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) { +bool DisplayListRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) { addOp(DisplayList::DrawDisplayList); addDisplayList(displayList); + return false; } void DisplayListRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) { diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index 35bb163..6c8e8f5 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -28,6 +28,7 @@ #include <SkTSearch.h> #include "OpenGLRenderer.h" +#include "Functor.h" namespace android { namespace uirenderer { @@ -124,13 +125,14 @@ public: SetupColorFilter, ResetShadow, SetupShadow, + DrawGLFunction, }; static const char* OP_NAMES[]; void initFromDisplayListRenderer(const DisplayListRenderer& recorder); - void replay(OpenGLRenderer& renderer, uint32_t level = 0); + bool replay(OpenGLRenderer& renderer, uint32_t level = 0); private: void init(); @@ -242,9 +244,13 @@ public: void prepare(bool opaque); void finish(); + bool callDrawGLFunction(Functor *functor); void acquireContext(); void releaseContext(); + void interrupt(); + void resume(); + int save(int flags); void restore(); void restoreToCount(int saveCount); @@ -264,7 +270,7 @@ public: bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op); - void drawDisplayList(DisplayList* displayList, uint32_t level = 0); + bool drawDisplayList(DisplayList* displayList, uint32_t level = 0); void drawLayer(Layer* layer, float x, float y, SkPaint* paint); void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint); void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint); diff --git a/libs/hwui/OpenGLDebugRenderer.cpp b/libs/hwui/OpenGLDebugRenderer.cpp index 29bcde8..58d6c26 100644 --- a/libs/hwui/OpenGLDebugRenderer.cpp +++ b/libs/hwui/OpenGLDebugRenderer.cpp @@ -48,10 +48,10 @@ int OpenGLDebugRenderer::saveLayer(float left, float top, float right, float bot return OpenGLRenderer::saveLayer(left, top, right, bottom, p, flags); } -void OpenGLDebugRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) { +bool OpenGLDebugRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) { mPrimitivesCount++; StopWatch w("drawDisplayList"); - OpenGLRenderer::drawDisplayList(displayList); + return OpenGLRenderer::drawDisplayList(displayList); } void OpenGLDebugRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) { diff --git a/libs/hwui/OpenGLDebugRenderer.h b/libs/hwui/OpenGLDebugRenderer.h index aefa7bf..76e6a2e 100644 --- a/libs/hwui/OpenGLDebugRenderer.h +++ b/libs/hwui/OpenGLDebugRenderer.h @@ -40,7 +40,7 @@ public: int saveLayer(float left, float top, float right, float bottom, SkPaint* p, int flags); - void drawDisplayList(DisplayList* displayList, uint32_t level = 0); + bool drawDisplayList(DisplayList* displayList, uint32_t level = 0); void drawLayer(Layer* layer, float x, float y, SkPaint* paint); void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint); void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index e8dc9f6..98f8fc5 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -213,6 +213,13 @@ void OpenGLRenderer::releaseContext() { resume(); } +bool OpenGLRenderer::callDrawGLFunction(Functor *functor) { + interrupt(); + status_t result = (*functor)(); + resume(); + return (result == 0) ? false : true; +} + /////////////////////////////////////////////////////////////////////////////// // State management /////////////////////////////////////////////////////////////////////////////// @@ -1031,12 +1038,13 @@ void OpenGLRenderer::finishDrawTexture() { // Drawing /////////////////////////////////////////////////////////////////////////////// -void OpenGLRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) { +bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) { // All the usual checks and setup operations (quickReject, setupDraw, etc.) // will be performed by the display list itself if (displayList) { - displayList->replay(*this, level); + return displayList->replay(*this, level); } + return false; } void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) { diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index eec3750..bd29609 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -27,6 +27,7 @@ #include <SkShader.h> #include <SkXfermode.h> +#include <utils/Functor.h> #include <utils/RefBase.h> #include <utils/Vector.h> @@ -65,9 +66,10 @@ public: virtual void finish(); // These two calls must not be recorded in display lists - void interrupt(); - void resume(); + virtual void interrupt(); + virtual void resume(); + virtual bool callDrawGLFunction(Functor *functor); virtual void acquireContext(); virtual void releaseContext(); @@ -95,7 +97,7 @@ public: bool quickReject(float left, float top, float right, float bottom); virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op); - virtual void drawDisplayList(DisplayList* displayList, uint32_t level = 0); + virtual bool drawDisplayList(DisplayList* displayList, uint32_t level = 0); virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint); virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint); virtual void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint); diff --git a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java index b0d29a1..54db8cd 100755 --- a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java +++ b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java @@ -1896,7 +1896,9 @@ class MediaArtistNativeHelper { private void onPreviewProgressUpdate(int progress, boolean isFinished) { if (mPreviewProgressListener != null) { mPreviewProgressListener.onProgress(mVideoEditor, progress, isFinished); - mPreviewProgress = progress; + if (progress != 0) { + mPreviewProgress = progress; + } } } diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel.xml b/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel.xml index 4cf28ee..821cf6a 100644 --- a/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel.xml +++ b/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel.xml @@ -31,6 +31,7 @@ android:layout_width="match_parent" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" + android:layout_marginBottom="-27dip" > <include layout="@layout/status_bar_notification_panel_title" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java index 9f48b48..092f0b8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java @@ -46,7 +46,10 @@ public class NotificationPanel extends RelativeLayout implements StatusBarPanel, static final String TAG = "Tablet/NotificationPanel"; static final boolean DEBUG = false; + final static int PANEL_FADE_DURATION = 150; + boolean mShowing; + int mNotificationCount = 0; View mTitleArea; View mModeToggle; View mSettingsButton; @@ -90,6 +93,10 @@ public class NotificationPanel extends RelativeLayout implements StatusBarPanel, } public void show(boolean show, boolean animate) { + if (show && !mShowing) { + setContentFrameVisible(mNotificationCount > 0, false); + } + if (animate) { if (mShowing != show) { mShowing = show; @@ -150,7 +157,43 @@ public class NotificationPanel extends RelativeLayout implements StatusBarPanel, } } - final static int PANEL_FADE_DURATION = 150; + public void setNotificationCount(int n) { + Slog.d(TAG, "notificationCount=" + n); + if (!mShowing) { + // just do it, already + setContentFrameVisible(n > 0, false); + } else if (mSettingsView == null) { + // we're looking at the notifications; time to maybe make some changes + if (mNotificationCount == 0 && n > 0) { + setContentFrameVisible(true, true); + } else if (mNotificationCount > 0 && n == 0) { + setContentFrameVisible(false, true); + } + } + mNotificationCount = n; + } + + public void setContentFrameVisible(final boolean showing, boolean animate) { + if (!animate) { + mContentFrame.setVisibility(showing ? View.VISIBLE : View.GONE); + mContentParent.setTranslationY(showing ? 0f : 100f); + return; + } + + mContentFrame.setVisibility(showing ? View.VISIBLE : View.GONE); + AnimatorSet set = new AnimatorSet(); + float adjust = mContentFrame.getBackground().getMinimumHeight() + 8; // fudge factor + set.play(ObjectAnimator.ofFloat( + mContentFrame, "alpha", + showing ? 0f : 1f, + showing ? 1f : 0f)) + .with(ObjectAnimator.ofFloat( + mContentParent, "translationY", + showing ? adjust : 0f, + showing ? 0f : adjust)); + set.setDuration(200); + set.start(); + } public void swapPanels() { final View toShow, toHide; @@ -168,12 +211,22 @@ public class NotificationPanel extends RelativeLayout implements StatusBarPanel, @Override public void onAnimationEnd(Animator _a) { toHide.setVisibility(View.GONE); - toShow.setVisibility(View.VISIBLE); - ObjectAnimator.ofFloat(toShow, "alpha", 0f, 1f) - .setDuration(PANEL_FADE_DURATION) - .start(); - if (toHide == mSettingsView) { - removeSettingsView(); + if (toShow != null) { + if (mNotificationCount == 0) { + // show the frame for settings, hide for notifications + setContentFrameVisible(toShow == mSettingsView, true); + } + + toShow.setVisibility(View.VISIBLE); + if (toShow == mSettingsView || mNotificationCount > 0) { + ObjectAnimator.ofFloat(toShow, "alpha", 0f, 1f) + .setDuration(PANEL_FADE_DURATION) + .start(); + } + + if (toHide == mSettingsView) { + removeSettingsView(); + } } updatePanelModeButtons(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java index c2f74f0..e26b8ea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java @@ -1219,6 +1219,8 @@ public class TabletStatusBar extends StatusBar implements mPile.addView(toShow.get(i)); } } + + mNotificationPanel.setNotificationCount(N); } void workAroundBadLayerDrawableOpacity(View v) { |
