Merge "Implement issue #3201795: Improve transition when keyboard comes up"
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 6f4abef..24a9f87 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -94,13 +94,18 @@
*/
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 @@
}
@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 @@
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 cb7d0e2..77083a9 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -25,7 +25,9 @@
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.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 @@
* {@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 @@
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 @@
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 @@
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 @@
// 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 @@
if (mScroller != null) {
mScroller.abortAnimation();
}
+ disposeResizeBitmap();
}
} catch (RemoteException e) {
}
@@ -1310,6 +1368,22 @@
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 @@
}
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 @@
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 @@
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 @@
Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
}
- if (scrolling) {
+ if (animating) {
mFullRedrawNeeded = true;
scheduleTraversals();
}
@@ -1600,7 +1695,7 @@
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 1cc6a2a..a95a6c7 100644
--- a/services/java/com/android/server/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/ScreenRotationAnimation.java
@@ -122,7 +122,9 @@
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 5e49404..27ec1af 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -6848,6 +6848,8 @@
}
if (!mParentFrame.equals(pf)) {
+ //Slog.i(TAG, "Window " + this + " content frame from " + mParentFrame
+ // + " to " + pf);
mParentFrame.set(pf);
mContentChanged = true;
}
@@ -7734,12 +7736,10 @@
* 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 @@
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 @@
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 @@
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 @@
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) {