• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wm;
18 
19 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_FIXED_TRANSFORM;
20 
21 import android.view.animation.AlphaAnimation;
22 import android.view.animation.Animation;
23 import android.view.animation.AnimationUtils;
24 
25 import com.android.internal.R;
26 
27 import java.util.ArrayList;
28 
29 /**
30  * Controller to fade out and in windows when the display is changing rotation. It can be used for
31  * both fixed rotation and normal rotation to hide some non-activity windows. The caller should show
32  * the windows until they are drawn with the new rotation.
33  */
34 public class FadeRotationAnimationController extends FadeAnimationController {
35 
36     private final ArrayList<WindowToken> mTargetWindowTokens = new ArrayList<>();
37     private final WindowManagerService mService;
38     /** If non-null, it usually indicates that there will be a screen rotation animation. */
39     private final Runnable mFrozenTimeoutRunnable;
40     private final WindowToken mNavBarToken;
41 
42     /** A runnable which gets called when the {@link #show()} is called. */
43     private Runnable mOnShowRunnable;
44 
FadeRotationAnimationController(DisplayContent displayContent)45     public FadeRotationAnimationController(DisplayContent displayContent) {
46         super(displayContent);
47         mService = displayContent.mWmService;
48         mFrozenTimeoutRunnable = mService.mDisplayFrozen ? () -> {
49             synchronized (mService.mGlobalLock) {
50                 displayContent.finishFadeRotationAnimationIfPossible();
51                 mService.mWindowPlacerLocked.performSurfacePlacement();
52             }
53         } : null;
54         final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
55         final WindowState navigationBar = displayPolicy.getNavigationBar();
56         if (navigationBar != null) {
57             mNavBarToken = navigationBar.mToken;
58             final RecentsAnimationController controller = mService.getRecentsAnimationController();
59             final boolean navBarControlledByRecents =
60                     controller != null && controller.isNavigationBarAttachedToApp();
61             // Do not animate movable navigation bar (e.g. non-gesture mode) or when the navigation
62             // bar is currently controlled by recents animation.
63             if (!displayPolicy.navigationBarCanMove() && !navBarControlledByRecents) {
64                 mTargetWindowTokens.add(mNavBarToken);
65             }
66         } else {
67             mNavBarToken = null;
68         }
69         // Collect the target windows to fade out. The display won't wait for them to unfreeze.
70         final WindowState notificationShade = displayPolicy.getNotificationShade();
71         displayContent.forAllWindows(w -> {
72             if (w.mActivityRecord == null && w.mHasSurface && !w.mForceSeamlesslyRotate
73                     && !w.mIsWallpaper && !w.mIsImWindow && w != navigationBar
74                     && w != notificationShade) {
75                 mTargetWindowTokens.add(w.mToken);
76             }
77         }, true /* traverseTopToBottom */);
78     }
79 
80     /** Applies show animation on the previously hidden window tokens. */
show()81     void show() {
82         for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
83             final WindowToken windowToken = mTargetWindowTokens.get(i);
84             fadeWindowToken(true /* show */, windowToken, ANIMATION_TYPE_FIXED_TRANSFORM);
85         }
86         mTargetWindowTokens.clear();
87         if (mFrozenTimeoutRunnable != null) {
88             mService.mH.removeCallbacks(mFrozenTimeoutRunnable);
89         }
90         if (mOnShowRunnable != null) {
91             mOnShowRunnable.run();
92             mOnShowRunnable = null;
93         }
94     }
95 
96     /**
97      * Returns {@code true} if all target windows are shown. It only takes effects if this
98      * controller is created for normal rotation.
99      */
show(WindowToken token)100     boolean show(WindowToken token) {
101         if (mFrozenTimeoutRunnable != null && mTargetWindowTokens.remove(token)) {
102             fadeWindowToken(true /* show */, token, ANIMATION_TYPE_FIXED_TRANSFORM);
103             if (mTargetWindowTokens.isEmpty()) {
104                 mService.mH.removeCallbacks(mFrozenTimeoutRunnable);
105                 return true;
106             }
107         }
108         return false;
109     }
110 
111     /** Applies hide animation on the window tokens which may be seamlessly rotated later. */
hide()112     void hide() {
113         for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
114             final WindowToken windowToken = mTargetWindowTokens.get(i);
115             fadeWindowToken(false /* show */, windowToken, ANIMATION_TYPE_FIXED_TRANSFORM);
116         }
117         if (mFrozenTimeoutRunnable != null) {
118             mService.mH.postDelayed(mFrozenTimeoutRunnable,
119                     WindowManagerService.WINDOW_FREEZE_TIMEOUT_DURATION);
120         }
121     }
122 
123     /** Returns {@code true} if the window is handled by this controller. */
isHandledToken(WindowToken token)124     boolean isHandledToken(WindowToken token) {
125         return token == mNavBarToken || isTargetToken(token);
126     }
127 
128     /** Returns {@code true} if the controller will run fade animations on the window. */
isTargetToken(WindowToken token)129     boolean isTargetToken(WindowToken token) {
130         return mTargetWindowTokens.contains(token);
131     }
132 
setOnShowRunnable(Runnable onShowRunnable)133     void setOnShowRunnable(Runnable onShowRunnable) {
134         mOnShowRunnable = onShowRunnable;
135     }
136 
137     @Override
getFadeInAnimation()138     public Animation getFadeInAnimation() {
139         if (mFrozenTimeoutRunnable != null) {
140             // Use a shorter animation so it is easier to align with screen rotation animation.
141             return AnimationUtils.loadAnimation(mContext, R.anim.screen_rotate_0_enter);
142         }
143         return super.getFadeInAnimation();
144     }
145 
146     @Override
getFadeOutAnimation()147     public Animation getFadeOutAnimation() {
148         if (mFrozenTimeoutRunnable != null) {
149             // Hide the window immediately because screen should have been covered by screenshot.
150             return new AlphaAnimation(0 /* fromAlpha */, 0 /* toAlpha */);
151         }
152         return super.getFadeOutAnimation();
153     }
154 }
155