Merge "TV Pip fixes after menu migration to Window"
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
index 763370b..aa888c6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
@@ -37,7 +37,6 @@
import android.content.pm.ParceledListSlice;
import android.content.res.Configuration;
import android.graphics.Rect;
-import android.os.Debug;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -56,8 +55,6 @@
import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipTaskOrganizer;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Objects;
/**
@@ -87,42 +84,21 @@
private static final int TASK_ID_NO_PIP = -1;
private static final int INVALID_RESOURCE_TYPE = -1;
- public static final int SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH = 0x1;
-
- /**
- * PIPed activity is playing a media and it can be paused.
- */
- static final int PLAYBACK_STATE_PLAYING = 0;
- /**
- * PIPed activity has a paused media and it can be played.
- */
- static final int PLAYBACK_STATE_PAUSED = 1;
- /**
- * Users are unable to control PIPed activity's media playback.
- */
- static final int PLAYBACK_STATE_UNAVAILABLE = 2;
-
- private static final int CLOSE_PIP_WHEN_MEDIA_SESSION_GONE_TIMEOUT_MS = 3000;
-
- private int mSuspendPipResizingReason;
-
private final Context mContext;
private final PipBoundsState mPipBoundsState;
private final PipBoundsAlgorithm mPipBoundsAlgorithm;
private final PipTaskOrganizer mPipTaskOrganizer;
private final PipMediaController mPipMediaController;
private final TvPipMenuController mTvPipMenuController;
+ private final PipNotification mPipNotification;
private IActivityTaskManager mActivityTaskManager;
private int mState = STATE_NO_PIP;
- private int mResumeResizePinnedStackRunnableState = STATE_NO_PIP;
private final Handler mHandler = new Handler();
- private List<Listener> mListeners = new ArrayList<>();
private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED;
private int mPipTaskId = TASK_ID_NO_PIP;
private int mPinnedStackId = INVALID_STACK_ID;
private String[] mLastPackagesResourceGranted;
- private PipNotification mPipNotification;
private ParceledListSlice<RemoteAction> mCustomActions;
private WindowManagerShellWrapper mWindowManagerShellWrapper;
private int mResizeAnimationDuration;
@@ -135,9 +111,7 @@
private boolean mImeVisible;
private int mImeHeightAdjustment;
- private final Runnable mResizePinnedStackRunnable =
- () -> resizePinnedStack(mResumeResizePinnedStackRunnableState);
- private final Runnable mClosePipRunnable = () -> closePip();
+ private final Runnable mClosePipRunnable = this::closePip;
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -237,8 +211,6 @@
mPipTaskOrganizer.registerPipTransitionCallback(this);
mActivityTaskManager = ActivityTaskManager.getService();
- addListener(mPipNotification);
-
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_CLOSE);
intentFilter.addAction(ACTION_MENU);
@@ -340,9 +312,8 @@
mPinnedStackId = INVALID_STACK_ID;
}
}
- for (int i = mListeners.size() - 1; i >= 0; --i) {
- mListeners.get(i).onPipActivityClosed();
- }
+ mPipNotification.dismiss();
+ mTvPipMenuController.hideMenu();
mHandler.removeCallbacks(mClosePipRunnable);
}
@@ -353,9 +324,9 @@
if (DEBUG) Log.d(TAG, "movePipToFullscreen(), current state=" + getStateDescription());
mPipTaskId = TASK_ID_NO_PIP;
- for (int i = mListeners.size() - 1; i >= 0; --i) {
- mListeners.get(i).onMoveToFullscreen();
- }
+ mTvPipMenuController.hideMenu();
+ mPipNotification.dismiss();
+
resizePinnedStack(STATE_NO_PIP);
}
@@ -379,9 +350,7 @@
// Set state to STATE_PIP so we show it when the pinned stack animation ends.
mState = STATE_PIP;
mPipMediaController.onActivityPinned();
- for (int i = mListeners.size() - 1; i >= 0; i--) {
- mListeners.get(i).onPipEntered(packageName);
- }
+ mPipNotification.show(packageName);
}
private void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
@@ -428,61 +397,17 @@
}
/**
- * Suspends resizing operation on the Pip until {@link #resumePipResizing} is called
- *
- * @param reason The reason for suspending resizing operations on the Pip.
- */
- public void suspendPipResizing(int reason) {
- if (DEBUG) {
- Log.d(TAG,
- "suspendPipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
- }
- mSuspendPipResizingReason |= reason;
- }
-
- /**
- * Resumes resizing operation on the Pip that was previously suspended.
- *
- * @param reason The reason resizing operations on the Pip was suspended.
- */
- public void resumePipResizing(int reason) {
- if ((mSuspendPipResizingReason & reason) == 0) {
- return;
- }
- if (DEBUG) {
- Log.d(TAG,
- "resumePipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
- }
- mSuspendPipResizingReason &= ~reason;
- mHandler.post(mResizePinnedStackRunnable);
- }
-
- /**
* Resize the Pip to the appropriate size for the input state.
*
* @param state In Pip state also used to determine the new size for the Pip.
*/
public void resizePinnedStack(int state) {
-
if (DEBUG) {
Log.d(TAG, "resizePinnedStack() state=" + stateToName(state) + ", current state="
+ getStateDescription(), new Exception());
}
-
- boolean wasStateNoPip = (mState == STATE_NO_PIP);
- for (int i = mListeners.size() - 1; i >= 0; --i) {
- mListeners.get(i).onPipResizeAboutToStart();
- }
- if (mSuspendPipResizingReason != 0) {
- mResumeResizePinnedStackRunnableState = state;
- if (DEBUG) {
- Log.d(TAG, "resizePinnedStack() deferring"
- + " mSuspendPipResizingReason=" + mSuspendPipResizingReason
- + " mResumeResizePinnedStackRunnableState="
- + stateToName(mResumeResizePinnedStackRunnableState));
- }
- return;
- }
+ final boolean wasStateNoPip = (mState == STATE_NO_PIP);
+ mTvPipMenuController.hideMenu();
mState = state;
final Rect newBounds;
switch (mState) {
@@ -510,45 +435,20 @@
}
/**
- * @return the current state, or the pending state if the state change was previously suspended.
+ * @return the current state.
*/
private int getState() {
- if (mSuspendPipResizingReason != 0) {
- return mResumeResizePinnedStackRunnableState;
- }
return mState;
}
- /**
- * Shows PIP menu UI by launching {@link PipMenuActivity}. It also locates the pinned
- * stack to the centered PIP bound {@link R.config_centeredPictureInPictureBounds}.
- */
private void showPipMenu() {
if (DEBUG) Log.d(TAG, "showPipMenu(), current state=" + getStateDescription());
mState = STATE_PIP_MENU;
- for (int i = mListeners.size() - 1; i >= 0; --i) {
- mListeners.get(i).onShowPipMenu();
- }
-
mTvPipMenuController.showMenu();
}
/**
- * Adds a {@link Listener} to PipController.
- */
- void addListener(Listener listener) {
- mListeners.add(listener);
- }
-
- /**
- * Removes a {@link Listener} from PipController.
- */
- void removeListener(Listener listener) {
- mListeners.remove(listener);
- }
-
- /**
* Returns {@code true} if PIP is shown.
*/
public boolean isPipShown() {
@@ -619,33 +519,8 @@
}
}
- /**
- * A listener interface to receive notification on changes in PIP.
- */
- public interface Listener {
- /**
- * Invoked when an activity is pinned and PIP manager is set corresponding information.
- * Classes must use this instead of {@link android.app.ITaskStackListener.onActivityPinned}
- * because there's no guarantee for the PIP manager be return relavent information
- * correctly. (e.g. {@link Pip.isPipShown}).
- */
- void onPipEntered(String packageName);
- /** Invoked when a PIPed activity is closed. */
- void onPipActivityClosed();
- /** Invoked when the PIP menu gets shown. */
- void onShowPipMenu();
- /** Invoked when the PIPed activity is about to return back to the fullscreen. */
- void onMoveToFullscreen();
- /** Invoked when we are above to start resizing the Pip. */
- void onPipResizeAboutToStart();
- }
-
private String getStateDescription() {
- if (mSuspendPipResizingReason == 0) {
- return stateToName(mState);
- }
- return stateToName(mResumeResizePinnedStackRunnableState) + " (while " + stateToName(mState)
- + " is suspended)";
+ return stateToName(mState);
}
private static String stateToName(int state) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuView.java
index 689c3ed..83cb7ce 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuView.java
@@ -16,6 +16,9 @@
package com.android.wm.shell.pip.tv;
+import static android.view.KeyEvent.ACTION_UP;
+import static android.view.KeyEvent.KEYCODE_BACK;
+
import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.annotation.Nullable;
@@ -36,25 +39,22 @@
/**
* The Menu View that shows controls of the PiP. Always fullscreen.
*/
-public class PipMenuView extends FrameLayout implements PipController.Listener {
+public class PipMenuView extends FrameLayout {
private static final String TAG = "PipMenuView";
private static final boolean DEBUG = PipController.DEBUG;
- private final PipController mPipController;
private final Animator mFadeInAnimation;
private final Animator mFadeOutAnimation;
private final PipControlsViewController mPipControlsViewController;
- private boolean mRestorePipSizeWhenClose;
+ @Nullable
+ private OnBackPressListener mOnBackPressListener;
public PipMenuView(Context context, PipController pipController) {
super(context, null, 0);
- mPipController = pipController;
-
inflate(context, R.layout.tv_pip_menu, this);
mPipControlsViewController = new PipControlsViewController(
- findViewById(R.id.pip_controls), mPipController);
- mRestorePipSizeWhenClose = true;
+ findViewById(R.id.pip_controls), pipController);
mFadeInAnimation = AnimatorInflater.loadAnimator(
mContext, R.anim.tv_pip_menu_fade_in_animation);
mFadeInAnimation.setTarget(mPipControlsViewController.getView());
@@ -63,16 +63,6 @@
mFadeOutAnimation.setTarget(mPipControlsViewController.getView());
}
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
- && event.getAction() == KeyEvent.ACTION_UP) {
- restorePipAndFinish();
- return true;
- }
- return super.dispatchKeyEvent(event);
- }
-
@Nullable
SurfaceControl getWindowSurfaceControl() {
final ViewRootImpl root = getViewRootImpl();
@@ -87,53 +77,39 @@
}
void showMenu() {
- mPipController.addListener(this);
mFadeInAnimation.start();
setAlpha(1.0f);
- try {
- WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
- getViewRootImpl().getInputToken(), true /* grantFocus */);
- } catch (Exception e) {
- Log.e(TAG, "Unable to update focus as menu appears", e);
- }
+ grantWindowFocus(true);
}
void hideMenu() {
- mPipController.removeListener(this);
- mPipController.resumePipResizing(
- PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
mFadeOutAnimation.start();
setAlpha(0.0f);
+ grantWindowFocus(false);
+ }
+
+ private void grantWindowFocus(boolean grantFocus) {
try {
WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
- getViewRootImpl().getInputToken(), false /* grantFocus */);
+ getViewRootImpl().getInputToken(), grantFocus);
} catch (Exception e) {
Log.e(TAG, "Unable to update focus as menu disappears", e);
}
}
- private void restorePipAndFinish() {
- if (DEBUG) Log.d(TAG, "restorePipAndFinish()");
+ void setOnBackPressListener(OnBackPressListener onBackPressListener) {
+ mOnBackPressListener = onBackPressListener;
+ }
- if (mRestorePipSizeWhenClose) {
- if (DEBUG) Log.d(TAG, " > restoring to the default position");
-
- // When PIP menu activity is closed, restore to the default position.
- mPipController.resizePinnedStack(PipController.STATE_PIP);
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (event.getKeyCode() == KEYCODE_BACK && event.getAction() == ACTION_UP
+ && mOnBackPressListener != null) {
+ mOnBackPressListener.onBackPress();
+ return true;
+ } else {
+ return super.dispatchKeyEvent(event);
}
- hideMenu();
- }
-
- @Override
- public void onPipEntered(String packageName) {
- if (DEBUG) Log.d(TAG, "onPipEntered(), packageName=" + packageName);
- }
-
- @Override
- public void onPipActivityClosed() {
- if (DEBUG) Log.d(TAG, "onPipActivityClosed()");
-
- hideMenu();
}
void setAppActions(ParceledListSlice<RemoteAction> actions) {
@@ -144,27 +120,7 @@
hasCustomActions ? actions.getList() : Collections.emptyList());
}
- @Override
- public void onShowPipMenu() {
- if (DEBUG) Log.d(TAG, "onShowPipMenu()");
- }
-
- @Override
- public void onMoveToFullscreen() {
- if (DEBUG) Log.d(TAG, "onMoveToFullscreen()");
-
- // Moving PIP to fullscreen is implemented by resizing PINNED_STACK with null bounds.
- // This conflicts with restoring PIP position, so disable it.
- mRestorePipSizeWhenClose = false;
- hideMenu();
- }
-
- @Override
- public void onPipResizeAboutToStart() {
- if (DEBUG) Log.d(TAG, "onPipResizeAboutToStart()");
-
- hideMenu();
- mPipController.suspendPipResizing(
- PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
+ interface OnBackPressListener {
+ void onBackPress();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java
index d56a888..4e0ab66 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java
@@ -39,7 +39,7 @@
* <p>Once it's created, it will manage the PIP notification UI by itself except for handling
* configuration changes.
*/
-public class PipNotification implements PipController.Listener {
+public class PipNotification {
private static final boolean DEBUG = PipController.DEBUG;
private static final String TAG = "PipNotification";
@@ -79,38 +79,21 @@
onConfigurationChanged(context);
}
- @Override
- public void onPipEntered(String packageName) {
+ void show(String packageName) {
mPackageName = packageName;
- notifyPipNotification();
+ update();
}
- @Override
- public void onPipActivityClosed() {
- dismissPipNotification();
+ void dismiss() {
+ mNotificationManager.cancel(NOTIFICATION_TAG, SystemMessage.NOTE_TV_PIP);
+ mNotified = false;
mPackageName = null;
}
- @Override
- public void onShowPipMenu() {
- // no-op.
- }
-
- @Override
- public void onMoveToFullscreen() {
- dismissPipNotification();
- mPackageName = null;
- }
-
- @Override
- public void onPipResizeAboutToStart() {
- // no-op.
- }
-
private void onMediaMetadataChanged(MediaMetadata metadata) {
if (updateMediaControllerMetadata(metadata) && mNotified) {
// update notification
- notifyPipNotification();
+ update();
}
}
@@ -123,11 +106,11 @@
mDefaultIconResId = R.drawable.pip_icon;
if (mNotified) {
// update notification
- notifyPipNotification();
+ update();
}
}
- private void notifyPipNotification() {
+ private void update() {
mNotified = true;
mNotificationBuilder
.setShowWhen(true)
@@ -144,11 +127,6 @@
mNotificationBuilder.build());
}
- private void dismissPipNotification() {
- mNotified = false;
- mNotificationManager.cancel(NOTIFICATION_TAG, SystemMessage.NOTE_TV_PIP);
- }
-
private boolean updateMediaControllerMetadata(MediaMetadata metadata) {
String title = null;
Bitmap art = null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index 91aef67..5d0d761 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -21,6 +21,7 @@
import android.app.RemoteAction;
import android.content.Context;
import android.content.pm.ParceledListSlice;
+import android.util.Log;
import android.view.SurfaceControl;
import com.android.wm.shell.common.SystemWindows;
@@ -31,6 +32,8 @@
* Manages the visibility of the PiP Menu as user interacts with PiP.
*/
public class TvPipMenuController implements PipMenuController {
+ private static final String TAG = "TvPipMenuController";
+ private static final boolean DEBUG = PipController.DEBUG;
private final Context mContext;
private final SystemWindows mSystemWindows;
@@ -52,6 +55,8 @@
@Override
public void showMenu() {
+ if (DEBUG) Log.d(TAG, "showMenu()");
+
if (mMenuView != null) {
mSystemWindows.updateViewLayout(mMenuView, getPipMenuLayoutParams(MENU_WINDOW_TITLE,
mPipBoundsState.getDisplayBounds().width(),
@@ -68,27 +73,62 @@
}
}
- @Override
- public void attach(SurfaceControl leash) {
- if (mMenuView == null) {
- mMenuView = new PipMenuView(mContext, mPipController);
- mSystemWindows.addView(mMenuView,
- getPipMenuLayoutParams(MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */),
- 0, SHELL_ROOT_LAYER_PIP);
- mLeash = leash;
+ void hideMenu() {
+ if (DEBUG) Log.d(TAG, "hideMenu()");
+
+ if (isMenuVisible()) {
+ mMenuView.hideMenu();
+ mPipController.resizePinnedStack(PipController.STATE_PIP);
}
}
@Override
+ public void attach(SurfaceControl leash) {
+ mLeash = leash;
+ attachPipMenuView();
+ }
+
+ @Override
public void detach() {
+ hideMenu();
+ detachPipMenuView();
+ mLeash = null;
+ }
+
+ private void attachPipMenuView() {
+ if (DEBUG) Log.d(TAG, "attachPipMenuView()");
+
+ if (mMenuView != null) {
+ detachPipMenuView();
+ }
+
+ mMenuView = new PipMenuView(mContext, mPipController);
+ mMenuView.setOnBackPressListener(this::hideMenu);
+ mSystemWindows.addView(mMenuView,
+ getPipMenuLayoutParams(MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */),
+ 0, SHELL_ROOT_LAYER_PIP);
+ }
+
+ private void detachPipMenuView() {
+ if (DEBUG) Log.d(TAG, "detachPipMenuView()");
+
+ if (mMenuView == null) {
+ return;
+ }
+
mSystemWindows.removeView(mMenuView);
mMenuView = null;
- mLeash = null;
}
@Override
public void setAppActions(ParceledListSlice<RemoteAction> appActions) {
- mMenuView.setAppActions(appActions);
+ if (DEBUG) Log.d(TAG, "setAppActions(), actions=" + appActions);
+
+ if (mMenuView != null) {
+ mMenuView.setAppActions(appActions);
+ } else {
+ Log.w(TAG, "Cannot set remote actions, there is no View");
+ }
}
@Override