• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.wm.shell.pip;
18 
19 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
20 import static android.view.WindowManager.TRANSIT_PIP;
21 
22 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_REMOVE_STACK;
23 import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection;
24 
25 import android.annotation.Nullable;
26 import android.app.PictureInPictureParams;
27 import android.app.TaskInfo;
28 import android.content.ComponentName;
29 import android.content.pm.ActivityInfo;
30 import android.graphics.Rect;
31 import android.os.IBinder;
32 import android.view.SurfaceControl;
33 import android.view.WindowManager;
34 import android.window.TransitionInfo;
35 import android.window.TransitionRequestInfo;
36 import android.window.WindowContainerTransaction;
37 
38 import androidx.annotation.NonNull;
39 
40 import com.android.wm.shell.ShellTaskOrganizer;
41 import com.android.wm.shell.sysui.ShellInit;
42 import com.android.wm.shell.transition.Transitions;
43 
44 import java.util.ArrayList;
45 import java.util.List;
46 
47 /**
48  * Responsible supplying PiP Transitions.
49  */
50 public abstract class PipTransitionController implements Transitions.TransitionHandler {
51 
52     protected final PipAnimationController mPipAnimationController;
53     protected final PipBoundsAlgorithm mPipBoundsAlgorithm;
54     protected final PipBoundsState mPipBoundsState;
55     protected final ShellTaskOrganizer mShellTaskOrganizer;
56     protected final PipMenuController mPipMenuController;
57     protected final Transitions mTransitions;
58     private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>();
59     protected PipTaskOrganizer mPipOrganizer;
60 
61     protected final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
62             new PipAnimationController.PipAnimationCallback() {
63                 @Override
64                 public void onPipAnimationStart(TaskInfo taskInfo,
65                         PipAnimationController.PipTransitionAnimator animator) {
66                     final int direction = animator.getTransitionDirection();
67                     sendOnPipTransitionStarted(direction);
68                 }
69 
70                 @Override
71                 public void onPipAnimationEnd(TaskInfo taskInfo, SurfaceControl.Transaction tx,
72                         PipAnimationController.PipTransitionAnimator animator) {
73                     final int direction = animator.getTransitionDirection();
74                     mPipBoundsState.setBounds(animator.getDestinationBounds());
75                     if (direction == TRANSITION_DIRECTION_REMOVE_STACK) {
76                         return;
77                     }
78                     if (isInPipDirection(direction) && animator.getContentOverlayLeash() != null) {
79                         mPipOrganizer.fadeOutAndRemoveOverlay(animator.getContentOverlayLeash(),
80                                 animator::clearContentOverlay, true /* withStartDelay*/);
81                     }
82                     onFinishResize(taskInfo, animator.getDestinationBounds(), direction, tx);
83                     sendOnPipTransitionFinished(direction);
84                 }
85 
86                 @Override
87                 public void onPipAnimationCancel(TaskInfo taskInfo,
88                         PipAnimationController.PipTransitionAnimator animator) {
89                     final int direction = animator.getTransitionDirection();
90                     if (isInPipDirection(direction) && animator.getContentOverlayLeash() != null) {
91                         mPipOrganizer.fadeOutAndRemoveOverlay(animator.getContentOverlayLeash(),
92                                 animator::clearContentOverlay, true /* withStartDelay */);
93                     }
94                     sendOnPipTransitionCancelled(animator.getTransitionDirection());
95                 }
96             };
97 
98     /**
99      * Called when transition is about to finish. This is usually for performing tasks such as
100      * applying WindowContainerTransaction to finalize the PiP bounds and send to the framework.
101      */
onFinishResize(TaskInfo taskInfo, Rect destinationBounds, @PipAnimationController.TransitionDirection int direction, SurfaceControl.Transaction tx)102     public void onFinishResize(TaskInfo taskInfo, Rect destinationBounds,
103             @PipAnimationController.TransitionDirection int direction,
104             SurfaceControl.Transaction tx) {
105     }
106 
107     /**
108      * Called to inform the transition that the animation should start with the assumption that
109      * PiP is not animating from its original bounds, but rather a continuation of another
110      * animation. For example, gesture navigation would first fade out the PiP activity, and the
111      * transition should be responsible to animate in (such as fade in) the PiP.
112      */
setIsFullAnimation(boolean isFullAnimation)113     public void setIsFullAnimation(boolean isFullAnimation) {
114     }
115 
116     /**
117      * Called when the Shell wants to start an exit Pip transition/animation.
118      */
startExitTransition(int type, WindowContainerTransaction out, @Nullable Rect destinationBounds)119     public void startExitTransition(int type, WindowContainerTransaction out,
120             @Nullable Rect destinationBounds) {
121         // Default implementation does nothing.
122     }
123 
124     /**
125      * Called when the transition animation can't continue (eg. task is removed during
126      * animation)
127      */
forceFinishTransition()128     public void forceFinishTransition() {
129     }
130 
131     /** Called when the fixed rotation started. */
onFixedRotationStarted()132     public void onFixedRotationStarted() {
133     }
134 
PipTransitionController( @onNull ShellInit shellInit, @NonNull ShellTaskOrganizer shellTaskOrganizer, @NonNull Transitions transitions, PipBoundsState pipBoundsState, PipMenuController pipMenuController, PipBoundsAlgorithm pipBoundsAlgorithm, PipAnimationController pipAnimationController)135     public PipTransitionController(
136             @NonNull ShellInit shellInit,
137             @NonNull ShellTaskOrganizer shellTaskOrganizer,
138             @NonNull Transitions transitions,
139             PipBoundsState pipBoundsState,
140             PipMenuController pipMenuController, PipBoundsAlgorithm pipBoundsAlgorithm,
141             PipAnimationController pipAnimationController) {
142         mPipBoundsState = pipBoundsState;
143         mPipMenuController = pipMenuController;
144         mShellTaskOrganizer = shellTaskOrganizer;
145         mPipBoundsAlgorithm = pipBoundsAlgorithm;
146         mPipAnimationController = pipAnimationController;
147         mTransitions = transitions;
148         if (Transitions.ENABLE_SHELL_TRANSITIONS) {
149             shellInit.addInitCallback(this::onInit, this);
150         }
151     }
152 
onInit()153     private void onInit() {
154         mTransitions.addHandler(this);
155     }
156 
setPipOrganizer(PipTaskOrganizer pto)157     void setPipOrganizer(PipTaskOrganizer pto) {
158         mPipOrganizer = pto;
159     }
160 
161     /**
162      * Registers {@link PipTransitionCallback} to receive transition callbacks.
163      */
registerPipTransitionCallback(PipTransitionCallback callback)164     public void registerPipTransitionCallback(PipTransitionCallback callback) {
165         mPipTransitionCallbacks.add(callback);
166     }
167 
sendOnPipTransitionStarted( @ipAnimationController.TransitionDirection int direction)168     protected void sendOnPipTransitionStarted(
169             @PipAnimationController.TransitionDirection int direction) {
170         final Rect pipBounds = mPipBoundsState.getBounds();
171         for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
172             final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
173             callback.onPipTransitionStarted(direction, pipBounds);
174         }
175     }
176 
sendOnPipTransitionFinished( @ipAnimationController.TransitionDirection int direction)177     protected void sendOnPipTransitionFinished(
178             @PipAnimationController.TransitionDirection int direction) {
179         for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
180             final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
181             callback.onPipTransitionFinished(direction);
182         }
183     }
184 
sendOnPipTransitionCancelled( @ipAnimationController.TransitionDirection int direction)185     protected void sendOnPipTransitionCancelled(
186             @PipAnimationController.TransitionDirection int direction) {
187         for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
188             final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
189             callback.onPipTransitionCanceled(direction);
190         }
191     }
192 
193     /**
194      * The windowing mode to restore to when resizing out of PIP direction. Defaults to undefined
195      * and can be overridden to restore to an alternate windowing mode.
196      */
getOutPipWindowingMode()197     public int getOutPipWindowingMode() {
198         // By default, simply reset the windowing mode to undefined.
199         return WINDOWING_MODE_UNDEFINED;
200     }
201 
setBoundsStateForEntry(ComponentName componentName, PictureInPictureParams params, ActivityInfo activityInfo)202     protected void setBoundsStateForEntry(ComponentName componentName,
203             PictureInPictureParams params,
204             ActivityInfo activityInfo) {
205         mPipBoundsState.setBoundsStateForEntry(componentName, activityInfo, params,
206                 mPipBoundsAlgorithm);
207     }
208 
209     /**
210      * Called when the display is going to rotate.
211      *
212      * @return {@code true} if it was handled, otherwise the existing pip logic
213      *                      will deal with rotation.
214      */
handleRotateDisplay(int startRotation, int endRotation, WindowContainerTransaction wct)215     public boolean handleRotateDisplay(int startRotation, int endRotation,
216             WindowContainerTransaction wct) {
217         return false;
218     }
219 
220     /** @return whether the transition-request represents a pip-entry. */
requestHasPipEnter(@onNull TransitionRequestInfo request)221     public boolean requestHasPipEnter(@NonNull TransitionRequestInfo request) {
222         return request.getType() == TRANSIT_PIP;
223     }
224 
225     /** Whether a particular change is a window that is entering pip. */
isEnteringPip(@onNull TransitionInfo.Change change, @WindowManager.TransitionType int transitType)226     public boolean isEnteringPip(@NonNull TransitionInfo.Change change,
227             @WindowManager.TransitionType int transitType) {
228         return false;
229     }
230 
231     /** Add PiP-related changes to `outWCT` for the given request. */
augmentRequest(@onNull IBinder transition, @NonNull TransitionRequestInfo request, @NonNull WindowContainerTransaction outWCT)232     public void augmentRequest(@NonNull IBinder transition,
233             @NonNull TransitionRequestInfo request, @NonNull WindowContainerTransaction outWCT) {
234         throw new IllegalStateException("Request isn't entering PiP");
235     }
236 
237     /** Play a transition animation for entering PiP on a specific PiP change. */
startEnterAnimation(@onNull final TransitionInfo.Change pipChange, @NonNull final SurfaceControl.Transaction startTransaction, @NonNull final SurfaceControl.Transaction finishTransaction, @NonNull final Transitions.TransitionFinishCallback finishCallback)238     public void startEnterAnimation(@NonNull final TransitionInfo.Change pipChange,
239             @NonNull final SurfaceControl.Transaction startTransaction,
240             @NonNull final SurfaceControl.Transaction finishTransaction,
241             @NonNull final Transitions.TransitionFinishCallback finishCallback) {
242     }
243 
244     /** End the currently-playing PiP animation. */
end()245     public void end() {
246     }
247 
248     /**
249      * Callback interface for PiP transitions (both from and to PiP mode)
250      */
251     public interface PipTransitionCallback {
252         /**
253          * Callback when the pip transition is started.
254          */
onPipTransitionStarted(int direction, Rect pipBounds)255         void onPipTransitionStarted(int direction, Rect pipBounds);
256 
257         /**
258          * Callback when the pip transition is finished.
259          */
onPipTransitionFinished(int direction)260         void onPipTransitionFinished(int direction);
261 
262         /**
263          * Callback when the pip transition is cancelled.
264          */
onPipTransitionCanceled(int direction)265         void onPipTransitionCanceled(int direction);
266     }
267 }
268