blob: 61ed40d5d78283e867f4143c608d0cba61d63ffb [file] [log] [blame]
Winson Chung97a60d92017-01-18 16:01:53 -08001/*
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
Winson Chung15504af2016-11-02 18:11:36 -070017package com.android.systemui.pip.phone;
18
Wale Ogunwale68278562017-09-23 17:13:55 -070019import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
20import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
Winson Chung15504af2016-11-02 18:11:36 -070021
22import android.app.ActivityManager.StackInfo;
23import android.app.ActivityOptions;
Winson Chung2dbcf092018-10-24 13:00:41 -070024import android.app.ActivityTaskManager;
Winson Chung97a60d92017-01-18 16:01:53 -080025import android.app.RemoteAction;
Winson Chung15504af2016-11-02 18:11:36 -070026import android.content.Context;
27import android.content.Intent;
Winson Chunga29eb982016-12-14 12:01:27 -080028import android.content.pm.ParceledListSlice;
Winson Chunge7a3d222017-03-09 13:26:45 -080029import android.graphics.Rect;
Winson Chung853c99a2017-03-21 22:16:42 -070030import android.os.Bundle;
Winson Chungbb233762017-05-15 14:20:46 -070031import android.os.Debug;
Winson Chung15504af2016-11-02 18:11:36 -070032import android.os.Handler;
Hongwei Wang081ecb32020-04-13 16:49:03 -070033import android.os.Looper;
Winson Chung15504af2016-11-02 18:11:36 -070034import android.os.Message;
35import android.os.Messenger;
36import android.os.RemoteException;
Winson Chung947ca482017-07-25 14:28:03 -070037import android.os.SystemClock;
Winson Chung15504af2016-11-02 18:11:36 -070038import android.os.UserHandle;
39import android.util.Log;
Arthur Hungd52d1192019-08-30 16:06:59 +080040import android.view.MotionEvent;
Gus Prevasab336792018-11-14 13:52:20 -050041
Winson Chung97a60d92017-01-18 16:01:53 -080042import com.android.systemui.pip.phone.PipMediaController.ActionListener;
Winson Chungcbb15a92018-01-25 17:46:16 +000043import com.android.systemui.shared.system.InputConsumerController;
Gus Prevasab336792018-11-14 13:52:20 -050044
Winson Chung29a78652017-02-09 18:35:26 -080045import java.io.PrintWriter;
Winson Chung97a60d92017-01-18 16:01:53 -080046import java.util.ArrayList;
47import java.util.List;
48
49/**
Mady Mellor81d40612017-03-10 15:14:10 -080050 * Manages the PiP menu activity which can show menu options or a scrim.
Winson Chung97a60d92017-01-18 16:01:53 -080051 *
52 * The current media session provides actions whenever there are no valid actions provided by the
53 * current PiP activity. Otherwise, those actions always take precedence.
54 */
Winson Chung15504af2016-11-02 18:11:36 -070055public class PipMenuActivityController {
56
Winson Chung97a60d92017-01-18 16:01:53 -080057 private static final String TAG = "PipMenuActController";
Winson Chung87e5d552017-04-05 11:49:38 -070058 private static final boolean DEBUG = false;
Winson Chung15504af2016-11-02 18:11:36 -070059
60 public static final String EXTRA_CONTROLLER_MESSENGER = "messenger";
Winson Chunga29eb982016-12-14 12:01:27 -080061 public static final String EXTRA_ACTIONS = "actions";
Winson Chunge7a3d222017-03-09 13:26:45 -080062 public static final String EXTRA_STACK_BOUNDS = "stack_bounds";
63 public static final String EXTRA_MOVEMENT_BOUNDS = "movement_bounds";
Winson Chung0f873de2017-03-30 10:26:48 -070064 public static final String EXTRA_ALLOW_TIMEOUT = "allow_timeout";
Winson Chungbb787442017-09-01 11:33:47 -070065 public static final String EXTRA_WILL_RESIZE_MENU = "resize_menu_on_show";
Winson Chung853c99a2017-03-21 22:16:42 -070066 public static final String EXTRA_DISMISS_FRACTION = "dismiss_fraction";
Mady Mellor637cd482017-03-21 10:39:42 -070067 public static final String EXTRA_MENU_STATE = "menu_state";
Winson Chunga29eb982016-12-14 12:01:27 -080068
Mady Mellor637cd482017-03-21 10:39:42 -070069 public static final int MESSAGE_MENU_STATE_CHANGED = 100;
Winson Chunga29eb982016-12-14 12:01:27 -080070 public static final int MESSAGE_EXPAND_PIP = 101;
Winson Chunga29eb982016-12-14 12:01:27 -080071 public static final int MESSAGE_DISMISS_PIP = 103;
Winson Chungc75ffe82016-12-16 16:20:16 -080072 public static final int MESSAGE_UPDATE_ACTIVITY_CALLBACK = 104;
Mady Mellor637cd482017-03-21 10:39:42 -070073 public static final int MESSAGE_SHOW_MENU = 107;
74
75 public static final int MENU_STATE_NONE = 0;
76 public static final int MENU_STATE_CLOSE = 1;
77 public static final int MENU_STATE_FULL = 2;
Winson Chung15504af2016-11-02 18:11:36 -070078
Winson Chung947ca482017-07-25 14:28:03 -070079 // The duration to wait before we consider the start activity as having timed out
80 private static final long START_ACTIVITY_REQUEST_TIMEOUT_MS = 300;
81
Winson Chung15504af2016-11-02 18:11:36 -070082 /**
83 * A listener interface to receive notification on changes in PIP.
84 */
85 public interface Listener {
86 /**
87 * Called when the PIP menu visibility changes.
Winson Chungd2d90972017-02-28 11:40:41 -080088 *
Mady Mellor637cd482017-03-21 10:39:42 -070089 * @param menuState the current state of the menu
90 * @param resize whether or not to resize the PiP with the state change
Winson Chung15504af2016-11-02 18:11:36 -070091 */
Mady Mellor637cd482017-03-21 10:39:42 -070092 void onPipMenuStateChanged(int menuState, boolean resize);
Winson Chunga29eb982016-12-14 12:01:27 -080093
94 /**
95 * Called when the PIP requested to be expanded.
96 */
97 void onPipExpand();
98
99 /**
Winson Chung14fbe142016-12-19 16:18:24 -0800100 * Called when the PIP requested to be dismissed.
Winson Chunga29eb982016-12-14 12:01:27 -0800101 */
102 void onPipDismiss();
Mady Mellor637cd482017-03-21 10:39:42 -0700103
104 /**
105 * Called when the PIP requested to show the menu.
106 */
107 void onPipShowMenu();
Winson Chung15504af2016-11-02 18:11:36 -0700108 }
109
110 private Context mContext;
Winson Chung97a60d92017-01-18 16:01:53 -0800111 private PipMediaController mMediaController;
Winson Chungd2d90972017-02-28 11:40:41 -0800112 private InputConsumerController mInputConsumerController;
Winson Chunga29eb982016-12-14 12:01:27 -0800113
Winson Chung15504af2016-11-02 18:11:36 -0700114 private ArrayList<Listener> mListeners = new ArrayList<>();
Winson Chung97a60d92017-01-18 16:01:53 -0800115 private ParceledListSlice mAppActions;
116 private ParceledListSlice mMediaActions;
Mady Mellor637cd482017-03-21 10:39:42 -0700117 private int mMenuState;
Winson Chung15504af2016-11-02 18:11:36 -0700118
Winson Chung0f873de2017-03-30 10:26:48 -0700119 // The dismiss fraction update is sent frequently, so use a temporary bundle for the message
120 private Bundle mTmpDismissFractionData = new Bundle();
Winson Chung853c99a2017-03-21 22:16:42 -0700121
Winson Chung2dbcf092018-10-24 13:00:41 -0700122 private Runnable mOnAnimationEndRunnable;
Mady Mellor81d40612017-03-10 15:14:10 -0800123 private boolean mStartActivityRequested;
Winson Chung947ca482017-07-25 14:28:03 -0700124 private long mStartActivityRequestedTime;
Winson Chung15504af2016-11-02 18:11:36 -0700125 private Messenger mToActivityMessenger;
Hongwei Wang081ecb32020-04-13 16:49:03 -0700126 private Handler mHandler = new Handler(Looper.getMainLooper()) {
Winson Chung15504af2016-11-02 18:11:36 -0700127 @Override
128 public void handleMessage(Message msg) {
129 switch (msg.what) {
Mady Mellor637cd482017-03-21 10:39:42 -0700130 case MESSAGE_MENU_STATE_CHANGED: {
131 int menuState = msg.arg1;
Ben Lin559ea4d2019-11-06 12:36:41 -0800132 boolean resize = msg.arg2 != 0;
133 onMenuStateChanged(menuState, resize);
Winson Chung15504af2016-11-02 18:11:36 -0700134 break;
135 }
136 case MESSAGE_EXPAND_PIP: {
Hongwei Wang081ecb32020-04-13 16:49:03 -0700137 mListeners.forEach(Listener::onPipExpand);
Winson Chunga29eb982016-12-14 12:01:27 -0800138 break;
139 }
Winson Chunga29eb982016-12-14 12:01:27 -0800140 case MESSAGE_DISMISS_PIP: {
Hongwei Wang081ecb32020-04-13 16:49:03 -0700141 mListeners.forEach(Listener::onPipDismiss);
Mady Mellor637cd482017-03-21 10:39:42 -0700142 break;
143 }
144 case MESSAGE_SHOW_MENU: {
Hongwei Wang081ecb32020-04-13 16:49:03 -0700145 mListeners.forEach(Listener::onPipShowMenu);
Winson Chungd2d90972017-02-28 11:40:41 -0800146 break;
147 }
Winson Chungc75ffe82016-12-16 16:20:16 -0800148 case MESSAGE_UPDATE_ACTIVITY_CALLBACK: {
149 mToActivityMessenger = msg.replyTo;
Winson Chung947ca482017-07-25 14:28:03 -0700150 setStartActivityRequested(false);
Winson Chung2dbcf092018-10-24 13:00:41 -0700151 if (mOnAnimationEndRunnable != null) {
152 mOnAnimationEndRunnable.run();
153 mOnAnimationEndRunnable = null;
Winson Chungb5026902017-05-03 12:45:13 -0700154 }
Winson Chung929d4f72017-01-13 10:21:33 -0800155 // Mark the menu as invisible once the activity finishes as well
156 if (mToActivityMessenger == null) {
Ben Lin559ea4d2019-11-06 12:36:41 -0800157 final boolean resize = msg.arg1 != 0;
158 onMenuStateChanged(MENU_STATE_NONE, resize);
Winson Chung929d4f72017-01-13 10:21:33 -0800159 }
Winson Chung15504af2016-11-02 18:11:36 -0700160 break;
161 }
162 }
163 }
Winson Chung947ca482017-07-25 14:28:03 -0700164 };
165 private Messenger mMessenger = new Messenger(mHandler);
166
167 private Runnable mStartActivityRequestedTimeoutRunnable = () -> {
168 setStartActivityRequested(false);
Winson Chung2dbcf092018-10-24 13:00:41 -0700169 if (mOnAnimationEndRunnable != null) {
170 mOnAnimationEndRunnable.run();
171 mOnAnimationEndRunnable = null;
Winson Chung947ca482017-07-25 14:28:03 -0700172 }
173 Log.e(TAG, "Expected start menu activity request timed out");
174 };
Winson Chung15504af2016-11-02 18:11:36 -0700175
Winson Chung97a60d92017-01-18 16:01:53 -0800176 private ActionListener mMediaActionListener = new ActionListener() {
177 @Override
178 public void onMediaActionsChanged(List<RemoteAction> mediaActions) {
179 mMediaActions = new ParceledListSlice<>(mediaActions);
180 updateMenuActions();
181 }
182 };
183
Hongwei Wang85cf41f2020-01-15 15:14:47 -0800184 public PipMenuActivityController(Context context,
Winson Chungd2d90972017-02-28 11:40:41 -0800185 PipMediaController mediaController, InputConsumerController inputConsumerController) {
Winson Chung15504af2016-11-02 18:11:36 -0700186 mContext = context;
Winson Chung97a60d92017-01-18 16:01:53 -0800187 mMediaController = mediaController;
Winson Chungd2d90972017-02-28 11:40:41 -0800188 mInputConsumerController = inputConsumerController;
189 }
190
Winson Chungbca03112017-08-16 10:38:15 -0700191 public boolean isMenuActivityVisible() {
192 return mToActivityMessenger != null;
193 }
194
Winson Chungd2d90972017-02-28 11:40:41 -0800195 public void onActivityPinned() {
Arthur Hungd52d1192019-08-30 16:06:59 +0800196 mInputConsumerController.registerInputConsumer();
Winson Chung15504af2016-11-02 18:11:36 -0700197 }
198
Winson Chung85d3c8a2017-09-15 15:41:00 -0700199 public void onActivityUnpinned() {
Winson Chung947ca482017-07-25 14:28:03 -0700200 hideMenu();
Arthur Hungd52d1192019-08-30 16:06:59 +0800201 mInputConsumerController.unregisterInputConsumer();
Winson Chung947ca482017-07-25 14:28:03 -0700202 setStartActivityRequested(false);
203 }
204
Winson Chung34488242017-04-26 15:53:51 -0700205 public void onPinnedStackAnimationEnded() {
206 // Note: Only active menu activities care about this event
207 if (mToActivityMessenger != null) {
208 Message m = Message.obtain();
209 m.what = PipMenuActivity.MESSAGE_ANIMATION_ENDED;
210 try {
211 mToActivityMessenger.send(m);
212 } catch (RemoteException e) {
213 Log.e(TAG, "Could not notify menu pinned animation ended", e);
214 }
215 }
216 }
217
Winson Chung15504af2016-11-02 18:11:36 -0700218 /**
219 * Adds a new menu activity listener.
220 */
221 public void addListener(Listener listener) {
222 if (!mListeners.contains(listener)) {
223 mListeners.add(listener);
224 }
225 }
226
227 /**
Mady Mellor81d40612017-03-10 15:14:10 -0800228 * Updates the appearance of the menu and scrim on top of the PiP while dismissing.
229 */
230 public void setDismissFraction(float fraction) {
Winson Chung87e5d552017-04-05 11:49:38 -0700231 if (DEBUG) {
232 Log.d(TAG, "setDismissFraction() hasActivity=" + (mToActivityMessenger != null)
233 + " fraction=" + fraction);
234 }
Mady Mellor81d40612017-03-10 15:14:10 -0800235 if (mToActivityMessenger != null) {
Winson Chung0f873de2017-03-30 10:26:48 -0700236 mTmpDismissFractionData.clear();
237 mTmpDismissFractionData.putFloat(EXTRA_DISMISS_FRACTION, fraction);
Mady Mellor81d40612017-03-10 15:14:10 -0800238 Message m = Message.obtain();
239 m.what = PipMenuActivity.MESSAGE_UPDATE_DISMISS_FRACTION;
Winson Chung0f873de2017-03-30 10:26:48 -0700240 m.obj = mTmpDismissFractionData;
Mady Mellor81d40612017-03-10 15:14:10 -0800241 try {
242 mToActivityMessenger.send(m);
243 } catch (RemoteException e) {
Mady Mellor637cd482017-03-21 10:39:42 -0700244 Log.e(TAG, "Could not notify menu to update dismiss fraction", e);
Mady Mellor81d40612017-03-10 15:14:10 -0800245 }
Winson Chung947ca482017-07-25 14:28:03 -0700246 } else if (!mStartActivityRequested || isStartActivityRequestedElapsed()) {
247 // If we haven't requested the start activity, or if it previously took too long to
248 // start, then start it
Mady Mellor637cd482017-03-21 10:39:42 -0700249 startMenuActivity(MENU_STATE_NONE, null /* stackBounds */,
Winson Chungbb787442017-09-01 11:33:47 -0700250 null /* movementBounds */, false /* allowMenuTimeout */,
251 false /* resizeMenuOnShow */);
Mady Mellor81d40612017-03-10 15:14:10 -0800252 }
253 }
254
255 /**
Winson Chung15504af2016-11-02 18:11:36 -0700256 * Shows the menu activity.
257 */
Mady Mellor637cd482017-03-21 10:39:42 -0700258 public void showMenu(int menuState, Rect stackBounds, Rect movementBounds,
Winson Chungbb787442017-09-01 11:33:47 -0700259 boolean allowMenuTimeout, boolean willResizeMenu) {
Winson Chung87e5d552017-04-05 11:49:38 -0700260 if (DEBUG) {
Winson Chungbb233762017-05-15 14:20:46 -0700261 Log.d(TAG, "showMenu() state=" + menuState
262 + " hasActivity=" + (mToActivityMessenger != null)
Hongwei Wang081ecb32020-04-13 16:49:03 -0700263 + " allowMenuTimeout=" + allowMenuTimeout
264 + " willResizeMenu=" + willResizeMenu
Winson Chungbb233762017-05-15 14:20:46 -0700265 + " callers=\n" + Debug.getCallers(5, " "));
Winson Chung87e5d552017-04-05 11:49:38 -0700266 }
Winson Chungbb787442017-09-01 11:33:47 -0700267
Winson Chungc75ffe82016-12-16 16:20:16 -0800268 if (mToActivityMessenger != null) {
Winson Chung0f873de2017-03-30 10:26:48 -0700269 Bundle data = new Bundle();
Mady Mellor637cd482017-03-21 10:39:42 -0700270 data.putInt(EXTRA_MENU_STATE, menuState);
Ben Line06266d2020-02-07 16:26:40 -0800271 if (stackBounds != null) {
272 data.putParcelable(EXTRA_STACK_BOUNDS, stackBounds);
273 }
Winson Chung0f873de2017-03-30 10:26:48 -0700274 data.putParcelable(EXTRA_MOVEMENT_BOUNDS, movementBounds);
275 data.putBoolean(EXTRA_ALLOW_TIMEOUT, allowMenuTimeout);
Winson Chungbb787442017-09-01 11:33:47 -0700276 data.putBoolean(EXTRA_WILL_RESIZE_MENU, willResizeMenu);
Winson Chungc75ffe82016-12-16 16:20:16 -0800277 Message m = Message.obtain();
278 m.what = PipMenuActivity.MESSAGE_SHOW_MENU;
Winson Chung0f873de2017-03-30 10:26:48 -0700279 m.obj = data;
Winson Chungc75ffe82016-12-16 16:20:16 -0800280 try {
281 mToActivityMessenger.send(m);
282 } catch (RemoteException e) {
283 Log.e(TAG, "Could not notify menu to show", e);
Winson Chung15504af2016-11-02 18:11:36 -0700284 }
Winson Chung947ca482017-07-25 14:28:03 -0700285 } else if (!mStartActivityRequested || isStartActivityRequestedElapsed()) {
286 // If we haven't requested the start activity, or if it previously took too long to
287 // start, then start it
Winson Chungbb787442017-09-01 11:33:47 -0700288 startMenuActivity(menuState, stackBounds, movementBounds, allowMenuTimeout,
289 willResizeMenu);
Winson Chung15504af2016-11-02 18:11:36 -0700290 }
291 }
292
293 /**
Mady Mellora7f69742017-02-03 11:00:20 -0800294 * Pokes the menu, indicating that the user is interacting with it.
295 */
296 public void pokeMenu() {
Winson Chung87e5d552017-04-05 11:49:38 -0700297 if (DEBUG) {
298 Log.d(TAG, "pokeMenu() hasActivity=" + (mToActivityMessenger != null));
299 }
Mady Mellora7f69742017-02-03 11:00:20 -0800300 if (mToActivityMessenger != null) {
301 Message m = Message.obtain();
302 m.what = PipMenuActivity.MESSAGE_POKE_MENU;
303 try {
304 mToActivityMessenger.send(m);
305 } catch (RemoteException e) {
306 Log.e(TAG, "Could not notify poke menu", e);
307 }
308 }
309 }
310
311 /**
Winson Chung15504af2016-11-02 18:11:36 -0700312 * Hides the menu activity.
313 */
314 public void hideMenu() {
Winson Chung87e5d552017-04-05 11:49:38 -0700315 if (DEBUG) {
Winson Chungbb233762017-05-15 14:20:46 -0700316 Log.d(TAG, "hideMenu() state=" + mMenuState
317 + " hasActivity=" + (mToActivityMessenger != null)
318 + " callers=\n" + Debug.getCallers(5, " "));
Winson Chung87e5d552017-04-05 11:49:38 -0700319 }
Winson Chung15504af2016-11-02 18:11:36 -0700320 if (mToActivityMessenger != null) {
321 Message m = Message.obtain();
Winson Chungc75ffe82016-12-16 16:20:16 -0800322 m.what = PipMenuActivity.MESSAGE_HIDE_MENU;
Winson Chung15504af2016-11-02 18:11:36 -0700323 try {
324 mToActivityMessenger.send(m);
325 } catch (RemoteException e) {
Winson Chungc75ffe82016-12-16 16:20:16 -0800326 Log.e(TAG, "Could not notify menu to hide", e);
Winson Chung15504af2016-11-02 18:11:36 -0700327 }
Winson Chung15504af2016-11-02 18:11:36 -0700328 }
329 }
Winson Chunga29eb982016-12-14 12:01:27 -0800330
331 /**
Winson Chung2dbcf092018-10-24 13:00:41 -0700332 * Hides the menu activity.
333 */
334 public void hideMenu(Runnable onStartCallback, Runnable onEndCallback) {
335 if (mStartActivityRequested) {
336 // If the menu has been start-requested, but not actually started, then we defer the
337 // trigger callback until the menu has started and called back to the controller.
338 mOnAnimationEndRunnable = onEndCallback;
339 onStartCallback.run();
340
341 // Fallback for b/63752800, we have started the PipMenuActivity but it has not made any
342 // callbacks. Don't continue to wait for the menu to show past some timeout.
343 mHandler.removeCallbacks(mStartActivityRequestedTimeoutRunnable);
344 mHandler.postDelayed(mStartActivityRequestedTimeoutRunnable,
345 START_ACTIVITY_REQUEST_TIMEOUT_MS);
346 } else if (mMenuState != MENU_STATE_NONE && mToActivityMessenger != null) {
347 // If the menu is visible in either the closed or full state, then hide the menu and
348 // trigger the animation trigger afterwards
349 onStartCallback.run();
350 Message m = Message.obtain();
351 m.what = PipMenuActivity.MESSAGE_HIDE_MENU;
352 m.obj = onEndCallback;
353 try {
354 mToActivityMessenger.send(m);
355 } catch (RemoteException e) {
356 Log.e(TAG, "Could not notify hide menu", e);
357 }
358 }
359 }
360
361 /**
Winson Chung79f852e2017-05-04 15:06:18 -0700362 * Preemptively mark the menu as invisible, used when we are directly manipulating the pinned
363 * stack and don't want to trigger a resize which can animate the stack in a conflicting way
364 * (ie. when manually expanding or dismissing).
365 */
366 public void hideMenuWithoutResize() {
367 onMenuStateChanged(MENU_STATE_NONE, false /* resize */);
368 }
369
370 /**
Winson Chung97a60d92017-01-18 16:01:53 -0800371 * Sets the menu actions to the actions provided by the current PiP activity.
Winson Chunga29eb982016-12-14 12:01:27 -0800372 */
Winson Chung97a60d92017-01-18 16:01:53 -0800373 public void setAppActions(ParceledListSlice appActions) {
374 mAppActions = appActions;
375 updateMenuActions();
376 }
Winson Chunga29eb982016-12-14 12:01:27 -0800377
Winson Chung97a60d92017-01-18 16:01:53 -0800378 /**
379 * @return the best set of actions to show in the PiP menu.
380 */
381 private ParceledListSlice resolveMenuActions() {
382 if (isValidActions(mAppActions)) {
383 return mAppActions;
384 }
385 return mMediaActions;
386 }
387
388 /**
Mady Mellor81d40612017-03-10 15:14:10 -0800389 * Starts the menu activity on the top task of the pinned stack.
390 */
Mady Mellor637cd482017-03-21 10:39:42 -0700391 private void startMenuActivity(int menuState, Rect stackBounds, Rect movementBounds,
Winson Chungbb787442017-09-01 11:33:47 -0700392 boolean allowMenuTimeout, boolean willResizeMenu) {
Mady Mellor81d40612017-03-10 15:14:10 -0800393 try {
Wale Ogunwale04d9cb52018-04-30 13:55:07 -0700394 StackInfo pinnedStackInfo = ActivityTaskManager.getService().getStackInfo(
Wale Ogunwale68278562017-09-23 17:13:55 -0700395 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
Mady Mellor81d40612017-03-10 15:14:10 -0800396 if (pinnedStackInfo != null && pinnedStackInfo.taskIds != null &&
397 pinnedStackInfo.taskIds.length > 0) {
398 Intent intent = new Intent(mContext, PipMenuActivity.class);
Hongwei Wang792f89f2019-07-18 11:15:48 -0700399 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Mady Mellor81d40612017-03-10 15:14:10 -0800400 intent.putExtra(EXTRA_CONTROLLER_MESSENGER, mMessenger);
401 intent.putExtra(EXTRA_ACTIONS, resolveMenuActions());
402 if (stackBounds != null) {
Winson Chung853c99a2017-03-21 22:16:42 -0700403 intent.putExtra(EXTRA_STACK_BOUNDS, stackBounds);
Mady Mellor81d40612017-03-10 15:14:10 -0800404 }
405 if (movementBounds != null) {
Winson Chung853c99a2017-03-21 22:16:42 -0700406 intent.putExtra(EXTRA_MOVEMENT_BOUNDS, movementBounds);
Mady Mellor81d40612017-03-10 15:14:10 -0800407 }
Mady Mellor637cd482017-03-21 10:39:42 -0700408 intent.putExtra(EXTRA_MENU_STATE, menuState);
Winson Chung0f873de2017-03-30 10:26:48 -0700409 intent.putExtra(EXTRA_ALLOW_TIMEOUT, allowMenuTimeout);
Winson Chungbb787442017-09-01 11:33:47 -0700410 intent.putExtra(EXTRA_WILL_RESIZE_MENU, willResizeMenu);
Mady Mellor81d40612017-03-10 15:14:10 -0800411 ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
412 options.setLaunchTaskId(
413 pinnedStackInfo.taskIds[pinnedStackInfo.taskIds.length - 1]);
414 options.setTaskOverlay(true, true /* canResume */);
415 mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
Winson Chung947ca482017-07-25 14:28:03 -0700416 setStartActivityRequested(true);
Mady Mellor81d40612017-03-10 15:14:10 -0800417 } else {
418 Log.e(TAG, "No PIP tasks found");
419 }
420 } catch (RemoteException e) {
Winson Chung947ca482017-07-25 14:28:03 -0700421 setStartActivityRequested(false);
Mady Mellor81d40612017-03-10 15:14:10 -0800422 Log.e(TAG, "Error showing PIP menu activity", e);
423 }
424 }
425
426 /**
Winson Chung97a60d92017-01-18 16:01:53 -0800427 * Updates the PiP menu activity with the best set of actions provided.
428 */
429 private void updateMenuActions() {
Winson Chunga29eb982016-12-14 12:01:27 -0800430 if (mToActivityMessenger != null) {
Winson Chunge7a3d222017-03-09 13:26:45 -0800431 // Fetch the pinned stack bounds
432 Rect stackBounds = null;
433 try {
Wale Ogunwale04d9cb52018-04-30 13:55:07 -0700434 StackInfo pinnedStackInfo = ActivityTaskManager.getService().getStackInfo(
Wale Ogunwale68278562017-09-23 17:13:55 -0700435 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
Winson Chunge7a3d222017-03-09 13:26:45 -0800436 if (pinnedStackInfo != null) {
437 stackBounds = pinnedStackInfo.bounds;
438 }
439 } catch (RemoteException e) {
440 Log.e(TAG, "Error showing PIP menu activity", e);
441 }
442
Winson Chung0f873de2017-03-30 10:26:48 -0700443 Bundle data = new Bundle();
444 data.putParcelable(EXTRA_STACK_BOUNDS, stackBounds);
445 data.putParcelable(EXTRA_ACTIONS, resolveMenuActions());
Winson Chunga29eb982016-12-14 12:01:27 -0800446 Message m = Message.obtain();
447 m.what = PipMenuActivity.MESSAGE_UPDATE_ACTIONS;
Winson Chung0f873de2017-03-30 10:26:48 -0700448 m.obj = data;
Winson Chunga29eb982016-12-14 12:01:27 -0800449 try {
450 mToActivityMessenger.send(m);
451 } catch (RemoteException e) {
452 Log.e(TAG, "Could not notify menu activity to update actions", e);
453 }
454 }
455 }
Winson Chung97a60d92017-01-18 16:01:53 -0800456
457 /**
458 * Returns whether the set of actions are valid.
459 */
460 private boolean isValidActions(ParceledListSlice actions) {
461 return actions != null && actions.getList().size() > 0;
462 }
463
464 /**
Winson Chung947ca482017-07-25 14:28:03 -0700465 * @return whether the time of the activity request has exceeded the timeout.
466 */
467 private boolean isStartActivityRequestedElapsed() {
468 return (SystemClock.uptimeMillis() - mStartActivityRequestedTime)
469 >= START_ACTIVITY_REQUEST_TIMEOUT_MS;
470 }
471
472 /**
Winson Chung97a60d92017-01-18 16:01:53 -0800473 * Handles changes in menu visibility.
474 */
Mady Mellor637cd482017-03-21 10:39:42 -0700475 private void onMenuStateChanged(int menuState, boolean resize) {
Winson Chung87e5d552017-04-05 11:49:38 -0700476 if (DEBUG) {
Mady Mellor637cd482017-03-21 10:39:42 -0700477 Log.d(TAG, "onMenuStateChanged() mMenuState=" + mMenuState
478 + " menuState=" + menuState + " resize=" + resize);
Winson Chung87e5d552017-04-05 11:49:38 -0700479 }
Arthur Hungd52d1192019-08-30 16:06:59 +0800480
Mady Mellor637cd482017-03-21 10:39:42 -0700481 if (menuState != mMenuState) {
482 mListeners.forEach(l -> l.onPipMenuStateChanged(menuState, resize));
483 if (menuState == MENU_STATE_FULL) {
Winson Chung97a60d92017-01-18 16:01:53 -0800484 // Once visible, start listening for media action changes. This call will trigger
485 // the menu actions to be updated again.
486 mMediaController.addListener(mMediaActionListener);
487 } else {
488 // Once hidden, stop listening for media action changes. This call will trigger
489 // the menu actions to be updated again.
490 mMediaController.removeListener(mMediaActionListener);
491 }
492 }
Mady Mellor637cd482017-03-21 10:39:42 -0700493 mMenuState = menuState;
Winson Chung97a60d92017-01-18 16:01:53 -0800494 }
Winson Chung29a78652017-02-09 18:35:26 -0800495
Winson Chung947ca482017-07-25 14:28:03 -0700496 private void setStartActivityRequested(boolean requested) {
497 mHandler.removeCallbacks(mStartActivityRequestedTimeoutRunnable);
498 mStartActivityRequested = requested;
499 mStartActivityRequestedTime = requested ? SystemClock.uptimeMillis() : 0;
500 }
501
Arthur Hungd52d1192019-08-30 16:06:59 +0800502 /**
Arthur Hungd8961972019-10-14 17:00:17 +0800503 * Handles a pointer event sent from pip input consumer.
Arthur Hungd52d1192019-08-30 16:06:59 +0800504 */
Arthur Hungd8961972019-10-14 17:00:17 +0800505 void handlePointerEvent(MotionEvent ev) {
Arthur Hungd52d1192019-08-30 16:06:59 +0800506 if (mToActivityMessenger != null) {
507 Message m = Message.obtain();
Arthur Hungd8961972019-10-14 17:00:17 +0800508 m.what = PipMenuActivity.MESSAGE_POINTER_EVENT;
Arthur Hungd52d1192019-08-30 16:06:59 +0800509 m.obj = ev;
510 try {
511 mToActivityMessenger.send(m);
512 } catch (RemoteException e) {
513 Log.e(TAG, "Could not dispatch touch event", e);
514 }
515 }
516 }
517
Winson Chung29a78652017-02-09 18:35:26 -0800518 public void dump(PrintWriter pw, String prefix) {
519 final String innerPrefix = prefix + " ";
520 pw.println(prefix + TAG);
Mady Mellor637cd482017-03-21 10:39:42 -0700521 pw.println(innerPrefix + "mMenuState=" + mMenuState);
Winson Chung87e5d552017-04-05 11:49:38 -0700522 pw.println(innerPrefix + "mToActivityMessenger=" + mToActivityMessenger);
Winson Chung29a78652017-02-09 18:35:26 -0800523 pw.println(innerPrefix + "mListeners=" + mListeners.size());
Winson Chung947ca482017-07-25 14:28:03 -0700524 pw.println(innerPrefix + "mStartActivityRequested=" + mStartActivityRequested);
525 pw.println(innerPrefix + "mStartActivityRequestedTime=" + mStartActivityRequestedTime);
Winson Chung29a78652017-02-09 18:35:26 -0800526 }
Winson Chung15504af2016-11-02 18:11:36 -0700527}