Loading services/core/java/com/android/server/wm/DisplayPolicy.java +39 −0 Original line number Diff line number Diff line Loading @@ -380,6 +380,14 @@ public class DisplayPolicy { private RefreshRatePolicy mRefreshRatePolicy; /** * If true, attach the navigation bar to the current transition app. * The value is read from config_attachNavBarToAppDuringTransition and could be overlaid by RRO * when the navigation bar mode is changed. */ private boolean mShouldAttachNavBarToAppDuringTransition; private NavBarFadeAnimationController mNavBarFadeAnimationController; // -------- PolicyHandler -------- private static final int MSG_REQUEST_TRANSIENT_BARS = 2; private static final int MSG_DISPOSE_INPUT_CONSUMER = 3; Loading Loading @@ -1086,6 +1094,7 @@ public class DisplayPolicy { break; case TYPE_NAVIGATION_BAR: mNavigationBar = win; updateNavBarFadeController(); mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, win, (displayFrames, windowState, inOutFrame) -> { Loading Loading @@ -1231,6 +1240,7 @@ public class DisplayPolicy { mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, null, null); } else if (mNavigationBar == win || mNavigationBarAlt == win) { mNavigationBar = null; updateNavBarFadeController(); mNavigationBarAlt = null; mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, null, null); } else if (mNotificationShade == win) { Loading Loading @@ -2195,6 +2205,13 @@ public class DisplayPolicy { - getNavigationBarFrameHeight(portraitRotation, uiMode); updateConfigurationAndScreenSizeDependentBehaviors(); final boolean shouldAttach = res.getBoolean(R.bool.config_attachNavBarToAppDuringTransition); if (mShouldAttachNavBarToAppDuringTransition != shouldAttach) { mShouldAttachNavBarToAppDuringTransition = shouldAttach; updateNavBarFadeController(); } } void updateConfigurationAndScreenSizeDependentBehaviors() { Loading Loading @@ -3177,4 +3194,26 @@ public class DisplayPolicy { return Rect.intersects(targetWindow.getFrame(), navBarWindow.getFrame()); } /** * @return Whether we should attach navigation bar to the app during transition. */ boolean shouldAttachNavBarToAppDuringTransition() { return mShouldAttachNavBarToAppDuringTransition && mNavigationBar != null; } @Nullable NavBarFadeAnimationController getNavBarFadeAnimationController() { return mNavBarFadeAnimationController; } private void updateNavBarFadeController() { if (shouldAttachNavBarToAppDuringTransition()) { if (mNavBarFadeAnimationController == null) { mNavBarFadeAnimationController = new NavBarFadeAnimationController(mDisplayContent); } } else { mNavBarFadeAnimationController = null; } } } services/core/java/com/android/server/wm/FadeAnimationController.java 0 → 100644 +156 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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 com.android.server.wm; import static com.android.server.wm.AnimationSpecProto.WINDOW; import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION; import android.annotation.NonNull; import android.content.Context; import android.util.ArrayMap; import android.util.proto.ProtoOutputStream; import android.view.SurfaceControl; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.Transformation; import com.android.internal.R; import java.io.PrintWriter; /** * An animation controller to fade-in/out for a window token. */ public class FadeAnimationController { protected final Context mContext; private final ArrayMap<WindowToken, Runnable> mDeferredFinishCallbacks = new ArrayMap<>(); public FadeAnimationController(DisplayContent displayContent) { mContext = displayContent.mWmService.mContext; } /** * @return a fade-in Animation. */ public Animation getFadeInAnimation() { return AnimationUtils.loadAnimation(mContext, R.anim.fade_in); } /** * @return a fade-out Animation. */ public Animation getFadeOutAnimation() { return AnimationUtils.loadAnimation(mContext, R.anim.fade_out); } /** * Run the fade in/out animation for a window token. * * @param show true for fade-in, otherwise for fade-out. * @param windowToken the window token to run the animation. * @param animationType the animation type defined in SurfaceAnimator. */ public void fadeWindowToken(boolean show, WindowToken windowToken, int animationType) { if (windowToken == null || windowToken.getParent() == null) { return; } final Animation animation = show ? getFadeInAnimation() : getFadeOutAnimation(); if (animation == null) { return; } final LocalAnimationAdapter.AnimationSpec windowAnimationSpec = createAnimationSpec(animation); final FadeAnimationAdapter animationAdapter = new FadeAnimationAdapter( windowAnimationSpec, windowToken.getSurfaceAnimationRunner(), show, windowToken); // We deferred the end of the animation when hiding the token, so we need to end it now that // it's shown again. final SurfaceAnimator.OnAnimationFinishedCallback finishedCallback = show ? (t, r) -> { final Runnable runnable = mDeferredFinishCallbacks.remove(windowToken); if (runnable != null) { runnable.run(); } } : null; windowToken.startAnimation(windowToken.getPendingTransaction(), animationAdapter, show /* hidden */, animationType, finishedCallback); } private LocalAnimationAdapter.AnimationSpec createAnimationSpec(@NonNull Animation animation) { return new LocalAnimationAdapter.AnimationSpec() { final Transformation mTransformation = new Transformation(); @Override public boolean getShowWallpaper() { return true; } @Override public long getDuration() { return animation.getDuration(); } @Override public void apply(SurfaceControl.Transaction t, SurfaceControl leash, long currentPlayTime) { mTransformation.clear(); animation.getTransformation(currentPlayTime, mTransformation); t.setAlpha(leash, mTransformation.getAlpha()); } @Override public void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.println(animation); } @Override public void dumpDebugInner(ProtoOutputStream proto) { final long token = proto.start(WINDOW); proto.write(ANIMATION, animation.toString()); proto.end(token); } }; } private class FadeAnimationAdapter extends LocalAnimationAdapter { private final boolean mShow; private final WindowToken mToken; FadeAnimationAdapter(AnimationSpec windowAnimationSpec, SurfaceAnimationRunner surfaceAnimationRunner, boolean show, WindowToken token) { super(windowAnimationSpec, surfaceAnimationRunner); mShow = show; mToken = token; } @Override public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) { // We defer the end of the hide animation to ensure the tokens stay hidden until // we show them again. if (!mShow) { mDeferredFinishCallbacks.put(mToken, endDeferFinishCallback); return true; } return false; } } } services/core/java/com/android/server/wm/FixedRotationAnimationController.java +10 −105 Original line number Diff line number Diff line Loading @@ -16,21 +16,8 @@ package com.android.server.wm; import static com.android.server.wm.AnimationSpecProto.WINDOW; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_FIXED_TRANSFORM; import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION; import android.content.Context; import android.util.ArrayMap; import android.util.proto.ProtoOutputStream; import android.view.SurfaceControl; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.Transformation; import com.android.internal.R; import java.io.PrintWriter; import java.util.ArrayList; /** Loading @@ -40,16 +27,14 @@ import java.util.ArrayList; * The system bars will be fade out when the fixed rotation transform starts and will be fade in * once all surfaces have been rotated. */ public class FixedRotationAnimationController { public class FixedRotationAnimationController extends FadeAnimationController { private final Context mContext; private final WindowState mStatusBar; private final WindowState mNavigationBar; private final ArrayList<WindowToken> mAnimatedWindowToken = new ArrayList<>(2); private final ArrayMap<WindowToken, Runnable> mDeferredFinishCallbacks = new ArrayMap<>(); public FixedRotationAnimationController(DisplayContent displayContent) { mContext = displayContent.mWmService.mContext; super(displayContent); final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy(); mStatusBar = displayPolicy.getStatusBar(); // Do not animate movable navigation bar (e.g. non-gesture mode). Loading @@ -62,105 +47,25 @@ public class FixedRotationAnimationController { void show() { for (int i = mAnimatedWindowToken.size() - 1; i >= 0; i--) { final WindowToken windowToken = mAnimatedWindowToken.get(i); fadeWindowToken(true /* show */, windowToken); fadeWindowToken(true /* show */, windowToken, ANIMATION_TYPE_FIXED_TRANSFORM); } } /** Applies hide animation on the window tokens which may be seamlessly rotated later. */ void hide() { if (mNavigationBar != null) { fadeWindowToken(false /* show */, mNavigationBar.mToken); fadeWindowToken(false /* show */, mNavigationBar.mToken, ANIMATION_TYPE_FIXED_TRANSFORM); } if (mStatusBar != null) { fadeWindowToken(false /* show */, mStatusBar.mToken); } } private void fadeWindowToken(boolean show, WindowToken windowToken) { if (windowToken == null || windowToken.getParent() == null) { return; } final Animation animation = AnimationUtils.loadAnimation(mContext, show ? R.anim.fade_in : R.anim.fade_out); final LocalAnimationAdapter.AnimationSpec windowAnimationSpec = createAnimationSpec(animation); final FixedRotationAnimationAdapter animationAdapter = new FixedRotationAnimationAdapter( windowAnimationSpec, windowToken.getSurfaceAnimationRunner(), show, windowToken); // We deferred the end of the animation when hiding the token, so we need to end it now that // it's shown again. final SurfaceAnimator.OnAnimationFinishedCallback finishedCallback = show ? (t, r) -> { final Runnable runnable = mDeferredFinishCallbacks.remove(windowToken); if (runnable != null) { runnable.run(); } } : null; windowToken.startAnimation(windowToken.getPendingTransaction(), animationAdapter, show /* hidden */, ANIMATION_TYPE_FIXED_TRANSFORM, finishedCallback); mAnimatedWindowToken.add(windowToken); } private LocalAnimationAdapter.AnimationSpec createAnimationSpec(Animation animation) { return new LocalAnimationAdapter.AnimationSpec() { final Transformation mTransformation = new Transformation(); @Override public boolean getShowWallpaper() { return true; } @Override public long getDuration() { return animation.getDuration(); fadeWindowToken(false /* show */, mStatusBar.mToken, ANIMATION_TYPE_FIXED_TRANSFORM); } @Override public void apply(SurfaceControl.Transaction t, SurfaceControl leash, long currentPlayTime) { mTransformation.clear(); animation.getTransformation(currentPlayTime, mTransformation); t.setAlpha(leash, mTransformation.getAlpha()); } @Override public void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.println(animation); } @Override public void dumpDebugInner(ProtoOutputStream proto) { final long token = proto.start(WINDOW); proto.write(ANIMATION, animation.toString()); proto.end(token); } }; } private class FixedRotationAnimationAdapter extends LocalAnimationAdapter { private final boolean mShow; private final WindowToken mToken; FixedRotationAnimationAdapter(AnimationSpec windowAnimationSpec, SurfaceAnimationRunner surfaceAnimationRunner, boolean show, WindowToken token) { super(windowAnimationSpec, surfaceAnimationRunner); mShow = show; mToken = token; } @Override public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) { // We defer the end of the hide animation to ensure the tokens stay hidden until // we show them again. if (!mShow) { mDeferredFinishCallbacks.put(mToken, endDeferFinishCallback); return true; } return false; } public void fadeWindowToken(boolean show, WindowToken windowToken, int animationType) { super.fadeWindowToken(show, windowToken, animationType); mAnimatedWindowToken.add(windowToken); } } services/core/java/com/android/server/wm/NavBarFadeAnimationController.java 0 → 100644 +72 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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 com.android.server.wm; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; /** * Controller to fade in and out navigation bar during app transition when * config_attachNavBarToAppDuringTransition is true. */ public class NavBarFadeAnimationController extends FadeAnimationController{ private static final int FADE_IN_DURATION = 266; private static final int FADE_OUT_DURATION = 133; private static final Interpolator FADE_IN_INTERPOLATOR = new PathInterpolator(0f, 0f, 0f, 1f); private static final Interpolator FADE_OUT_INTERPOLATOR = new PathInterpolator(0.2f, 0f, 1f, 1f); private final WindowState mNavigationBar; private Animation mFadeInAnimation; private Animation mFadeOutAnimation; public NavBarFadeAnimationController(DisplayContent displayContent) { super(displayContent); mNavigationBar = displayContent.getDisplayPolicy().getNavigationBar(); mFadeInAnimation = new AlphaAnimation(0f, 1f); mFadeInAnimation.setDuration(FADE_IN_DURATION); mFadeInAnimation.setInterpolator(FADE_IN_INTERPOLATOR); mFadeOutAnimation = new AlphaAnimation(1f, 0f); mFadeOutAnimation.setDuration(FADE_OUT_DURATION); mFadeOutAnimation.setInterpolator(FADE_OUT_INTERPOLATOR); } @Override public Animation getFadeInAnimation() { return mFadeInAnimation; } @Override public Animation getFadeOutAnimation() { return mFadeOutAnimation; } /** * Run the fade-in/out animation for the navigation bar. * * @param show true for fade-in, otherwise for fade-out. */ public void fadeWindowToken(boolean show) { fadeWindowToken(show, mNavigationBar.mToken, ANIMATION_TYPE_APP_TRANSITION); } } services/core/java/com/android/server/wm/RecentsAnimationController.java +71 −1 Original line number Diff line number Diff line Loading @@ -33,7 +33,6 @@ import static com.android.server.wm.WindowManagerInternal.AppTransitionListener; import android.annotation.IntDef; import android.annotation.NonNull; import android.window.TaskSnapshot; import android.app.WindowConfiguration; import android.graphics.Point; import android.graphics.Rect; Loading @@ -54,6 +53,7 @@ import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import android.view.WindowInsets.Type; import android.window.TaskSnapshot; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.inputmethod.SoftInputShowHideReason; Loading Loading @@ -147,6 +147,9 @@ public class RecentsAnimationController implements DeathRecipient { // Whether to take a screenshot when handling a deferred cancel private boolean mCancelDeferredWithScreenshot; @VisibleForTesting boolean mShouldAttachNavBarToAppDuringTransition; /** * Animates the screenshot of task that used to be controlled by RecentsAnimation. * @see {@link #setCancelOnNextTransitionStart} Loading Loading @@ -390,6 +393,8 @@ public class RecentsAnimationController implements DeathRecipient { mDisplayId = displayId; mStatusBar = LocalServices.getService(StatusBarManagerInternal.class); mDisplayContent = service.mRoot.getDisplayContent(displayId); mShouldAttachNavBarToAppDuringTransition = mDisplayContent.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition(); } /** Loading Loading @@ -439,6 +444,10 @@ public class RecentsAnimationController implements DeathRecipient { return; } if (mShouldAttachNavBarToAppDuringTransition) { attachNavBarToApp(); } // Adjust the wallpaper visibility for the showing target activity ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "setHomeApp(%s)", targetActivity.getName()); Loading Loading @@ -572,6 +581,63 @@ public class RecentsAnimationController implements DeathRecipient { } } @VisibleForTesting WindowToken getNavigationBarWindowToken() { WindowState navBar = mDisplayContent.getDisplayPolicy().getNavigationBar(); if (navBar != null) { return navBar.mToken; } return null; } private void attachNavBarToApp() { ActivityRecord topActivity = null; for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { final TaskAnimationAdapter adapter = mPendingAnimations.get(i); final Task task = adapter.mTask; if (!task.isHomeOrRecentsRootTask()) { topActivity = task.getTopVisibleActivity(); break; } } final WindowToken navToken = getNavigationBarWindowToken(); if (topActivity == null || navToken == null) { return; } final SurfaceControl.Transaction t = navToken.getPendingTransaction(); final SurfaceControl navSurfaceControl = navToken.getSurfaceControl(); t.reparent(navSurfaceControl, topActivity.getSurfaceControl()); t.show(navSurfaceControl); final WindowContainer imeContainer = mDisplayContent.getImeContainer(); if (imeContainer.isVisible()) { t.setRelativeLayer(navSurfaceControl, imeContainer.getSurfaceControl(), 1); } else { // Place the nav bar on top of anything else in the top activity. t.setLayer(navSurfaceControl, Integer.MAX_VALUE); } } private void restoreNavBarFromApp(boolean animate) { // Reparent the SurfaceControl of nav bar token back. final WindowToken navToken = getNavigationBarWindowToken(); final SurfaceControl.Transaction t = mDisplayContent.getPendingTransaction(); if (navToken != null) { final WindowContainer parent = navToken.getParent(); t.reparent(navToken.getSurfaceControl(), parent.getSurfaceControl()); } if (animate) { // Run fade-in animation to show navigation bar back to bottom of the display. final NavBarFadeAnimationController controller = mDisplayContent.getDisplayPolicy().getNavBarFadeAnimationController(); if (controller != null) { controller.fadeWindowToken(true); } } } void addTaskToTargets(Task task, OnAnimationFinishedCallback finishedCallback) { if (mRunner != null) { // No need to send task appeared when the task target already exists, or when the Loading Loading @@ -790,6 +856,10 @@ public class RecentsAnimationController implements DeathRecipient { removeWallpaperAnimation(wallpaperAdapter); } if (mShouldAttachNavBarToAppDuringTransition) { restoreNavBarFromApp(reorderMode == REORDER_MOVE_TO_TOP); } // Clear any pending failsafe runnables mService.mH.removeCallbacks(mFailsafeRunnable); mDisplayContent.mAppTransition.unregisterListener(mAppTransitionListener); Loading Loading
services/core/java/com/android/server/wm/DisplayPolicy.java +39 −0 Original line number Diff line number Diff line Loading @@ -380,6 +380,14 @@ public class DisplayPolicy { private RefreshRatePolicy mRefreshRatePolicy; /** * If true, attach the navigation bar to the current transition app. * The value is read from config_attachNavBarToAppDuringTransition and could be overlaid by RRO * when the navigation bar mode is changed. */ private boolean mShouldAttachNavBarToAppDuringTransition; private NavBarFadeAnimationController mNavBarFadeAnimationController; // -------- PolicyHandler -------- private static final int MSG_REQUEST_TRANSIENT_BARS = 2; private static final int MSG_DISPOSE_INPUT_CONSUMER = 3; Loading Loading @@ -1086,6 +1094,7 @@ public class DisplayPolicy { break; case TYPE_NAVIGATION_BAR: mNavigationBar = win; updateNavBarFadeController(); mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, win, (displayFrames, windowState, inOutFrame) -> { Loading Loading @@ -1231,6 +1240,7 @@ public class DisplayPolicy { mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, null, null); } else if (mNavigationBar == win || mNavigationBarAlt == win) { mNavigationBar = null; updateNavBarFadeController(); mNavigationBarAlt = null; mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, null, null); } else if (mNotificationShade == win) { Loading Loading @@ -2195,6 +2205,13 @@ public class DisplayPolicy { - getNavigationBarFrameHeight(portraitRotation, uiMode); updateConfigurationAndScreenSizeDependentBehaviors(); final boolean shouldAttach = res.getBoolean(R.bool.config_attachNavBarToAppDuringTransition); if (mShouldAttachNavBarToAppDuringTransition != shouldAttach) { mShouldAttachNavBarToAppDuringTransition = shouldAttach; updateNavBarFadeController(); } } void updateConfigurationAndScreenSizeDependentBehaviors() { Loading Loading @@ -3177,4 +3194,26 @@ public class DisplayPolicy { return Rect.intersects(targetWindow.getFrame(), navBarWindow.getFrame()); } /** * @return Whether we should attach navigation bar to the app during transition. */ boolean shouldAttachNavBarToAppDuringTransition() { return mShouldAttachNavBarToAppDuringTransition && mNavigationBar != null; } @Nullable NavBarFadeAnimationController getNavBarFadeAnimationController() { return mNavBarFadeAnimationController; } private void updateNavBarFadeController() { if (shouldAttachNavBarToAppDuringTransition()) { if (mNavBarFadeAnimationController == null) { mNavBarFadeAnimationController = new NavBarFadeAnimationController(mDisplayContent); } } else { mNavBarFadeAnimationController = null; } } }
services/core/java/com/android/server/wm/FadeAnimationController.java 0 → 100644 +156 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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 com.android.server.wm; import static com.android.server.wm.AnimationSpecProto.WINDOW; import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION; import android.annotation.NonNull; import android.content.Context; import android.util.ArrayMap; import android.util.proto.ProtoOutputStream; import android.view.SurfaceControl; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.Transformation; import com.android.internal.R; import java.io.PrintWriter; /** * An animation controller to fade-in/out for a window token. */ public class FadeAnimationController { protected final Context mContext; private final ArrayMap<WindowToken, Runnable> mDeferredFinishCallbacks = new ArrayMap<>(); public FadeAnimationController(DisplayContent displayContent) { mContext = displayContent.mWmService.mContext; } /** * @return a fade-in Animation. */ public Animation getFadeInAnimation() { return AnimationUtils.loadAnimation(mContext, R.anim.fade_in); } /** * @return a fade-out Animation. */ public Animation getFadeOutAnimation() { return AnimationUtils.loadAnimation(mContext, R.anim.fade_out); } /** * Run the fade in/out animation for a window token. * * @param show true for fade-in, otherwise for fade-out. * @param windowToken the window token to run the animation. * @param animationType the animation type defined in SurfaceAnimator. */ public void fadeWindowToken(boolean show, WindowToken windowToken, int animationType) { if (windowToken == null || windowToken.getParent() == null) { return; } final Animation animation = show ? getFadeInAnimation() : getFadeOutAnimation(); if (animation == null) { return; } final LocalAnimationAdapter.AnimationSpec windowAnimationSpec = createAnimationSpec(animation); final FadeAnimationAdapter animationAdapter = new FadeAnimationAdapter( windowAnimationSpec, windowToken.getSurfaceAnimationRunner(), show, windowToken); // We deferred the end of the animation when hiding the token, so we need to end it now that // it's shown again. final SurfaceAnimator.OnAnimationFinishedCallback finishedCallback = show ? (t, r) -> { final Runnable runnable = mDeferredFinishCallbacks.remove(windowToken); if (runnable != null) { runnable.run(); } } : null; windowToken.startAnimation(windowToken.getPendingTransaction(), animationAdapter, show /* hidden */, animationType, finishedCallback); } private LocalAnimationAdapter.AnimationSpec createAnimationSpec(@NonNull Animation animation) { return new LocalAnimationAdapter.AnimationSpec() { final Transformation mTransformation = new Transformation(); @Override public boolean getShowWallpaper() { return true; } @Override public long getDuration() { return animation.getDuration(); } @Override public void apply(SurfaceControl.Transaction t, SurfaceControl leash, long currentPlayTime) { mTransformation.clear(); animation.getTransformation(currentPlayTime, mTransformation); t.setAlpha(leash, mTransformation.getAlpha()); } @Override public void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.println(animation); } @Override public void dumpDebugInner(ProtoOutputStream proto) { final long token = proto.start(WINDOW); proto.write(ANIMATION, animation.toString()); proto.end(token); } }; } private class FadeAnimationAdapter extends LocalAnimationAdapter { private final boolean mShow; private final WindowToken mToken; FadeAnimationAdapter(AnimationSpec windowAnimationSpec, SurfaceAnimationRunner surfaceAnimationRunner, boolean show, WindowToken token) { super(windowAnimationSpec, surfaceAnimationRunner); mShow = show; mToken = token; } @Override public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) { // We defer the end of the hide animation to ensure the tokens stay hidden until // we show them again. if (!mShow) { mDeferredFinishCallbacks.put(mToken, endDeferFinishCallback); return true; } return false; } } }
services/core/java/com/android/server/wm/FixedRotationAnimationController.java +10 −105 Original line number Diff line number Diff line Loading @@ -16,21 +16,8 @@ package com.android.server.wm; import static com.android.server.wm.AnimationSpecProto.WINDOW; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_FIXED_TRANSFORM; import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION; import android.content.Context; import android.util.ArrayMap; import android.util.proto.ProtoOutputStream; import android.view.SurfaceControl; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.Transformation; import com.android.internal.R; import java.io.PrintWriter; import java.util.ArrayList; /** Loading @@ -40,16 +27,14 @@ import java.util.ArrayList; * The system bars will be fade out when the fixed rotation transform starts and will be fade in * once all surfaces have been rotated. */ public class FixedRotationAnimationController { public class FixedRotationAnimationController extends FadeAnimationController { private final Context mContext; private final WindowState mStatusBar; private final WindowState mNavigationBar; private final ArrayList<WindowToken> mAnimatedWindowToken = new ArrayList<>(2); private final ArrayMap<WindowToken, Runnable> mDeferredFinishCallbacks = new ArrayMap<>(); public FixedRotationAnimationController(DisplayContent displayContent) { mContext = displayContent.mWmService.mContext; super(displayContent); final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy(); mStatusBar = displayPolicy.getStatusBar(); // Do not animate movable navigation bar (e.g. non-gesture mode). Loading @@ -62,105 +47,25 @@ public class FixedRotationAnimationController { void show() { for (int i = mAnimatedWindowToken.size() - 1; i >= 0; i--) { final WindowToken windowToken = mAnimatedWindowToken.get(i); fadeWindowToken(true /* show */, windowToken); fadeWindowToken(true /* show */, windowToken, ANIMATION_TYPE_FIXED_TRANSFORM); } } /** Applies hide animation on the window tokens which may be seamlessly rotated later. */ void hide() { if (mNavigationBar != null) { fadeWindowToken(false /* show */, mNavigationBar.mToken); fadeWindowToken(false /* show */, mNavigationBar.mToken, ANIMATION_TYPE_FIXED_TRANSFORM); } if (mStatusBar != null) { fadeWindowToken(false /* show */, mStatusBar.mToken); } } private void fadeWindowToken(boolean show, WindowToken windowToken) { if (windowToken == null || windowToken.getParent() == null) { return; } final Animation animation = AnimationUtils.loadAnimation(mContext, show ? R.anim.fade_in : R.anim.fade_out); final LocalAnimationAdapter.AnimationSpec windowAnimationSpec = createAnimationSpec(animation); final FixedRotationAnimationAdapter animationAdapter = new FixedRotationAnimationAdapter( windowAnimationSpec, windowToken.getSurfaceAnimationRunner(), show, windowToken); // We deferred the end of the animation when hiding the token, so we need to end it now that // it's shown again. final SurfaceAnimator.OnAnimationFinishedCallback finishedCallback = show ? (t, r) -> { final Runnable runnable = mDeferredFinishCallbacks.remove(windowToken); if (runnable != null) { runnable.run(); } } : null; windowToken.startAnimation(windowToken.getPendingTransaction(), animationAdapter, show /* hidden */, ANIMATION_TYPE_FIXED_TRANSFORM, finishedCallback); mAnimatedWindowToken.add(windowToken); } private LocalAnimationAdapter.AnimationSpec createAnimationSpec(Animation animation) { return new LocalAnimationAdapter.AnimationSpec() { final Transformation mTransformation = new Transformation(); @Override public boolean getShowWallpaper() { return true; } @Override public long getDuration() { return animation.getDuration(); fadeWindowToken(false /* show */, mStatusBar.mToken, ANIMATION_TYPE_FIXED_TRANSFORM); } @Override public void apply(SurfaceControl.Transaction t, SurfaceControl leash, long currentPlayTime) { mTransformation.clear(); animation.getTransformation(currentPlayTime, mTransformation); t.setAlpha(leash, mTransformation.getAlpha()); } @Override public void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.println(animation); } @Override public void dumpDebugInner(ProtoOutputStream proto) { final long token = proto.start(WINDOW); proto.write(ANIMATION, animation.toString()); proto.end(token); } }; } private class FixedRotationAnimationAdapter extends LocalAnimationAdapter { private final boolean mShow; private final WindowToken mToken; FixedRotationAnimationAdapter(AnimationSpec windowAnimationSpec, SurfaceAnimationRunner surfaceAnimationRunner, boolean show, WindowToken token) { super(windowAnimationSpec, surfaceAnimationRunner); mShow = show; mToken = token; } @Override public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) { // We defer the end of the hide animation to ensure the tokens stay hidden until // we show them again. if (!mShow) { mDeferredFinishCallbacks.put(mToken, endDeferFinishCallback); return true; } return false; } public void fadeWindowToken(boolean show, WindowToken windowToken, int animationType) { super.fadeWindowToken(show, windowToken, animationType); mAnimatedWindowToken.add(windowToken); } }
services/core/java/com/android/server/wm/NavBarFadeAnimationController.java 0 → 100644 +72 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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 com.android.server.wm; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; /** * Controller to fade in and out navigation bar during app transition when * config_attachNavBarToAppDuringTransition is true. */ public class NavBarFadeAnimationController extends FadeAnimationController{ private static final int FADE_IN_DURATION = 266; private static final int FADE_OUT_DURATION = 133; private static final Interpolator FADE_IN_INTERPOLATOR = new PathInterpolator(0f, 0f, 0f, 1f); private static final Interpolator FADE_OUT_INTERPOLATOR = new PathInterpolator(0.2f, 0f, 1f, 1f); private final WindowState mNavigationBar; private Animation mFadeInAnimation; private Animation mFadeOutAnimation; public NavBarFadeAnimationController(DisplayContent displayContent) { super(displayContent); mNavigationBar = displayContent.getDisplayPolicy().getNavigationBar(); mFadeInAnimation = new AlphaAnimation(0f, 1f); mFadeInAnimation.setDuration(FADE_IN_DURATION); mFadeInAnimation.setInterpolator(FADE_IN_INTERPOLATOR); mFadeOutAnimation = new AlphaAnimation(1f, 0f); mFadeOutAnimation.setDuration(FADE_OUT_DURATION); mFadeOutAnimation.setInterpolator(FADE_OUT_INTERPOLATOR); } @Override public Animation getFadeInAnimation() { return mFadeInAnimation; } @Override public Animation getFadeOutAnimation() { return mFadeOutAnimation; } /** * Run the fade-in/out animation for the navigation bar. * * @param show true for fade-in, otherwise for fade-out. */ public void fadeWindowToken(boolean show) { fadeWindowToken(show, mNavigationBar.mToken, ANIMATION_TYPE_APP_TRANSITION); } }
services/core/java/com/android/server/wm/RecentsAnimationController.java +71 −1 Original line number Diff line number Diff line Loading @@ -33,7 +33,6 @@ import static com.android.server.wm.WindowManagerInternal.AppTransitionListener; import android.annotation.IntDef; import android.annotation.NonNull; import android.window.TaskSnapshot; import android.app.WindowConfiguration; import android.graphics.Point; import android.graphics.Rect; Loading @@ -54,6 +53,7 @@ import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import android.view.WindowInsets.Type; import android.window.TaskSnapshot; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.inputmethod.SoftInputShowHideReason; Loading Loading @@ -147,6 +147,9 @@ public class RecentsAnimationController implements DeathRecipient { // Whether to take a screenshot when handling a deferred cancel private boolean mCancelDeferredWithScreenshot; @VisibleForTesting boolean mShouldAttachNavBarToAppDuringTransition; /** * Animates the screenshot of task that used to be controlled by RecentsAnimation. * @see {@link #setCancelOnNextTransitionStart} Loading Loading @@ -390,6 +393,8 @@ public class RecentsAnimationController implements DeathRecipient { mDisplayId = displayId; mStatusBar = LocalServices.getService(StatusBarManagerInternal.class); mDisplayContent = service.mRoot.getDisplayContent(displayId); mShouldAttachNavBarToAppDuringTransition = mDisplayContent.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition(); } /** Loading Loading @@ -439,6 +444,10 @@ public class RecentsAnimationController implements DeathRecipient { return; } if (mShouldAttachNavBarToAppDuringTransition) { attachNavBarToApp(); } // Adjust the wallpaper visibility for the showing target activity ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "setHomeApp(%s)", targetActivity.getName()); Loading Loading @@ -572,6 +581,63 @@ public class RecentsAnimationController implements DeathRecipient { } } @VisibleForTesting WindowToken getNavigationBarWindowToken() { WindowState navBar = mDisplayContent.getDisplayPolicy().getNavigationBar(); if (navBar != null) { return navBar.mToken; } return null; } private void attachNavBarToApp() { ActivityRecord topActivity = null; for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { final TaskAnimationAdapter adapter = mPendingAnimations.get(i); final Task task = adapter.mTask; if (!task.isHomeOrRecentsRootTask()) { topActivity = task.getTopVisibleActivity(); break; } } final WindowToken navToken = getNavigationBarWindowToken(); if (topActivity == null || navToken == null) { return; } final SurfaceControl.Transaction t = navToken.getPendingTransaction(); final SurfaceControl navSurfaceControl = navToken.getSurfaceControl(); t.reparent(navSurfaceControl, topActivity.getSurfaceControl()); t.show(navSurfaceControl); final WindowContainer imeContainer = mDisplayContent.getImeContainer(); if (imeContainer.isVisible()) { t.setRelativeLayer(navSurfaceControl, imeContainer.getSurfaceControl(), 1); } else { // Place the nav bar on top of anything else in the top activity. t.setLayer(navSurfaceControl, Integer.MAX_VALUE); } } private void restoreNavBarFromApp(boolean animate) { // Reparent the SurfaceControl of nav bar token back. final WindowToken navToken = getNavigationBarWindowToken(); final SurfaceControl.Transaction t = mDisplayContent.getPendingTransaction(); if (navToken != null) { final WindowContainer parent = navToken.getParent(); t.reparent(navToken.getSurfaceControl(), parent.getSurfaceControl()); } if (animate) { // Run fade-in animation to show navigation bar back to bottom of the display. final NavBarFadeAnimationController controller = mDisplayContent.getDisplayPolicy().getNavBarFadeAnimationController(); if (controller != null) { controller.fadeWindowToken(true); } } } void addTaskToTargets(Task task, OnAnimationFinishedCallback finishedCallback) { if (mRunner != null) { // No need to send task appeared when the task target already exists, or when the Loading Loading @@ -790,6 +856,10 @@ public class RecentsAnimationController implements DeathRecipient { removeWallpaperAnimation(wallpaperAdapter); } if (mShouldAttachNavBarToAppDuringTransition) { restoreNavBarFromApp(reorderMode == REORDER_MOVE_TO_TOP); } // Clear any pending failsafe runnables mService.mH.removeCallbacks(mFailsafeRunnable); mDisplayContent.mAppTransition.unregisterListener(mAppTransitionListener); Loading