blob: c558056530b667898cff52c7fdc8bfe143b6709d [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
19import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
Winson Chung15504af2016-11-02 18:11:36 -070020
21import android.app.ActivityManager.StackInfo;
22import android.app.ActivityOptions;
23import android.app.IActivityManager;
Winson Chung97a60d92017-01-18 16:01:53 -080024import android.app.RemoteAction;
Winson Chung947ca482017-07-25 14:28:03 -070025import android.content.ComponentName;
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;
33import android.os.Message;
34import android.os.Messenger;
35import android.os.RemoteException;
Winson Chung947ca482017-07-25 14:28:03 -070036import android.os.SystemClock;
Winson Chung15504af2016-11-02 18:11:36 -070037import android.os.UserHandle;
38import android.util.Log;
39import android.view.IWindowManager;
40
Winson Chung97a60d92017-01-18 16:01:53 -080041import com.android.systemui.pip.phone.PipMediaController.ActionListener;
Winson Chungb5026902017-05-03 12:45:13 -070042import com.android.systemui.recents.events.EventBus;
43import com.android.systemui.recents.events.component.HidePipMenuEvent;
44import com.android.systemui.recents.misc.ReferenceCountedTrigger;
Winson Chung15504af2016-11-02 18:11:36 -070045
Winson Chung29a78652017-02-09 18:35:26 -080046import java.io.PrintWriter;
Winson Chung97a60d92017-01-18 16:01:53 -080047import java.util.ArrayList;
48import java.util.List;
49
50/**
Mady Mellor81d40612017-03-10 15:14:10 -080051 * Manages the PiP menu activity which can show menu options or a scrim.
Winson Chung97a60d92017-01-18 16:01:53 -080052 *
53 * The current media session provides actions whenever there are no valid actions provided by the
54 * current PiP activity. Otherwise, those actions always take precedence.
55 */
Winson Chung15504af2016-11-02 18:11:36 -070056public class PipMenuActivityController {
57
Winson Chung97a60d92017-01-18 16:01:53 -080058 private static final String TAG = "PipMenuActController";
Winson Chung87e5d552017-04-05 11:49:38 -070059 private static final boolean DEBUG = false;
Winson Chung15504af2016-11-02 18:11:36 -070060
61 public static final String EXTRA_CONTROLLER_MESSENGER = "messenger";
Winson Chunga29eb982016-12-14 12:01:27 -080062 public static final String EXTRA_ACTIONS = "actions";
Winson Chunge7a3d222017-03-09 13:26:45 -080063 public static final String EXTRA_STACK_BOUNDS = "stack_bounds";
64 public static final String EXTRA_MOVEMENT_BOUNDS = "movement_bounds";
Winson Chung0f873de2017-03-30 10:26:48 -070065 public static final String EXTRA_ALLOW_TIMEOUT = "allow_timeout";
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;
71 public static final int MESSAGE_MINIMIZE_PIP = 102;
72 public static final int MESSAGE_DISMISS_PIP = 103;
Winson Chungc75ffe82016-12-16 16:20:16 -080073 public static final int MESSAGE_UPDATE_ACTIVITY_CALLBACK = 104;
Winson Chungd2d90972017-02-28 11:40:41 -080074 public static final int MESSAGE_REGISTER_INPUT_CONSUMER = 105;
Winson Chung2824d7c2017-03-15 19:43:00 -070075 public static final int MESSAGE_UNREGISTER_INPUT_CONSUMER = 106;
Mady Mellor637cd482017-03-21 10:39:42 -070076 public static final int MESSAGE_SHOW_MENU = 107;
77
78 public static final int MENU_STATE_NONE = 0;
79 public static final int MENU_STATE_CLOSE = 1;
80 public static final int MENU_STATE_FULL = 2;
Winson Chung15504af2016-11-02 18:11:36 -070081
Winson Chung947ca482017-07-25 14:28:03 -070082 // The duration to wait before we consider the start activity as having timed out
83 private static final long START_ACTIVITY_REQUEST_TIMEOUT_MS = 300;
84
Winson Chung15504af2016-11-02 18:11:36 -070085 /**
86 * A listener interface to receive notification on changes in PIP.
87 */
88 public interface Listener {
89 /**
90 * Called when the PIP menu visibility changes.
Winson Chungd2d90972017-02-28 11:40:41 -080091 *
Mady Mellor637cd482017-03-21 10:39:42 -070092 * @param menuState the current state of the menu
93 * @param resize whether or not to resize the PiP with the state change
Winson Chung15504af2016-11-02 18:11:36 -070094 */
Mady Mellor637cd482017-03-21 10:39:42 -070095 void onPipMenuStateChanged(int menuState, boolean resize);
Winson Chunga29eb982016-12-14 12:01:27 -080096
97 /**
98 * Called when the PIP requested to be expanded.
99 */
100 void onPipExpand();
101
102 /**
103 * Called when the PIP requested to be minimized.
104 */
105 void onPipMinimize();
106
107 /**
Winson Chung14fbe142016-12-19 16:18:24 -0800108 * Called when the PIP requested to be dismissed.
Winson Chunga29eb982016-12-14 12:01:27 -0800109 */
110 void onPipDismiss();
Mady Mellor637cd482017-03-21 10:39:42 -0700111
112 /**
113 * Called when the PIP requested to show the menu.
114 */
115 void onPipShowMenu();
Winson Chung15504af2016-11-02 18:11:36 -0700116 }
117
118 private Context mContext;
119 private IActivityManager mActivityManager;
Winson Chung97a60d92017-01-18 16:01:53 -0800120 private PipMediaController mMediaController;
Winson Chungd2d90972017-02-28 11:40:41 -0800121 private InputConsumerController mInputConsumerController;
Winson Chunga29eb982016-12-14 12:01:27 -0800122
Winson Chung15504af2016-11-02 18:11:36 -0700123 private ArrayList<Listener> mListeners = new ArrayList<>();
Winson Chung97a60d92017-01-18 16:01:53 -0800124 private ParceledListSlice mAppActions;
125 private ParceledListSlice mMediaActions;
Mady Mellor637cd482017-03-21 10:39:42 -0700126 private int mMenuState;
Winson Chung15504af2016-11-02 18:11:36 -0700127
Winson Chung0f873de2017-03-30 10:26:48 -0700128 // The dismiss fraction update is sent frequently, so use a temporary bundle for the message
129 private Bundle mTmpDismissFractionData = new Bundle();
Winson Chung853c99a2017-03-21 22:16:42 -0700130
Winson Chungb5026902017-05-03 12:45:13 -0700131 private ReferenceCountedTrigger mOnAttachDecrementTrigger;
Mady Mellor81d40612017-03-10 15:14:10 -0800132 private boolean mStartActivityRequested;
Winson Chung947ca482017-07-25 14:28:03 -0700133 private long mStartActivityRequestedTime;
Winson Chung15504af2016-11-02 18:11:36 -0700134 private Messenger mToActivityMessenger;
Winson Chung947ca482017-07-25 14:28:03 -0700135 private Handler mHandler = new Handler() {
Winson Chung15504af2016-11-02 18:11:36 -0700136 @Override
137 public void handleMessage(Message msg) {
138 switch (msg.what) {
Mady Mellor637cd482017-03-21 10:39:42 -0700139 case MESSAGE_MENU_STATE_CHANGED: {
140 int menuState = msg.arg1;
141 onMenuStateChanged(menuState, true /* resize */);
Winson Chung15504af2016-11-02 18:11:36 -0700142 break;
143 }
144 case MESSAGE_EXPAND_PIP: {
Winson Chungc75ffe82016-12-16 16:20:16 -0800145 mListeners.forEach(l -> l.onPipExpand());
Winson Chunga29eb982016-12-14 12:01:27 -0800146 break;
147 }
148 case MESSAGE_MINIMIZE_PIP: {
Winson Chungc75ffe82016-12-16 16:20:16 -0800149 mListeners.forEach(l -> l.onPipMinimize());
Winson Chunga29eb982016-12-14 12:01:27 -0800150 break;
151 }
152 case MESSAGE_DISMISS_PIP: {
Winson Chungc75ffe82016-12-16 16:20:16 -0800153 mListeners.forEach(l -> l.onPipDismiss());
Mady Mellor637cd482017-03-21 10:39:42 -0700154 break;
155 }
156 case MESSAGE_SHOW_MENU: {
157 mListeners.forEach(l -> l.onPipShowMenu());
Winson Chungd2d90972017-02-28 11:40:41 -0800158 break;
159 }
160 case MESSAGE_REGISTER_INPUT_CONSUMER: {
161 mInputConsumerController.registerInputConsumer();
Winson Chungc75ffe82016-12-16 16:20:16 -0800162 break;
163 }
Winson Chung2824d7c2017-03-15 19:43:00 -0700164 case MESSAGE_UNREGISTER_INPUT_CONSUMER: {
165 mInputConsumerController.unregisterInputConsumer();
166 break;
167 }
Winson Chungc75ffe82016-12-16 16:20:16 -0800168 case MESSAGE_UPDATE_ACTIVITY_CALLBACK: {
169 mToActivityMessenger = msg.replyTo;
Winson Chung947ca482017-07-25 14:28:03 -0700170 setStartActivityRequested(false);
Winson Chungb5026902017-05-03 12:45:13 -0700171 if (mOnAttachDecrementTrigger != null) {
172 mOnAttachDecrementTrigger.decrement();
173 mOnAttachDecrementTrigger = null;
174 }
Winson Chung929d4f72017-01-13 10:21:33 -0800175 // Mark the menu as invisible once the activity finishes as well
176 if (mToActivityMessenger == null) {
Mady Mellor637cd482017-03-21 10:39:42 -0700177 onMenuStateChanged(MENU_STATE_NONE, true /* resize */);
Winson Chung929d4f72017-01-13 10:21:33 -0800178 }
Winson Chung15504af2016-11-02 18:11:36 -0700179 break;
180 }
181 }
182 }
Winson Chung947ca482017-07-25 14:28:03 -0700183 };
184 private Messenger mMessenger = new Messenger(mHandler);
185
186 private Runnable mStartActivityRequestedTimeoutRunnable = () -> {
187 setStartActivityRequested(false);
188 if (mOnAttachDecrementTrigger != null) {
189 mOnAttachDecrementTrigger.decrement();
190 mOnAttachDecrementTrigger = null;
191 }
192 Log.e(TAG, "Expected start menu activity request timed out");
193 };
Winson Chung15504af2016-11-02 18:11:36 -0700194
Winson Chung97a60d92017-01-18 16:01:53 -0800195 private ActionListener mMediaActionListener = new ActionListener() {
196 @Override
197 public void onMediaActionsChanged(List<RemoteAction> mediaActions) {
198 mMediaActions = new ParceledListSlice<>(mediaActions);
199 updateMenuActions();
200 }
201 };
202
Winson Chung15504af2016-11-02 18:11:36 -0700203 public PipMenuActivityController(Context context, IActivityManager activityManager,
Winson Chungd2d90972017-02-28 11:40:41 -0800204 PipMediaController mediaController, InputConsumerController inputConsumerController) {
Winson Chung15504af2016-11-02 18:11:36 -0700205 mContext = context;
206 mActivityManager = activityManager;
Winson Chung97a60d92017-01-18 16:01:53 -0800207 mMediaController = mediaController;
Winson Chungd2d90972017-02-28 11:40:41 -0800208 mInputConsumerController = inputConsumerController;
Winson Chungb5026902017-05-03 12:45:13 -0700209
210 EventBus.getDefault().register(this);
Winson Chungd2d90972017-02-28 11:40:41 -0800211 }
212
213 public void onActivityPinned() {
Mady Mellor637cd482017-03-21 10:39:42 -0700214 if (mMenuState == MENU_STATE_NONE) {
Winson Chungd2d90972017-02-28 11:40:41 -0800215 // If the menu is not visible, then re-register the input consumer if it is not already
216 // registered
217 mInputConsumerController.registerInputConsumer();
218 }
Winson Chung15504af2016-11-02 18:11:36 -0700219 }
220
Winson Chung947ca482017-07-25 14:28:03 -0700221 public void onActivityUnpinned(ComponentName topPipActivity) {
222 hideMenu();
223 setStartActivityRequested(false);
224 }
225
Winson Chung34488242017-04-26 15:53:51 -0700226 public void onPinnedStackAnimationEnded() {
227 // Note: Only active menu activities care about this event
228 if (mToActivityMessenger != null) {
229 Message m = Message.obtain();
230 m.what = PipMenuActivity.MESSAGE_ANIMATION_ENDED;
231 try {
232 mToActivityMessenger.send(m);
233 } catch (RemoteException e) {
234 Log.e(TAG, "Could not notify menu pinned animation ended", e);
235 }
236 }
237 }
238
Winson Chung15504af2016-11-02 18:11:36 -0700239 /**
240 * Adds a new menu activity listener.
241 */
242 public void addListener(Listener listener) {
243 if (!mListeners.contains(listener)) {
244 mListeners.add(listener);
245 }
246 }
247
248 /**
Mady Mellor81d40612017-03-10 15:14:10 -0800249 * Updates the appearance of the menu and scrim on top of the PiP while dismissing.
250 */
251 public void setDismissFraction(float fraction) {
Winson Chung87e5d552017-04-05 11:49:38 -0700252 if (DEBUG) {
253 Log.d(TAG, "setDismissFraction() hasActivity=" + (mToActivityMessenger != null)
254 + " fraction=" + fraction);
255 }
Mady Mellor81d40612017-03-10 15:14:10 -0800256 if (mToActivityMessenger != null) {
Winson Chung0f873de2017-03-30 10:26:48 -0700257 mTmpDismissFractionData.clear();
258 mTmpDismissFractionData.putFloat(EXTRA_DISMISS_FRACTION, fraction);
Mady Mellor81d40612017-03-10 15:14:10 -0800259 Message m = Message.obtain();
260 m.what = PipMenuActivity.MESSAGE_UPDATE_DISMISS_FRACTION;
Winson Chung0f873de2017-03-30 10:26:48 -0700261 m.obj = mTmpDismissFractionData;
Mady Mellor81d40612017-03-10 15:14:10 -0800262 try {
263 mToActivityMessenger.send(m);
264 } catch (RemoteException e) {
Mady Mellor637cd482017-03-21 10:39:42 -0700265 Log.e(TAG, "Could not notify menu to update dismiss fraction", e);
Mady Mellor81d40612017-03-10 15:14:10 -0800266 }
Winson Chung947ca482017-07-25 14:28:03 -0700267 } else if (!mStartActivityRequested || isStartActivityRequestedElapsed()) {
268 // If we haven't requested the start activity, or if it previously took too long to
269 // start, then start it
Mady Mellor637cd482017-03-21 10:39:42 -0700270 startMenuActivity(MENU_STATE_NONE, null /* stackBounds */,
271 null /* movementBounds */, false /* allowMenuTimeout */);
Mady Mellor81d40612017-03-10 15:14:10 -0800272 }
273 }
274
275 /**
Winson Chung15504af2016-11-02 18:11:36 -0700276 * Shows the menu activity.
277 */
Mady Mellor637cd482017-03-21 10:39:42 -0700278 public void showMenu(int menuState, Rect stackBounds, Rect movementBounds,
279 boolean allowMenuTimeout) {
Winson Chung87e5d552017-04-05 11:49:38 -0700280 if (DEBUG) {
Winson Chungbb233762017-05-15 14:20:46 -0700281 Log.d(TAG, "showMenu() state=" + menuState
282 + " hasActivity=" + (mToActivityMessenger != null)
283 + " callers=\n" + Debug.getCallers(5, " "));
Winson Chung87e5d552017-04-05 11:49:38 -0700284 }
Winson Chungc75ffe82016-12-16 16:20:16 -0800285 if (mToActivityMessenger != null) {
Winson Chung0f873de2017-03-30 10:26:48 -0700286 Bundle data = new Bundle();
Mady Mellor637cd482017-03-21 10:39:42 -0700287 data.putInt(EXTRA_MENU_STATE, menuState);
Winson Chung0f873de2017-03-30 10:26:48 -0700288 data.putParcelable(EXTRA_STACK_BOUNDS, stackBounds);
289 data.putParcelable(EXTRA_MOVEMENT_BOUNDS, movementBounds);
290 data.putBoolean(EXTRA_ALLOW_TIMEOUT, allowMenuTimeout);
Winson Chungc75ffe82016-12-16 16:20:16 -0800291 Message m = Message.obtain();
292 m.what = PipMenuActivity.MESSAGE_SHOW_MENU;
Winson Chung0f873de2017-03-30 10:26:48 -0700293 m.obj = data;
Winson Chungc75ffe82016-12-16 16:20:16 -0800294 try {
295 mToActivityMessenger.send(m);
296 } catch (RemoteException e) {
297 Log.e(TAG, "Could not notify menu to show", e);
Winson Chung15504af2016-11-02 18:11:36 -0700298 }
Winson Chung947ca482017-07-25 14:28:03 -0700299 } else if (!mStartActivityRequested || isStartActivityRequestedElapsed()) {
300 // If we haven't requested the start activity, or if it previously took too long to
301 // start, then start it
Mady Mellor637cd482017-03-21 10:39:42 -0700302 startMenuActivity(menuState, stackBounds, movementBounds, allowMenuTimeout);
Winson Chung15504af2016-11-02 18:11:36 -0700303 }
304 }
305
306 /**
Mady Mellora7f69742017-02-03 11:00:20 -0800307 * Pokes the menu, indicating that the user is interacting with it.
308 */
309 public void pokeMenu() {
Winson Chung87e5d552017-04-05 11:49:38 -0700310 if (DEBUG) {
311 Log.d(TAG, "pokeMenu() hasActivity=" + (mToActivityMessenger != null));
312 }
Mady Mellora7f69742017-02-03 11:00:20 -0800313 if (mToActivityMessenger != null) {
314 Message m = Message.obtain();
315 m.what = PipMenuActivity.MESSAGE_POKE_MENU;
316 try {
317 mToActivityMessenger.send(m);
318 } catch (RemoteException e) {
319 Log.e(TAG, "Could not notify poke menu", e);
320 }
321 }
322 }
323
324 /**
Winson Chung15504af2016-11-02 18:11:36 -0700325 * Hides the menu activity.
326 */
327 public void hideMenu() {
Winson Chung87e5d552017-04-05 11:49:38 -0700328 if (DEBUG) {
Winson Chungbb233762017-05-15 14:20:46 -0700329 Log.d(TAG, "hideMenu() state=" + mMenuState
330 + " hasActivity=" + (mToActivityMessenger != null)
331 + " callers=\n" + Debug.getCallers(5, " "));
Winson Chung87e5d552017-04-05 11:49:38 -0700332 }
Winson Chung15504af2016-11-02 18:11:36 -0700333 if (mToActivityMessenger != null) {
334 Message m = Message.obtain();
Winson Chungc75ffe82016-12-16 16:20:16 -0800335 m.what = PipMenuActivity.MESSAGE_HIDE_MENU;
Winson Chung15504af2016-11-02 18:11:36 -0700336 try {
337 mToActivityMessenger.send(m);
338 } catch (RemoteException e) {
Winson Chungc75ffe82016-12-16 16:20:16 -0800339 Log.e(TAG, "Could not notify menu to hide", e);
Winson Chung15504af2016-11-02 18:11:36 -0700340 }
Winson Chung15504af2016-11-02 18:11:36 -0700341 }
342 }
Winson Chunga29eb982016-12-14 12:01:27 -0800343
344 /**
Winson Chung79f852e2017-05-04 15:06:18 -0700345 * Preemptively mark the menu as invisible, used when we are directly manipulating the pinned
346 * stack and don't want to trigger a resize which can animate the stack in a conflicting way
347 * (ie. when manually expanding or dismissing).
348 */
349 public void hideMenuWithoutResize() {
350 onMenuStateChanged(MENU_STATE_NONE, false /* resize */);
351 }
352
353 /**
Winson Chung97a60d92017-01-18 16:01:53 -0800354 * Sets the menu actions to the actions provided by the current PiP activity.
Winson Chunga29eb982016-12-14 12:01:27 -0800355 */
Winson Chung97a60d92017-01-18 16:01:53 -0800356 public void setAppActions(ParceledListSlice appActions) {
357 mAppActions = appActions;
358 updateMenuActions();
359 }
Winson Chunga29eb982016-12-14 12:01:27 -0800360
Winson Chung97a60d92017-01-18 16:01:53 -0800361 /**
362 * @return the best set of actions to show in the PiP menu.
363 */
364 private ParceledListSlice resolveMenuActions() {
365 if (isValidActions(mAppActions)) {
366 return mAppActions;
367 }
368 return mMediaActions;
369 }
370
371 /**
Mady Mellor81d40612017-03-10 15:14:10 -0800372 * Starts the menu activity on the top task of the pinned stack.
373 */
Mady Mellor637cd482017-03-21 10:39:42 -0700374 private void startMenuActivity(int menuState, Rect stackBounds, Rect movementBounds,
Winson Chung0f873de2017-03-30 10:26:48 -0700375 boolean allowMenuTimeout) {
Mady Mellor81d40612017-03-10 15:14:10 -0800376 try {
377 StackInfo pinnedStackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
378 if (pinnedStackInfo != null && pinnedStackInfo.taskIds != null &&
379 pinnedStackInfo.taskIds.length > 0) {
380 Intent intent = new Intent(mContext, PipMenuActivity.class);
381 intent.putExtra(EXTRA_CONTROLLER_MESSENGER, mMessenger);
382 intent.putExtra(EXTRA_ACTIONS, resolveMenuActions());
383 if (stackBounds != null) {
Winson Chung853c99a2017-03-21 22:16:42 -0700384 intent.putExtra(EXTRA_STACK_BOUNDS, stackBounds);
Mady Mellor81d40612017-03-10 15:14:10 -0800385 }
386 if (movementBounds != null) {
Winson Chung853c99a2017-03-21 22:16:42 -0700387 intent.putExtra(EXTRA_MOVEMENT_BOUNDS, movementBounds);
Mady Mellor81d40612017-03-10 15:14:10 -0800388 }
Mady Mellor637cd482017-03-21 10:39:42 -0700389 intent.putExtra(EXTRA_MENU_STATE, menuState);
Winson Chung0f873de2017-03-30 10:26:48 -0700390 intent.putExtra(EXTRA_ALLOW_TIMEOUT, allowMenuTimeout);
Mady Mellor81d40612017-03-10 15:14:10 -0800391 ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
392 options.setLaunchTaskId(
393 pinnedStackInfo.taskIds[pinnedStackInfo.taskIds.length - 1]);
394 options.setTaskOverlay(true, true /* canResume */);
395 mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
Winson Chung947ca482017-07-25 14:28:03 -0700396 setStartActivityRequested(true);
Mady Mellor81d40612017-03-10 15:14:10 -0800397 } else {
398 Log.e(TAG, "No PIP tasks found");
399 }
400 } catch (RemoteException e) {
Winson Chung947ca482017-07-25 14:28:03 -0700401 setStartActivityRequested(false);
Mady Mellor81d40612017-03-10 15:14:10 -0800402 Log.e(TAG, "Error showing PIP menu activity", e);
403 }
404 }
405
406 /**
Winson Chung97a60d92017-01-18 16:01:53 -0800407 * Updates the PiP menu activity with the best set of actions provided.
408 */
409 private void updateMenuActions() {
Winson Chunga29eb982016-12-14 12:01:27 -0800410 if (mToActivityMessenger != null) {
Winson Chunge7a3d222017-03-09 13:26:45 -0800411 // Fetch the pinned stack bounds
412 Rect stackBounds = null;
413 try {
414 StackInfo pinnedStackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
415 if (pinnedStackInfo != null) {
416 stackBounds = pinnedStackInfo.bounds;
417 }
418 } catch (RemoteException e) {
419 Log.e(TAG, "Error showing PIP menu activity", e);
420 }
421
Winson Chung0f873de2017-03-30 10:26:48 -0700422 Bundle data = new Bundle();
423 data.putParcelable(EXTRA_STACK_BOUNDS, stackBounds);
424 data.putParcelable(EXTRA_ACTIONS, resolveMenuActions());
Winson Chunga29eb982016-12-14 12:01:27 -0800425 Message m = Message.obtain();
426 m.what = PipMenuActivity.MESSAGE_UPDATE_ACTIONS;
Winson Chung0f873de2017-03-30 10:26:48 -0700427 m.obj = data;
Winson Chunga29eb982016-12-14 12:01:27 -0800428 try {
429 mToActivityMessenger.send(m);
430 } catch (RemoteException e) {
431 Log.e(TAG, "Could not notify menu activity to update actions", e);
432 }
433 }
434 }
Winson Chung97a60d92017-01-18 16:01:53 -0800435
436 /**
437 * Returns whether the set of actions are valid.
438 */
439 private boolean isValidActions(ParceledListSlice actions) {
440 return actions != null && actions.getList().size() > 0;
441 }
442
443 /**
Winson Chung947ca482017-07-25 14:28:03 -0700444 * @return whether the time of the activity request has exceeded the timeout.
445 */
446 private boolean isStartActivityRequestedElapsed() {
447 return (SystemClock.uptimeMillis() - mStartActivityRequestedTime)
448 >= START_ACTIVITY_REQUEST_TIMEOUT_MS;
449 }
450
451 /**
Winson Chung97a60d92017-01-18 16:01:53 -0800452 * Handles changes in menu visibility.
453 */
Mady Mellor637cd482017-03-21 10:39:42 -0700454 private void onMenuStateChanged(int menuState, boolean resize) {
Winson Chung87e5d552017-04-05 11:49:38 -0700455 if (DEBUG) {
Mady Mellor637cd482017-03-21 10:39:42 -0700456 Log.d(TAG, "onMenuStateChanged() mMenuState=" + mMenuState
457 + " menuState=" + menuState + " resize=" + resize);
Winson Chung87e5d552017-04-05 11:49:38 -0700458 }
Mady Mellor637cd482017-03-21 10:39:42 -0700459 if (menuState == MENU_STATE_NONE) {
Winson Chungd2d90972017-02-28 11:40:41 -0800460 mInputConsumerController.registerInputConsumer();
Mady Mellor637cd482017-03-21 10:39:42 -0700461 } else {
462 mInputConsumerController.unregisterInputConsumer();
Winson Chungd2d90972017-02-28 11:40:41 -0800463 }
Mady Mellor637cd482017-03-21 10:39:42 -0700464 if (menuState != mMenuState) {
465 mListeners.forEach(l -> l.onPipMenuStateChanged(menuState, resize));
466 if (menuState == MENU_STATE_FULL) {
Winson Chung97a60d92017-01-18 16:01:53 -0800467 // Once visible, start listening for media action changes. This call will trigger
468 // the menu actions to be updated again.
469 mMediaController.addListener(mMediaActionListener);
470 } else {
471 // Once hidden, stop listening for media action changes. This call will trigger
472 // the menu actions to be updated again.
473 mMediaController.removeListener(mMediaActionListener);
474 }
475 }
Mady Mellor637cd482017-03-21 10:39:42 -0700476 mMenuState = menuState;
Winson Chung97a60d92017-01-18 16:01:53 -0800477 }
Winson Chung29a78652017-02-09 18:35:26 -0800478
Winson Chung947ca482017-07-25 14:28:03 -0700479 private void setStartActivityRequested(boolean requested) {
480 mHandler.removeCallbacks(mStartActivityRequestedTimeoutRunnable);
481 mStartActivityRequested = requested;
482 mStartActivityRequestedTime = requested ? SystemClock.uptimeMillis() : 0;
483 }
484
Winson Chungb5026902017-05-03 12:45:13 -0700485 public final void onBusEvent(HidePipMenuEvent event) {
486 if (mStartActivityRequested) {
487 // If the menu has been start-requested, but not actually started, then we defer the
Winson Chung947ca482017-07-25 14:28:03 -0700488 // trigger callback until the menu has started and called back to the controller.
Winson Chungb5026902017-05-03 12:45:13 -0700489 mOnAttachDecrementTrigger = event.getAnimationTrigger();
490 mOnAttachDecrementTrigger.increment();
Winson Chung947ca482017-07-25 14:28:03 -0700491
492 // Fallback for b/63752800, we have started the PipMenuActivity but it has not made any
493 // callbacks. Don't continue to wait for the menu to show past some timeout.
494 mHandler.removeCallbacks(mStartActivityRequestedTimeoutRunnable);
495 mHandler.postDelayed(mStartActivityRequestedTimeoutRunnable,
496 START_ACTIVITY_REQUEST_TIMEOUT_MS);
Winson Chungb5026902017-05-03 12:45:13 -0700497 }
498 }
499
Winson Chung29a78652017-02-09 18:35:26 -0800500 public void dump(PrintWriter pw, String prefix) {
501 final String innerPrefix = prefix + " ";
502 pw.println(prefix + TAG);
Mady Mellor637cd482017-03-21 10:39:42 -0700503 pw.println(innerPrefix + "mMenuState=" + mMenuState);
Winson Chung87e5d552017-04-05 11:49:38 -0700504 pw.println(innerPrefix + "mToActivityMessenger=" + mToActivityMessenger);
Winson Chung29a78652017-02-09 18:35:26 -0800505 pw.println(innerPrefix + "mListeners=" + mListeners.size());
Winson Chung947ca482017-07-25 14:28:03 -0700506 pw.println(innerPrefix + "mStartActivityRequested=" + mStartActivityRequested);
507 pw.println(innerPrefix + "mStartActivityRequestedTime=" + mStartActivityRequestedTime);
Winson Chung29a78652017-02-09 18:35:26 -0800508 }
Winson Chung15504af2016-11-02 18:11:36 -0700509}