PIP: Send KEYCODE_WINDOW to app first if PIP isn't exist
Bug: 27954955
Change-Id: I517e378d5c1672ac0eb87bdf4375b7d733276e58
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index eb895ff..2fc1187 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3071,6 +3071,13 @@
/**
* @hide
*
+ * Whether the TV's picture-in-picture is visible or not.
+ */
+ public static final int TV_PICTURE_IN_PICTURE_VISIBLE = 0x00010000;
+
+ /**
+ * @hide
+ *
* Makes navigation bar transparent (but not the status bar).
*/
public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index e3abb5d..e598113 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -24,6 +24,7 @@
import android.annotation.Nullable;
import android.annotation.StyleRes;
import android.annotation.SystemApi;
+import android.app.ActivityManagerNative;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -1256,6 +1257,18 @@
}
/**
+ * Puts the activity in picture-in-picture mode.
+ * @see android.R.attr#supportsPictureInPicture
+ * @hide
+ */
+ protected void enterPictureInPictureMode() {
+ try {
+ ActivityManagerNative.getDefault().enterPictureInPictureMode(mAppToken);
+ } catch (IllegalArgumentException|RemoteException e) {
+ }
+ }
+
+ /**
* Convenience for
* {@link #setContentView(View, android.view.ViewGroup.LayoutParams)}
* to set the screen content from a layout resource. The resource will be
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 151c530..1619843 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -2002,6 +2002,13 @@
}
return true;
}
+
+ case KeyEvent.KEYCODE_WINDOW: {
+ if (!event.isCanceled()) {
+ enterPictureInPictureMode();
+ }
+ return true;
+ }
}
return false;
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 5cbe1ce..7706ff7 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -105,14 +105,9 @@
void onCameraLaunchGestureDetected(int source);
/**
- * Request picture-in-picture.
- *
- * <p>
- * This is called when an user presses picture-in-picture key or equivalent.
- * TV device may start picture-in-picture from foreground activity if there's none.
- * Picture-in-picture overlay menu will be shown instead otherwise.
+ * Shows the TV's picture-in-picture menu if an activity is in picture-in-picture mode.
*/
- void requestTvPictureInPicture();
+ void showTvPictureInPictureMenu();
void addQsTile(in ComponentName tile);
void remQsTile(in ComponentName tile);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 1bc2ebc..7b23c80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -68,7 +68,7 @@
private static final int MSG_START_ASSIST = 23 << MSG_SHIFT;
private static final int MSG_CAMERA_LAUNCH_GESTURE = 24 << MSG_SHIFT;
private static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS = 25 << MSG_SHIFT;
- private static final int MSG_REQUEST_TV_PICTURE_IN_PICTURE = 26 << MSG_SHIFT;
+ private static final int MSG_SHOW_TV_PICTURE_IN_PICTURE_MENU = 26 << MSG_SHIFT;
private static final int MSG_ADD_QS_TILE = 27 << MSG_SHIFT;
private static final int MSG_REMOVE_QS_TILE = 28 << MSG_SHIFT;
private static final int MSG_CLICK_QS_TILE = 29 << MSG_SHIFT;
@@ -124,7 +124,7 @@
void showAssistDisclosure();
void startAssist(Bundle args);
void onCameraLaunchGestureDetected(int source);
- void requestTvPictureInPicture();
+ void showTvPictureInPictureMenu();
void addQsTile(ComponentName tile);
void remQsTile(ComponentName tile);
@@ -274,10 +274,10 @@
}
@Override
- public void requestTvPictureInPicture() {
+ public void showTvPictureInPictureMenu() {
synchronized (mLock) {
- mHandler.removeMessages(MSG_REQUEST_TV_PICTURE_IN_PICTURE);
- mHandler.obtainMessage(MSG_REQUEST_TV_PICTURE_IN_PICTURE).sendToTarget();
+ mHandler.removeMessages(MSG_SHOW_TV_PICTURE_IN_PICTURE_MENU);
+ mHandler.obtainMessage(MSG_SHOW_TV_PICTURE_IN_PICTURE_MENU).sendToTarget();
}
}
@@ -488,8 +488,8 @@
case MSG_CAMERA_LAUNCH_GESTURE:
mCallbacks.onCameraLaunchGestureDetected(msg.arg1);
break;
- case MSG_REQUEST_TV_PICTURE_IN_PICTURE:
- mCallbacks.requestTvPictureInPicture();
+ case MSG_SHOW_TV_PICTURE_IN_PICTURE_MENU:
+ mCallbacks.showTvPictureInPictureMenu();
break;
case MSG_ADD_QS_TILE:
mCallbacks.addQsTile((ComponentName) msg.obj);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 436dc9d..23e3561 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -4503,7 +4503,7 @@
}
@Override
- public void requestTvPictureInPicture() {
+ public void showTvPictureInPictureMenu() {
// no-op.
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index f9202c4..27726af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -189,8 +189,8 @@
}
@Override
- public void requestTvPictureInPicture() {
- PipManager.getInstance().requestTvPictureInPicture();
+ public void showTvPictureInPictureMenu() {
+ PipManager.getInstance().showTvPictureInPictureMenu();
}
@Override
@@ -224,8 +224,22 @@
putComponent(TvStatusBar.class, this);
}
+ /**
+ * Updates the visibility of the picture-in-picture.
+ */
+ public void updatePipVisibility(boolean visible) {
+ if (visible) {
+ mSystemUiVisibility |= View.TV_PICTURE_IN_PICTURE_VISIBLE;
+ } else {
+ mSystemUiVisibility &= ~View.TV_PICTURE_IN_PICTURE_VISIBLE;
+ }
+ notifyUiVisibilityChanged(mSystemUiVisibility);
+ }
+
+ /**
+ * Updates the visibility of the Recents
+ */
public void updateRecentsVisibility(boolean visible) {
- // Update the recents visibility flag
if (visible) {
mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index d7efca7..9842634 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -41,8 +41,10 @@
import com.android.systemui.Prefs;
import com.android.systemui.R;
-import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.SystemUIApplication;
import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.statusbar.tv.TvStatusBar;
import java.util.ArrayList;
import java.util.List;
@@ -225,26 +227,14 @@
}
/**
- * Request PIP.
- * It could either start PIP if there's none, and show PIP menu otherwise.
+ * Shows the picture-in-picture menu if an activity is in picture-in-picture mode.
*/
- public void requestTvPictureInPicture() {
- if (DEBUG) Log.d(TAG, "requestTvPictureInPicture()");
- if (!isPipShown()) {
- startPip();
- } else if (mState == STATE_PIP_OVERLAY) {
+ public void showTvPictureInPictureMenu() {
+ if (mState == STATE_PIP_OVERLAY) {
resizePinnedStack(STATE_PIP_MENU);
}
}
- private void startPip() {
- try {
- mActivityManager.moveTopActivityToPinnedStack(FULLSCREEN_WORKSPACE_STACK_ID, mPipBounds);
- } catch (RemoteException|IllegalArgumentException e) {
- Log.e(TAG, "moveTopActivityToPinnedStack failed", e);
- }
- }
-
/**
* Closes PIP (PIPed activity and PIP system UI).
*/
@@ -268,6 +258,7 @@
mListeners.get(i).onPipActivityClosed();
}
mHandler.removeCallbacks(mClosePipRunnable);
+ updatePipVisibility(false);
}
/**
@@ -622,6 +613,7 @@
for (int i = mListeners.size() - 1; i >= 0; i--) {
mListeners.get(i).onPipEntered();
}
+ updatePipVisibility(true);
}
@Override
@@ -706,4 +698,11 @@
public PipRecentsOverlayManager getPipRecentsOverlayManager() {
return mPipRecentsOverlayManager;
}
+
+ private void updatePipVisibility(boolean visible) {
+ TvStatusBar statusBar = ((SystemUIApplication) mContext).getComponent(TvStatusBar.class);
+ if (statusBar != null) {
+ statusBar.updatePipVisibility(visible);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 4e4b2f3..4ac94be 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -404,8 +404,9 @@
volatile boolean mEndCallKeyHandled;
volatile boolean mCameraGestureTriggeredDuringGoingToSleep;
volatile boolean mGoingToSleep;
+ volatile boolean mRecentsVisible;
+ volatile boolean mTvPictureInPictureVisible;
- boolean mRecentsVisible;
int mRecentAppsHeldModifiers;
boolean mLanguageSwitchKeyPressed;
@@ -712,7 +713,7 @@
private static final int MSG_POWER_LONG_PRESS = 14;
private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 15;
private static final int MSG_REQUEST_TRANSIENT_BARS = 16;
- private static final int MSG_REQUEST_TV_PICTURE_IN_PICTURE = 17;
+ private static final int MSG_SHOW_TV_PICTURE_IN_PICTURE_MENU = 17;
private static final int MSG_BACK_LONG_PRESS = 18;
private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
@@ -775,8 +776,8 @@
requestTransientBars(targetBar);
}
break;
- case MSG_REQUEST_TV_PICTURE_IN_PICTURE:
- requestTvPictureInPictureInternal();
+ case MSG_SHOW_TV_PICTURE_IN_PICTURE_MENU:
+ showTvPictureInPictureMenuInternal();
break;
case MSG_BACK_LONG_PRESS:
backLongPress();
@@ -1457,22 +1458,18 @@
}
}
- private void requestTvPictureInPicture(KeyEvent event) {
- if (DEBUG_INPUT) Log.d(TAG, "requestTvPictureInPicture event=" + event);
- mHandler.removeMessages(MSG_REQUEST_TV_PICTURE_IN_PICTURE);
- Message msg = mHandler.obtainMessage(MSG_REQUEST_TV_PICTURE_IN_PICTURE);
+ private void showTvPictureInPictureMenu(KeyEvent event) {
+ if (DEBUG_INPUT) Log.d(TAG, "showTvPictureInPictureMenu event=" + event);
+ mHandler.removeMessages(MSG_SHOW_TV_PICTURE_IN_PICTURE_MENU);
+ Message msg = mHandler.obtainMessage(MSG_SHOW_TV_PICTURE_IN_PICTURE_MENU);
msg.setAsynchronous(true);
msg.sendToTarget();
}
- private void requestTvPictureInPictureInternal() {
- try {
- StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
- if (statusbar != null) {
- statusbar.requestTvPictureInPicture();
- }
- } catch (IllegalArgumentException e) {
- Slog.e(TAG, "Cannot handle picture-in-picture key", e);
+ private void showTvPictureInPictureMenuInternal() {
+ StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
+ if (statusbar != null) {
+ statusbar.showTvPictureInPictureMenu();
}
}
@@ -3787,6 +3784,7 @@
mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
mRecentsVisible = (visibility & View.RECENT_APPS_VISIBLE) > 0;
+ mTvPictureInPictureVisible = (visibility & View.TV_PICTURE_IN_PICTURE_VISIBLE) > 0;
// Reset any bits in mForceClearingStatusBarVisibility that
// are now clear.
@@ -5674,10 +5672,16 @@
}
case KeyEvent.KEYCODE_WINDOW: {
if (mShortPressWindowBehavior == SHORT_PRESS_WINDOW_PICTURE_IN_PICTURE) {
- if (!down) {
- requestTvPictureInPicture(event);
+ if (mTvPictureInPictureVisible) {
+ // Consumes the key only if picture-in-picture is visible
+ // to show picture-in-picture control menu.
+ // This gives a chance to the foreground activity
+ // to customize PIP key behavior.
+ if (!down) {
+ showTvPictureInPictureMenu(event);
+ }
+ result &= ~ACTION_PASS_TO_USER;
}
- result &= ~ACTION_PASS_TO_USER;
}
break;
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 52b2439..fb0dd2a 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -41,14 +41,9 @@
void toggleKeyboardShortcutsMenu(int deviceId);
/**
- * Request picture-in-picture.
- *
- * <p>
- * This is called when an user presses picture-in-picture key or equivalent.
- * TV device may start picture-in-picture from foreground activity if there's none.
- * Picture-in-picture overlay menu will be shown instead otherwise.
+ * Show TV picture-in-picture menu.
*/
- void requestTvPictureInPicture();
+ void showTvPictureInPictureMenu();
void setWindowState(int window, int state);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index c630d4a..baa7f1e 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -295,10 +295,10 @@
}
@Override
- public void requestTvPictureInPicture() {
+ public void showTvPictureInPictureMenu() {
if (mBar != null) {
try {
- mBar.requestTvPictureInPicture();
+ mBar.showTvPictureInPictureMenu();
} catch (RemoteException ex) {}
}
}