Loading services/core/java/com/android/server/wm/AppTransition.java +98 −40 Original line number Diff line number Diff line Loading @@ -46,7 +46,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.annotation.Nullable; import android.content.Context; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Rect; import android.os.Debug; Loading @@ -64,8 +63,6 @@ import android.view.animation.Animation; import android.view.animation.AnimationSet; import android.view.animation.AnimationUtils; import android.view.animation.ClipRectAnimation; import android.view.animation.ClipRectLRAnimation; import android.view.animation.ClipRectTBAnimation; import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; import android.view.animation.ScaleAnimation; Loading @@ -74,10 +71,11 @@ import android.view.animation.TranslateAnimation; import com.android.internal.util.DumpUtils.Dump; import com.android.server.AttributeCache; import com.android.server.wm.WindowManagerService.H; import com.android.server.wm.animation.ClipRectLRAnimation; import com.android.server.wm.animation.ClipRectTBAnimation; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; Loading Loading @@ -136,6 +134,16 @@ public class AppTransition implements Dump { private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.5f; static final int DEFAULT_APP_TRANSITION_DURATION = 336; /** Interpolator to be used for animations that respond directly to a touch */ static final Interpolator TOUCH_RESPONSE_INTERPOLATOR = new PathInterpolator(0.3f, 0f, 0.1f, 1f); /** * Maximum duration for the clip reveal animation. This is used when there is a lot of movement * involved, to make it more understandable. */ private static final int MAX_CLIP_REVEAL_TRANSITION_DURATION = 420; private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336; private static final int THUMBNAIL_APP_TRANSITION_ALPHA_DURATION = 336; private static final long APP_TRANSITION_TIMEOUT_MS = 5000; Loading Loading @@ -200,13 +208,10 @@ public class AppTransition implements Dump { private final Interpolator mFastOutLinearInInterpolator; private final Interpolator mClipHorizontalInterpolator = new PathInterpolator(0, 0, 0.4f, 1f); /** Interpolator to be used for animations that respond directly to a touch */ private final Interpolator mTouchResponseInterpolator = new PathInterpolator(0.3f, 0f, 0.1f, 1f); private final int mClipRevealTranslationY; private int mCurrentUserId = 0; private long mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION; private final ArrayList<AppTransitionListener> mListeners = new ArrayList<>(); private final ExecutorService mDefaultExecutor = Executors.newSingleThreadExecutor(); Loading Loading @@ -636,50 +641,101 @@ public class AppTransition implements Dump { bitmap, new Rect(left, top, left + width, top + height)); } private Animation createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame) { long getLastClipRevealTransitionDuration() { return mLastClipRevealTransitionDuration; } /** * Calculates the duration for the clip reveal animation. If the clip is "cut off", meaning that * the start rect is outside of the target rect, and there is a lot of movement going on. * * @param cutOff whether the start rect was not fully contained by the end rect * @param translationX the total translation the surface moves in x direction * @param translationY the total translation the surfaces moves in y direction * @param displayFrame our display frame * * @return the duration of the clip reveal animation, in milliseconds */ private long calculateClipRevealTransitionDuration(boolean cutOff, float translationX, float translationY, Rect displayFrame) { if (!cutOff) { return DEFAULT_APP_TRANSITION_DURATION; } final float fraction = Math.max(Math.abs(translationX) / displayFrame.width(), Math.abs(translationY) / displayFrame.height()); return (long) (DEFAULT_APP_TRANSITION_DURATION + fraction * (MAX_CLIP_REVEAL_TRANSITION_DURATION - DEFAULT_APP_TRANSITION_DURATION)); } private Animation createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame, Rect displayFrame) { final Animation anim; if (enter) { // Reveal will expand and move faster in horizontal direction final int appWidth = appFrame.width(); final int appHeight = appFrame.height(); // mTmpRect will contain an area around the launcher icon that was pressed. We will // clip reveal from that area in the final area of the app. getDefaultNextAppTransitionStartRect(mTmpRect); float t = 0f; if (appHeight > 0) { t = (float) mTmpRect.left / appHeight; t = (float) mTmpRect.top / displayFrame.height(); } int translationY = mClipRevealTranslationY + (int)(appHeight / 7f * t); int translationY = mClipRevealTranslationY + (int)(displayFrame.height() / 7f * t); int translationX = 0; int translationYCorrection = translationY; int centerX = mTmpRect.centerX(); int centerY = mTmpRect.centerY(); int halfWidth = mTmpRect.width() / 2; int halfHeight = mTmpRect.height() / 2; int clipStartX = centerX - halfWidth - appFrame.left; int clipStartY = centerY - halfHeight - appFrame.top; boolean cutOff = false; // If the starting rectangle is fully or partially outside of the target rectangle, we // need to start the clipping at the edge and then achieve the rest with translation // and extending the clip rect from that edge. if (appFrame.top > centerY - halfHeight) { translationY = (centerY - halfHeight) - appFrame.top; translationYCorrection = 0; clipStartY = 0; cutOff = true; } if (appFrame.left > centerX - halfWidth) { translationX = (centerX - halfWidth) - appFrame.left; clipStartX = 0; cutOff = true; } if (appFrame.right < centerX + halfWidth) { translationX = (centerX + halfWidth) - appFrame.right; clipStartX = appWidth - mTmpRect.width(); cutOff = true; } final long duration = calculateClipRevealTransitionDuration(cutOff, translationX, translationY, displayFrame); // Clip third of the from size of launch icon, expand to full width/height Animation clipAnimLR = new ClipRectLRAnimation( centerX - halfWidth, centerX + halfWidth, 0, appWidth); clipStartX, clipStartX + mTmpRect.width(), 0, appWidth); clipAnimLR.setInterpolator(mClipHorizontalInterpolator); clipAnimLR.setDuration((long) (DEFAULT_APP_TRANSITION_DURATION / 2.5f)); Animation clipAnimTB = new ClipRectTBAnimation(centerY - halfHeight - translationY, centerY + halfHeight/ 2 - translationY, 0, appHeight); clipAnimTB.setInterpolator(mTouchResponseInterpolator); clipAnimTB.setDuration(DEFAULT_APP_TRANSITION_DURATION); // We might be animating entrance of a docked task, so we need the translate to account // for the app frame in which the window will reside. Every other calculation here // is performed as if the window started at 0,0. translationY -= appFrame.top; TranslateAnimation translate = new TranslateAnimation(-appFrame.left, 0, translationY, 0); translate.setInterpolator(mLinearOutSlowInInterpolator); translate.setDuration(DEFAULT_APP_TRANSITION_DURATION); clipAnimLR.setDuration((long) (duration / 2.5f)); TranslateAnimation translate = new TranslateAnimation(translationX, 0, translationY, 0); translate.setInterpolator(cutOff ? TOUCH_RESPONSE_INTERPOLATOR : mLinearOutSlowInInterpolator); translate.setDuration(duration); Animation clipAnimTB = new ClipRectTBAnimation( clipStartY, clipStartY + mTmpRect.height(), 0, appHeight, translationYCorrection, 0, mLinearOutSlowInInterpolator); clipAnimTB.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); clipAnimTB.setDuration(duration); // Quick fade-in from icon to app window final int alphaDuration = DEFAULT_APP_TRANSITION_DURATION / 4; final long alphaDuration = duration / 4; AlphaAnimation alpha = new AlphaAnimation(0.5f, 1); alpha.setDuration(alphaDuration); alpha.setInterpolator(mLinearOutSlowInInterpolator); Loading @@ -692,6 +748,7 @@ public class AppTransition implements Dump { set.setZAdjustment(Animation.ZORDER_TOP); set.initialize(appWidth, appHeight, appWidth, appHeight); anim = set; mLastClipRevealTransitionDuration = duration; } else { final long duration; switch (transit) { Loading Loading @@ -798,7 +855,7 @@ public class AppTransition implements Dump { // Animation up from the thumbnail to the full screen Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW, mTmpRect.left + (thumbWidth / 2f), mTmpRect.top + (thumbHeight / 2f)); scale.setInterpolator(mTouchResponseInterpolator); scale.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); Animation alpha = new AlphaAnimation(1f, 0f); alpha.setInterpolator(mThumbnailFadeOutInterpolator); Loading @@ -806,7 +863,7 @@ public class AppTransition implements Dump { final float toX = appRect.left + appRect.width() / 2 - (mTmpRect.left + thumbWidth / 2); Animation translate = new TranslateAnimation(0, toX, 0, toY); translate.setInterpolator(mTouchResponseInterpolator); translate.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); // This AnimationSet uses the Interpolators assigned above. Loading @@ -819,7 +876,7 @@ public class AppTransition implements Dump { // Animation down from the full screen to the thumbnail Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f, mTmpRect.left + (thumbWidth / 2f), mTmpRect.top + (thumbHeight / 2f)); scale.setInterpolator(mTouchResponseInterpolator); scale.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); Animation alpha = new AlphaAnimation(0f, 1f); alpha.setInterpolator(mThumbnailFadeInInterpolator); Loading @@ -827,7 +884,7 @@ public class AppTransition implements Dump { final float toX = appRect.left + appRect.width() / 2 - (mTmpRect.left + thumbWidth / 2); Animation translate = new TranslateAnimation(toX, 0, toY, 0); translate.setInterpolator(mTouchResponseInterpolator); translate.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); // This AnimationSet uses the Interpolators assigned above. Loading @@ -839,7 +896,7 @@ public class AppTransition implements Dump { } return prepareThumbnailAnimationWithDuration(a, appWidth, appRect.height(), 0, mTouchResponseInterpolator); TOUCH_RESPONSE_INTERPOLATOR); } /** Loading Loading @@ -971,7 +1028,7 @@ public class AppTransition implements Dump { int duration = Math.max(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION, THUMBNAIL_APP_TRANSITION_DURATION); return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration, mTouchResponseInterpolator); TOUCH_RESPONSE_INTERPOLATOR); } private Animation createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame, Loading Loading @@ -1223,8 +1280,9 @@ public class AppTransition implements Dump { * bigger. */ Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, int orientation, Rect frame, Rect insets, @Nullable Rect surfaceInsets, boolean isVoiceInteraction, boolean freeform, int taskId) { int orientation, Rect frame, Rect displayFrame, Rect insets, @Nullable Rect surfaceInsets, boolean isVoiceInteraction, boolean freeform, int taskId) { Animation a; if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN || transit == TRANSIT_TASK_OPEN Loading Loading @@ -1269,7 +1327,7 @@ public class AppTransition implements Dump { + " transit=" + appTransitionToString(transit) + " Callers=" + Debug.getCallers(3)); } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) { a = createClipRevealAnimationLocked(transit, enter, frame); a = createClipRevealAnimationLocked(transit, enter, frame, displayFrame); if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, "applyAnimation:" + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL" Loading services/core/java/com/android/server/wm/DockedStackDividerController.java +17 −6 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.view.IDockedStackListener; import android.view.SurfaceControl; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; import com.android.server.wm.DimLayer.DimLayerUser; Loading @@ -39,6 +40,8 @@ import static android.view.WindowManager.DOCKED_BOTTOM; import static android.view.WindowManager.DOCKED_LEFT; import static android.view.WindowManager.DOCKED_RIGHT; import static android.view.WindowManager.DOCKED_TOP; import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION; import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; Loading @@ -49,8 +52,6 @@ public class DockedStackDividerController implements DimLayerUser { private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM; private static final long MINIMIZED_DOCK_ANIMATION_DURATION = 400; private final WindowManagerService mService; private final DisplayContent mDisplayContent; private final int mDividerWindowWidth; Loading @@ -71,6 +72,7 @@ public class DockedStackDividerController implements DimLayerUser { private long mAnimationStartTime; private float mAnimationStart; private float mAnimationTarget; private long mAnimationDuration; private final Interpolator mMinimizedDockInterpolator; DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) { Loading Loading @@ -331,6 +333,10 @@ public class DockedStackDividerController implements DimLayerUser { notifyDockedStackMinimizedChanged(minimized, 0); } private boolean isAnimationMaximizing() { return mAnimationTarget == 0f; } public boolean animate(long now) { if (!mAnimating) { return false; Loading @@ -339,12 +345,17 @@ public class DockedStackDividerController implements DimLayerUser { if (!mAnimationStarted) { mAnimationStarted = true; mAnimationStartTime = now; final long transitionDuration = isAnimationMaximizing() ? mService.mAppTransition.getLastClipRevealTransitionDuration() : DEFAULT_APP_TRANSITION_DURATION; mAnimationDuration = (long) (transitionDuration * mService.getTransitionAnimationScaleLocked()); notifyDockedStackMinimizedChanged(mMinimizedDock, MINIMIZED_DOCK_ANIMATION_DURATION); mAnimationDuration); } float t = Math.min(1f, (float) (now - mAnimationStartTime) / MINIMIZED_DOCK_ANIMATION_DURATION); t = mMinimizedDockInterpolator.getInterpolation(t); float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration); t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator) .getInterpolation(t); final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked(); if (stack != null) { final float amount = t * mAnimationTarget + (1 - t) * mAnimationStart; Loading services/core/java/com/android/server/wm/WindowManagerService.java +4 −2 Original line number Diff line number Diff line Loading @@ -2970,6 +2970,8 @@ public class WindowManagerService extends IWindowManager.Stub // Determine the visible rect to calculate the thumbnail clip final WindowState win = atoken.findMainWindow(); final Rect frame = new Rect(0, 0, width, height); final Rect displayFrame = new Rect(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight); final Rect insets = new Rect(); Rect surfaceInsets = null; final boolean freeform = win != null && win.inFreeformWorkspace(); Loading Loading @@ -2997,8 +2999,8 @@ public class WindowManagerService extends IWindowManager.Stub + " transit=" + AppTransition.appTransitionToString(transit) + " enter=" + enter + " frame=" + frame + " insets=" + insets + " surfaceInsets=" + surfaceInsets); Animation a = mAppTransition.loadAnimation(lp, transit, enter, mCurConfiguration.orientation, frame, insets, surfaceInsets, isVoiceInteraction, freeform, atoken.mTask.mTaskId); mCurConfiguration.orientation, frame, displayFrame, insets, surfaceInsets, isVoiceInteraction, freeform, atoken.mTask.mTaskId); if (a != null) { if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + atoken); final int containingWidth = frame.width(); Loading core/java/android/view/animation/ClipRectLRAnimation.java→services/core/java/com/android/server/wm/animation/ClipRectLRAnimation.java +5 −3 Original line number Diff line number Diff line /* * Copyright (C) 2015 The Android Open Source Project * Copyright (C) 2016 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. Loading @@ -11,12 +11,14 @@ * 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. * limitations under the License */ package android.view.animation; package com.android.server.wm.animation; import android.graphics.Rect; import android.view.animation.ClipRectAnimation; import android.view.animation.Transformation; /** * Special case of ClipRectAnimation that animates only the left/right Loading core/java/android/view/animation/ClipRectTBAnimation.java→services/core/java/com/android/server/wm/animation/ClipRectTBAnimation.java +86 −0 Original line number Diff line number Diff line /* * Copyright (C) 2015 The Android Open Source Project * Copyright (C) 2016 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. Loading @@ -11,27 +11,60 @@ * 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. * limitations under the License */ package android.view.animation; package com.android.server.wm.animation; import android.graphics.Rect; import android.view.animation.ClipRectAnimation; import android.view.animation.Interpolator; import android.view.animation.Transformation; import android.view.animation.TranslateAnimation; /** * Special case of ClipRectAnimation that animates only the top/bottom * dimensions of the clip, picking up the other dimensions from whatever is * set on the transform already. * * @hide * set on the transform already. In addition to that, information about a vertical translation * animation can be specified so this animation simulates as the clip would be applied after instead * of before applying the translation. */ public class ClipRectTBAnimation extends ClipRectAnimation { private final int mFromTranslateY; private final int mToTranslateY; private final Interpolator mTranslateInterpolator; private float mNormalizedTime; /** * Constructor. Passes in 0 for Left/Right parameters of ClipRectAnimation */ public ClipRectTBAnimation(int fromT, int fromB, int toT, int toB) { public ClipRectTBAnimation(int fromT, int fromB, int toT, int toB, int fromTranslateY, int toTranslateY, Interpolator translateInterpolator) { super(0, fromT, 0, fromB, 0, toT, 0, toB); mFromTranslateY = fromTranslateY; mToTranslateY = toTranslateY; mTranslateInterpolator = translateInterpolator; } @Override public boolean getTransformation(long currentTime, Transformation outTransformation) { // Hack: Because translation animation has a different interpolator, we need to duplicate // code from Animation here and use it to calculate/store the uninterpolated normalized // time. final long startOffset = getStartOffset(); final long duration = getDuration(); float normalizedTime; if (duration != 0) { normalizedTime = ((float) (currentTime - (getStartTime() + startOffset))) / (float) duration; } else { // time is a step-change with a zero duration normalizedTime = currentTime < getStartTime() ? 0.0f : 1.0f; } mNormalizedTime = normalizedTime; return super.getTransformation(currentTime, outTransformation); } /** Loading @@ -40,10 +73,14 @@ public class ClipRectTBAnimation extends ClipRectAnimation { */ @Override protected void applyTransformation(float it, Transformation tr) { float translationT = mTranslateInterpolator.getInterpolation(mNormalizedTime); int translation = (int) (mFromTranslateY + (mToTranslateY - mFromTranslateY) * translationT); Rect oldClipRect = tr.getClipRect(); tr.setClipRect(oldClipRect.left, mFromRect.top + (int) ((mToRect.top - mFromRect.top) * it), tr.setClipRect(oldClipRect.left, mFromRect.top - translation + (int) ((mToRect.top - mFromRect.top) * it), oldClipRect.right, mFromRect.bottom + (int) ((mToRect.bottom - mFromRect.bottom) * it)); mFromRect.bottom - translation + (int) ((mToRect.bottom - mFromRect.bottom) * it)); } } Loading
services/core/java/com/android/server/wm/AppTransition.java +98 −40 Original line number Diff line number Diff line Loading @@ -46,7 +46,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.annotation.Nullable; import android.content.Context; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Rect; import android.os.Debug; Loading @@ -64,8 +63,6 @@ import android.view.animation.Animation; import android.view.animation.AnimationSet; import android.view.animation.AnimationUtils; import android.view.animation.ClipRectAnimation; import android.view.animation.ClipRectLRAnimation; import android.view.animation.ClipRectTBAnimation; import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; import android.view.animation.ScaleAnimation; Loading @@ -74,10 +71,11 @@ import android.view.animation.TranslateAnimation; import com.android.internal.util.DumpUtils.Dump; import com.android.server.AttributeCache; import com.android.server.wm.WindowManagerService.H; import com.android.server.wm.animation.ClipRectLRAnimation; import com.android.server.wm.animation.ClipRectTBAnimation; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; Loading Loading @@ -136,6 +134,16 @@ public class AppTransition implements Dump { private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.5f; static final int DEFAULT_APP_TRANSITION_DURATION = 336; /** Interpolator to be used for animations that respond directly to a touch */ static final Interpolator TOUCH_RESPONSE_INTERPOLATOR = new PathInterpolator(0.3f, 0f, 0.1f, 1f); /** * Maximum duration for the clip reveal animation. This is used when there is a lot of movement * involved, to make it more understandable. */ private static final int MAX_CLIP_REVEAL_TRANSITION_DURATION = 420; private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336; private static final int THUMBNAIL_APP_TRANSITION_ALPHA_DURATION = 336; private static final long APP_TRANSITION_TIMEOUT_MS = 5000; Loading Loading @@ -200,13 +208,10 @@ public class AppTransition implements Dump { private final Interpolator mFastOutLinearInInterpolator; private final Interpolator mClipHorizontalInterpolator = new PathInterpolator(0, 0, 0.4f, 1f); /** Interpolator to be used for animations that respond directly to a touch */ private final Interpolator mTouchResponseInterpolator = new PathInterpolator(0.3f, 0f, 0.1f, 1f); private final int mClipRevealTranslationY; private int mCurrentUserId = 0; private long mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION; private final ArrayList<AppTransitionListener> mListeners = new ArrayList<>(); private final ExecutorService mDefaultExecutor = Executors.newSingleThreadExecutor(); Loading Loading @@ -636,50 +641,101 @@ public class AppTransition implements Dump { bitmap, new Rect(left, top, left + width, top + height)); } private Animation createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame) { long getLastClipRevealTransitionDuration() { return mLastClipRevealTransitionDuration; } /** * Calculates the duration for the clip reveal animation. If the clip is "cut off", meaning that * the start rect is outside of the target rect, and there is a lot of movement going on. * * @param cutOff whether the start rect was not fully contained by the end rect * @param translationX the total translation the surface moves in x direction * @param translationY the total translation the surfaces moves in y direction * @param displayFrame our display frame * * @return the duration of the clip reveal animation, in milliseconds */ private long calculateClipRevealTransitionDuration(boolean cutOff, float translationX, float translationY, Rect displayFrame) { if (!cutOff) { return DEFAULT_APP_TRANSITION_DURATION; } final float fraction = Math.max(Math.abs(translationX) / displayFrame.width(), Math.abs(translationY) / displayFrame.height()); return (long) (DEFAULT_APP_TRANSITION_DURATION + fraction * (MAX_CLIP_REVEAL_TRANSITION_DURATION - DEFAULT_APP_TRANSITION_DURATION)); } private Animation createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame, Rect displayFrame) { final Animation anim; if (enter) { // Reveal will expand and move faster in horizontal direction final int appWidth = appFrame.width(); final int appHeight = appFrame.height(); // mTmpRect will contain an area around the launcher icon that was pressed. We will // clip reveal from that area in the final area of the app. getDefaultNextAppTransitionStartRect(mTmpRect); float t = 0f; if (appHeight > 0) { t = (float) mTmpRect.left / appHeight; t = (float) mTmpRect.top / displayFrame.height(); } int translationY = mClipRevealTranslationY + (int)(appHeight / 7f * t); int translationY = mClipRevealTranslationY + (int)(displayFrame.height() / 7f * t); int translationX = 0; int translationYCorrection = translationY; int centerX = mTmpRect.centerX(); int centerY = mTmpRect.centerY(); int halfWidth = mTmpRect.width() / 2; int halfHeight = mTmpRect.height() / 2; int clipStartX = centerX - halfWidth - appFrame.left; int clipStartY = centerY - halfHeight - appFrame.top; boolean cutOff = false; // If the starting rectangle is fully or partially outside of the target rectangle, we // need to start the clipping at the edge and then achieve the rest with translation // and extending the clip rect from that edge. if (appFrame.top > centerY - halfHeight) { translationY = (centerY - halfHeight) - appFrame.top; translationYCorrection = 0; clipStartY = 0; cutOff = true; } if (appFrame.left > centerX - halfWidth) { translationX = (centerX - halfWidth) - appFrame.left; clipStartX = 0; cutOff = true; } if (appFrame.right < centerX + halfWidth) { translationX = (centerX + halfWidth) - appFrame.right; clipStartX = appWidth - mTmpRect.width(); cutOff = true; } final long duration = calculateClipRevealTransitionDuration(cutOff, translationX, translationY, displayFrame); // Clip third of the from size of launch icon, expand to full width/height Animation clipAnimLR = new ClipRectLRAnimation( centerX - halfWidth, centerX + halfWidth, 0, appWidth); clipStartX, clipStartX + mTmpRect.width(), 0, appWidth); clipAnimLR.setInterpolator(mClipHorizontalInterpolator); clipAnimLR.setDuration((long) (DEFAULT_APP_TRANSITION_DURATION / 2.5f)); Animation clipAnimTB = new ClipRectTBAnimation(centerY - halfHeight - translationY, centerY + halfHeight/ 2 - translationY, 0, appHeight); clipAnimTB.setInterpolator(mTouchResponseInterpolator); clipAnimTB.setDuration(DEFAULT_APP_TRANSITION_DURATION); // We might be animating entrance of a docked task, so we need the translate to account // for the app frame in which the window will reside. Every other calculation here // is performed as if the window started at 0,0. translationY -= appFrame.top; TranslateAnimation translate = new TranslateAnimation(-appFrame.left, 0, translationY, 0); translate.setInterpolator(mLinearOutSlowInInterpolator); translate.setDuration(DEFAULT_APP_TRANSITION_DURATION); clipAnimLR.setDuration((long) (duration / 2.5f)); TranslateAnimation translate = new TranslateAnimation(translationX, 0, translationY, 0); translate.setInterpolator(cutOff ? TOUCH_RESPONSE_INTERPOLATOR : mLinearOutSlowInInterpolator); translate.setDuration(duration); Animation clipAnimTB = new ClipRectTBAnimation( clipStartY, clipStartY + mTmpRect.height(), 0, appHeight, translationYCorrection, 0, mLinearOutSlowInInterpolator); clipAnimTB.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); clipAnimTB.setDuration(duration); // Quick fade-in from icon to app window final int alphaDuration = DEFAULT_APP_TRANSITION_DURATION / 4; final long alphaDuration = duration / 4; AlphaAnimation alpha = new AlphaAnimation(0.5f, 1); alpha.setDuration(alphaDuration); alpha.setInterpolator(mLinearOutSlowInInterpolator); Loading @@ -692,6 +748,7 @@ public class AppTransition implements Dump { set.setZAdjustment(Animation.ZORDER_TOP); set.initialize(appWidth, appHeight, appWidth, appHeight); anim = set; mLastClipRevealTransitionDuration = duration; } else { final long duration; switch (transit) { Loading Loading @@ -798,7 +855,7 @@ public class AppTransition implements Dump { // Animation up from the thumbnail to the full screen Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW, mTmpRect.left + (thumbWidth / 2f), mTmpRect.top + (thumbHeight / 2f)); scale.setInterpolator(mTouchResponseInterpolator); scale.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); Animation alpha = new AlphaAnimation(1f, 0f); alpha.setInterpolator(mThumbnailFadeOutInterpolator); Loading @@ -806,7 +863,7 @@ public class AppTransition implements Dump { final float toX = appRect.left + appRect.width() / 2 - (mTmpRect.left + thumbWidth / 2); Animation translate = new TranslateAnimation(0, toX, 0, toY); translate.setInterpolator(mTouchResponseInterpolator); translate.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); // This AnimationSet uses the Interpolators assigned above. Loading @@ -819,7 +876,7 @@ public class AppTransition implements Dump { // Animation down from the full screen to the thumbnail Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f, mTmpRect.left + (thumbWidth / 2f), mTmpRect.top + (thumbHeight / 2f)); scale.setInterpolator(mTouchResponseInterpolator); scale.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); Animation alpha = new AlphaAnimation(0f, 1f); alpha.setInterpolator(mThumbnailFadeInInterpolator); Loading @@ -827,7 +884,7 @@ public class AppTransition implements Dump { final float toX = appRect.left + appRect.width() / 2 - (mTmpRect.left + thumbWidth / 2); Animation translate = new TranslateAnimation(toX, 0, toY, 0); translate.setInterpolator(mTouchResponseInterpolator); translate.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); // This AnimationSet uses the Interpolators assigned above. Loading @@ -839,7 +896,7 @@ public class AppTransition implements Dump { } return prepareThumbnailAnimationWithDuration(a, appWidth, appRect.height(), 0, mTouchResponseInterpolator); TOUCH_RESPONSE_INTERPOLATOR); } /** Loading Loading @@ -971,7 +1028,7 @@ public class AppTransition implements Dump { int duration = Math.max(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION, THUMBNAIL_APP_TRANSITION_DURATION); return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration, mTouchResponseInterpolator); TOUCH_RESPONSE_INTERPOLATOR); } private Animation createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame, Loading Loading @@ -1223,8 +1280,9 @@ public class AppTransition implements Dump { * bigger. */ Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, int orientation, Rect frame, Rect insets, @Nullable Rect surfaceInsets, boolean isVoiceInteraction, boolean freeform, int taskId) { int orientation, Rect frame, Rect displayFrame, Rect insets, @Nullable Rect surfaceInsets, boolean isVoiceInteraction, boolean freeform, int taskId) { Animation a; if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN || transit == TRANSIT_TASK_OPEN Loading Loading @@ -1269,7 +1327,7 @@ public class AppTransition implements Dump { + " transit=" + appTransitionToString(transit) + " Callers=" + Debug.getCallers(3)); } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) { a = createClipRevealAnimationLocked(transit, enter, frame); a = createClipRevealAnimationLocked(transit, enter, frame, displayFrame); if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, "applyAnimation:" + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL" Loading
services/core/java/com/android/server/wm/DockedStackDividerController.java +17 −6 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.view.IDockedStackListener; import android.view.SurfaceControl; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; import com.android.server.wm.DimLayer.DimLayerUser; Loading @@ -39,6 +40,8 @@ import static android.view.WindowManager.DOCKED_BOTTOM; import static android.view.WindowManager.DOCKED_LEFT; import static android.view.WindowManager.DOCKED_RIGHT; import static android.view.WindowManager.DOCKED_TOP; import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION; import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; Loading @@ -49,8 +52,6 @@ public class DockedStackDividerController implements DimLayerUser { private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM; private static final long MINIMIZED_DOCK_ANIMATION_DURATION = 400; private final WindowManagerService mService; private final DisplayContent mDisplayContent; private final int mDividerWindowWidth; Loading @@ -71,6 +72,7 @@ public class DockedStackDividerController implements DimLayerUser { private long mAnimationStartTime; private float mAnimationStart; private float mAnimationTarget; private long mAnimationDuration; private final Interpolator mMinimizedDockInterpolator; DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) { Loading Loading @@ -331,6 +333,10 @@ public class DockedStackDividerController implements DimLayerUser { notifyDockedStackMinimizedChanged(minimized, 0); } private boolean isAnimationMaximizing() { return mAnimationTarget == 0f; } public boolean animate(long now) { if (!mAnimating) { return false; Loading @@ -339,12 +345,17 @@ public class DockedStackDividerController implements DimLayerUser { if (!mAnimationStarted) { mAnimationStarted = true; mAnimationStartTime = now; final long transitionDuration = isAnimationMaximizing() ? mService.mAppTransition.getLastClipRevealTransitionDuration() : DEFAULT_APP_TRANSITION_DURATION; mAnimationDuration = (long) (transitionDuration * mService.getTransitionAnimationScaleLocked()); notifyDockedStackMinimizedChanged(mMinimizedDock, MINIMIZED_DOCK_ANIMATION_DURATION); mAnimationDuration); } float t = Math.min(1f, (float) (now - mAnimationStartTime) / MINIMIZED_DOCK_ANIMATION_DURATION); t = mMinimizedDockInterpolator.getInterpolation(t); float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration); t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator) .getInterpolation(t); final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked(); if (stack != null) { final float amount = t * mAnimationTarget + (1 - t) * mAnimationStart; Loading
services/core/java/com/android/server/wm/WindowManagerService.java +4 −2 Original line number Diff line number Diff line Loading @@ -2970,6 +2970,8 @@ public class WindowManagerService extends IWindowManager.Stub // Determine the visible rect to calculate the thumbnail clip final WindowState win = atoken.findMainWindow(); final Rect frame = new Rect(0, 0, width, height); final Rect displayFrame = new Rect(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight); final Rect insets = new Rect(); Rect surfaceInsets = null; final boolean freeform = win != null && win.inFreeformWorkspace(); Loading Loading @@ -2997,8 +2999,8 @@ public class WindowManagerService extends IWindowManager.Stub + " transit=" + AppTransition.appTransitionToString(transit) + " enter=" + enter + " frame=" + frame + " insets=" + insets + " surfaceInsets=" + surfaceInsets); Animation a = mAppTransition.loadAnimation(lp, transit, enter, mCurConfiguration.orientation, frame, insets, surfaceInsets, isVoiceInteraction, freeform, atoken.mTask.mTaskId); mCurConfiguration.orientation, frame, displayFrame, insets, surfaceInsets, isVoiceInteraction, freeform, atoken.mTask.mTaskId); if (a != null) { if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + atoken); final int containingWidth = frame.width(); Loading
core/java/android/view/animation/ClipRectLRAnimation.java→services/core/java/com/android/server/wm/animation/ClipRectLRAnimation.java +5 −3 Original line number Diff line number Diff line /* * Copyright (C) 2015 The Android Open Source Project * Copyright (C) 2016 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. Loading @@ -11,12 +11,14 @@ * 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. * limitations under the License */ package android.view.animation; package com.android.server.wm.animation; import android.graphics.Rect; import android.view.animation.ClipRectAnimation; import android.view.animation.Transformation; /** * Special case of ClipRectAnimation that animates only the left/right Loading
core/java/android/view/animation/ClipRectTBAnimation.java→services/core/java/com/android/server/wm/animation/ClipRectTBAnimation.java +86 −0 Original line number Diff line number Diff line /* * Copyright (C) 2015 The Android Open Source Project * Copyright (C) 2016 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. Loading @@ -11,27 +11,60 @@ * 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. * limitations under the License */ package android.view.animation; package com.android.server.wm.animation; import android.graphics.Rect; import android.view.animation.ClipRectAnimation; import android.view.animation.Interpolator; import android.view.animation.Transformation; import android.view.animation.TranslateAnimation; /** * Special case of ClipRectAnimation that animates only the top/bottom * dimensions of the clip, picking up the other dimensions from whatever is * set on the transform already. * * @hide * set on the transform already. In addition to that, information about a vertical translation * animation can be specified so this animation simulates as the clip would be applied after instead * of before applying the translation. */ public class ClipRectTBAnimation extends ClipRectAnimation { private final int mFromTranslateY; private final int mToTranslateY; private final Interpolator mTranslateInterpolator; private float mNormalizedTime; /** * Constructor. Passes in 0 for Left/Right parameters of ClipRectAnimation */ public ClipRectTBAnimation(int fromT, int fromB, int toT, int toB) { public ClipRectTBAnimation(int fromT, int fromB, int toT, int toB, int fromTranslateY, int toTranslateY, Interpolator translateInterpolator) { super(0, fromT, 0, fromB, 0, toT, 0, toB); mFromTranslateY = fromTranslateY; mToTranslateY = toTranslateY; mTranslateInterpolator = translateInterpolator; } @Override public boolean getTransformation(long currentTime, Transformation outTransformation) { // Hack: Because translation animation has a different interpolator, we need to duplicate // code from Animation here and use it to calculate/store the uninterpolated normalized // time. final long startOffset = getStartOffset(); final long duration = getDuration(); float normalizedTime; if (duration != 0) { normalizedTime = ((float) (currentTime - (getStartTime() + startOffset))) / (float) duration; } else { // time is a step-change with a zero duration normalizedTime = currentTime < getStartTime() ? 0.0f : 1.0f; } mNormalizedTime = normalizedTime; return super.getTransformation(currentTime, outTransformation); } /** Loading @@ -40,10 +73,14 @@ public class ClipRectTBAnimation extends ClipRectAnimation { */ @Override protected void applyTransformation(float it, Transformation tr) { float translationT = mTranslateInterpolator.getInterpolation(mNormalizedTime); int translation = (int) (mFromTranslateY + (mToTranslateY - mFromTranslateY) * translationT); Rect oldClipRect = tr.getClipRect(); tr.setClipRect(oldClipRect.left, mFromRect.top + (int) ((mToRect.top - mFromRect.top) * it), tr.setClipRect(oldClipRect.left, mFromRect.top - translation + (int) ((mToRect.top - mFromRect.top) * it), oldClipRect.right, mFromRect.bottom + (int) ((mToRect.bottom - mFromRect.bottom) * it)); mFromRect.bottom - translation + (int) ((mToRect.bottom - mFromRect.bottom) * it)); } }