Merge "Adding support for clipping window transition for alternate recents."

This commit is contained in:
Winson Chung
2014-03-21 01:02:43 +00:00
committed by Android (Google) Code Review
5 changed files with 405 additions and 89 deletions

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2014 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.
*/
package android.view.animation;
import android.graphics.Rect;
/**
* An animation that controls the clip of an object. See the
* {@link android.view.animation full package} description for details and
* sample code.
*
* @hide
*/
public class ClipRectAnimation extends Animation {
private Rect mFromRect = new Rect();
private Rect mToRect = new Rect();
/**
* Constructor to use when building a ClipRectAnimation from code
*
* @param fromClip the clip rect to animate from
* @param toClip the clip rect to animate to
*/
public ClipRectAnimation(Rect fromClip, Rect toClip) {
if (fromClip == null || toClip == null) {
throw new RuntimeException("Expected non-null animation clip rects");
}
mFromRect.set(fromClip);
mToRect.set(toClip);
}
@Override
protected void applyTransformation(float it, Transformation tr) {
int l = mFromRect.left + (int) ((mToRect.left - mFromRect.left) * it);
int t = mFromRect.top + (int) ((mToRect.top - mFromRect.top) * it);
int r = mFromRect.right + (int) ((mToRect.right - mFromRect.right) * it);
int b = mFromRect.bottom + (int) ((mToRect.bottom - mFromRect.bottom) * it);
tr.setClipRect(l, t, r, b);
}
@Override
public boolean willChangeTransformationMatrix() {
return false;
}
}

View File

@@ -17,6 +17,7 @@
package android.view.animation; package android.view.animation;
import android.graphics.Matrix; import android.graphics.Matrix;
import android.graphics.Rect;
import java.io.PrintWriter; import java.io.PrintWriter;
@@ -47,6 +48,9 @@ public class Transformation {
protected float mAlpha; protected float mAlpha;
protected int mTransformationType; protected int mTransformationType;
private boolean mHasClipRect;
private Rect mClipRect = new Rect();
/** /**
* Creates a new transformation with alpha = 1 and the identity matrix. * Creates a new transformation with alpha = 1 and the identity matrix.
*/ */
@@ -65,6 +69,8 @@ public class Transformation {
} else { } else {
mMatrix.reset(); mMatrix.reset();
} }
mClipRect.setEmpty();
mHasClipRect = false;
mAlpha = 1.0f; mAlpha = 1.0f;
mTransformationType = TYPE_BOTH; mTransformationType = TYPE_BOTH;
} }
@@ -98,9 +104,15 @@ public class Transformation {
public void set(Transformation t) { public void set(Transformation t) {
mAlpha = t.getAlpha(); mAlpha = t.getAlpha();
mMatrix.set(t.getMatrix()); mMatrix.set(t.getMatrix());
if (t.mHasClipRect) {
setClipRect(t.getClipRect());
} else {
mHasClipRect = false;
mClipRect.setEmpty();
}
mTransformationType = t.getTransformationType(); mTransformationType = t.getTransformationType();
} }
/** /**
* Apply this Transformation to an existing Transformation, e.g. apply * Apply this Transformation to an existing Transformation, e.g. apply
* a scale effect to something that has already been rotated. * a scale effect to something that has already been rotated.
@@ -109,6 +121,9 @@ public class Transformation {
public void compose(Transformation t) { public void compose(Transformation t) {
mAlpha *= t.getAlpha(); mAlpha *= t.getAlpha();
mMatrix.preConcat(t.getMatrix()); mMatrix.preConcat(t.getMatrix());
if (t.mHasClipRect) {
setClipRect(t.getClipRect());
}
} }
/** /**
@@ -119,6 +134,9 @@ public class Transformation {
public void postCompose(Transformation t) { public void postCompose(Transformation t) {
mAlpha *= t.getAlpha(); mAlpha *= t.getAlpha();
mMatrix.postConcat(t.getMatrix()); mMatrix.postConcat(t.getMatrix());
if (t.mHasClipRect) {
setClipRect(t.getClipRect());
}
} }
/** /**
@@ -137,6 +155,39 @@ public class Transformation {
mAlpha = alpha; mAlpha = alpha;
} }
/**
* Sets the current Transform's clip rect
* @hide
*/
public void setClipRect(Rect r) {
setClipRect(r.left, r.top, r.right, r.bottom);
}
/**
* Sets the current Transform's clip rect
* @hide
*/
public void setClipRect(int l, int t, int r, int b) {
mClipRect.set(l, t, r, b);
mHasClipRect = true;
}
/**
* Returns the current Transform's clip rect
* @hide
*/
public Rect getClipRect() {
return mClipRect;
}
/**
* Returns whether the current Transform's clip rect is set
* @hide
*/
public boolean hasClipRect() {
return mHasClipRect;
}
/** /**
* @return The degree of transparency * @return The degree of transparency
*/ */

View File

@@ -19,18 +19,22 @@ package com.android.server.wm;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Point; import android.graphics.Point;
import android.graphics.Rect;
import android.os.Debug; import android.os.Debug;
import android.os.Handler; import android.os.Handler;
import android.os.IRemoteCallback; import android.os.IRemoteCallback;
import android.os.SystemProperties;
import android.util.Slog; import android.util.Slog;
import android.view.WindowManager; import android.view.WindowManager;
import android.view.animation.AlphaAnimation; import android.view.animation.AlphaAnimation;
import android.view.animation.Animation; import android.view.animation.Animation;
import android.view.animation.AnimationSet; import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils; import android.view.animation.AnimationUtils;
import android.view.animation.ClipRectAnimation;
import android.view.animation.Interpolator; import android.view.animation.Interpolator;
import android.view.animation.ScaleAnimation; import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import com.android.internal.util.DumpUtils.Dump; import com.android.internal.util.DumpUtils.Dump;
import com.android.server.AttributeCache; import com.android.server.AttributeCache;
import com.android.server.wm.WindowManagerService.H; import com.android.server.wm.WindowManagerService.H;
@@ -125,6 +129,12 @@ public class AppTransition implements Dump {
private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN = 4; private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN = 4;
private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE; private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
// These are the possible states for the enter/exit activities during a thumbnail transition
private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_UP = 0;
private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_UP = 1;
private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN = 2;
private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN = 3;
private String mNextAppTransitionPackage; private String mNextAppTransitionPackage;
private Bitmap mNextAppTransitionThumbnail; private Bitmap mNextAppTransitionThumbnail;
// Used for thumbnail transitions. True if we're scaling up, false if scaling down // Used for thumbnail transitions. True if we're scaling up, false if scaling down
@@ -148,10 +158,13 @@ public class AppTransition implements Dump {
private final Interpolator mThumbnailFadeoutInterpolator; private final Interpolator mThumbnailFadeoutInterpolator;
private int mCurrentUserId = 0; private int mCurrentUserId = 0;
private boolean mUseAlternateThumbnailAnimation;
AppTransition(Context context, Handler h) { AppTransition(Context context, Handler h) {
mContext = context; mContext = context;
mH = h; mH = h;
mUseAlternateThumbnailAnimation =
SystemProperties.getBoolean("persist.anim.use_alt_thumbnail", false);
mConfigShortAnimTime = context.getResources().getInteger( mConfigShortAnimTime = context.getResources().getInteger(
com.android.internal.R.integer.config_shortAnimTime); com.android.internal.R.integer.config_shortAnimTime);
mDecelerateInterpolator = AnimationUtils.loadInterpolator(context, mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
@@ -384,80 +397,10 @@ public class AppTransition implements Dump {
return a; return a;
} }
Animation createThumbnailAnimationLocked(int transit, boolean enter, boolean thumb, /**
int appWidth, int appHeight) { * Prepares the specified animation with a standard duration, interpolator, etc.
Animation a; */
final int thumbWidthI = mNextAppTransitionThumbnail.getWidth(); Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit) {
final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
if (thumb) {
// Animation for zooming thumbnail from its initial size to
// filling the screen.
if (mNextAppTransitionScaleUp) {
float scaleW = appWidth / thumbWidth;
float scaleH = appHeight / thumbHeight;
Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
computePivot(mNextAppTransitionStartX, 1 / scaleW),
computePivot(mNextAppTransitionStartY, 1 / scaleH));
scale.setInterpolator(mDecelerateInterpolator);
Animation alpha = new AlphaAnimation(1, 0);
alpha.setInterpolator(mThumbnailFadeoutInterpolator);
// This AnimationSet uses the Interpolators assigned above.
AnimationSet set = new AnimationSet(false);
set.addAnimation(scale);
set.addAnimation(alpha);
a = set;
} else {
float scaleW = appWidth / thumbWidth;
float scaleH = appHeight / thumbHeight;
a = new ScaleAnimation(scaleW, 1, scaleH, 1,
computePivot(mNextAppTransitionStartX, 1 / scaleW),
computePivot(mNextAppTransitionStartY, 1 / scaleH));
}
} else if (enter) {
// Entering app zooms out from the center of the thumbnail.
if (mNextAppTransitionScaleUp) {
float scaleW = thumbWidth / appWidth;
float scaleH = thumbHeight / appHeight;
a = new ScaleAnimation(scaleW, 1, scaleH, 1,
computePivot(mNextAppTransitionStartX, scaleW),
computePivot(mNextAppTransitionStartY, scaleH));
} else {
// noop animation
a = new AlphaAnimation(1, 1);
}
} else {
// Exiting app
if (mNextAppTransitionScaleUp) {
if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
// Fade out while bringing up selected activity. This keeps the
// current activity from showing through a launching wallpaper
// activity.
a = new AlphaAnimation(1, 0);
} else {
// noop animation
a = new AlphaAnimation(1, 1);
}
} else {
float scaleW = thumbWidth / appWidth;
float scaleH = thumbHeight / appHeight;
Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
computePivot(mNextAppTransitionStartX, scaleW),
computePivot(mNextAppTransitionStartY, scaleH));
Animation alpha = new AlphaAnimation(1, 0);
AnimationSet set = new AnimationSet(true);
set.addAnimation(scale);
set.addAnimation(alpha);
set.setZAdjustment(Animation.ZORDER_TOP);
a = set;
}
}
// Pick the desired duration. If this is an inter-activity transition, // Pick the desired duration. If this is an inter-activity transition,
// it is the standard duration for that. Otherwise we use the longer // it is the standard duration for that. Otherwise we use the longer
// task transition duration. // task transition duration.
@@ -478,9 +421,223 @@ public class AppTransition implements Dump {
return a; return a;
} }
/**
* Return the current thumbnail transition state.
*/
int getThumbnailTransitionState(boolean enter) {
if (enter) {
if (mNextAppTransitionScaleUp) {
return THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
} else {
return THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN;
}
} else {
if (mNextAppTransitionScaleUp) {
return THUMBNAIL_TRANSITION_EXIT_SCALE_UP;
} else {
return THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN;
}
}
}
/**
* This animation runs for the thumbnail that gets cross faded with the enter/exit activity
* when a thumbnail is specified with the activity options.
*/
Animation createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit) {
Animation a;
final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
if (mNextAppTransitionScaleUp) {
// Animation for the thumbnail zooming from its initial size to the full screen
float scaleW = appWidth / thumbWidth;
float scaleH = appHeight / thumbHeight;
Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
computePivot(mNextAppTransitionStartX, 1 / scaleW),
computePivot(mNextAppTransitionStartY, 1 / scaleH));
scale.setInterpolator(mDecelerateInterpolator);
Animation alpha = new AlphaAnimation(1, 0);
alpha.setInterpolator(mThumbnailFadeoutInterpolator);
// This AnimationSet uses the Interpolators assigned above.
AnimationSet set = new AnimationSet(false);
set.addAnimation(scale);
set.addAnimation(alpha);
a = set;
} else {
// Animation for the thumbnail zooming down from the full screen to its final size
float scaleW = appWidth / thumbWidth;
float scaleH = appHeight / thumbHeight;
a = new ScaleAnimation(scaleW, 1, scaleH, 1,
computePivot(mNextAppTransitionStartX, 1 / scaleW),
computePivot(mNextAppTransitionStartY, 1 / scaleH));
}
return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
}
/**
* This alternate animation is created when we are doing a thumbnail transition, for the
* activity that is leaving, and the activity that is entering.
*/
Animation createAlternateThumbnailEnterExitAnimationLocked(int thumbTransitState, int appWidth,
int appHeight, int transit,
Rect containingFrame, Rect contentInsets) {
Animation a;
final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
switch (thumbTransitState) {
case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
// Entering app scales up with the thumbnail
float scale = thumbWidth / appWidth;
int unscaledThumbHeight = (int) (thumbHeight / scale);
int scaledTopDecor = (int) (scale * contentInsets.top);
Rect fromClipRect = new Rect(containingFrame);
fromClipRect.bottom = (fromClipRect.top + unscaledThumbHeight);
Rect toClipRect = new Rect(containingFrame);
Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1,
computePivot(mNextAppTransitionStartX, scale),
computePivot(mNextAppTransitionStartY, scale));
Animation alphaAnim = new AlphaAnimation(1, 1);
Animation clipAnim = new ClipRectAnimation(fromClipRect, toClipRect);
Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0);
AnimationSet set = new AnimationSet(true);
set.addAnimation(alphaAnim);
set.addAnimation(clipAnim);
set.addAnimation(scaleAnim);
set.addAnimation(translateAnim);
a = set;
break;
}
case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
// Exiting app while the thumbnail is scaling up should fade
if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
// Fade out while bringing up selected activity. This keeps the
// current activity from showing through a launching wallpaper
// activity.
a = new AlphaAnimation(1, 0);
} else {
// noop animation
a = new AlphaAnimation(1, 1);
}
break;
}
case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
// Entering the other app, it should just be visible while we scale the thumbnail
// down above it
a = new AlphaAnimation(1, 1);
break;
}
case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
// Exiting the current app, the app should scale down with the thumbnail
float scale = thumbWidth / appWidth;
int unscaledThumbHeight = (int) (thumbHeight / scale);
int scaledTopDecor = (int) (scale * contentInsets.top);
Rect fromClipRect = new Rect(containingFrame);
Rect toClipRect = new Rect(containingFrame);
toClipRect.bottom = (toClipRect.top + unscaledThumbHeight);
Animation scaleAnim = new ScaleAnimation(1, scale, 1, scale,
computePivot(mNextAppTransitionStartX, scale),
computePivot(mNextAppTransitionStartY, scale));
Animation alphaAnim = new AlphaAnimation(1, 1);
Animation clipAnim = new ClipRectAnimation(fromClipRect, toClipRect);
Animation translateAnim = new TranslateAnimation(0, 0, 0, -scaledTopDecor);
AnimationSet set = new AnimationSet(true);
set.addAnimation(alphaAnim);
set.addAnimation(clipAnim);
set.addAnimation(scaleAnim);
set.addAnimation(translateAnim);
a = set;
a.setZAdjustment(Animation.ZORDER_TOP);
break;
}
default:
throw new RuntimeException("Invalid thumbnail transition state");
}
return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
}
/**
* This animation is created when we are doing a thumbnail transition, for the activity that is
* leaving, and the activity that is entering.
*/
Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, int appWidth,
int appHeight, int transit) {
Animation a;
final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
switch (thumbTransitState) {
case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
// Entering app scales up with the thumbnail
float scaleW = thumbWidth / appWidth;
float scaleH = thumbHeight / appHeight;
a = new ScaleAnimation(scaleW, 1, scaleH, 1,
computePivot(mNextAppTransitionStartX, scaleW),
computePivot(mNextAppTransitionStartY, scaleH));
break;
}
case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
// Exiting app while the thumbnail is scaling up should fade or stay in place
if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
// Fade out while bringing up selected activity. This keeps the
// current activity from showing through a launching wallpaper
// activity.
a = new AlphaAnimation(1, 0);
} else {
// noop animation
a = new AlphaAnimation(1, 1);
}
break;
}
case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
// Entering the other app, it should just be visible while we scale the thumbnail
// down above it
a = new AlphaAnimation(1, 1);
break;
}
case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
// Exiting the current app, the app should scale down with the thumbnail
float scaleW = thumbWidth / appWidth;
float scaleH = thumbHeight / appHeight;
Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
computePivot(mNextAppTransitionStartX, scaleW),
computePivot(mNextAppTransitionStartY, scaleH));
Animation alpha = new AlphaAnimation(1, 0);
AnimationSet set = new AnimationSet(true);
set.addAnimation(scale);
set.addAnimation(alpha);
set.setZAdjustment(Animation.ZORDER_TOP);
a = set;
break;
}
default:
throw new RuntimeException("Invalid thumbnail transition state");
}
return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
}
Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
int appWidth, int appHeight) { int appWidth, int appHeight, Rect containingFrame, Rect contentInsets) {
Animation a; Animation a;
if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) { if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
a = loadAnimation(mNextAppTransitionPackage, enter ? a = loadAnimation(mNextAppTransitionPackage, enter ?
@@ -501,7 +658,14 @@ public class AppTransition implements Dump {
mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) { mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
mNextAppTransitionScaleUp = mNextAppTransitionScaleUp =
(mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP); (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
a = createThumbnailAnimationLocked(transit, enter, false, appWidth, appHeight); if (mUseAlternateThumbnailAnimation) {
a = createAlternateThumbnailEnterExitAnimationLocked(
getThumbnailTransitionState(enter), appWidth, appHeight, transit,
containingFrame, contentInsets);
} else {
a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
appWidth, appHeight, transit);
}
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
String animName = mNextAppTransitionScaleUp ? String animName = mNextAppTransitionScaleUp ?
"ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN"; "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";

View File

@@ -3155,7 +3155,22 @@ public class WindowManagerService extends IWindowManager.Stub
final int height = displayInfo.appHeight; final int height = displayInfo.appHeight;
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, "applyAnimation: atoken=" if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, "applyAnimation: atoken="
+ atoken); + atoken);
Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height);
// Determine the visible rect to calculate the thumbnail clip
WindowState win = atoken.findMainWindow();
Rect containingFrame = new Rect(0, 0, width, height);
Rect contentInsets = new Rect();
if (win != null) {
if (win.mContainingFrame != null) {
containingFrame.set(win.mContainingFrame);
}
if (win.mContentInsets != null) {
contentInsets.set(win.mContentInsets);
}
}
Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height,
containingFrame, contentInsets);
if (a != null) { if (a != null) {
if (DEBUG_ANIM) { if (DEBUG_ANIM) {
RuntimeException e = null; RuntimeException e = null;
@@ -8608,11 +8623,13 @@ public class WindowManagerService extends IWindowManager.Stub
wtoken.deferClearAllDrawn = false; wtoken.deferClearAllDrawn = false;
} }
boolean useAlternateThumbnailAnimation =
SystemProperties.getBoolean("persist.anim.use_alt_thumbnail", false);
AppWindowAnimator appAnimator = AppWindowAnimator appAnimator =
topOpeningApp == null ? null : topOpeningApp.mAppAnimator; topOpeningApp == null ? null : topOpeningApp.mAppAnimator;
Bitmap nextAppTransitionThumbnail = mAppTransition.getNextAppTransitionThumbnail(); Bitmap nextAppTransitionThumbnail = mAppTransition.getNextAppTransitionThumbnail();
if (nextAppTransitionThumbnail != null && appAnimator != null if (!useAlternateThumbnailAnimation && nextAppTransitionThumbnail != null
&& appAnimator.animation != null) { && appAnimator != null && appAnimator.animation != null) {
// This thumbnail animation is very special, we need to have // This thumbnail animation is very special, we need to have
// an extra surface with the thumbnail included with the animation. // an extra surface with the thumbnail included with the animation.
Rect dirty = new Rect(0, 0, nextAppTransitionThumbnail.getWidth(), Rect dirty = new Rect(0, 0, nextAppTransitionThumbnail.getWidth(),
@@ -8636,8 +8653,8 @@ public class WindowManagerService extends IWindowManager.Stub
drawSurface.release(); drawSurface.release();
appAnimator.thumbnailLayer = topOpeningLayer; appAnimator.thumbnailLayer = topOpeningLayer;
DisplayInfo displayInfo = getDefaultDisplayInfoLocked(); DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
Animation anim = mAppTransition.createThumbnailAnimationLocked( Animation anim = mAppTransition.createThumbnailScaleAnimationLocked(
transit, true, true, displayInfo.appWidth, displayInfo.appHeight); displayInfo.appWidth, displayInfo.appHeight, transit);
appAnimator.thumbnailAnimation = anim; appAnimator.thumbnailAnimation = anim;
anim.restrictDuration(MAX_ANIMATION_DURATION); anim.restrictDuration(MAX_ANIMATION_DURATION);
anim.scaleCurrentDuration(mTransitionAnimationScale); anim.scaleCurrentDuration(mTransitionAnimationScale);

View File

@@ -113,6 +113,11 @@ class WindowStateAnimator {
float mAlpha = 0; float mAlpha = 0;
float mLastAlpha = 0; float mLastAlpha = 0;
boolean mHasClipRect;
Rect mClipRect = new Rect();
Rect mTmpClipRect = new Rect();
Rect mLastClipRect = new Rect();
// Used to save animation distances between the time they are calculated and when they are // Used to save animation distances between the time they are calculated and when they are
// used. // used.
int mAnimDw; int mAnimDw;
@@ -951,6 +956,7 @@ class WindowStateAnimator {
if (screenAnimation) { if (screenAnimation) {
tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix()); tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
} }
//TODO (multidisplay): Magnification is supported only for the default display. //TODO (multidisplay): Magnification is supported only for the default display.
if (mService.mAccessibilityController != null && displayId == Display.DEFAULT_DISPLAY) { if (mService.mAccessibilityController != null && displayId == Display.DEFAULT_DISPLAY) {
MagnificationSpec spec = mService.mAccessibilityController MagnificationSpec spec = mService.mAccessibilityController
@@ -985,6 +991,7 @@ class WindowStateAnimator {
// transforming since it is more important to have that // transforming since it is more important to have that
// animation be smooth. // animation be smooth.
mShownAlpha = mAlpha; mShownAlpha = mAlpha;
mHasClipRect = false;
if (!mService.mLimitedAlphaCompositing if (!mService.mLimitedAlphaCompositing
|| (!PixelFormat.formatHasAlpha(mWin.mAttrs.format) || (!PixelFormat.formatHasAlpha(mWin.mAttrs.format)
|| (mWin.isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy) || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy)
@@ -998,6 +1005,10 @@ class WindowStateAnimator {
} }
if (appTransformation != null) { if (appTransformation != null) {
mShownAlpha *= appTransformation.getAlpha(); mShownAlpha *= appTransformation.getAlpha();
if (appTransformation.hasClipRect()) {
mClipRect.set(appTransformation.getClipRect());
mHasClipRect = true;
}
} }
if (mAnimator.mUniverseBackground != null) { if (mAnimator.mUniverseBackground != null) {
mShownAlpha *= mAnimator.mUniverseBackground.mUniverseTransform.getAlpha(); mShownAlpha *= mAnimator.mUniverseBackground.mUniverseTransform.getAlpha();
@@ -1149,15 +1160,29 @@ class WindowStateAnimator {
applyDecorRect(w.mDecorFrame); applyDecorRect(w.mDecorFrame);
} }
if (!w.mSystemDecorRect.equals(w.mLastSystemDecorRect)) { // By default, the clip rect is the system decor rect
w.mLastSystemDecorRect.set(w.mSystemDecorRect); Rect clipRect = w.mSystemDecorRect;
if (mHasClipRect) {
// If we have an animated clip rect, intersect it with the system decor rect
int offsetTop = w.mSystemDecorRect.top;
mTmpClipRect.set(w.mSystemDecorRect);
mTmpClipRect.offset(0, -offsetTop);
mTmpClipRect.intersect(mClipRect);
mTmpClipRect.offset(0, offsetTop);
clipRect = mTmpClipRect;
}
if (!clipRect.equals(mLastClipRect)) {
mLastClipRect.set(clipRect);
try { try {
if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
"CROP " + w.mSystemDecorRect.toShortString(), null); "CROP " + clipRect.toShortString(), null);
mSurfaceControl.setWindowCrop(w.mSystemDecorRect); mSurfaceControl.setWindowCrop(clipRect);
} catch (RuntimeException e) { } catch (RuntimeException e) {
Slog.w(TAG, "Error setting crop surface of " + w Slog.w(TAG, "Error setting crop surface of " + w
+ " crop=" + w.mSystemDecorRect.toShortString(), e); + " crop=" + clipRect.toShortString(), e);
if (!recoveringMemory) { if (!recoveringMemory) {
mService.reclaimSomeSurfaceMemoryLocked(this, "crop", true); mService.reclaimSomeSurfaceMemoryLocked(this, "crop", true);
} }
@@ -1302,8 +1327,8 @@ class WindowStateAnimator {
mSurfaceLayer = mAnimLayer; mSurfaceLayer = mAnimLayer;
mSurfaceControl.setLayer(mAnimLayer); mSurfaceControl.setLayer(mAnimLayer);
mSurfaceControl.setMatrix( mSurfaceControl.setMatrix(
mDsDx*w.mHScale, mDtDx*w.mVScale, mDsDx * w.mHScale, mDtDx * w.mVScale,
mDsDy*w.mHScale, mDtDy*w.mVScale); mDsDy * w.mHScale, mDtDy * w.mVScale);
if (mLastHidden && mDrawState == HAS_DRAWN) { if (mLastHidden && mDrawState == HAS_DRAWN) {
if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,