blob: bb627bc9db99571fa176841c1901aabeb2e70679 [file] [log] [blame]
Hongwei Wang85cf41f2020-01-15 15:14:47 -08001/*
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
17package com.android.systemui.pip;
18
Winson Chungc4d4ee82020-05-05 12:51:06 -070019import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
20import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
21import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
Hongwei Wangd39583a2020-03-04 11:14:32 -080022import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
23
Hongwei Wang85cf41f2020-01-15 15:14:47 -080024import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_ALPHA;
25import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
Hongwei Wangdf8bb002020-03-03 17:41:02 -080026import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_NONE;
27import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_SAME;
28import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN;
29import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
Hongwei Wang5c52ff82020-04-20 16:02:30 -070030import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_SPLIT_SCREEN;
Winson Chungc4d4ee82020-05-05 12:51:06 -070031import static com.android.systemui.pip.PipAnimationController.isInPipDirection;
Hongwei Wang5c52ff82020-04-20 16:02:30 -070032import static com.android.systemui.pip.PipAnimationController.isOutPipDirection;
Hongwei Wang85cf41f2020-01-15 15:14:47 -080033
34import android.annotation.NonNull;
35import android.annotation.Nullable;
36import android.app.ActivityManager;
Winson Chungc4d4ee82020-05-05 12:51:06 -070037import android.app.ActivityTaskManager;
Hongwei Wang85cf41f2020-01-15 15:14:47 -080038import android.app.PictureInPictureParams;
Hongwei Wang221fe3d2020-03-26 13:13:04 -070039import android.content.ComponentName;
Hongwei Wang85cf41f2020-01-15 15:14:47 -080040import android.content.Context;
Hongwei Wang2e725be2020-03-10 11:01:28 -070041import android.content.pm.ActivityInfo;
Winson Chungc4d4ee82020-05-05 12:51:06 -070042import android.content.res.Configuration;
Hongwei Wang85cf41f2020-01-15 15:14:47 -080043import android.graphics.Rect;
44import android.os.Handler;
Hongwei Wangfbc25fe2020-03-16 11:59:28 -070045import android.os.IBinder;
Hongwei Wang85cf41f2020-01-15 15:14:47 -080046import android.os.Looper;
Winson Chungc4d4ee82020-05-05 12:51:06 -070047import android.os.RemoteException;
Hongwei Wang85cf41f2020-01-15 15:14:47 -080048import android.util.Log;
Hongwei Wang2e725be2020-03-10 11:01:28 -070049import android.util.Size;
Hongwei Wangd39583a2020-03-04 11:14:32 -080050import android.view.SurfaceControl;
Wale Ogunwaleadf116e2020-03-27 16:36:01 -070051import android.window.TaskOrganizer;
52import android.window.WindowContainerToken;
Wale Ogunwale57946582020-03-21 14:29:07 -070053import android.window.WindowContainerTransaction;
Winson Chungc4d4ee82020-05-05 12:51:06 -070054import android.window.WindowContainerTransactionCallback;
Wale Ogunwale568f9f412020-03-21 22:27:35 -070055import android.window.WindowOrganizer;
Hongwei Wang85cf41f2020-01-15 15:14:47 -080056
Winson Chung55701472020-03-04 19:30:30 -080057import com.android.internal.os.SomeArgs;
Hongwei Wangdf8bb002020-03-03 17:41:02 -080058import com.android.systemui.R;
Winson Chung55701472020-03-04 19:30:30 -080059import com.android.systemui.pip.phone.PipUpdateThread;
Hongwei Wang5c52ff82020-04-20 16:02:30 -070060import com.android.systemui.stackdivider.Divider;
Winson Chung55701472020-03-04 19:30:30 -080061
Winson Chungc4d4ee82020-05-05 12:51:06 -070062import java.io.PrintWriter;
Hongwei Wang85cf41f2020-01-15 15:14:47 -080063import java.util.ArrayList;
Hongwei Wangfbc25fe2020-03-16 11:59:28 -070064import java.util.HashMap;
Hongwei Wang85cf41f2020-01-15 15:14:47 -080065import java.util.List;
Hongwei Wangfbc25fe2020-03-16 11:59:28 -070066import java.util.Map;
Hongwei Wang85cf41f2020-01-15 15:14:47 -080067import java.util.Objects;
Winson Chung55701472020-03-04 19:30:30 -080068import java.util.function.Consumer;
Hongwei Wang85cf41f2020-01-15 15:14:47 -080069
Ben Lin6189fa42020-04-29 14:59:16 -070070import javax.inject.Inject;
71import javax.inject.Singleton;
72
Hongwei Wang85cf41f2020-01-15 15:14:47 -080073/**
74 * Manages PiP tasks such as resize and offset.
75 *
Wale Ogunwaleadf116e2020-03-27 16:36:01 -070076 * This class listens on {@link TaskOrganizer} callbacks for windowing mode change
Hongwei Wang85cf41f2020-01-15 15:14:47 -080077 * both to and from PiP and issues corresponding animation if applicable.
78 * Normally, we apply series of {@link SurfaceControl.Transaction} when the animator is running
79 * and files a final {@link WindowContainerTransaction} at the end of the transition.
80 *
81 * This class is also responsible for general resize/offset PiP operations within SysUI component,
82 * see also {@link com.android.systemui.pip.phone.PipMotionHelper}.
83 */
Ben Lin6189fa42020-04-29 14:59:16 -070084@Singleton
Wale Ogunwaleadf116e2020-03-27 16:36:01 -070085public class PipTaskOrganizer extends TaskOrganizer {
Hongwei Wang85cf41f2020-01-15 15:14:47 -080086 private static final String TAG = PipTaskOrganizer.class.getSimpleName();
87
Winson Chung55701472020-03-04 19:30:30 -080088 private static final int MSG_RESIZE_IMMEDIATE = 1;
89 private static final int MSG_RESIZE_ANIMATE = 2;
90 private static final int MSG_OFFSET_ANIMATE = 3;
91 private static final int MSG_FINISH_RESIZE = 4;
Ben Lin75ba9c32020-03-19 17:55:12 -070092 private static final int MSG_RESIZE_USER = 5;
Winson Chung55701472020-03-04 19:30:30 -080093
Hongwei Wang85cf41f2020-01-15 15:14:47 -080094 private final Handler mMainHandler;
Winson Chung55701472020-03-04 19:30:30 -080095 private final Handler mUpdateHandler;
Hongwei Wang85cf41f2020-01-15 15:14:47 -080096 private final PipBoundsHandler mPipBoundsHandler;
97 private final PipAnimationController mPipAnimationController;
98 private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>();
Hongwei Wang85cf41f2020-01-15 15:14:47 -080099 private final Rect mLastReportedBounds = new Rect();
Ben Linede9a602020-02-26 12:16:09 -0800100 private final int mEnterExitAnimationDuration;
Hongwei Wangec3cb3c2020-03-09 10:43:21 -0700101 private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
Winson Chungc4d4ee82020-05-05 12:51:06 -0700102 private final Map<IBinder, Configuration> mInitialState = new HashMap<>();
Hongwei Wang5c52ff82020-04-20 16:02:30 -0700103 private final Divider mSplitDivider;
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800104
Winson Chung55701472020-03-04 19:30:30 -0800105 // These callbacks are called on the update thread
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800106 private final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
107 new PipAnimationController.PipAnimationCallback() {
108 @Override
Winson Chung55701472020-03-04 19:30:30 -0800109 public void onPipAnimationStart(PipAnimationController.PipTransitionAnimator animator) {
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800110 mMainHandler.post(() -> {
111 for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
112 final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
Hongwei Wang221fe3d2020-03-26 13:13:04 -0700113 callback.onPipTransitionStarted(mTaskInfo.baseActivity,
114 animator.getTransitionDirection());
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800115 }
116 });
117 }
118
119 @Override
Winson Chung55701472020-03-04 19:30:30 -0800120 public void onPipAnimationEnd(SurfaceControl.Transaction tx,
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800121 PipAnimationController.PipTransitionAnimator animator) {
Winson Chungc4d4ee82020-05-05 12:51:06 -0700122 finishResize(tx, animator.getDestinationBounds(), animator.getTransitionDirection(),
123 animator.getAnimationType());
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800124 mMainHandler.post(() -> {
125 for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
126 final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
Hongwei Wang221fe3d2020-03-26 13:13:04 -0700127 callback.onPipTransitionFinished(mTaskInfo.baseActivity,
128 animator.getTransitionDirection());
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800129 }
130 });
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800131 }
132
133 @Override
Winson Chung55701472020-03-04 19:30:30 -0800134 public void onPipAnimationCancel(PipAnimationController.PipTransitionAnimator animator) {
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800135 mMainHandler.post(() -> {
136 for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
137 final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
Hongwei Wang221fe3d2020-03-26 13:13:04 -0700138 callback.onPipTransitionCanceled(mTaskInfo.baseActivity,
139 animator.getTransitionDirection());
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800140 }
141 });
142 }
143 };
144
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800145 @SuppressWarnings("unchecked")
Hongwei Wange8e32862020-04-08 13:23:45 -0700146 private final Handler.Callback mUpdateCallbacks = (msg) -> {
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800147 SomeArgs args = (SomeArgs) msg.obj;
148 Consumer<Rect> updateBoundsCallback = (Consumer<Rect>) args.arg1;
149 switch (msg.what) {
150 case MSG_RESIZE_IMMEDIATE: {
151 Rect toBounds = (Rect) args.arg2;
152 resizePip(toBounds);
153 if (updateBoundsCallback != null) {
154 updateBoundsCallback.accept(toBounds);
Winson Chung55701472020-03-04 19:30:30 -0800155 }
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800156 break;
Winson Chung55701472020-03-04 19:30:30 -0800157 }
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800158 case MSG_RESIZE_ANIMATE: {
159 Rect currentBounds = (Rect) args.arg2;
160 Rect toBounds = (Rect) args.arg3;
161 int duration = args.argi2;
162 animateResizePip(currentBounds, toBounds, args.argi1 /* direction */, duration);
163 if (updateBoundsCallback != null) {
164 updateBoundsCallback.accept(toBounds);
165 }
166 break;
167 }
168 case MSG_OFFSET_ANIMATE: {
169 Rect originalBounds = (Rect) args.arg2;
170 final int offset = args.argi1;
171 final int duration = args.argi2;
172 offsetPip(originalBounds, 0 /* xOffset */, offset, duration);
173 Rect toBounds = new Rect(originalBounds);
174 toBounds.offset(0, offset);
175 if (updateBoundsCallback != null) {
176 updateBoundsCallback.accept(toBounds);
177 }
178 break;
179 }
180 case MSG_FINISH_RESIZE: {
181 SurfaceControl.Transaction tx = (SurfaceControl.Transaction) args.arg2;
182 Rect toBounds = (Rect) args.arg3;
Winson Chungc4d4ee82020-05-05 12:51:06 -0700183 finishResize(tx, toBounds, args.argi1 /* direction */, -1);
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800184 if (updateBoundsCallback != null) {
185 updateBoundsCallback.accept(toBounds);
186 }
187 break;
188 }
Ben Lin75ba9c32020-03-19 17:55:12 -0700189 case MSG_RESIZE_USER: {
190 Rect startBounds = (Rect) args.arg2;
191 Rect toBounds = (Rect) args.arg3;
192 userResizePip(startBounds, toBounds);
193 break;
194 }
Winson Chung55701472020-03-04 19:30:30 -0800195 }
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800196 args.recycle();
197 return true;
Winson Chung55701472020-03-04 19:30:30 -0800198 };
199
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800200 private ActivityManager.RunningTaskInfo mTaskInfo;
Wale Ogunwaleadf116e2020-03-27 16:36:01 -0700201 private WindowContainerToken mToken;
Winson Chung55701472020-03-04 19:30:30 -0800202 private SurfaceControl mLeash;
203 private boolean mInPip;
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800204 private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS;
Hongwei Wangec3cb3c2020-03-09 10:43:21 -0700205 private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
206 mSurfaceControlTransactionFactory;
Hongwei Wang8c95ce52020-04-30 15:06:12 -0700207 private PictureInPictureParams mPictureInPictureParams;
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800208
Ben Lin6189fa42020-04-29 14:59:16 -0700209 @Inject
Hongwei Wangec3cb3c2020-03-09 10:43:21 -0700210 public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler,
Hongwei Wang5c52ff82020-04-20 16:02:30 -0700211 @NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
212 @Nullable Divider divider) {
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800213 mMainHandler = new Handler(Looper.getMainLooper());
Winson Chung55701472020-03-04 19:30:30 -0800214 mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800215 mPipBoundsHandler = boundsHandler;
Ben Linede9a602020-02-26 12:16:09 -0800216 mEnterExitAnimationDuration = context.getResources()
217 .getInteger(R.integer.config_pipResizeAnimationDuration);
Hongwei Wangec3cb3c2020-03-09 10:43:21 -0700218 mSurfaceTransactionHelper = surfaceTransactionHelper;
219 mPipAnimationController = new PipAnimationController(context, surfaceTransactionHelper);
220 mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
Hongwei Wang5c52ff82020-04-20 16:02:30 -0700221 mSplitDivider = divider;
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800222 }
223
Winson Chung55701472020-03-04 19:30:30 -0800224 public Handler getUpdateHandler() {
225 return mUpdateHandler;
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800226 }
227
Hongwei Wang221fe3d2020-03-26 13:13:04 -0700228 public Rect getLastReportedBounds() {
229 return new Rect(mLastReportedBounds);
230 }
231
Joshua Tsuji0d4cbeb2020-05-01 12:45:41 -0400232 public boolean isInPip() {
233 return mInPip;
234 }
235
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800236 /**
237 * Registers {@link PipTransitionCallback} to receive transition callbacks.
238 */
239 public void registerPipTransitionCallback(PipTransitionCallback callback) {
240 mPipTransitionCallbacks.add(callback);
241 }
242
243 /**
244 * Sets the preferred animation type for one time.
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800245 * This is typically used to set the animation type to
246 * {@link PipAnimationController#ANIM_TYPE_ALPHA}.
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800247 */
248 public void setOneShotAnimationType(@PipAnimationController.AnimationType int animationType) {
249 mOneShotAnimationType = animationType;
250 }
251
Hongwei Wangd39583a2020-03-04 11:14:32 -0800252 /**
Winson Chungc4d4ee82020-05-05 12:51:06 -0700253 * Expands PiP to the previous bounds, this is done in two phases using
254 * {@link WindowContainerTransaction}
255 * - setActivityWindowingMode to either fullscreen or split-secondary at beginning of the
256 * transaction. without changing the windowing mode of the Task itself. This makes sure the
257 * activity render it's final configuration while the Task is still in PiP.
Hongwei Wang5c52ff82020-04-20 16:02:30 -0700258 * - setWindowingMode to undefined at the end of transition
Hongwei Wangd39583a2020-03-04 11:14:32 -0800259 * @param animationDurationMs duration in millisecond for the exiting PiP transition
260 */
Winson Chungc4d4ee82020-05-05 12:51:06 -0700261 public void exitPip(int animationDurationMs) {
Hongwei Wang1273c952020-04-30 13:28:29 -0700262 if (!mInPip || mToken == null) {
Winson Chungc4d4ee82020-05-05 12:51:06 -0700263 Log.wtf(TAG, "Not allowed to exitPip in current state"
Hongwei Wang1273c952020-04-30 13:28:29 -0700264 + " mInPip=" + mInPip + " mToken=" + mToken);
265 return;
266 }
Winson Chungc4d4ee82020-05-05 12:51:06 -0700267
268 final Configuration initialConfig = mInitialState.remove(mToken.asBinder());
269 final boolean orientationDiffers = initialConfig.windowConfiguration.getRotation()
270 != mPipBoundsHandler.getDisplayRotation();
Wale Ogunwaleadf116e2020-03-27 16:36:01 -0700271 final WindowContainerTransaction wct = new WindowContainerTransaction();
Winson Chungc4d4ee82020-05-05 12:51:06 -0700272 if (orientationDiffers) {
273 // Don't bother doing an animation if the display rotation differs or if it's in
274 // a non-supported windowing mode
275 wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
276 wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
277 WindowOrganizer.applyTransaction(wct);
278 mInPip = false;
279 } else {
280 final Rect destinationBounds = initialConfig.windowConfiguration.getBounds();
281 final int direction = syncWithSplitScreenBounds(destinationBounds)
282 ? TRANSITION_DIRECTION_TO_SPLIT_SCREEN
283 : TRANSITION_DIRECTION_TO_FULLSCREEN;
284 final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
285 mSurfaceTransactionHelper.scale(tx, mLeash, destinationBounds,
286 mLastReportedBounds);
287 tx.setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height());
288 wct.setActivityWindowingMode(mToken, direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN
289 ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
290 : WINDOWING_MODE_FULLSCREEN);
291 wct.setBounds(mToken, destinationBounds);
292 wct.setBoundsChangeTransaction(mToken, tx);
293 applySyncTransaction(wct, new WindowContainerTransactionCallback() {
294 @Override
295 public void onTransactionReady(int id, SurfaceControl.Transaction t) {
296 t.apply();
297 scheduleAnimateResizePip(mLastReportedBounds, destinationBounds,
298 direction, animationDurationMs, null /* updateBoundsCallback */);
299 mInPip = false;
300 }
301 });
302 }
303 }
304
305 /**
306 * Removes PiP immediately.
307 */
308 public void removePip() {
309 if (!mInPip || mToken == null) {
310 Log.wtf(TAG, "Not allowed to removePip in current state"
311 + " mInPip=" + mInPip + " mToken=" + mToken);
312 return;
313 }
314 getUpdateHandler().post(() -> {
315 try {
316 ActivityTaskManager.getService().removeStacksInWindowingModes(
317 new int[]{ WINDOWING_MODE_PINNED });
318 } catch (RemoteException e) {
319 Log.e(TAG, "Failed to remove PiP", e);
320 }
321 });
322 mInitialState.remove(mToken.asBinder());
Hongwei Wangd39583a2020-03-04 11:14:32 -0800323 }
324
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800325 @Override
chaviw7de50002020-04-27 12:33:30 -0700326 public void onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash) {
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800327 Objects.requireNonNull(info, "Requires RunningTaskInfo");
Hongwei Wang8c95ce52020-04-30 15:06:12 -0700328 mPictureInPictureParams = info.pictureInPictureParams;
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800329 final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
Hongwei Wang8c95ce52020-04-30 15:06:12 -0700330 info.topActivity, getAspectRatioOrDefault(mPictureInPictureParams),
Hongwei Wang2e725be2020-03-10 11:01:28 -0700331 null /* bounds */, getMinimalSize(info.topActivityInfo));
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800332 Objects.requireNonNull(destinationBounds, "Missing destination bounds");
333 mTaskInfo = info;
Winson Chung55701472020-03-04 19:30:30 -0800334 mToken = mTaskInfo.token;
335 mInPip = true;
chaviw7de50002020-04-27 12:33:30 -0700336 mLeash = leash;
Wale Ogunwaleadf116e2020-03-27 16:36:01 -0700337
Winson Chungc4d4ee82020-05-05 12:51:06 -0700338 // TODO: Skip enter animation when entering pip from another orientation
Hongwei Wang89f18ff2020-03-10 10:24:35 -0700339 final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
Winson Chungc4d4ee82020-05-05 12:51:06 -0700340 mInitialState.put(mToken.asBinder(), new Configuration(mTaskInfo.configuration));
341
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800342 if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800343 scheduleAnimateResizePip(currentBounds, destinationBounds,
Hongwei Wangd39583a2020-03-04 11:14:32 -0800344 TRANSITION_DIRECTION_TO_PIP, mEnterExitAnimationDuration,
345 null /* updateBoundsCallback */);
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800346 } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
Winson Chungc4d4ee82020-05-05 12:51:06 -0700347 // If we are fading the PIP in, then we should move the pip to the final location as
348 // soon as possible, but set the alpha immediately since the transaction can take a
349 // while to process
350 final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
351 tx.setAlpha(mLeash, 0f);
352 tx.apply();
353 final WindowContainerTransaction wct = new WindowContainerTransaction();
354 wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
355 wct.setBounds(mToken, destinationBounds);
356 wct.scheduleFinishEnterPip(mToken, destinationBounds);
357 applySyncTransaction(wct, new WindowContainerTransactionCallback() {
358 @Override
359 public void onTransactionReady(int id, SurfaceControl.Transaction t) {
360 t.apply();
361 mUpdateHandler.post(() -> mPipAnimationController
362 .getAnimator(mLeash, destinationBounds, 0f, 1f)
363 .setTransitionDirection(TRANSITION_DIRECTION_TO_PIP)
364 .setPipAnimationCallback(mPipAnimationCallback)
365 .setDuration(mEnterExitAnimationDuration)
366 .start());
367 }
368 });
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800369 mOneShotAnimationType = ANIM_TYPE_BOUNDS;
370 } else {
371 throw new RuntimeException("Unrecognized animation type: " + mOneShotAnimationType);
372 }
373 }
374
Hongwei Wangd39583a2020-03-04 11:14:32 -0800375 /**
Winson Chungc4d4ee82020-05-05 12:51:06 -0700376 * Note that dismissing PiP is now originated from SystemUI, see {@link #exitPip(int)}.
Hongwei Wangd39583a2020-03-04 11:14:32 -0800377 * Meanwhile this callback is invoked whenever the task is removed. For instance:
378 * - as a result of removeStacksInWindowingModes from WM
379 * - activity itself is died
Hongwei Wang180162e2020-04-22 14:40:32 -0700380 * Nevertheless, we simply update the internal state here as all the heavy lifting should
381 * have been done in WM.
Hongwei Wangd39583a2020-03-04 11:14:32 -0800382 */
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800383 @Override
Wale Ogunwaledec34082020-03-22 09:45:00 -0700384 public void onTaskVanished(ActivityManager.RunningTaskInfo info) {
Hongwei Wang5c52ff82020-04-20 16:02:30 -0700385 if (!mInPip) {
386 return;
387 }
Hongwei Wange8e32862020-04-08 13:23:45 -0700388 final WindowContainerToken token = info.token;
Wale Ogunwaleadf116e2020-03-27 16:36:01 -0700389 Objects.requireNonNull(token, "Requires valid WindowContainerToken");
Winson Chung55701472020-03-04 19:30:30 -0800390 if (token.asBinder() != mToken.asBinder()) {
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800391 Log.wtf(TAG, "Unrecognized token: " + token);
392 return;
393 }
Hongwei Wang8c95ce52020-04-30 15:06:12 -0700394 mPictureInPictureParams = null;
Winson Chung55701472020-03-04 19:30:30 -0800395 mInPip = false;
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800396 }
397
398 @Override
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800399 public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
Hongwei Wange8e32862020-04-08 13:23:45 -0700400 Objects.requireNonNull(mToken, "onTaskInfoChanged requires valid existing mToken");
Hongwei Wang8e8a8ae2020-03-03 11:06:56 -0800401 final PictureInPictureParams newParams = info.pictureInPictureParams;
Hongwei Wang8c95ce52020-04-30 15:06:12 -0700402 if (!applyPictureInPictureParams(newParams)) {
Hongwei Wang8e8a8ae2020-03-03 11:06:56 -0800403 Log.d(TAG, "Ignored onTaskInfoChanged with PiP param: " + newParams);
404 return;
405 }
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800406 final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
Hongwei Wang309cffa2020-04-06 11:11:01 -0700407 info.topActivity, getAspectRatioOrDefault(newParams),
Hongwei Wang2e725be2020-03-10 11:01:28 -0700408 null /* bounds */, getMinimalSize(info.topActivityInfo));
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800409 Objects.requireNonNull(destinationBounds, "Missing destination bounds");
Hongwei Wangd39583a2020-03-04 11:14:32 -0800410 scheduleAnimateResizePip(destinationBounds, mEnterExitAnimationDuration,
411 null /* updateBoundsCallback */);
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800412 }
413
Winson Chunga1f869d2020-03-21 23:02:48 -0700414 @Override
415 public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
416 // Do nothing
417 }
418
Hongwei Wang8e8a8ae2020-03-03 11:06:56 -0800419 /**
Hongwei Wang951dc022020-03-30 16:16:16 -0700420 * TODO(b/152809058): consolidate the display info handling logic in SysUI
Hongwei Wang3c981f62020-04-07 16:16:26 -0700421 *
422 * @param destinationBoundsOut the current destination bounds will be populated to this param
Hongwei Wang951dc022020-03-30 16:16:16 -0700423 */
424 @SuppressWarnings("unchecked")
Hongwei Wange0412d12020-04-13 18:27:25 -0700425 public void onMovementBoundsChanged(Rect destinationBoundsOut, boolean fromRotation,
Hongwei Wang3c981f62020-04-07 16:16:26 -0700426 boolean fromImeAdjustment, boolean fromShelfAdjustment) {
Hongwei Wang951dc022020-03-30 16:16:16 -0700427 final PipAnimationController.PipTransitionAnimator animator =
428 mPipAnimationController.getCurrentAnimator();
Hongwei Wang6e68af52020-04-06 12:34:06 -0700429 if (animator == null || !animator.isRunning()
430 || animator.getTransitionDirection() != TRANSITION_DIRECTION_TO_PIP) {
Hongwei Wange0412d12020-04-13 18:27:25 -0700431 if (mInPip && fromRotation) {
432 // this could happen if rotation finishes before the animation
433 mLastReportedBounds.set(destinationBoundsOut);
434 scheduleFinishResizePip(mLastReportedBounds);
435 } else if (!mLastReportedBounds.isEmpty()) {
436 destinationBoundsOut.set(mLastReportedBounds);
437 }
Hongwei Wang6e68af52020-04-06 12:34:06 -0700438 return;
Hongwei Wang951dc022020-03-30 16:16:16 -0700439 }
Hongwei Wang6e68af52020-04-06 12:34:06 -0700440
441 final Rect currentDestinationBounds = animator.getDestinationBounds();
Hongwei Wang3c981f62020-04-07 16:16:26 -0700442 destinationBoundsOut.set(currentDestinationBounds);
Hongwei Wang6e68af52020-04-06 12:34:06 -0700443 if (!fromImeAdjustment && !fromShelfAdjustment
444 && mPipBoundsHandler.getDisplayBounds().contains(currentDestinationBounds)) {
445 // no need to update the destination bounds, bail early
446 return;
447 }
448
449 final Rect newDestinationBounds = mPipBoundsHandler.getDestinationBounds(
Hongwei Wang8c95ce52020-04-30 15:06:12 -0700450 mTaskInfo.topActivity, getAspectRatioOrDefault(mPictureInPictureParams),
Hongwei Wang6e68af52020-04-06 12:34:06 -0700451 null /* bounds */, getMinimalSize(mTaskInfo.topActivityInfo));
452 if (newDestinationBounds.equals(currentDestinationBounds)) return;
453 if (animator.getAnimationType() == ANIM_TYPE_BOUNDS) {
454 animator.updateEndValue(newDestinationBounds);
455 }
456 animator.setDestinationBounds(newDestinationBounds);
Hongwei Wang3c981f62020-04-07 16:16:26 -0700457 destinationBoundsOut.set(newDestinationBounds);
Hongwei Wang951dc022020-03-30 16:16:16 -0700458 }
459
460 /**
Hongwei Wang8e8a8ae2020-03-03 11:06:56 -0800461 * @return {@code true} if the aspect ratio is changed since no other parameters within
462 * {@link PictureInPictureParams} would affect the bounds.
463 */
Hongwei Wang8c95ce52020-04-30 15:06:12 -0700464 private boolean applyPictureInPictureParams(@NonNull PictureInPictureParams params) {
465 final boolean changed = (mPictureInPictureParams == null) ? true : !Objects.equals(
466 mPictureInPictureParams.getAspectRatioRational(), params.getAspectRatioRational());
467 if (changed) {
468 mPictureInPictureParams = params;
469 mPipBoundsHandler.onAspectRatioChanged(params.getAspectRatio());
Hongwei Wang8e8a8ae2020-03-03 11:06:56 -0800470 }
Hongwei Wang8c95ce52020-04-30 15:06:12 -0700471 return changed;
Hongwei Wang8e8a8ae2020-03-03 11:06:56 -0800472 }
Ben Lin7d6b8e72020-02-27 17:48:16 -0800473
474 /**
Winson Chung55701472020-03-04 19:30:30 -0800475 * Animates resizing of the pinned stack given the duration.
Ben Lin7d6b8e72020-02-27 17:48:16 -0800476 */
Winson Chung55701472020-03-04 19:30:30 -0800477 public void scheduleAnimateResizePip(Rect toBounds, int duration,
478 Consumer<Rect> updateBoundsCallback) {
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800479 scheduleAnimateResizePip(mLastReportedBounds, toBounds,
480 TRANSITION_DIRECTION_NONE, duration, updateBoundsCallback);
Ben Lin7d6b8e72020-02-27 17:48:16 -0800481 }
482
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800483 private void scheduleAnimateResizePip(Rect currentBounds, Rect destinationBounds,
484 @PipAnimationController.TransitionDirection int direction, int durationMs,
Winson Chung55701472020-03-04 19:30:30 -0800485 Consumer<Rect> updateBoundsCallback) {
Winson Chung55701472020-03-04 19:30:30 -0800486 if (!mInPip) {
Hongwei Wange8e32862020-04-08 13:23:45 -0700487 // can be initiated in other component, ignore if we are no longer in PIP
Winson Chung55701472020-03-04 19:30:30 -0800488 return;
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800489 }
Winson Chungc4d4ee82020-05-05 12:51:06 -0700490
Winson Chung55701472020-03-04 19:30:30 -0800491 SomeArgs args = SomeArgs.obtain();
492 args.arg1 = updateBoundsCallback;
493 args.arg2 = currentBounds;
494 args.arg3 = destinationBounds;
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800495 args.argi1 = direction;
Winson Chung55701472020-03-04 19:30:30 -0800496 args.argi2 = durationMs;
497 mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_RESIZE_ANIMATE, args));
498 }
499
500 /**
501 * Directly perform manipulation/resize on the leash. This will not perform any
502 * {@link WindowContainerTransaction} until {@link #scheduleFinishResizePip} is called.
503 */
504 public void scheduleResizePip(Rect toBounds, Consumer<Rect> updateBoundsCallback) {
Winson Chung55701472020-03-04 19:30:30 -0800505 SomeArgs args = SomeArgs.obtain();
506 args.arg1 = updateBoundsCallback;
507 args.arg2 = toBounds;
508 mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_RESIZE_IMMEDIATE, args));
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800509 }
510
Ben Lin7d6b8e72020-02-27 17:48:16 -0800511 /**
Ben Lin75ba9c32020-03-19 17:55:12 -0700512 * Directly perform a scaled matrix transformation on the leash. This will not perform any
513 * {@link WindowContainerTransaction} until {@link #scheduleFinishResizePip} is called.
514 */
515 public void scheduleUserResizePip(Rect startBounds, Rect toBounds,
516 Consumer<Rect> updateBoundsCallback) {
517 SomeArgs args = SomeArgs.obtain();
518 args.arg1 = updateBoundsCallback;
519 args.arg2 = startBounds;
520 args.arg3 = toBounds;
521 mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_RESIZE_USER, args));
522 }
523
524 /**
Hongwei Wangec3cb3c2020-03-09 10:43:21 -0700525 * Finish an intermediate resize operation. This is expected to be called after
Winson Chung55701472020-03-04 19:30:30 -0800526 * {@link #scheduleResizePip}.
Ben Lin7d6b8e72020-02-27 17:48:16 -0800527 */
Winson Chung55701472020-03-04 19:30:30 -0800528 public void scheduleFinishResizePip(Rect destinationBounds) {
Ben Lin4a8e2572020-05-08 15:55:15 -0700529 scheduleFinishResizePip(destinationBounds, null);
530 }
531
532 /**
533 * Same as {@link #scheduleFinishResizePip} but with a callback.
534 */
535 public void scheduleFinishResizePip(Rect destinationBounds,
536 Consumer<Rect> updateBoundsCallback) {
Hongwei Wangec3cb3c2020-03-09 10:43:21 -0700537 final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
538 mSurfaceTransactionHelper
539 .crop(tx, mLeash, destinationBounds)
Ben Linf603b272020-03-23 15:39:07 -0700540 .resetScale(tx, mLeash, destinationBounds)
Hongwei Wangec3cb3c2020-03-09 10:43:21 -0700541 .round(tx, mLeash, mInPip);
Ben Lin4a8e2572020-05-08 15:55:15 -0700542 scheduleFinishResizePip(tx, destinationBounds, TRANSITION_DIRECTION_NONE,
543 updateBoundsCallback);
Ben Lin7d6b8e72020-02-27 17:48:16 -0800544 }
545
Winson Chung55701472020-03-04 19:30:30 -0800546 private void scheduleFinishResizePip(SurfaceControl.Transaction tx,
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800547 Rect destinationBounds, @PipAnimationController.TransitionDirection int direction,
Winson Chung55701472020-03-04 19:30:30 -0800548 Consumer<Rect> updateBoundsCallback) {
Hongwei Wange8e32862020-04-08 13:23:45 -0700549 if (!mInPip) {
550 // can be initiated in other component, ignore if we are no longer in PIP
551 return;
552 }
Winson Chung55701472020-03-04 19:30:30 -0800553 SomeArgs args = SomeArgs.obtain();
554 args.arg1 = updateBoundsCallback;
555 args.arg2 = tx;
556 args.arg3 = destinationBounds;
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800557 args.argi1 = direction;
Winson Chung55701472020-03-04 19:30:30 -0800558 mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_FINISH_RESIZE, args));
559 }
560
561 /**
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800562 * Offset the PiP window by a given offset on Y-axis, triggered also from screen rotation.
Winson Chung55701472020-03-04 19:30:30 -0800563 */
564 public void scheduleOffsetPip(Rect originalBounds, int offset, int duration,
565 Consumer<Rect> updateBoundsCallback) {
566 if (!mInPip) {
Hongwei Wange8e32862020-04-08 13:23:45 -0700567 // can be initiated in other component, ignore if we are no longer in PIP
Winson Chung55701472020-03-04 19:30:30 -0800568 return;
569 }
Winson Chung55701472020-03-04 19:30:30 -0800570 SomeArgs args = SomeArgs.obtain();
571 args.arg1 = updateBoundsCallback;
572 args.arg2 = originalBounds;
573 // offset would be zero if triggered from screen rotation.
574 args.argi1 = offset;
575 args.argi2 = duration;
576 mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_OFFSET_ANIMATE, args));
577 }
578
579 private void offsetPip(Rect originalBounds, int xOffset, int yOffset, int durationMs) {
580 if (Looper.myLooper() != mUpdateHandler.getLooper()) {
581 throw new RuntimeException("Callers should call scheduleOffsetPip() instead of this "
582 + "directly");
583 }
584 if (mTaskInfo == null) {
585 Log.w(TAG, "mTaskInfo is not set");
586 return;
587 }
588 final Rect destinationBounds = new Rect(originalBounds);
589 destinationBounds.offset(xOffset, yOffset);
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800590 animateResizePip(originalBounds, destinationBounds, TRANSITION_DIRECTION_SAME, durationMs);
Winson Chung55701472020-03-04 19:30:30 -0800591 }
592
593 private void resizePip(Rect destinationBounds) {
594 if (Looper.myLooper() != mUpdateHandler.getLooper()) {
595 throw new RuntimeException("Callers should call scheduleResizePip() instead of this "
596 + "directly");
597 }
Winson Chungc4d4ee82020-05-05 12:51:06 -0700598 // Could happen when exitPip
Winson Chung55701472020-03-04 19:30:30 -0800599 if (mToken == null || mLeash == null) {
600 Log.w(TAG, "Abort animation, invalid leash");
601 return;
602 }
Hongwei Wangec3cb3c2020-03-09 10:43:21 -0700603 final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
604 mSurfaceTransactionHelper
605 .crop(tx, mLeash, destinationBounds)
606 .round(tx, mLeash, mInPip);
607 tx.apply();
Winson Chung55701472020-03-04 19:30:30 -0800608 }
609
Ben Lin75ba9c32020-03-19 17:55:12 -0700610 private void userResizePip(Rect startBounds, Rect destinationBounds) {
611 if (Looper.myLooper() != mUpdateHandler.getLooper()) {
612 throw new RuntimeException("Callers should call scheduleUserResizePip() instead of "
613 + "this directly");
614 }
Winson Chungc4d4ee82020-05-05 12:51:06 -0700615 // Could happen when exitPip
Ben Lin75ba9c32020-03-19 17:55:12 -0700616 if (mToken == null || mLeash == null) {
617 Log.w(TAG, "Abort animation, invalid leash");
618 return;
619 }
620 final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
621 mSurfaceTransactionHelper.scale(tx, mLeash, startBounds, destinationBounds);
622 tx.apply();
623 }
624
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800625 private void finishResize(SurfaceControl.Transaction tx, Rect destinationBounds,
Winson Chungc4d4ee82020-05-05 12:51:06 -0700626 @PipAnimationController.TransitionDirection int direction,
627 @PipAnimationController.AnimationType int type) {
Winson Chung55701472020-03-04 19:30:30 -0800628 if (Looper.myLooper() != mUpdateHandler.getLooper()) {
629 throw new RuntimeException("Callers should call scheduleResizePip() instead of this "
630 + "directly");
631 }
Ben Lin7d6b8e72020-02-27 17:48:16 -0800632 mLastReportedBounds.set(destinationBounds);
Winson Chungc4d4ee82020-05-05 12:51:06 -0700633 if (isInPipDirection(direction) && type == ANIM_TYPE_ALPHA) {
634 return;
635 }
636
Wale Ogunwaleadf116e2020-03-27 16:36:01 -0700637 final WindowContainerTransaction wct = new WindowContainerTransaction();
638 final Rect taskBounds;
Winson Chungc4d4ee82020-05-05 12:51:06 -0700639 if (isInPipDirection(direction)) {
640 // If we are animating from fullscreen using a bounds animation, then reset the
641 // activity windowing mode set by WM, and set the task bounds to the final bounds
642 taskBounds = destinationBounds;
643 wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
644 wct.scheduleFinishEnterPip(mToken, destinationBounds);
645 } else if (isOutPipDirection(direction)) {
Wale Ogunwaleadf116e2020-03-27 16:36:01 -0700646 // If we are animating to fullscreen, then we need to reset the override bounds
Hongwei Wang5c52ff82020-04-20 16:02:30 -0700647 // on the task to ensure that the task "matches" the parent's bounds.
648 taskBounds = (direction == TRANSITION_DIRECTION_TO_FULLSCREEN)
649 ? null : destinationBounds;
Winson Chungc4d4ee82020-05-05 12:51:06 -0700650 // As for the final windowing mode, simply reset it to undefined and reset the activity
651 // mode set prior to the animation running
Hongwei Wang5c52ff82020-04-20 16:02:30 -0700652 wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
Winson Chungc4d4ee82020-05-05 12:51:06 -0700653 wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
Evan Roskydc1d29f2020-05-04 13:46:14 -0700654 if (mSplitDivider != null && direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN) {
655 wct.reparent(mToken, mSplitDivider.getSecondaryRoot(), true /* onTop */);
656 }
Wale Ogunwaleadf116e2020-03-27 16:36:01 -0700657 } else {
Winson Chungc4d4ee82020-05-05 12:51:06 -0700658 // Just a resize in PIP
Wale Ogunwaleadf116e2020-03-27 16:36:01 -0700659 taskBounds = destinationBounds;
Ben Lin7d6b8e72020-02-27 17:48:16 -0800660 }
Winson Chungc4d4ee82020-05-05 12:51:06 -0700661
662 wct.setBounds(mToken, taskBounds);
Wale Ogunwaleadf116e2020-03-27 16:36:01 -0700663 wct.setBoundsChangeTransaction(mToken, tx);
664 WindowOrganizer.applyTransaction(wct);
Ben Lin7d6b8e72020-02-27 17:48:16 -0800665 }
666
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800667 private void animateResizePip(Rect currentBounds, Rect destinationBounds,
668 @PipAnimationController.TransitionDirection int direction, int durationMs) {
Winson Chung55701472020-03-04 19:30:30 -0800669 if (Looper.myLooper() != mUpdateHandler.getLooper()) {
670 throw new RuntimeException("Callers should call scheduleAnimateResizePip() instead of "
671 + "this directly");
Ben Lin7d6b8e72020-02-27 17:48:16 -0800672 }
Winson Chungc4d4ee82020-05-05 12:51:06 -0700673 // Could happen when exitPip
Winson Chung55701472020-03-04 19:30:30 -0800674 if (mToken == null || mLeash == null) {
675 Log.w(TAG, "Abort animation, invalid leash");
676 return;
677 }
Winson Chungc4d4ee82020-05-05 12:51:06 -0700678 mPipAnimationController
Hongwei Wangdf8bb002020-03-03 17:41:02 -0800679 .getAnimator(mLeash, currentBounds, destinationBounds)
680 .setTransitionDirection(direction)
Winson Chung55701472020-03-04 19:30:30 -0800681 .setPipAnimationCallback(mPipAnimationCallback)
682 .setDuration(durationMs)
Winson Chungc4d4ee82020-05-05 12:51:06 -0700683 .start();
Ben Lin7d6b8e72020-02-27 17:48:16 -0800684 }
685
Hongwei Wang2e725be2020-03-10 11:01:28 -0700686 private Size getMinimalSize(ActivityInfo activityInfo) {
687 if (activityInfo == null || activityInfo.windowLayout == null) {
688 return null;
689 }
690 final ActivityInfo.WindowLayout windowLayout = activityInfo.windowLayout;
Hongwei Wang907fd632020-04-02 17:13:08 -0700691 // -1 will be populated if an activity specifies defaultWidth/defaultHeight in <layout>
692 // without minWidth/minHeight
693 if (windowLayout.minWidth > 0 && windowLayout.minHeight > 0) {
694 return new Size(windowLayout.minWidth, windowLayout.minHeight);
695 }
696 return null;
Hongwei Wang2e725be2020-03-10 11:01:28 -0700697 }
698
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800699 private float getAspectRatioOrDefault(@Nullable PictureInPictureParams params) {
700 return params == null
701 ? mPipBoundsHandler.getDefaultAspectRatio()
702 : params.getAspectRatio();
703 }
704
705 /**
Hongwei Wang5c52ff82020-04-20 16:02:30 -0700706 * Sync with {@link #mSplitDivider} on destination bounds if PiP is going to split screen.
707 *
708 * @param destinationBoundsOut contain the updated destination bounds if applicable
709 * @return {@code true} if destinationBounds is altered for split screen
710 */
711 private boolean syncWithSplitScreenBounds(Rect destinationBoundsOut) {
712 if (mSplitDivider == null || !mSplitDivider.inSplitMode()) {
713 // bail early if system is not in split screen mode
714 return false;
715 }
716 // PiP window will go to split-secondary mode instead of fullscreen, populates the
717 // split screen bounds here.
718 destinationBoundsOut.set(
719 mSplitDivider.getView().getNonMinimizedSplitScreenSecondaryBounds());
720 return true;
721 }
722
723 /**
Winson Chungc4d4ee82020-05-05 12:51:06 -0700724 * Dumps internal states.
725 */
726 public void dump(PrintWriter pw, String prefix) {
727 final String innerPrefix = prefix + " ";
728 pw.println(prefix + TAG);
729 pw.println(innerPrefix + "mTaskInfo=" + mTaskInfo);
730 pw.println(innerPrefix + "mToken=" + mToken
731 + " binder=" + (mToken != null ? mToken.asBinder() : null));
732 pw.println(innerPrefix + "mLeash=" + mLeash);
733 pw.println(innerPrefix + "mInPip=" + mInPip);
734 pw.println(innerPrefix + "mOneShotAnimationType=" + mOneShotAnimationType);
735 pw.println(innerPrefix + "mPictureInPictureParams=" + mPictureInPictureParams);
736 pw.println(innerPrefix + "mLastReportedBounds=" + mLastReportedBounds);
737 pw.println(innerPrefix + "mInitialState:");
738 for (Map.Entry<IBinder, Configuration> e : mInitialState.entrySet()) {
739 pw.println(innerPrefix + " binder=" + e.getKey()
740 + " winConfig=" + e.getValue().windowConfiguration);
741 }
742 }
743
744 /**
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800745 * Callback interface for PiP transitions (both from and to PiP mode)
746 */
747 public interface PipTransitionCallback {
748 /**
749 * Callback when the pip transition is started.
750 */
Hongwei Wang221fe3d2020-03-26 13:13:04 -0700751 void onPipTransitionStarted(ComponentName activity, int direction);
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800752
753 /**
754 * Callback when the pip transition is finished.
755 */
Hongwei Wang221fe3d2020-03-26 13:13:04 -0700756 void onPipTransitionFinished(ComponentName activity, int direction);
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800757
758 /**
759 * Callback when the pip transition is cancelled.
760 */
Hongwei Wang221fe3d2020-03-26 13:13:04 -0700761 void onPipTransitionCanceled(ComponentName activity, int direction);
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800762 }
763}