summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java3
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java10
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java15
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java31
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java22
5 files changed, 77 insertions, 4 deletions
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index ebfffec1774e..00ab973b9c90 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -40,6 +40,9 @@ public interface StatusBarManagerInternal {
void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
+ /** Collapses the notification shade. */
+ void collapsePanels();
+
void dismissKeyboardShortcutsMenu();
void toggleKeyboardShortcutsMenu(int deviceId);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index c08500926650..3ee8dd7e9d81 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -384,6 +384,16 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
}
@Override
+ public void collapsePanels() {
+ if (mBar != null) {
+ try {
+ mBar.animateCollapsePanels();
+ } catch (RemoteException ex) {
+ }
+ }
+ }
+
+ @Override
public void dismissKeyboardShortcutsMenu() {
if (mBar != null) {
try {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 7a4bcb1b8c37..20625c83a924 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -118,6 +118,7 @@ import com.android.internal.protolog.common.ProtoLog;
import com.android.server.am.PendingIntentRecord;
import com.android.server.pm.InstantAppResolver;
import com.android.server.power.ShutdownCheckPoints;
+import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.NeededUriGrants;
import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
import com.android.server.wm.ActivityTaskSupervisor.PendingActivityLaunch;
@@ -1589,6 +1590,20 @@ class ActivityStarter {
newTransition.abort();
}
} else {
+ if (!mAvoidMoveToFront && mDoResume
+ && mRootWindowContainer.hasVisibleWindowAboveNotificationShade(
+ r.launchedFromUid)) {
+ // If the UID launching the activity has a visible window on top of the
+ // notification shade and it's launching an activity that's going to be at the
+ // front, we should move the shade out of the way so the user can see it.
+ // We want to avoid the case where the activity is launched on top of a
+ // background task which is not moved to the front.
+ StatusBarManagerInternal statusBar = mService.getStatusBarManagerInternal();
+ if (statusBar != null) {
+ // This results in a async call since the interface is one-way
+ statusBar.collapsePanels();
+ }
+ }
if (result == START_SUCCESS || result == START_TASK_TO_FRONT) {
// The activity is started new rather than just brought forward, so record
// it as an existence change.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index caf20a9749a9..9bee59cd3ee3 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -28,6 +28,8 @@ import static android.Manifest.permission.READ_FRAME_BUFFER;
import static android.Manifest.permission.REMOVE_TASKS;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.Manifest.permission.STOP_APP_SWITCHES;
+import static android.app.ActivityManager.DROP_CLOSE_SYSTEM_DIALOGS;
+import static android.app.ActivityManager.LOCK_DOWN_CLOSE_SYSTEM_DIALOGS;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
@@ -253,6 +255,7 @@ import com.android.server.firewall.IntentFirewall;
import com.android.server.inputmethod.InputMethodSystemProperty;
import com.android.server.pm.UserManagerService;
import com.android.server.policy.PermissionPolicyInternal;
+import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.NeededUriGrants;
import com.android.server.uri.UriGrantsManagerInternal;
@@ -342,6 +345,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
/** The cached sys ui service component name from package manager. */
private ComponentName mSysUiServiceComponent;
private PermissionPolicyInternal mPermissionPolicyInternal;
+ private StatusBarManagerInternal mStatusBarManagerInternal;
@VisibleForTesting
final ActivityTaskManagerInternal mInternal;
PowerManagerInternal mPowerManagerInternal;
@@ -2927,14 +2931,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
if (!canCloseSystemDialogs(pid, uid, process)) {
// The app can't close system dialogs, throw only if it targets S+
- if (CompatChanges.isChangeEnabled(
- ActivityManager.LOCK_DOWN_CLOSE_SYSTEM_DIALOGS, uid)) {
+ if (CompatChanges.isChangeEnabled(LOCK_DOWN_CLOSE_SYSTEM_DIALOGS, uid)) {
throw new SecurityException(
"Permission Denial: " + Intent.ACTION_CLOSE_SYSTEM_DIALOGS
+ " broadcast from " + caller + " requires "
+ Manifest.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS + ".");
- } else if (CompatChanges.isChangeEnabled(
- ActivityManager.DROP_CLOSE_SYSTEM_DIALOGS, uid)) {
+ } else if (CompatChanges.isChangeEnabled(DROP_CLOSE_SYSTEM_DIALOGS, uid)) {
Slog.e(TAG,
"Permission Denial: " + Intent.ACTION_CLOSE_SYSTEM_DIALOGS
+ " broadcast from " + caller + " requires "
@@ -2983,6 +2985,20 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return true;
}
}
+ // This covers the case where the app is displaying some UI on top of the notification shade
+ // and wants to start an activity. The app then sends the intent in order to move the
+ // notification shade out of the way and show the activity to the user. This is fine since
+ // the caller already has privilege to show a visible window on top of the notification
+ // shade, so it can already prevent the user from accessing the shade if it wants to.
+ // We only allow for targetSdk < S, for S+ we automatically collapse the shade on
+ // startActivity() for these apps.
+ if (!CompatChanges.isChangeEnabled(LOCK_DOWN_CLOSE_SYSTEM_DIALOGS, uid)) {
+ synchronized (mGlobalLock) {
+ if (mRootWindowContainer.hasVisibleWindowAboveNotificationShade(uid)) {
+ return true;
+ }
+ }
+ }
return false;
}
@@ -4787,6 +4803,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return mPermissionPolicyInternal;
}
+ StatusBarManagerInternal getStatusBarManagerInternal() {
+ if (mStatusBarManagerInternal == null) {
+ mStatusBarManagerInternal = LocalServices.getService(StatusBarManagerInternal.class);
+ }
+ return mStatusBarManagerInternal;
+ }
+
AppWarnings getAppWarningsLocked() {
return mAppWarnings;
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 0a95f8f852a9..ff349fa637a5 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -36,6 +36,7 @@ import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE;
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED;
import static android.view.WindowManager.TRANSIT_NONE;
@@ -3137,6 +3138,27 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
});
}
+ /**
+ * Returns {@code true} if {@code uid} has a visible window that's above a window of type {@link
+ * WindowManager.LayoutParams#TYPE_NOTIFICATION_SHADE}. If there is no window with type {@link
+ * WindowManager.LayoutParams#TYPE_NOTIFICATION_SHADE}, it returns {@code false}.
+ */
+ boolean hasVisibleWindowAboveNotificationShade(int uid) {
+ boolean[] visibleWindowFound = {false};
+ // We only return true if we found the notification shade (ie. window of type
+ // TYPE_NOTIFICATION_SHADE). Usually, it should always be there, but if for some reason
+ // it isn't, we should better be on the safe side and return false for this.
+ return forAllWindows(w -> {
+ if (w.mOwnerUid == uid && w.isVisible()) {
+ visibleWindowFound[0] = true;
+ }
+ if (w.mAttrs.type == TYPE_NOTIFICATION_SHADE) {
+ return visibleWindowFound[0];
+ }
+ return false;
+ }, true /* traverseTopToBottom */);
+ }
+
private boolean shouldCloseAssistant(ActivityRecord r, String reason) {
if (!r.isActivityTypeAssistant()) return false;
if (reason == SYSTEM_DIALOG_REASON_ASSIST) return false;