blob: 46d53e41072551ba3335fb349dee645656e98bcf [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 Chung15504af2016-11-02 18:11:36 -070025import android.app.IActivityManager;
Winson Chung97a60d92017-01-18 16:01:53 -080026import android.app.RemoteAction;
Winson Chung15504af2016-11-02 18:11:36 -070027import android.content.Context;
28import android.content.Intent;
Winson Chunga29eb982016-12-14 12:01:27 -080029import android.content.pm.ParceledListSlice;
Winson Chunge7a3d222017-03-09 13:26:45 -080030import android.graphics.Rect;
Winson Chung853c99a2017-03-21 22:16:42 -070031import android.os.Bundle;
Winson Chungbb233762017-05-15 14:20:46 -070032import android.os.Debug;
Winson Chung15504af2016-11-02 18:11:36 -070033import android.os.Handler;
34import 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;
Gus Prevasab336792018-11-14 13:52:20 -050040
Winson Chung97a60d92017-01-18 16:01:53 -080041import com.android.systemui.pip.phone.PipMediaController.ActionListener;
Winson Chungcbb15a92018-01-25 17:46:16 +000042import com.android.systemui.shared.system.InputConsumerController;
Gus Prevasab336792018-11-14 13:52:20 -050043
Winson Chung29a78652017-02-09 18:35:26 -080044import java.io.PrintWriter;
Winson Chung97a60d92017-01-18 16:01:53 -080045import java.util.ArrayList;
46import java.util.List;
47
48/**
Mady Mellor81d40612017-03-10 15:14:10 -080049 * Manages the PiP menu activity which can show menu options or a scrim.
Winson Chung97a60d92017-01-18 16:01:53 -080050 *
51 * The current media session provides actions whenever there are no valid actions provided by the
52 * current PiP activity. Otherwise, those actions always take precedence.
53 */
Winson Chung15504af2016-11-02 18:11:36 -070054public class PipMenuActivityController {
55
Winson Chung97a60d92017-01-18 16:01:53 -080056 private static final String TAG = "PipMenuActController";
Winson Chung87e5d552017-04-05 11:49:38 -070057 private static final boolean DEBUG = false;
Winson Chung15504af2016-11-02 18:11:36 -070058
59 public static final String EXTRA_CONTROLLER_MESSENGER = "messenger";
Winson Chunga29eb982016-12-14 12:01:27 -080060 public static final String EXTRA_ACTIONS = "actions";
Winson Chunge7a3d222017-03-09 13:26:45 -080061 public static final String EXTRA_STACK_BOUNDS = "stack_bounds";
62 public static final String EXTRA_MOVEMENT_BOUNDS = "movement_bounds";
Winson Chung0f873de2017-03-30 10:26:48 -070063 public static final String EXTRA_ALLOW_TIMEOUT = "allow_timeout";
Winson Chungbb787442017-09-01 11:33:47 -070064 public static final String EXTRA_WILL_RESIZE_MENU = "resize_menu_on_show";
Winson Chung853c99a2017-03-21 22:16:42 -070065 public static final String EXTRA_DISMISS_FRACTION = "dismiss_fraction";
Mady Mellor637cd482017-03-21 10:39:42 -070066 public static final String EXTRA_MENU_STATE = "menu_state";
Winson Chunga29eb982016-12-14 12:01:27 -080067
Mady Mellor637cd482017-03-21 10:39:42 -070068 public static final int MESSAGE_MENU_STATE_CHANGED = 100;
Winson Chunga29eb982016-12-14 12:01:27 -080069 public static final int MESSAGE_EXPAND_PIP = 101;
70 public static final int MESSAGE_MINIMIZE_PIP = 102;
71 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;
Winson Chungd2d90972017-02-28 11:40:41 -080073 public static final int MESSAGE_REGISTER_INPUT_CONSUMER = 105;
Winson Chung2824d7c2017-03-15 19:43:00 -070074 public static final int MESSAGE_UNREGISTER_INPUT_CONSUMER = 106;
Mady Mellor637cd482017-03-21 10:39:42 -070075 public static final int MESSAGE_SHOW_MENU = 107;
76
77 public static final int MENU_STATE_NONE = 0;
78 public static final int MENU_STATE_CLOSE = 1;
79 public static final int MENU_STATE_FULL = 2;
Winson Chung15504af2016-11-02 18:11:36 -070080
Winson Chung947ca482017-07-25 14:28:03 -070081 // The duration to wait before we consider the start activity as having timed out
82 private static final long START_ACTIVITY_REQUEST_TIMEOUT_MS = 300;
83
Winson Chung15504af2016-11-02 18:11:36 -070084 /**
85 * A listener interface to receive notification on changes in PIP.
86 */
87 public interface Listener {
88 /**
89 * Called when the PIP menu visibility changes.
Winson Chungd2d90972017-02-28 11:40:41 -080090 *
Mady Mellor637cd482017-03-21 10:39:42 -070091 * @param menuState the current state of the menu
92 * @param resize whether or not to resize the PiP with the state change
Winson Chung15504af2016-11-02 18:11:36 -070093 */
Mady Mellor637cd482017-03-21 10:39:42 -070094 void onPipMenuStateChanged(int menuState, boolean resize);
Winson Chunga29eb982016-12-14 12:01:27 -080095
96 /**
97 * Called when the PIP requested to be expanded.
98 */
99 void onPipExpand();
100
101 /**
102 * Called when the PIP requested to be minimized.
103 */
104 void onPipMinimize();
105
106 /**
Winson Chung14fbe142016-12-19 16:18:24 -0800107 * Called when the PIP requested to be dismissed.
Winson Chunga29eb982016-12-14 12:01:27 -0800108 */
109 void onPipDismiss();
Mady Mellor637cd482017-03-21 10:39:42 -0700110
111 /**
112 * Called when the PIP requested to show the menu.
113 */
114 void onPipShowMenu();
Winson Chung15504af2016-11-02 18:11:36 -0700115 }
116
117 private Context mContext;
118 private IActivityManager mActivityManager;
Winson Chung97a60d92017-01-18 16:01:53 -0800119 private PipMediaController mMediaController;
Winson Chungd2d90972017-02-28 11:40:41 -0800120 private InputConsumerController mInputConsumerController;
Winson Chunga29eb982016-12-14 12:01:27 -0800121
Winson Chung15504af2016-11-02 18:11:36 -0700122 private ArrayList<Listener> mListeners = new ArrayList<>();
Winson Chung97a60d92017-01-18 16:01:53 -0800123 private ParceledListSlice mAppActions;
124 private ParceledListSlice mMediaActions;
Mady Mellor637cd482017-03-21 10:39:42 -0700125 private int mMenuState;
Winson Chung15504af2016-11-02 18:11:36 -0700126
Winson Chung0f873de2017-03-30 10:26:48 -0700127 // The dismiss fraction update is sent frequently, so use a temporary bundle for the message
128 private Bundle mTmpDismissFractionData = new Bundle();
Winson Chung853c99a2017-03-21 22:16:42 -0700129
Winson Chung2dbcf092018-10-24 13:00:41 -0700130 private Runnable mOnAnimationEndRunnable;
Mady Mellor81d40612017-03-10 15:14:10 -0800131 private boolean mStartActivityRequested;
Winson Chung947ca482017-07-25 14:28:03 -0700132 private long mStartActivityRequestedTime;
Winson Chung15504af2016-11-02 18:11:36 -0700133 private Messenger mToActivityMessenger;
Winson Chung947ca482017-07-25 14:28:03 -0700134 private Handler mHandler = new Handler() {
Winson Chung15504af2016-11-02 18:11:36 -0700135 @Override
136 public void handleMessage(Message msg) {
137 switch (msg.what) {
Mady Mellor637cd482017-03-21 10:39:42 -0700138 case MESSAGE_MENU_STATE_CHANGED: {
139 int menuState = msg.arg1;
140 onMenuStateChanged(menuState, true /* resize */);
Winson Chung15504af2016-11-02 18:11:36 -0700141 break;
142 }
143 case MESSAGE_EXPAND_PIP: {
Winson Chungc75ffe82016-12-16 16:20:16 -0800144 mListeners.forEach(l -> l.onPipExpand());
Winson Chunga29eb982016-12-14 12:01:27 -0800145 break;
146 }
147 case MESSAGE_MINIMIZE_PIP: {
Winson Chungc75ffe82016-12-16 16:20:16 -0800148 mListeners.forEach(l -> l.onPipMinimize());
Winson Chunga29eb982016-12-14 12:01:27 -0800149 break;
150 }
151 case MESSAGE_DISMISS_PIP: {
Winson Chungc75ffe82016-12-16 16:20:16 -0800152 mListeners.forEach(l -> l.onPipDismiss());
Mady Mellor637cd482017-03-21 10:39:42 -0700153 break;
154 }
155 case MESSAGE_SHOW_MENU: {
156 mListeners.forEach(l -> l.onPipShowMenu());
Winson Chungd2d90972017-02-28 11:40:41 -0800157 break;
158 }
159 case MESSAGE_REGISTER_INPUT_CONSUMER: {
160 mInputConsumerController.registerInputConsumer();
Winson Chungc75ffe82016-12-16 16:20:16 -0800161 break;
162 }
Winson Chung2824d7c2017-03-15 19:43:00 -0700163 case MESSAGE_UNREGISTER_INPUT_CONSUMER: {
164 mInputConsumerController.unregisterInputConsumer();
165 break;
166 }
Winson Chungc75ffe82016-12-16 16:20:16 -0800167 case MESSAGE_UPDATE_ACTIVITY_CALLBACK: {
168 mToActivityMessenger = msg.replyTo;
Winson Chung947ca482017-07-25 14:28:03 -0700169 setStartActivityRequested(false);
Winson Chung2dbcf092018-10-24 13:00:41 -0700170 if (mOnAnimationEndRunnable != null) {
171 mOnAnimationEndRunnable.run();
172 mOnAnimationEndRunnable = null;
Winson Chungb5026902017-05-03 12:45:13 -0700173 }
Winson Chung929d4f72017-01-13 10:21:33 -0800174 // Mark the menu as invisible once the activity finishes as well
175 if (mToActivityMessenger == null) {
Mady Mellor637cd482017-03-21 10:39:42 -0700176 onMenuStateChanged(MENU_STATE_NONE, true /* resize */);
Winson Chung929d4f72017-01-13 10:21:33 -0800177 }
Winson Chung15504af2016-11-02 18:11:36 -0700178 break;
179 }
180 }
181 }
Winson Chung947ca482017-07-25 14:28:03 -0700182 };
183 private Messenger mMessenger = new Messenger(mHandler);
184
185 private Runnable mStartActivityRequestedTimeoutRunnable = () -> {
186 setStartActivityRequested(false);
Winson Chung2dbcf092018-10-24 13:00:41 -0700187 if (mOnAnimationEndRunnable != null) {
188 mOnAnimationEndRunnable.run();
189 mOnAnimationEndRunnable = null;
Winson Chung947ca482017-07-25 14:28:03 -0700190 }
191 Log.e(TAG, "Expected start menu activity request timed out");
192 };
Winson Chung15504af2016-11-02 18:11:36 -0700193
Winson Chung97a60d92017-01-18 16:01:53 -0800194 private ActionListener mMediaActionListener = new ActionListener() {
195 @Override
196 public void onMediaActionsChanged(List<RemoteAction> mediaActions) {
197 mMediaActions = new ParceledListSlice<>(mediaActions);
198 updateMenuActions();
199 }
200 };
201
Winson Chung15504af2016-11-02 18:11:36 -0700202 public PipMenuActivityController(Context context, IActivityManager activityManager,
Winson Chungd2d90972017-02-28 11:40:41 -0800203 PipMediaController mediaController, InputConsumerController inputConsumerController) {
Winson Chung15504af2016-11-02 18:11:36 -0700204 mContext = context;
205 mActivityManager = activityManager;
Winson Chung97a60d92017-01-18 16:01:53 -0800206 mMediaController = mediaController;
Winson Chungd2d90972017-02-28 11:40:41 -0800207 mInputConsumerController = inputConsumerController;
208 }
209
Winson Chungbca03112017-08-16 10:38:15 -0700210 public boolean isMenuActivityVisible() {
211 return mToActivityMessenger != null;
212 }
213
Winson Chungd2d90972017-02-28 11:40:41 -0800214 public void onActivityPinned() {
Mady Mellor637cd482017-03-21 10:39:42 -0700215 if (mMenuState == MENU_STATE_NONE) {
Winson Chungd2d90972017-02-28 11:40:41 -0800216 // If the menu is not visible, then re-register the input consumer if it is not already
217 // registered
218 mInputConsumerController.registerInputConsumer();
219 }
Winson Chung15504af2016-11-02 18:11:36 -0700220 }
221
Winson Chung85d3c8a2017-09-15 15:41:00 -0700222 public void onActivityUnpinned() {
Winson Chung947ca482017-07-25 14:28:03 -0700223 hideMenu();
224 setStartActivityRequested(false);
225 }
226
Winson Chung34488242017-04-26 15:53:51 -0700227 public void onPinnedStackAnimationEnded() {
228 // Note: Only active menu activities care about this event
229 if (mToActivityMessenger != null) {
230 Message m = Message.obtain();
231 m.what = PipMenuActivity.MESSAGE_ANIMATION_ENDED;
232 try {
233 mToActivityMessenger.send(m);
234 } catch (RemoteException e) {
235 Log.e(TAG, "Could not notify menu pinned animation ended", e);
236 }
237 }
238 }
239
Winson Chung15504af2016-11-02 18:11:36 -0700240 /**
241 * Adds a new menu activity listener.
242 */
243 public void addListener(Listener listener) {
244 if (!mListeners.contains(listener)) {
245 mListeners.add(listener);
246 }
247 }
248
249 /**
Mady Mellor81d40612017-03-10 15:14:10 -0800250 * Updates the appearance of the menu and scrim on top of the PiP while dismissing.
251 */
252 public void setDismissFraction(float fraction) {
Winson Chung87e5d552017-04-05 11:49:38 -0700253 if (DEBUG) {
254 Log.d(TAG, "setDismissFraction() hasActivity=" + (mToActivityMessenger != null)
255 + " fraction=" + fraction);
256 }
Mady Mellor81d40612017-03-10 15:14:10 -0800257 if (mToActivityMessenger != null) {
Winson Chung0f873de2017-03-30 10:26:48 -0700258 mTmpDismissFractionData.clear();
259 mTmpDismissFractionData.putFloat(EXTRA_DISMISS_FRACTION, fraction);
Mady Mellor81d40612017-03-10 15:14:10 -0800260 Message m = Message.obtain();
261 m.what = PipMenuActivity.MESSAGE_UPDATE_DISMISS_FRACTION;
Winson Chung0f873de2017-03-30 10:26:48 -0700262 m.obj = mTmpDismissFractionData;
Mady Mellor81d40612017-03-10 15:14:10 -0800263 try {
264 mToActivityMessenger.send(m);
265 } catch (RemoteException e) {
Mady Mellor637cd482017-03-21 10:39:42 -0700266 Log.e(TAG, "Could not notify menu to update dismiss fraction", e);
Mady Mellor81d40612017-03-10 15:14:10 -0800267 }
Winson Chung947ca482017-07-25 14:28:03 -0700268 } else if (!mStartActivityRequested || isStartActivityRequestedElapsed()) {
269 // If we haven't requested the start activity, or if it previously took too long to
270 // start, then start it
Mady Mellor637cd482017-03-21 10:39:42 -0700271 startMenuActivity(MENU_STATE_NONE, null /* stackBounds */,
Winson Chungbb787442017-09-01 11:33:47 -0700272 null /* movementBounds */, false /* allowMenuTimeout */,
273 false /* resizeMenuOnShow */);
Mady Mellor81d40612017-03-10 15:14:10 -0800274 }
275 }
276
277 /**
Winson Chung15504af2016-11-02 18:11:36 -0700278 * Shows the menu activity.
279 */
Mady Mellor637cd482017-03-21 10:39:42 -0700280 public void showMenu(int menuState, Rect stackBounds, Rect movementBounds,
Winson Chungbb787442017-09-01 11:33:47 -0700281 boolean allowMenuTimeout, boolean willResizeMenu) {
Winson Chung87e5d552017-04-05 11:49:38 -0700282 if (DEBUG) {
Winson Chungbb233762017-05-15 14:20:46 -0700283 Log.d(TAG, "showMenu() state=" + menuState
284 + " hasActivity=" + (mToActivityMessenger != null)
285 + " callers=\n" + Debug.getCallers(5, " "));
Winson Chung87e5d552017-04-05 11:49:38 -0700286 }
Winson Chungbb787442017-09-01 11:33:47 -0700287
Winson Chungc75ffe82016-12-16 16:20:16 -0800288 if (mToActivityMessenger != null) {
Winson Chung0f873de2017-03-30 10:26:48 -0700289 Bundle data = new Bundle();
Mady Mellor637cd482017-03-21 10:39:42 -0700290 data.putInt(EXTRA_MENU_STATE, menuState);
Winson Chung0f873de2017-03-30 10:26:48 -0700291 data.putParcelable(EXTRA_STACK_BOUNDS, stackBounds);
292 data.putParcelable(EXTRA_MOVEMENT_BOUNDS, movementBounds);
293 data.putBoolean(EXTRA_ALLOW_TIMEOUT, allowMenuTimeout);
Winson Chungbb787442017-09-01 11:33:47 -0700294 data.putBoolean(EXTRA_WILL_RESIZE_MENU, willResizeMenu);
Winson Chungc75ffe82016-12-16 16:20:16 -0800295 Message m = Message.obtain();
296 m.what = PipMenuActivity.MESSAGE_SHOW_MENU;
Winson Chung0f873de2017-03-30 10:26:48 -0700297 m.obj = data;
Winson Chungc75ffe82016-12-16 16:20:16 -0800298 try {
299 mToActivityMessenger.send(m);
300 } catch (RemoteException e) {
301 Log.e(TAG, "Could not notify menu to show", e);
Winson Chung15504af2016-11-02 18:11:36 -0700302 }
Winson Chung947ca482017-07-25 14:28:03 -0700303 } else if (!mStartActivityRequested || isStartActivityRequestedElapsed()) {
304 // If we haven't requested the start activity, or if it previously took too long to
305 // start, then start it
Winson Chungbb787442017-09-01 11:33:47 -0700306 startMenuActivity(menuState, stackBounds, movementBounds, allowMenuTimeout,
307 willResizeMenu);
Winson Chung15504af2016-11-02 18:11:36 -0700308 }
309 }
310
311 /**
Mady Mellora7f69742017-02-03 11:00:20 -0800312 * Pokes the menu, indicating that the user is interacting with it.
313 */
314 public void pokeMenu() {
Winson Chung87e5d552017-04-05 11:49:38 -0700315 if (DEBUG) {
316 Log.d(TAG, "pokeMenu() hasActivity=" + (mToActivityMessenger != null));
317 }
Mady Mellora7f69742017-02-03 11:00:20 -0800318 if (mToActivityMessenger != null) {
319 Message m = Message.obtain();
320 m.what = PipMenuActivity.MESSAGE_POKE_MENU;
321 try {
322 mToActivityMessenger.send(m);
323 } catch (RemoteException e) {
324 Log.e(TAG, "Could not notify poke menu", e);
325 }
326 }
327 }
328
329 /**
Winson Chung15504af2016-11-02 18:11:36 -0700330 * Hides the menu activity.
331 */
332 public void hideMenu() {
Winson Chung87e5d552017-04-05 11:49:38 -0700333 if (DEBUG) {
Winson Chungbb233762017-05-15 14:20:46 -0700334 Log.d(TAG, "hideMenu() state=" + mMenuState
335 + " hasActivity=" + (mToActivityMessenger != null)
336 + " callers=\n" + Debug.getCallers(5, " "));
Winson Chung87e5d552017-04-05 11:49:38 -0700337 }
Winson Chung15504af2016-11-02 18:11:36 -0700338 if (mToActivityMessenger != null) {
339 Message m = Message.obtain();
Winson Chungc75ffe82016-12-16 16:20:16 -0800340 m.what = PipMenuActivity.MESSAGE_HIDE_MENU;
Winson Chung15504af2016-11-02 18:11:36 -0700341 try {
342 mToActivityMessenger.send(m);
343 } catch (RemoteException e) {
Winson Chungc75ffe82016-12-16 16:20:16 -0800344 Log.e(TAG, "Could not notify menu to hide", e);
Winson Chung15504af2016-11-02 18:11:36 -0700345 }
Winson Chung15504af2016-11-02 18:11:36 -0700346 }
347 }
Winson Chunga29eb982016-12-14 12:01:27 -0800348
349 /**
Winson Chung2dbcf092018-10-24 13:00:41 -0700350 * Hides the menu activity.
351 */
352 public void hideMenu(Runnable onStartCallback, Runnable onEndCallback) {
353 if (mStartActivityRequested) {
354 // If the menu has been start-requested, but not actually started, then we defer the
355 // trigger callback until the menu has started and called back to the controller.
356 mOnAnimationEndRunnable = onEndCallback;
357 onStartCallback.run();
358
359 // Fallback for b/63752800, we have started the PipMenuActivity but it has not made any
360 // callbacks. Don't continue to wait for the menu to show past some timeout.
361 mHandler.removeCallbacks(mStartActivityRequestedTimeoutRunnable);
362 mHandler.postDelayed(mStartActivityRequestedTimeoutRunnable,
363 START_ACTIVITY_REQUEST_TIMEOUT_MS);
364 } else if (mMenuState != MENU_STATE_NONE && mToActivityMessenger != null) {
365 // If the menu is visible in either the closed or full state, then hide the menu and
366 // trigger the animation trigger afterwards
367 onStartCallback.run();
368 Message m = Message.obtain();
369 m.what = PipMenuActivity.MESSAGE_HIDE_MENU;
370 m.obj = onEndCallback;
371 try {
372 mToActivityMessenger.send(m);
373 } catch (RemoteException e) {
374 Log.e(TAG, "Could not notify hide menu", e);
375 }
376 }
377 }
378
379 /**
Winson Chung79f852e2017-05-04 15:06:18 -0700380 * Preemptively mark the menu as invisible, used when we are directly manipulating the pinned
381 * stack and don't want to trigger a resize which can animate the stack in a conflicting way
382 * (ie. when manually expanding or dismissing).
383 */
384 public void hideMenuWithoutResize() {
385 onMenuStateChanged(MENU_STATE_NONE, false /* resize */);
386 }
387
388 /**
Winson Chung97a60d92017-01-18 16:01:53 -0800389 * Sets the menu actions to the actions provided by the current PiP activity.
Winson Chunga29eb982016-12-14 12:01:27 -0800390 */
Winson Chung97a60d92017-01-18 16:01:53 -0800391 public void setAppActions(ParceledListSlice appActions) {
392 mAppActions = appActions;
393 updateMenuActions();
394 }
Winson Chunga29eb982016-12-14 12:01:27 -0800395
Winson Chung97a60d92017-01-18 16:01:53 -0800396 /**
397 * @return the best set of actions to show in the PiP menu.
398 */
399 private ParceledListSlice resolveMenuActions() {
400 if (isValidActions(mAppActions)) {
401 return mAppActions;
402 }
403 return mMediaActions;
404 }
405
406 /**
Mady Mellor81d40612017-03-10 15:14:10 -0800407 * Starts the menu activity on the top task of the pinned stack.
408 */
Mady Mellor637cd482017-03-21 10:39:42 -0700409 private void startMenuActivity(int menuState, Rect stackBounds, Rect movementBounds,
Winson Chungbb787442017-09-01 11:33:47 -0700410 boolean allowMenuTimeout, boolean willResizeMenu) {
Mady Mellor81d40612017-03-10 15:14:10 -0800411 try {
Wale Ogunwale04d9cb52018-04-30 13:55:07 -0700412 StackInfo pinnedStackInfo = ActivityTaskManager.getService().getStackInfo(
Wale Ogunwale68278562017-09-23 17:13:55 -0700413 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
Mady Mellor81d40612017-03-10 15:14:10 -0800414 if (pinnedStackInfo != null && pinnedStackInfo.taskIds != null &&
415 pinnedStackInfo.taskIds.length > 0) {
416 Intent intent = new Intent(mContext, PipMenuActivity.class);
417 intent.putExtra(EXTRA_CONTROLLER_MESSENGER, mMessenger);
418 intent.putExtra(EXTRA_ACTIONS, resolveMenuActions());
419 if (stackBounds != null) {
Winson Chung853c99a2017-03-21 22:16:42 -0700420 intent.putExtra(EXTRA_STACK_BOUNDS, stackBounds);
Mady Mellor81d40612017-03-10 15:14:10 -0800421 }
422 if (movementBounds != null) {
Winson Chung853c99a2017-03-21 22:16:42 -0700423 intent.putExtra(EXTRA_MOVEMENT_BOUNDS, movementBounds);
Mady Mellor81d40612017-03-10 15:14:10 -0800424 }
Mady Mellor637cd482017-03-21 10:39:42 -0700425 intent.putExtra(EXTRA_MENU_STATE, menuState);
Winson Chung0f873de2017-03-30 10:26:48 -0700426 intent.putExtra(EXTRA_ALLOW_TIMEOUT, allowMenuTimeout);
Winson Chungbb787442017-09-01 11:33:47 -0700427 intent.putExtra(EXTRA_WILL_RESIZE_MENU, willResizeMenu);
Mady Mellor81d40612017-03-10 15:14:10 -0800428 ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
429 options.setLaunchTaskId(
430 pinnedStackInfo.taskIds[pinnedStackInfo.taskIds.length - 1]);
431 options.setTaskOverlay(true, true /* canResume */);
432 mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
Winson Chung947ca482017-07-25 14:28:03 -0700433 setStartActivityRequested(true);
Mady Mellor81d40612017-03-10 15:14:10 -0800434 } else {
435 Log.e(TAG, "No PIP tasks found");
436 }
437 } catch (RemoteException e) {
Winson Chung947ca482017-07-25 14:28:03 -0700438 setStartActivityRequested(false);
Mady Mellor81d40612017-03-10 15:14:10 -0800439 Log.e(TAG, "Error showing PIP menu activity", e);
440 }
441 }
442
443 /**
Winson Chung97a60d92017-01-18 16:01:53 -0800444 * Updates the PiP menu activity with the best set of actions provided.
445 */
446 private void updateMenuActions() {
Winson Chunga29eb982016-12-14 12:01:27 -0800447 if (mToActivityMessenger != null) {
Winson Chunge7a3d222017-03-09 13:26:45 -0800448 // Fetch the pinned stack bounds
449 Rect stackBounds = null;
450 try {
Wale Ogunwale04d9cb52018-04-30 13:55:07 -0700451 StackInfo pinnedStackInfo = ActivityTaskManager.getService().getStackInfo(
Wale Ogunwale68278562017-09-23 17:13:55 -0700452 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
Winson Chunge7a3d222017-03-09 13:26:45 -0800453 if (pinnedStackInfo != null) {
454 stackBounds = pinnedStackInfo.bounds;
455 }
456 } catch (RemoteException e) {
457 Log.e(TAG, "Error showing PIP menu activity", e);
458 }
459
Winson Chung0f873de2017-03-30 10:26:48 -0700460 Bundle data = new Bundle();
461 data.putParcelable(EXTRA_STACK_BOUNDS, stackBounds);
462 data.putParcelable(EXTRA_ACTIONS, resolveMenuActions());
Winson Chunga29eb982016-12-14 12:01:27 -0800463 Message m = Message.obtain();
464 m.what = PipMenuActivity.MESSAGE_UPDATE_ACTIONS;
Winson Chung0f873de2017-03-30 10:26:48 -0700465 m.obj = data;
Winson Chunga29eb982016-12-14 12:01:27 -0800466 try {
467 mToActivityMessenger.send(m);
468 } catch (RemoteException e) {
469 Log.e(TAG, "Could not notify menu activity to update actions", e);
470 }
471 }
472 }
Winson Chung97a60d92017-01-18 16:01:53 -0800473
474 /**
475 * Returns whether the set of actions are valid.
476 */
477 private boolean isValidActions(ParceledListSlice actions) {
478 return actions != null && actions.getList().size() > 0;
479 }
480
481 /**
Winson Chung947ca482017-07-25 14:28:03 -0700482 * @return whether the time of the activity request has exceeded the timeout.
483 */
484 private boolean isStartActivityRequestedElapsed() {
485 return (SystemClock.uptimeMillis() - mStartActivityRequestedTime)
486 >= START_ACTIVITY_REQUEST_TIMEOUT_MS;
487 }
488
489 /**
Winson Chung97a60d92017-01-18 16:01:53 -0800490 * Handles changes in menu visibility.
491 */
Mady Mellor637cd482017-03-21 10:39:42 -0700492 private void onMenuStateChanged(int menuState, boolean resize) {
Winson Chung87e5d552017-04-05 11:49:38 -0700493 if (DEBUG) {
Mady Mellor637cd482017-03-21 10:39:42 -0700494 Log.d(TAG, "onMenuStateChanged() mMenuState=" + mMenuState
495 + " menuState=" + menuState + " resize=" + resize);
Winson Chung87e5d552017-04-05 11:49:38 -0700496 }
Mady Mellor637cd482017-03-21 10:39:42 -0700497 if (menuState == MENU_STATE_NONE) {
Winson Chungd2d90972017-02-28 11:40:41 -0800498 mInputConsumerController.registerInputConsumer();
Mady Mellor637cd482017-03-21 10:39:42 -0700499 } else {
500 mInputConsumerController.unregisterInputConsumer();
Winson Chungd2d90972017-02-28 11:40:41 -0800501 }
Mady Mellor637cd482017-03-21 10:39:42 -0700502 if (menuState != mMenuState) {
503 mListeners.forEach(l -> l.onPipMenuStateChanged(menuState, resize));
504 if (menuState == MENU_STATE_FULL) {
Winson Chung97a60d92017-01-18 16:01:53 -0800505 // Once visible, start listening for media action changes. This call will trigger
506 // the menu actions to be updated again.
507 mMediaController.addListener(mMediaActionListener);
508 } else {
509 // Once hidden, stop listening for media action changes. This call will trigger
510 // the menu actions to be updated again.
511 mMediaController.removeListener(mMediaActionListener);
512 }
513 }
Mady Mellor637cd482017-03-21 10:39:42 -0700514 mMenuState = menuState;
Winson Chung97a60d92017-01-18 16:01:53 -0800515 }
Winson Chung29a78652017-02-09 18:35:26 -0800516
Winson Chung947ca482017-07-25 14:28:03 -0700517 private void setStartActivityRequested(boolean requested) {
518 mHandler.removeCallbacks(mStartActivityRequestedTimeoutRunnable);
519 mStartActivityRequested = requested;
520 mStartActivityRequestedTime = requested ? SystemClock.uptimeMillis() : 0;
521 }
522
Winson Chung29a78652017-02-09 18:35:26 -0800523 public void dump(PrintWriter pw, String prefix) {
524 final String innerPrefix = prefix + " ";
525 pw.println(prefix + TAG);
Mady Mellor637cd482017-03-21 10:39:42 -0700526 pw.println(innerPrefix + "mMenuState=" + mMenuState);
Winson Chung87e5d552017-04-05 11:49:38 -0700527 pw.println(innerPrefix + "mToActivityMessenger=" + mToActivityMessenger);
Winson Chung29a78652017-02-09 18:35:26 -0800528 pw.println(innerPrefix + "mListeners=" + mListeners.size());
Winson Chung947ca482017-07-25 14:28:03 -0700529 pw.println(innerPrefix + "mStartActivityRequested=" + mStartActivityRequested);
530 pw.println(innerPrefix + "mStartActivityRequestedTime=" + mStartActivityRequestedTime);
Winson Chung29a78652017-02-09 18:35:26 -0800531 }
Winson Chung15504af2016-11-02 18:11:36 -0700532}