1 /*
2  * Copyright (C) 2021 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 android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
20 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
21 import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
22 import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_FRONT;
23 import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_CLOSE;
24 
25 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS;
26 import static com.android.server.wm.AnimationAdapterProto.REMOTE;
27 import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
28 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
29 
30 import android.annotation.NonNull;
31 import android.graphics.Rect;
32 import android.os.SystemClock;
33 import android.util.proto.ProtoOutputStream;
34 import android.view.RemoteAnimationTarget;
35 import android.view.SurfaceControl;
36 import android.view.WindowManager;
37 
38 import com.android.internal.protolog.common.ProtoLog;
39 import com.android.server.policy.WindowManagerPolicy;
40 
41 import java.io.PrintWriter;
42 import java.util.ArrayList;
43 
44 class NonAppWindowAnimationAdapter implements AnimationAdapter {
45 
46     private final WindowContainer mWindowContainer;
47     private RemoteAnimationTarget mTarget;
48     private SurfaceControl mCapturedLeash;
49     private SurfaceAnimator.OnAnimationFinishedCallback mCapturedLeashFinishCallback;
50     private @SurfaceAnimator.AnimationType int mLastAnimationType;
51 
52     private long mDurationHint;
53     private long mStatusBarTransitionDelay;
54 
55     @Override
getShowWallpaper()56     public boolean getShowWallpaper() {
57         return false;
58     }
59 
NonAppWindowAnimationAdapter(WindowContainer w, long durationHint, long statusBarTransitionDelay)60     NonAppWindowAnimationAdapter(WindowContainer w, long durationHint,
61             long statusBarTransitionDelay) {
62         mWindowContainer = w;
63         mDurationHint = durationHint;
64         mStatusBarTransitionDelay = statusBarTransitionDelay;
65     }
66 
startNonAppWindowAnimations(WindowManagerService service, DisplayContent displayContent, @WindowManager.TransitionOldType int transit, long durationHint, long statusBarTransitionDelay, ArrayList<NonAppWindowAnimationAdapter> adaptersOut)67     static RemoteAnimationTarget[] startNonAppWindowAnimations(WindowManagerService service,
68             DisplayContent displayContent, @WindowManager.TransitionOldType int transit,
69             long durationHint, long statusBarTransitionDelay,
70             ArrayList<NonAppWindowAnimationAdapter> adaptersOut) {
71         final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
72         if (shouldStartNonAppWindowAnimationsForKeyguardExit(transit)) {
73             startNonAppWindowAnimationsForKeyguardExit(
74                     service, durationHint, statusBarTransitionDelay, targets, adaptersOut);
75         } else if (shouldAttachNavBarToApp(service, displayContent, transit)) {
76             startNavigationBarWindowAnimation(
77                     displayContent, durationHint, statusBarTransitionDelay, targets,
78                     adaptersOut);
79         }
80         return targets.toArray(new RemoteAnimationTarget[targets.size()]);
81     }
82 
shouldStartNonAppWindowAnimationsForKeyguardExit( @indowManager.TransitionOldType int transit)83     static boolean shouldStartNonAppWindowAnimationsForKeyguardExit(
84             @WindowManager.TransitionOldType int transit) {
85         return transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY
86                 || transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
87     }
88 
shouldAttachNavBarToApp(WindowManagerService service, DisplayContent displayContent, @WindowManager.TransitionOldType int transit)89     static boolean shouldAttachNavBarToApp(WindowManagerService service,
90             DisplayContent displayContent, @WindowManager.TransitionOldType int transit) {
91         return (transit == TRANSIT_OLD_TASK_OPEN || transit == TRANSIT_OLD_TASK_TO_FRONT
92                 || transit == TRANSIT_OLD_WALLPAPER_CLOSE)
93                 && displayContent.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition()
94                 && service.getRecentsAnimationController() == null
95                 && displayContent.getAsyncRotationController() == null;
96     }
97 
98     /**
99      * Creates and starts remote animations for all the visible non app windows.
100      *
101      * @return RemoteAnimationTarget[] targets for all the visible non app windows
102      */
startNonAppWindowAnimationsForKeyguardExit(WindowManagerService service, long durationHint, long statusBarTransitionDelay, ArrayList<RemoteAnimationTarget> targets, ArrayList<NonAppWindowAnimationAdapter> adaptersOut)103     private static void startNonAppWindowAnimationsForKeyguardExit(WindowManagerService service,
104             long durationHint, long statusBarTransitionDelay,
105             ArrayList<RemoteAnimationTarget> targets,
106             ArrayList<NonAppWindowAnimationAdapter> adaptersOut) {
107 
108         final WindowManagerPolicy policy = service.mPolicy;
109         service.mRoot.forAllWindows(nonAppWindow -> {
110             // Animation on the IME window is controlled via Insets.
111             if (nonAppWindow.mActivityRecord == null && nonAppWindow.canBeHiddenByKeyguard()
112                     && nonAppWindow.wouldBeVisibleIfPolicyIgnored() && !nonAppWindow.isVisible()
113                     && nonAppWindow != service.mRoot.getCurrentInputMethodWindow()) {
114                 final NonAppWindowAnimationAdapter nonAppAdapter = new NonAppWindowAnimationAdapter(
115                         nonAppWindow, durationHint, statusBarTransitionDelay);
116                 adaptersOut.add(nonAppAdapter);
117                 nonAppWindow.startAnimation(nonAppWindow.getPendingTransaction(),
118                         nonAppAdapter, false /* hidden */, ANIMATION_TYPE_WINDOW_ANIMATION);
119                 targets.add(nonAppAdapter.createRemoteAnimationTarget());
120             }
121         }, true /* traverseTopToBottom */);
122     }
123 
124     /**
125      * Creates and starts remote animation for the navigation bar windows.
126      *
127      * @return RemoteAnimationTarget[] targets for all the visible non app windows
128      */
startNavigationBarWindowAnimation(DisplayContent displayContent, long durationHint, long statusBarTransitionDelay, ArrayList<RemoteAnimationTarget> targets, ArrayList<NonAppWindowAnimationAdapter> adaptersOut)129     private static void startNavigationBarWindowAnimation(DisplayContent displayContent,
130             long durationHint, long statusBarTransitionDelay,
131             ArrayList<RemoteAnimationTarget> targets,
132             ArrayList<NonAppWindowAnimationAdapter> adaptersOut) {
133         final WindowState navWindow = displayContent.getDisplayPolicy().getNavigationBar();
134         final NonAppWindowAnimationAdapter nonAppAdapter = new NonAppWindowAnimationAdapter(
135                 navWindow.mToken, durationHint, statusBarTransitionDelay);
136         adaptersOut.add(nonAppAdapter);
137         navWindow.mToken.startAnimation(navWindow.mToken.getPendingTransaction(),
138                 nonAppAdapter, false /* hidden */, ANIMATION_TYPE_WINDOW_ANIMATION);
139         targets.add(nonAppAdapter.createRemoteAnimationTarget());
140     }
141 
142     /**
143      * Create a remote animation target for this animation adapter.
144      */
createRemoteAnimationTarget()145     RemoteAnimationTarget createRemoteAnimationTarget() {
146         mTarget = new RemoteAnimationTarget(-1, -1, getLeash(), false,
147                 new Rect(), null, mWindowContainer.getPrefixOrderIndex(),
148                 mWindowContainer.getLastSurfacePosition(), mWindowContainer.getBounds(), null,
149                 mWindowContainer.getWindowConfiguration(), true, null, null, null, false,
150                 mWindowContainer.getWindowType());
151         return mTarget;
152     }
153 
154     @Override
startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t, int type, @NonNull SurfaceAnimator.OnAnimationFinishedCallback finishCallback)155     public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t,
156             int type, @NonNull SurfaceAnimator.OnAnimationFinishedCallback finishCallback) {
157         ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation");
158         mCapturedLeash = animationLeash;
159         mCapturedLeashFinishCallback = finishCallback;
160         mLastAnimationType = type;
161     }
162 
163     /**
164      * @return the callback to call to clean up when the animation has finished.
165      */
getLeashFinishedCallback()166     SurfaceAnimator.OnAnimationFinishedCallback getLeashFinishedCallback() {
167         return mCapturedLeashFinishCallback;
168     }
169 
170     /**
171      * @return the type of animation.
172      */
173     @SurfaceAnimator.AnimationType
getLastAnimationType()174     int getLastAnimationType() {
175         return mLastAnimationType;
176     }
177 
getWindowContainer()178     WindowContainer getWindowContainer() {
179         return mWindowContainer;
180     }
181 
182     @Override
getDurationHint()183     public long getDurationHint() {
184         return mDurationHint;
185     }
186 
187     @Override
getStatusBarTransitionsStartTime()188     public long getStatusBarTransitionsStartTime() {
189         return SystemClock.uptimeMillis() + mStatusBarTransitionDelay;
190     }
191 
192     /**
193      * @return the leash for this animation (only valid after the non app window surface animation
194      * has started).
195      */
getLeash()196     SurfaceControl getLeash() {
197         return mCapturedLeash;
198     }
199 
200     @Override
onAnimationCancelled(SurfaceControl animationLeash)201     public void onAnimationCancelled(SurfaceControl animationLeash) {
202         ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "onAnimationCancelled");
203     }
204 
205     @Override
dump(PrintWriter pw, String prefix)206     public void dump(PrintWriter pw, String prefix) {
207         pw.print(prefix);
208         pw.print("windowContainer=");
209         pw.println(mWindowContainer);
210         if (mTarget != null) {
211             pw.print(prefix);
212             pw.println("Target:");
213             mTarget.dump(pw, prefix + "  ");
214         } else {
215             pw.print(prefix);
216             pw.println("Target: null");
217         }
218     }
219 
220     @Override
dumpDebug(ProtoOutputStream proto)221     public void dumpDebug(ProtoOutputStream proto) {
222         final long token = proto.start(REMOTE);
223         if (mTarget != null) {
224             mTarget.dumpDebug(proto, TARGET);
225         }
226         proto.end(token);
227     }
228 }
229