Disallow entering PiP without dismissing keyguard.
- If an activity is showing on the keyguard and enters picture-
in-picture, then prompt the user to authenticate first
- Fixing NPE in SystemUI due to null runnable being added to the
post-keyguard-gone callbacks
- Prevent FLAG_SHOW_WHEN_LOCKED from applying when determining
visibility over keyguard for activities that are in the pinned
stack
Bug: 33660880
Test: android.server.cts.KeyguardLockedTests
Test: #testEnterPipOverKeyguard
Change-Id: I89477a8a0067e285e5d0122e918fac45274c57ad
(cherry picked from commit 0655da0374caff1569c09017e17ac28c4b0b7069)
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 ea4e102..34a0ae4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -3592,17 +3592,14 @@
final boolean dismissShade,
final boolean afterKeyguardGone,
final boolean deferred) {
- final Runnable dismissAction = () -> {
- if (runnable != null) {
- AsyncTask.execute(runnable);
- }
- };
dismissKeyguardThenExecute(() -> {
- if (mStatusBarKeyguardViewManager.isShowing()
- && mStatusBarKeyguardViewManager.isOccluded()) {
- mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
- } else {
- dismissAction.run();
+ if (runnable != null) {
+ if (mStatusBarKeyguardViewManager.isShowing()
+ && mStatusBarKeyguardViewManager.isOccluded()) {
+ mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
+ } else {
+ AsyncTask.execute(runnable);
+ }
}
if (dismissShade) {
if (mExpandedVisible) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1583023..87b4221 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6710,6 +6710,13 @@
}
}
+ /**
+ * @return whther the keyguard is currently locked.
+ */
+ boolean isKeyguardLocked() {
+ return mKeyguardController.isKeyguardLocked();
+ }
+
final void finishBooting() {
synchronized (this) {
if (!mBootAnimationComplete) {
@@ -7557,10 +7564,40 @@
final ActivityRecord r = ensureValidPictureInPictureActivityLocked(
"enterPictureInPictureMode", token, aspectRatio, checkAspectRatio,
true /* checkActivityVisibility */);
+ final Runnable enterPipRunnable = () -> {
+ r.pictureInPictureArgs.aspectRatio = aspectRatio;
+ enterPictureInPictureModeLocked(r, displayId, r.pictureInPictureArgs,
+ true /* moveHomeStackToFront */, "enterPictureInPictureMode");
+ };
- r.pictureInPictureArgs.aspectRatio = aspectRatio;
- enterPictureInPictureModeLocked(r, displayId, r.pictureInPictureArgs,
- true /* moveHomeStackToFront */, "enterPictureInPictureMode");
+ if (isKeyguardLocked()) {
+ // If the keyguard is showing or occluded, then try and dismiss it before
+ // entering picture-in-picture (this will prompt the user to authenticate if the
+ // device is currently locked).
+ try {
+ dismissKeyguard(token, new IKeyguardDismissCallback.Stub() {
+ @Override
+ public void onDismissError() throws RemoteException {
+ // Do nothing
+ }
+
+ @Override
+ public void onDismissSucceeded() throws RemoteException {
+ mHandler.post(enterPipRunnable);
+ }
+
+ @Override
+ public void onDismissCancelled() throws RemoteException {
+ // Do nothing
+ }
+ });
+ } catch (RemoteException e) {
+ // Local call
+ }
+ } else {
+ // Enter picture in picture immediately otherwise
+ enterPipRunnable.run();
+ }
}
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index ba95abd..beeadac 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1810,9 +1810,10 @@
*/
private boolean checkKeyguardVisibility(ActivityRecord r, boolean shouldBeVisible,
boolean isTop) {
+ final boolean isInPinnedStack = r.getStack().getStackId() == PINNED_STACK_ID;
final boolean keyguardShowing = mStackSupervisor.mKeyguardController.isKeyguardShowing();
final boolean keyguardLocked = mStackSupervisor.mKeyguardController.isKeyguardLocked();
- final boolean showWhenLocked = r.hasShowWhenLockedWindows();
+ final boolean showWhenLocked = r.hasShowWhenLockedWindows() && !isInPinnedStack;
final boolean dismissKeyguard = r.hasDismissKeyguardWindows();
if (shouldBeVisible) {
if (dismissKeyguard && mTopDismissingKeyguardActivity == null) {
@@ -1885,10 +1886,13 @@
private boolean enterPictureInPictureOnActivityInvisible(ActivityRecord r) {
final boolean hasPinnedStack =
mStackSupervisor.getStack(PINNED_STACK_ID) != null;
+ final boolean isKeyguardLocked = mService.isKeyguardLocked();
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, " enterPictureInPictureOnInvisible="
+ r.shouldEnterPictureInPictureOnInvisible()
- + " hasPinnedStack=" + hasPinnedStack);
- if (!hasPinnedStack && r.visible && r.shouldEnterPictureInPictureOnInvisible()) {
+ + " hasPinnedStack=" + hasPinnedStack
+ + " isKeyguardLocked=" + isKeyguardLocked);
+ if (!hasPinnedStack && !isKeyguardLocked && r.visible &&
+ r.shouldEnterPictureInPictureOnInvisible()) {
r.setEnterPipOnMoveToBackground(false);
// Enter picture in picture, but don't move the home stack to the front