blob: 239ef3638ff6f2ac3e3d92fb55f4686a5e70a6f4 [file] [log] [blame]
Winson73bc1592016-10-18 18:47:43 -07001/*
2 * Copyright (C) 2016 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.phone;
18
Arthur Hungd52d1192019-08-30 16:06:59 +080019import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
20import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
21
Sudheer Shankadc589ac2016-11-10 15:30:17 -080022import android.app.ActivityManager;
Wale Ogunwale65ebd952018-04-25 15:41:44 -070023import android.app.ActivityTaskManager;
Winson73bc1592016-10-18 18:47:43 -070024import android.app.IActivityManager;
Wale Ogunwale65ebd952018-04-25 15:41:44 -070025import android.app.IActivityTaskManager;
Winson Chung3535df22017-01-17 18:43:39 -080026import android.content.ComponentName;
Winson73bc1592016-10-18 18:47:43 -070027import android.content.Context;
Winson Chunga29eb982016-12-14 12:01:27 -080028import android.content.pm.ParceledListSlice;
Winson Chung0c5a5922017-05-22 17:41:06 -070029import android.content.res.Configuration;
Winson Chung2a82fe52017-02-02 14:43:34 -080030import android.graphics.Rect;
Winson Chunga29eb982016-12-14 12:01:27 -080031import android.os.Handler;
32import android.os.RemoteException;
33import android.util.Log;
Winson Chung85d3c8a2017-09-15 15:41:00 -070034import android.util.Pair;
Hongwei Wang43a752b2019-09-17 20:20:30 +000035import android.view.DisplayInfo;
Winson Chunga29eb982016-12-14 12:01:27 -080036import android.view.IPinnedStackController;
Hongwei Wangebf18082019-09-26 14:25:11 -070037import android.view.WindowContainerTransaction;
Gus Prevasab336792018-11-14 13:52:20 -050038
Winson Chung67f5c8b2018-09-24 12:09:19 -070039import com.android.systemui.Dependency;
40import com.android.systemui.UiOffloadThread;
Fabian Kozynski5ca7a512019-10-16 19:56:11 +000041import com.android.systemui.broadcast.BroadcastDispatcher;
Winson Chung29a78652017-02-09 18:35:26 -080042import com.android.systemui.pip.BasePipManager;
Hongwei Wang43a752b2019-09-17 20:20:30 +000043import com.android.systemui.pip.PipBoundsHandler;
Winson Chungaa357452017-10-31 11:35:30 -070044import com.android.systemui.shared.system.ActivityManagerWrapper;
Winson Chungcbb15a92018-01-25 17:46:16 +000045import com.android.systemui.shared.system.InputConsumerController;
Hongwei Wang43a752b2019-09-17 20:20:30 +000046import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
Winson Chung67f5c8b2018-09-24 12:09:19 -070047import com.android.systemui.shared.system.TaskStackChangeListener;
48import com.android.systemui.shared.system.WindowManagerWrapper;
Winson Chung95c9fca2020-01-22 09:48:40 -080049import com.android.systemui.wm.DisplayChangeController;
50import com.android.systemui.wm.DisplayController;
Gus Prevasab336792018-11-14 13:52:20 -050051
Winson Chung29a78652017-02-09 18:35:26 -080052import java.io.PrintWriter;
53
Winson73bc1592016-10-18 18:47:43 -070054/**
55 * Manages the picture-in-picture (PIP) UI and states for Phones.
56 */
Winson Chung29a78652017-02-09 18:35:26 -080057public class PipManager implements BasePipManager {
Winson73bc1592016-10-18 18:47:43 -070058 private static final String TAG = "PipManager";
59
60 private static PipManager sPipController;
61
62 private Context mContext;
63 private IActivityManager mActivityManager;
Wale Ogunwale65ebd952018-04-25 15:41:44 -070064 private IActivityTaskManager mActivityTaskManager;
Winson Chunga29eb982016-12-14 12:01:27 -080065 private Handler mHandler = new Handler();
66
Hongwei Wang43a752b2019-09-17 20:20:30 +000067 private final PinnedStackListener mPinnedStackListener = new PipManagerPinnedStackListener();
68 private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
69 private final Rect mTmpInsetBounds = new Rect();
70 private final Rect mTmpNormalBounds = new Rect();
jorgegil@google.com62f735e2019-10-30 14:37:19 -070071 private final Rect mReentryBounds = new Rect();
Winson73bc1592016-10-18 18:47:43 -070072
Hongwei Wang43a752b2019-09-17 20:20:30 +000073 private PipBoundsHandler mPipBoundsHandler;
Winson Chungd2d90972017-02-28 11:40:41 -080074 private InputConsumerController mInputConsumerController;
Winson Chung15504af2016-11-02 18:11:36 -070075 private PipMenuActivityController mMenuController;
Winson Chung97a60d92017-01-18 16:01:53 -080076 private PipMediaController mMediaController;
Winson73bc1592016-10-18 18:47:43 -070077 private PipTouchHandler mTouchHandler;
Winson Chung95bccdc2018-01-03 11:45:47 -080078 private PipAppOpsListener mAppOpsListener;
Winson73bc1592016-10-18 18:47:43 -070079
Winson Chunga29eb982016-12-14 12:01:27 -080080 /**
Hongwei Wangebf18082019-09-26 14:25:11 -070081 * Handler for display rotation changes.
82 */
Winson Chung95c9fca2020-01-22 09:48:40 -080083 private final DisplayChangeController.OnDisplayChangingListener mRotationController = (
Hongwei Wangebf18082019-09-26 14:25:11 -070084 int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) -> {
85 final boolean changed = mPipBoundsHandler.onDisplayRotationChanged(mTmpNormalBounds,
86 displayId, fromRotation, toRotation, t);
87 if (changed) {
88 updateMovementBounds(mTmpNormalBounds, false /* fromImeAdjustment */,
89 false /* fromShelfAdjustment */);
90 }
91 };
92
93 /**
Winson Chung929d4f72017-01-13 10:21:33 -080094 * Handler for system task stack changes.
95 */
Hongwei Wangebf18082019-09-26 14:25:11 -070096 private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
Winson Chung929d4f72017-01-13 10:21:33 -080097 @Override
Wale Ogunwale89be5762017-10-04 13:27:49 -070098 public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
Winson Chung929d4f72017-01-13 10:21:33 -080099 mTouchHandler.onActivityPinned();
Winson Chung97a60d92017-01-18 16:01:53 -0800100 mMediaController.onActivityPinned();
Winson Chungd2d90972017-02-28 11:40:41 -0800101 mMenuController.onActivityPinned();
Winson Chung95bccdc2018-01-03 11:45:47 -0800102 mAppOpsListener.onActivityPinned(packageName);
Winson Chungac52f282017-03-30 14:44:52 -0700103
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -0500104 Dependency.get(UiOffloadThread.class).execute(() -> {
Winson Chung67f5c8b2018-09-24 12:09:19 -0700105 WindowManagerWrapper.getInstance().setPipVisibility(true);
106 });
Winson Chungc81c0ce2017-03-17 12:27:30 -0700107 }
108
109 @Override
110 public void onActivityUnpinned() {
Winson Chung85d3c8a2017-09-15 15:41:00 -0700111 final Pair<ComponentName, Integer> topPipActivityInfo = PipUtils.getTopPinnedActivity(
112 mContext, mActivityManager);
113 final ComponentName topActivity = topPipActivityInfo.first;
Winson Chung85d3c8a2017-09-15 15:41:00 -0700114 mMenuController.onActivityUnpinned();
115 mTouchHandler.onActivityUnpinned(topActivity);
Winson Chung95bccdc2018-01-03 11:45:47 -0800116 mAppOpsListener.onActivityUnpinned();
Winson Chungac52f282017-03-30 14:44:52 -0700117
Dave Mankoffc7cf9fc2019-12-19 15:43:20 -0500118 Dependency.get(UiOffloadThread.class).execute(() -> {
Winson Chung67f5c8b2018-09-24 12:09:19 -0700119 WindowManagerWrapper.getInstance().setPipVisibility(topActivity != null);
120 });
Winson Chung929d4f72017-01-13 10:21:33 -0800121 }
122
123 @Override
Winson Chung85d39982017-02-24 15:21:25 -0800124 public void onPinnedStackAnimationStarted() {
125 // Disable touches while the animation is running
126 mTouchHandler.setTouchEnabled(false);
127 }
128
129 @Override
Winson Chung929d4f72017-01-13 10:21:33 -0800130 public void onPinnedStackAnimationEnded() {
Winson Chung85d39982017-02-24 15:21:25 -0800131 // Re-enable touches after the animation completes
132 mTouchHandler.setTouchEnabled(true);
Winson Chungac52f282017-03-30 14:44:52 -0700133 mTouchHandler.onPinnedStackAnimationEnded();
Winson Chung34488242017-04-26 15:53:51 -0700134 mMenuController.onPinnedStackAnimationEnded();
Winson Chung929d4f72017-01-13 10:21:33 -0800135 }
136
137 @Override
Winson Chunge6385a22017-05-02 18:15:16 -0700138 public void onPinnedActivityRestartAttempt(boolean clearedTask) {
Winson Chunge6385a22017-05-02 18:15:16 -0700139 mTouchHandler.getMotionHelper().expandPip(clearedTask /* skipAnimation */);
Winson Chung929d4f72017-01-13 10:21:33 -0800140 }
141 };
142
143 /**
Winson Chunga29eb982016-12-14 12:01:27 -0800144 * Handler for messages from the PIP controller.
145 */
Hongwei Wang43a752b2019-09-17 20:20:30 +0000146 private class PipManagerPinnedStackListener extends PinnedStackListener {
Winson Chunga29eb982016-12-14 12:01:27 -0800147 @Override
148 public void onListenerRegistered(IPinnedStackController controller) {
149 mHandler.post(() -> {
Hongwei Wang43a752b2019-09-17 20:20:30 +0000150 mPipBoundsHandler.setPinnedStackController(controller);
Winson Chunga29eb982016-12-14 12:01:27 -0800151 mTouchHandler.setPinnedStackController(controller);
152 });
153 }
154
155 @Override
Winson Chung2a82fe52017-02-02 14:43:34 -0800156 public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
Winson Chunga29eb982016-12-14 12:01:27 -0800157 mHandler.post(() -> {
Hongwei Wang43a752b2019-09-17 20:20:30 +0000158 mPipBoundsHandler.onImeVisibilityChanged(imeVisible, imeHeight);
Winson Chung2a82fe52017-02-02 14:43:34 -0800159 mTouchHandler.onImeVisibilityChanged(imeVisible, imeHeight);
Winson Chunga29eb982016-12-14 12:01:27 -0800160 });
161 }
162
163 @Override
164 public void onMinimizedStateChanged(boolean isMinimized) {
165 mHandler.post(() -> {
Hongwei Wang43a752b2019-09-17 20:20:30 +0000166 mPipBoundsHandler.onMinimizedStateChanged(isMinimized);
Winson Chung2a82fe52017-02-02 14:43:34 -0800167 mTouchHandler.setMinimizedState(isMinimized, true /* fromController */);
Winson Chunga29eb982016-12-14 12:01:27 -0800168 });
169 }
170
171 @Override
Hongwei Wang43a752b2019-09-17 20:20:30 +0000172 public void onMovementBoundsChanged(Rect animatingBounds, boolean fromImeAdjustment,
173 boolean fromShelfAdjustment) {
Hongwei Wang9b751802019-09-11 12:13:21 -0700174 mHandler.post(() -> updateMovementBounds(animatingBounds, fromImeAdjustment,
175 fromShelfAdjustment));
Winson Chung2a82fe52017-02-02 14:43:34 -0800176 }
177
178 @Override
179 public void onActionsChanged(ParceledListSlice actions) {
Hongwei Wang43a752b2019-09-17 20:20:30 +0000180 mHandler.post(() -> mMenuController.setAppActions(actions));
181 }
182
183 @Override
jorgegil@google.com62f735e2019-10-30 14:37:19 -0700184 public void onSaveReentryBounds(ComponentName componentName, Rect bounds) {
185 mHandler.post(() -> {
186 // On phones, the expansion animation that happens on pip tap before restoring
187 // to fullscreen makes it so that the bounds received here are the expanded
188 // bounds. We want to restore to the unexpanded bounds when re-entering pip,
189 // so we save the bounds before expansion (normal) instead of the current
190 // bounds.
191 mReentryBounds.set(mTouchHandler.getNormalBounds());
192 // Apply the snap fraction of the current bounds to the normal bounds.
193 float snapFraction = mPipBoundsHandler.getSnapFraction(bounds);
194 mPipBoundsHandler.applySnapFraction(mReentryBounds, snapFraction);
195 // Save reentry bounds (normal non-expand bounds with current position applied).
196 mPipBoundsHandler.onSaveReentryBounds(componentName, mReentryBounds);
197 });
Hongwei Wang43a752b2019-09-17 20:20:30 +0000198 }
199
200 @Override
jorgegil@google.com62f735e2019-10-30 14:37:19 -0700201 public void onResetReentryBounds(ComponentName componentName) {
202 mHandler.post(() -> mPipBoundsHandler.onResetReentryBounds(componentName));
Hongwei Wang43a752b2019-09-17 20:20:30 +0000203 }
204
205 @Override
206 public void onDisplayInfoChanged(DisplayInfo displayInfo) {
207 mHandler.post(() -> mPipBoundsHandler.onDisplayInfoChanged(displayInfo));
208 }
209
210 @Override
211 public void onConfigurationChanged() {
212 mHandler.post(() -> mPipBoundsHandler.onConfigurationChanged());
213 }
214
215 @Override
216 public void onAspectRatioChanged(float aspectRatio) {
217 mHandler.post(() -> mPipBoundsHandler.onAspectRatioChanged(aspectRatio));
218 }
219
220 @Override
221 public void onPrepareAnimation(Rect sourceRectHint, float aspectRatio, Rect bounds) {
Winson Chung2a82fe52017-02-02 14:43:34 -0800222 mHandler.post(() -> {
Hongwei Wang43a752b2019-09-17 20:20:30 +0000223 mPipBoundsHandler.onPrepareAnimation(sourceRectHint, aspectRatio, bounds);
Winson Chunga29eb982016-12-14 12:01:27 -0800224 });
225 }
226 }
227
Winson73bc1592016-10-18 18:47:43 -0700228 private PipManager() {}
229
230 /**
231 * Initializes {@link PipManager}.
232 */
Hongwei Wangebf18082019-09-26 14:25:11 -0700233 public void initialize(Context context, BroadcastDispatcher broadcastDispatcher,
Winson Chung95c9fca2020-01-22 09:48:40 -0800234 DisplayController displayController) {
Winson73bc1592016-10-18 18:47:43 -0700235 mContext = context;
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800236 mActivityManager = ActivityManager.getService();
Wale Ogunwale65ebd952018-04-25 15:41:44 -0700237 mActivityTaskManager = ActivityTaskManager.getService();
Winson73bc1592016-10-18 18:47:43 -0700238
Winson Chunga29eb982016-12-14 12:01:27 -0800239 try {
Joshua Tsujia19515f2019-02-13 18:02:29 -0500240 WindowManagerWrapper.getInstance().addPinnedStackListener(mPinnedStackListener);
Winson Chunga29eb982016-12-14 12:01:27 -0800241 } catch (RemoteException e) {
242 Log.e(TAG, "Failed to register pinned stack listener", e);
243 }
Winson Chung2cf6ad82017-11-09 17:36:59 -0800244 ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
Winson Chunga29eb982016-12-14 12:01:27 -0800245
Hongwei Wang43a752b2019-09-17 20:20:30 +0000246 mPipBoundsHandler = new PipBoundsHandler(context);
Winson Chungcbb15a92018-01-25 17:46:16 +0000247 mInputConsumerController = InputConsumerController.getPipInputConsumer();
Fabian Kozynski5ca7a512019-10-16 19:56:11 +0000248 mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher);
Winson Chungd2d90972017-02-28 11:40:41 -0800249 mMenuController = new PipMenuActivityController(context, mActivityManager, mMediaController,
250 mInputConsumerController);
Wale Ogunwale65ebd952018-04-25 15:41:44 -0700251 mTouchHandler = new PipTouchHandler(context, mActivityManager, mActivityTaskManager,
Hongwei Wang43a752b2019-09-17 20:20:30 +0000252 mMenuController, mInputConsumerController, mPipBoundsHandler);
Winson Chung95bccdc2018-01-03 11:45:47 -0800253 mAppOpsListener = new PipAppOpsListener(context, mActivityManager,
254 mTouchHandler.getMotionHelper());
Winson Chung95c9fca2020-01-22 09:48:40 -0800255 displayController.addDisplayChangingController(mRotationController);
Arthur Hungd52d1192019-08-30 16:06:59 +0800256
257 // If SystemUI restart, and it already existed a pinned stack,
258 // register the pip input consumer to ensure touch can send to it.
259 try {
260 ActivityManager.StackInfo stackInfo = mActivityTaskManager.getStackInfo(
261 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
262 if (stackInfo != null) {
263 mInputConsumerController.registerInputConsumer();
264 }
265 } catch (RemoteException e) {
266 e.printStackTrace();
267 }
Winson73bc1592016-10-18 18:47:43 -0700268 }
269
270 /**
271 * Updates the PIP per configuration changed.
272 */
Winson Chung0c5a5922017-05-22 17:41:06 -0700273 public void onConfigurationChanged(Configuration newConfig) {
Winson Chung303c6b72016-10-24 17:12:49 -0700274 mTouchHandler.onConfigurationChanged();
275 }
Winson73bc1592016-10-18 18:47:43 -0700276
277 /**
Winson Chungb5026902017-05-03 12:45:13 -0700278 * Expands the PIP.
279 */
Winson Chung2dbcf092018-10-24 13:00:41 -0700280 @Override
281 public void expandPip() {
Winson Chungb5026902017-05-03 12:45:13 -0700282 mTouchHandler.getMotionHelper().expandPip(false /* skipAnimation */);
283 }
284
285 /**
Winson Chung2dbcf092018-10-24 13:00:41 -0700286 * Hides the PIP menu.
287 */
288 @Override
289 public void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {
290 mMenuController.hideMenu(onStartCallback, onEndCallback);
291 }
292
293 /**
Winson Chungac52f282017-03-30 14:44:52 -0700294 * Sent from KEYCODE_WINDOW handler in PhoneWindowManager, to request the menu to be shown.
295 */
296 public void showPictureInPictureMenu() {
297 mTouchHandler.showPictureInPictureMenu();
298 }
299
300 /**
Ben Lin1a80f122020-01-27 14:09:52 -0800301 * Sets a customized touch gesture that replaces the default one.
302 */
303 public void setTouchGesture(PipTouchGesture gesture) {
304 mTouchHandler.setTouchGesture(gesture);
305 }
306
307 /**
Hongwei Wang9b751802019-09-11 12:13:21 -0700308 * Sets both shelf visibility and its height.
309 */
310 @Override
311 public void setShelfHeight(boolean visible, int height) {
312 mHandler.post(() -> {
313 final boolean changed = mPipBoundsHandler.setShelfHeight(visible, height);
314 if (changed) {
315 mTouchHandler.onShelfVisibilityChanged(visible, height);
316 updateMovementBounds(mPipBoundsHandler.getLastDestinationBounds(),
317 false /* fromImeAdjustment */, true /* fromShelfAdjustment */);
318 }
319 });
320 }
321
322 private void updateMovementBounds(Rect animatingBounds, boolean fromImeAdjustment,
323 boolean fromShelfAdjustment) {
324 // Populate inset / normal bounds and DisplayInfo from mPipBoundsHandler first.
325 mPipBoundsHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds,
326 animatingBounds, mTmpDisplayInfo);
327 mTouchHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds,
328 animatingBounds, fromImeAdjustment, fromShelfAdjustment,
329 mTmpDisplayInfo.rotation);
330 }
331
332 /**
Winson73bc1592016-10-18 18:47:43 -0700333 * Gets an instance of {@link PipManager}.
334 */
335 public static PipManager getInstance() {
336 if (sPipController == null) {
337 sPipController = new PipManager();
338 }
339 return sPipController;
340 }
Winson Chung29a78652017-02-09 18:35:26 -0800341
342 public void dump(PrintWriter pw) {
343 final String innerPrefix = " ";
344 pw.println(TAG);
Winson Chungd2d90972017-02-28 11:40:41 -0800345 mInputConsumerController.dump(pw, innerPrefix);
Winson Chung29a78652017-02-09 18:35:26 -0800346 mMenuController.dump(pw, innerPrefix);
347 mTouchHandler.dump(pw, innerPrefix);
Hongwei Wang43a752b2019-09-17 20:20:30 +0000348 mPipBoundsHandler.dump(pw, innerPrefix);
Winson Chung29a78652017-02-09 18:35:26 -0800349 }
Winson73bc1592016-10-18 18:47:43 -0700350}