• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.wm.shell.transition;
18 
19 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_UNOCCLUDING;
20 
21 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
22 import static com.android.wm.shell.transition.DefaultMixedHandler.handoverTransitionLeashes;
23 import static com.android.wm.shell.transition.MixedTransitionHelper.animateEnterPipFromSplit;
24 import static com.android.wm.shell.transition.MixedTransitionHelper.animateKeyguard;
25 
26 import android.annotation.NonNull;
27 import android.annotation.Nullable;
28 import android.os.IBinder;
29 import android.view.SurfaceControl;
30 import android.window.TransitionInfo;
31 import android.window.WindowContainerTransaction;
32 
33 import com.android.internal.protolog.ProtoLog;
34 import com.android.wm.shell.desktopmode.DesktopTasksController;
35 import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
36 import com.android.wm.shell.pip.PipTransitionController;
37 import com.android.wm.shell.protolog.ShellProtoLogGroup;
38 import com.android.wm.shell.recents.RecentsTransitionHandler;
39 import com.android.wm.shell.splitscreen.StageCoordinator;
40 
41 class RecentsMixedTransition extends DefaultMixedHandler.MixedTransition {
42     private final RecentsTransitionHandler mRecentsHandler;
43     private final DesktopTasksController mDesktopTasksController;
44 
RecentsMixedTransition(int type, IBinder transition, Transitions player, MixedTransitionHandler mixedHandler, PipTransitionController pipHandler, StageCoordinator splitHandler, KeyguardTransitionHandler keyguardHandler, RecentsTransitionHandler recentsHandler, DesktopTasksController desktopTasksController)45     RecentsMixedTransition(int type, IBinder transition, Transitions player,
46             MixedTransitionHandler mixedHandler, PipTransitionController pipHandler,
47             StageCoordinator splitHandler, KeyguardTransitionHandler keyguardHandler,
48             RecentsTransitionHandler recentsHandler,
49             DesktopTasksController desktopTasksController) {
50         super(type, transition, player, mixedHandler, pipHandler, splitHandler, keyguardHandler);
51         mRecentsHandler = recentsHandler;
52         mDesktopTasksController = desktopTasksController;
53         mLeftoversHandler = mRecentsHandler;
54     }
55 
56     @Override
startAnimation( @onNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback)57     boolean startAnimation(
58             @NonNull IBinder transition, @NonNull TransitionInfo info,
59             @NonNull SurfaceControl.Transaction startTransaction,
60             @NonNull SurfaceControl.Transaction finishTransaction,
61             @NonNull Transitions.TransitionFinishCallback finishCallback) {
62         return switch (mType) {
63             case TYPE_RECENTS_DURING_DESKTOP ->
64                     animateRecentsDuringDesktop(
65                             info, startTransaction, finishTransaction, finishCallback);
66             case TYPE_RECENTS_DURING_KEYGUARD ->
67                     animateRecentsDuringKeyguard(
68                             info, startTransaction, finishTransaction, finishCallback);
69             case TYPE_RECENTS_DURING_SPLIT ->
70                     animateRecentsDuringSplit(
71                             info, startTransaction, finishTransaction, finishCallback);
72             default -> throw new IllegalStateException(
73                     "Starting Recents mixed animation with unknown or illegal type: " + mType);
74         };
75     }
76 
animateRecentsDuringDesktop( @onNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback)77     private boolean animateRecentsDuringDesktop(
78             @NonNull TransitionInfo info,
79             @NonNull SurfaceControl.Transaction startTransaction,
80             @NonNull SurfaceControl.Transaction finishTransaction,
81             @NonNull Transitions.TransitionFinishCallback finishCallback) {
82         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition for Recents during"
83                 + " Desktop #%d", info.getDebugId());
84 
85         if (mInfo == null) {
86             mInfo = info;
87             mFinishT = finishTransaction;
88             mFinishCB = finishCallback;
89         }
90         Transitions.TransitionFinishCallback finishCB = wct -> {
91             mInFlightSubAnimations--;
92             if (mInFlightSubAnimations == 0) {
93                 finishCallback.onTransitionFinished(wct);
94             }
95         };
96 
97         mInFlightSubAnimations++;
98         boolean consumed = mRecentsHandler.startAnimation(
99                 mTransition, info, startTransaction, finishTransaction, finishCB);
100         if (!consumed) {
101             mInFlightSubAnimations--;
102             return false;
103         }
104         if (mDesktopTasksController != null) {
105             mDesktopTasksController.syncSurfaceState(info, finishTransaction);
106             return true;
107         }
108 
109         return false;
110     }
111 
animateRecentsDuringKeyguard( @onNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback)112     private boolean animateRecentsDuringKeyguard(
113             @NonNull TransitionInfo info,
114             @NonNull SurfaceControl.Transaction startTransaction,
115             @NonNull SurfaceControl.Transaction finishTransaction,
116             @NonNull Transitions.TransitionFinishCallback finishCallback) {
117         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Mixed transition for Recents during"
118                 + " Keyguard #%d", info.getDebugId());
119 
120         if (!mKeyguardHandler.isKeyguardShowing() || mKeyguardHandler.isKeyguardAnimating()) {
121             ProtoLog.w(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Cancel mixed transition because "
122                     + "keyguard state was changed #%d", info.getDebugId());
123             return false;
124         }
125         if (mInfo == null) {
126             mInfo = info;
127             mFinishT = finishTransaction;
128             mFinishCB = finishCallback;
129         }
130         return startSubAnimation(mRecentsHandler, info, startTransaction, finishTransaction);
131     }
132 
animateRecentsDuringSplit( @onNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback)133     private boolean animateRecentsDuringSplit(
134             @NonNull TransitionInfo info,
135             @NonNull SurfaceControl.Transaction startTransaction,
136             @NonNull SurfaceControl.Transaction finishTransaction,
137             @NonNull Transitions.TransitionFinishCallback finishCallback) {
138         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Mixed transition for Recents during"
139                 + " split screen #%d", info.getDebugId());
140 
141         for (int i = info.getChanges().size() - 1; i >= 0; --i) {
142             final TransitionInfo.Change change = info.getChanges().get(i);
143             // Pip auto-entering info might be appended to recent transition like pressing
144             // home-key in 3-button navigation. This offers split handler the opportunity to
145             // handle split to pip animation.
146             if (mPipHandler.isEnteringPip(change, info.getType())
147                     && mSplitHandler.getSplitItemPosition(change.getLastParent())
148                     != SPLIT_POSITION_UNDEFINED) {
149                 return animateEnterPipFromSplit(this, info, startTransaction, finishTransaction,
150                         finishCallback, mPlayer, mMixedHandler, mPipHandler, mSplitHandler,
151                         /*replacingPip*/ false);
152             }
153         }
154 
155         // Split-screen is only interested in the recents transition finishing (and merging), so
156         // just wrap finish and start recents animation directly.
157         Transitions.TransitionFinishCallback finishCB = (wct) -> {
158             mInFlightSubAnimations = 0;
159             // If pair-to-pair switching, the post-recents clean-up isn't needed.
160             wct = wct != null ? wct : new WindowContainerTransaction();
161             if (mAnimType != ANIM_TYPE_PAIR_TO_PAIR) {
162                 // We've dispatched to the mLeftoversHandler to handle the rest of the transition
163                 // and called onRecentsInSplitAnimationStart(), but if the recents handler is not
164                 // actually handling the transition, then onRecentsInSplitAnimationFinishing()
165                 // won't actually get called by the recents handler.  In such cases, we still need
166                 // to clean up after the changes from the start call.
167                 boolean splitNotifiedByRecents = mRecentsHandler == mLeftoversHandler;
168                 if (!splitNotifiedByRecents) {
169                     mSplitHandler.onRecentsInSplitAnimationFinishing(
170                             mSplitHandler.wctIsReorderingSplitToTop(wct),
171                             wct, finishTransaction);
172                 }
173             } else {
174                 // notify pair-to-pair recents animation finish
175                 mSplitHandler.onRecentsPairToPairAnimationFinish(wct);
176             }
177             mSplitHandler.onTransitionAnimationComplete();
178             finishCallback.onTransitionFinished(wct);
179         };
180         mInFlightSubAnimations = 1;
181         mSplitHandler.onRecentsInSplitAnimationStart(info);
182         final boolean handled = mLeftoversHandler.startAnimation(
183                 mTransition, info, startTransaction, finishTransaction, finishCB);
184         if (!handled) {
185             mSplitHandler.onRecentsInSplitAnimationCanceled();
186         }
187         return handled;
188     }
189 
190     /**
191      * Called when the recents animation during split is about to finish.
192      */
onAnimateRecentsDuringSplitFinishing(boolean returnToApp, @NonNull WindowContainerTransaction finishWct, @NonNull SurfaceControl.Transaction finishT)193     void onAnimateRecentsDuringSplitFinishing(boolean returnToApp,
194             @NonNull WindowContainerTransaction finishWct,
195             @NonNull SurfaceControl.Transaction finishT) {
196         if (mAnimType != ANIM_TYPE_PAIR_TO_PAIR) {
197             mSplitHandler.onRecentsInSplitAnimationFinishing(returnToApp, finishWct, finishT);
198         }
199     }
200 
201     /**
202      * Called when the recents animation during desktop is about to finish.
203      */
onAnimateRecentsDuringDesktopFinishing(boolean returnToApp, @NonNull WindowContainerTransaction finishWct)204     void onAnimateRecentsDuringDesktopFinishing(boolean returnToApp,
205             @NonNull WindowContainerTransaction finishWct) {
206         mDesktopTasksController.onRecentsInDesktopAnimationFinishing(mTransition, finishWct,
207                 returnToApp);
208     }
209 
210     @Override
mergeAnimation( @onNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startT, @NonNull SurfaceControl.Transaction finishT, @NonNull IBinder mergeTarget, @NonNull Transitions.TransitionFinishCallback finishCallback)211     void mergeAnimation(
212             @NonNull IBinder transition, @NonNull TransitionInfo info,
213             @NonNull SurfaceControl.Transaction startT, @NonNull SurfaceControl.Transaction finishT,
214             @NonNull IBinder mergeTarget,
215             @NonNull Transitions.TransitionFinishCallback finishCallback) {
216         switch (mType) {
217             case TYPE_RECENTS_DURING_DESKTOP:
218                 mLeftoversHandler.mergeAnimation(transition, info, startT, finishT, mergeTarget,
219                         finishCallback);
220                 return;
221             case TYPE_RECENTS_DURING_KEYGUARD:
222                 if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_UNOCCLUDING) != 0) {
223                     handoverTransitionLeashes(mInfo, info, startT, finishT);
224                     if (animateKeyguard(
225                             this, info, startT, finishT, mFinishCB, mKeyguardHandler,
226                             mPipHandler)) {
227                         finishCallback.onTransitionFinished(null);
228                     }
229                 }
230                 mLeftoversHandler.mergeAnimation(transition, info, startT, finishT, mergeTarget,
231                         finishCallback);
232                 return;
233             case TYPE_RECENTS_DURING_SPLIT:
234                 if (mSplitHandler.isPendingEnter(transition)) {
235                     // Recents -> enter-split means that we are switching from one pair to
236                     // another pair.
237                     mAnimType = DefaultMixedHandler.MixedTransition.ANIM_TYPE_PAIR_TO_PAIR;
238                 }
239                 mLeftoversHandler.mergeAnimation(transition, info, startT, finishT, mergeTarget,
240                         finishCallback);
241                 return;
242             default:
243                 throw new IllegalStateException("Playing a Recents mixed transition with unknown or"
244                         + " illegal type: " + mType);
245         }
246     }
247 
248     @Override
onTransitionConsumed( @onNull IBinder transition, boolean aborted, @Nullable SurfaceControl.Transaction finishT)249     void onTransitionConsumed(
250             @NonNull IBinder transition, boolean aborted,
251             @Nullable SurfaceControl.Transaction finishT) {
252         switch (mType) {
253             case TYPE_RECENTS_DURING_DESKTOP:
254             case TYPE_RECENTS_DURING_SPLIT:
255             case TYPE_RECENTS_DURING_KEYGUARD:
256                 mLeftoversHandler.onTransitionConsumed(transition, aborted, finishT);
257                 break;
258             default:
259                 break;
260         }
261 
262         if (mHasRequestToRemote) {
263             mPlayer.getRemoteTransitionHandler().onTransitionConsumed(transition, aborted, finishT);
264         }
265     }
266 }
267