diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 6f4abefbddfd7..24a9f870ec875 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -94,13 +94,18 @@ public abstract class HardwareRenderer { */ abstract void setup(int width, int height); + interface HardwareDrawCallbacks { + void onHardwarePreDraw(Canvas canvas); + void onHardwarePostDraw(Canvas canvas); + } + /** * Draws the specified view. * * @param view The view to draw. * @param attachInfo AttachInfo tied to the specified view. */ - abstract void draw(View view, View.AttachInfo attachInfo, int yOffset); + abstract void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks); /** * Creates a new display list that can be used to record batches of @@ -456,7 +461,7 @@ public abstract class HardwareRenderer { } @Override - void draw(View view, View.AttachInfo attachInfo, int yOffset) { + void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks) { if (canDraw()) { attachInfo.mDrawingTime = SystemClock.uptimeMillis(); attachInfo.mIgnoreDirtyState = true; @@ -473,11 +478,12 @@ public abstract class HardwareRenderer { Canvas canvas = mCanvas; int saveCount = canvas.save(); - canvas.translate(0, -yOffset); + callbacks.onHardwarePreDraw(canvas); try { view.draw(canvas); } finally { + callbacks.onHardwarePostDraw(canvas); canvas.restoreToCount(saveCount); } diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index cb7d0e277e623..77083a9021125 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -25,7 +25,9 @@ import android.content.pm.PackageManager; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Resources; +import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.PointF; @@ -57,6 +59,8 @@ import android.util.TypedValue; import android.view.View.MeasureSpec; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.Interpolator; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.widget.Scroller; @@ -79,7 +83,8 @@ import java.util.ArrayList; * {@hide} */ @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"}) -public final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Callbacks { +public final class ViewRoot extends Handler implements ViewParent, + View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks { private static final String TAG = "ViewRoot"; private static final boolean DBG = false; private static final boolean SHOW_FPS = false; @@ -213,6 +218,10 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn int mScrollY; int mCurScrollY; Scroller mScroller; + Bitmap mResizeBitmap; + long mResizeBitmapStartTime; + int mResizeBitmapDuration; + static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator(); final ViewConfiguration mViewConfiguration; @@ -626,6 +635,13 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn return mAppVisible ? mView.getVisibility() : View.GONE; } + void disposeResizeBitmap() { + if (mResizeBitmap != null) { + mResizeBitmap.recycle(); + mResizeBitmap = null; + } + } + private void performTraversals() { // cache mView since it is used so much below... final View host = mView; @@ -734,6 +750,48 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn ensureTouchModeLocally(mAddedTouchMode); } else { if (!mAttachInfo.mContentInsets.equals(mPendingContentInsets)) { + if (mWidth > 0 && mHeight > 0 && + mSurface != null && mSurface.isValid() && + mAttachInfo.mHardwareRenderer != null && + mAttachInfo.mHardwareRenderer.isEnabled() && + lp != null && !PixelFormat.formatHasAlpha(lp.format)) { + + disposeResizeBitmap(); + + boolean completed = false; + try { + mResizeBitmap = Bitmap.createBitmap(mWidth, mHeight, + Bitmap.Config.ARGB_8888); + mResizeBitmap.setHasAlpha(false); + Canvas canvas = new Canvas(mResizeBitmap); + int yoff; + final boolean scrolling = mScroller != null + && mScroller.computeScrollOffset(); + if (scrolling) { + yoff = mScroller.getCurrY(); + mScroller.abortAnimation(); + } else { + yoff = mScrollY; + } + canvas.translate(0, -yoff); + if (mTranslator != null) { + mTranslator.translateCanvas(canvas); + } + canvas.setScreenDensity(mAttachInfo.mScalingRequired + ? DisplayMetrics.DENSITY_DEVICE : 0); + mView.draw(canvas); + mResizeBitmapStartTime = SystemClock.uptimeMillis(); + mResizeBitmapDuration = mView.getResources().getInteger( + com.android.internal.R.integer.config_mediumAnimTime); + completed = true; + } catch (OutOfMemoryError e) { + Log.w(TAG, "Not enough memory for content change anim buffer", e); + } finally { + if (!completed) { + mResizeBitmap = null; + } + } + } mAttachInfo.mContentInsets.set(mPendingContentInsets); host.fitSystemWindows(mAttachInfo.mContentInsets); insetsChanged = true; @@ -787,7 +845,6 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn // Maybe we can just try the next size up, and see if that reduces // the height? if (host.getWidth() <= baseSize /*&& host.getHeight() <= maxHeight*/) { - Log.v(TAG, "Good!"); goodMeasure = true; } else { // Didn't fit in that size... try expanding a bit. @@ -972,6 +1029,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn if (mScroller != null) { mScroller.abortAnimation(); } + disposeResizeBitmap(); } } catch (RemoteException e) { } @@ -1310,6 +1368,22 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn return measureSpec; } + int mHardwareYOffset; + int mResizeAlpha; + final Paint mResizePaint = new Paint(); + + public void onHardwarePreDraw(Canvas canvas) { + canvas.translate(0, -mHardwareYOffset); + } + + public void onHardwarePostDraw(Canvas canvas) { + if (mResizeBitmap != null) { + canvas.translate(0, mHardwareYOffset); + mResizePaint.setAlpha(mResizeAlpha); + canvas.drawBitmap(mResizeBitmap, 0, 0, mResizePaint); + } + } + private void draw(boolean fullRedrawNeeded) { Surface surface = mSurface; if (surface == null || !surface.isValid()) { @@ -1334,8 +1408,8 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn } int yoff; - final boolean scrolling = mScroller != null && mScroller.computeScrollOffset(); - if (scrolling) { + boolean animating = mScroller != null && mScroller.computeScrollOffset(); + if (animating) { yoff = mScroller.getCurrY(); } else { yoff = mScrollY; @@ -1347,10 +1421,29 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn float appScale = mAttachInfo.mApplicationScale; boolean scalingRequired = mAttachInfo.mScalingRequired; + int resizeAlpha = 0; + if (mResizeBitmap != null) { + long deltaTime = SystemClock.uptimeMillis() - mResizeBitmapStartTime; + if (deltaTime < mResizeBitmapDuration) { + float amt = deltaTime/(float)mResizeBitmapDuration; + amt = mResizeInterpolator.getInterpolation(amt); + animating = true; + resizeAlpha = 255 - (int)(amt*255); + } else { + disposeResizeBitmap(); + } + } + Rect dirty = mDirty; if (mSurfaceHolder != null) { // The app owns the surface, we won't draw. dirty.setEmpty(); + if (animating) { + if (mScroller != null) { + mScroller.abortAnimation(); + } + disposeResizeBitmap(); + } return; } @@ -1363,10 +1456,12 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn if (!dirty.isEmpty() || mIsAnimating) { mIsAnimating = false; dirty.setEmpty(); - mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, yoff); + mHardwareYOffset = yoff; + mResizeAlpha = resizeAlpha; + mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this); } - if (scrolling) { + if (animating) { mFullRedrawNeeded = true; scheduleTraversals(); } @@ -1486,7 +1581,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost"); } - if (scrolling) { + if (animating) { mFullRedrawNeeded = true; scheduleTraversals(); } @@ -1600,7 +1695,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn if (scrollY != mScrollY) { if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old=" + mScrollY + " , new=" + scrollY); - if (!immediate) { + if (!immediate && mResizeBitmap == null) { if (mScroller == null) { mScroller = new Scroller(mView.getContext()); } diff --git a/services/java/com/android/server/ScreenRotationAnimation.java b/services/java/com/android/server/ScreenRotationAnimation.java index 1cc6a2a551219..a95a6c715774f 100644 --- a/services/java/com/android/server/ScreenRotationAnimation.java +++ b/services/java/com/android/server/ScreenRotationAnimation.java @@ -122,7 +122,9 @@ class ScreenRotationAnimation { mSurface.unlockCanvasAndPost(c); Surface.closeTransaction(); - screenshot.recycle(); + if (screenshot != null) { + screenshot.recycle(); + } } static int deltaRotation(int oldRotation, int newRotation) { diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index 5e4940400ef35..27ec1af5eda0e 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -6848,6 +6848,8 @@ public class WindowManagerService extends IWindowManager.Stub } if (!mParentFrame.equals(pf)) { + //Slog.i(TAG, "Window " + this + " content frame from " + mParentFrame + // + " to " + pf); mParentFrame.set(pf); mContentChanged = true; } @@ -7734,12 +7736,10 @@ public class WindowManagerService extends IWindowManager.Stub * sense to call from performLayoutAndPlaceSurfacesLockedInner().) */ boolean shouldAnimateMove() { - return mContentChanged && !mAnimating && !mLastHidden && !mDisplayFrozen + return mContentChanged && !mExiting && !mLastHidden && !mDisplayFrozen && (mFrame.top != mLastFrame.top || mFrame.left != mLastFrame.left) - && (mAttachedWindow == null - || (mAttachedWindow.mAnimation == null - && !mAttachedWindow.shouldAnimateMove())) + && (mAttachedWindow == null || !mAttachedWindow.shouldAnimateMove()) && mPolicy.isScreenOn(); } @@ -9223,6 +9223,7 @@ public class WindowManagerService extends IWindowManager.Stub if (!gone || !win.mHaveFrame) { if (!win.mLayoutAttached) { if (initial) { + //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial"); win.mContentChanged = false; } mPolicy.layoutWindowLw(win, win.mAttrs, null); @@ -9257,6 +9258,7 @@ public class WindowManagerService extends IWindowManager.Stub if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled) || !win.mHaveFrame) { if (initial) { + //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial"); win.mContentChanged = false; } mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow); @@ -9455,7 +9457,6 @@ public class WindowManagerService extends IWindowManager.Stub w.setAnimation(a); animDw = w.mLastFrame.left - w.mFrame.left; animDh = w.mLastFrame.top - w.mFrame.top; - w.mContentChanged = false; } // Execute animation. @@ -10242,6 +10243,11 @@ public class WindowManagerService extends IWindowManager.Stub w.mOrientationChanging = false; } + if (w.mContentChanged) { + //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing"); + w.mContentChanged = false; + } + final boolean canBeSeen = w.isDisplayedLw(); if (someoneLosingFocus && w == mCurrentFocus && canBeSeen) {