Merge "Remove RESET_PASSWORD_TOKEN policy when the generated escrow token is not valid." into main
diff --git a/core/api/current.txt b/core/api/current.txt
index 2c6e1cb..8eb8811 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -7015,6 +7015,7 @@
method public boolean areNotificationsEnabled();
method public boolean areNotificationsPaused();
method public boolean canNotifyAsPackage(@NonNull String);
+ method @FlaggedApi("android.app.api_rich_ongoing") public boolean canPostPromotedNotifications();
method public boolean canUseFullScreenIntent();
method public void cancel(int);
method public void cancel(@Nullable String, int);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 72a68f8..659222d 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -398,6 +398,7 @@
method public android.content.ComponentName getEffectsSuppressor();
method public boolean isNotificationPolicyAccessGrantedForPackage(@NonNull String);
method @FlaggedApi("android.app.modes_api") public boolean removeAutomaticZenRule(@NonNull String, boolean);
+ method @FlaggedApi("android.app.api_rich_ongoing") public void setCanPostPromotedNotifications(@NonNull String, int, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public void setNotificationListenerAccessGranted(@NonNull android.content.ComponentName, boolean, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_TOAST_RATE_LIMITING) public void setToastRateLimitingEnabled(boolean);
method @FlaggedApi("android.app.modes_api") public boolean updateAutomaticZenRule(@NonNull String, @NonNull android.app.AutomaticZenRule, boolean);
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index b9fe356..237780f 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -259,5 +259,6 @@
void unregisterCallNotificationEventListener(String packageName, in UserHandle userHandle, in ICallNotificationEventCallback listener);
void setCanBePromoted(String pkg, int uid, boolean promote);
- boolean canBePromoted(String pkg, int uid);
+ boolean appCanBePromoted(String pkg, int uid);
+ boolean canBePromoted(String pkg);
}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 83f9ff7..06f21b8 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -953,6 +953,36 @@
}
/**
+ * Returns whether the calling app's properly formatted notifications can appear in a promoted
+ * format, which may result in higher ranking, appearances on additional surfaces, and richer
+ * presentation.
+ */
+ @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING)
+ public boolean canPostPromotedNotifications() {
+ INotificationManager service = getService();
+ try {
+ return service.canBePromoted(mContext.getPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Setter for {@link #canPostPromotedNotifications()}. Only callable by the OS.
+ * @hide
+ */
+ @TestApi
+ @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING)
+ public void setCanPostPromotedNotifications(@NonNull String pkg, int uid, boolean allowed) {
+ INotificationManager service = getService();
+ try {
+ service.setCanBePromoted(pkg, uid, allowed);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Creates a group container for {@link NotificationChannel} objects.
*
* This can be used to rename an existing group.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
index c807960..ba0d938 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
@@ -17,12 +17,15 @@
package com.android.systemui.qs.composefragment
import android.annotation.SuppressLint
+import android.content.Context
+import android.graphics.PointF
import android.graphics.Rect
import android.os.Bundle
import android.util.IndentingPrintWriter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import android.widget.FrameLayout
import androidx.activity.OnBackPressedDispatcher
import androidx.activity.OnBackPressedDispatcherOwner
import androidx.activity.setViewTreeOnBackPressedDispatcherOwner
@@ -185,62 +188,76 @@
savedInstanceState: Bundle?,
): View {
val context = inflater.context
- return ComposeView(context).apply {
- setBackPressedDispatcher()
- setContent {
- PlatformTheme {
- val visible by viewModel.qsVisible.collectAsStateWithLifecycle()
+ val composeView =
+ ComposeView(context).apply {
+ setBackPressedDispatcher()
+ setContent {
+ PlatformTheme {
+ val visible by viewModel.qsVisible.collectAsStateWithLifecycle()
- AnimatedVisibility(
- visible = visible,
- modifier =
- Modifier.windowInsetsPadding(WindowInsets.navigationBars)
- .thenIf(notificationScrimClippingParams.isEnabled) {
- Modifier.notificationScrimClip(
- notificationScrimClippingParams.leftInset,
- notificationScrimClippingParams.top,
- notificationScrimClippingParams.rightInset,
- notificationScrimClippingParams.bottom,
- notificationScrimClippingParams.radius,
+ AnimatedVisibility(
+ visible = visible,
+ modifier =
+ Modifier.windowInsetsPadding(WindowInsets.navigationBars)
+ .thenIf(notificationScrimClippingParams.isEnabled) {
+ Modifier.notificationScrimClip(
+ notificationScrimClippingParams.leftInset,
+ notificationScrimClippingParams.top,
+ notificationScrimClippingParams.rightInset,
+ notificationScrimClippingParams.bottom,
+ notificationScrimClippingParams.radius,
+ )
+ }
+ .graphicsLayer { elevation = 4.dp.toPx() },
+ ) {
+ val isEditing by
+ viewModel.containerViewModel.editModeViewModel.isEditing
+ .collectAsStateWithLifecycle()
+ val animationSpecEditMode = tween<Float>(EDIT_MODE_TIME_MILLIS)
+ AnimatedContent(
+ targetState = isEditing,
+ transitionSpec = {
+ fadeIn(animationSpecEditMode) togetherWith
+ fadeOut(animationSpecEditMode)
+ },
+ label = "EditModeAnimatedContent",
+ ) { editing ->
+ if (editing) {
+ val qqsPadding by
+ viewModel.qqsHeaderHeight.collectAsStateWithLifecycle()
+ EditMode(
+ viewModel = viewModel.containerViewModel.editModeViewModel,
+ modifier =
+ Modifier.fillMaxWidth()
+ .padding(top = { qqsPadding })
+ .padding(
+ horizontal = {
+ QuickSettingsShade.Dimensions.Padding
+ .roundToPx()
+ }
+ ),
)
+ } else {
+ CollapsableQuickSettingsSTL()
}
- .graphicsLayer { elevation = 4.dp.toPx() },
- ) {
- val isEditing by
- viewModel.containerViewModel.editModeViewModel.isEditing
- .collectAsStateWithLifecycle()
- val animationSpecEditMode = tween<Float>(EDIT_MODE_TIME_MILLIS)
- AnimatedContent(
- targetState = isEditing,
- transitionSpec = {
- fadeIn(animationSpecEditMode) togetherWith
- fadeOut(animationSpecEditMode)
- },
- label = "EditModeAnimatedContent",
- ) { editing ->
- if (editing) {
- val qqsPadding by
- viewModel.qqsHeaderHeight.collectAsStateWithLifecycle()
- EditMode(
- viewModel = viewModel.containerViewModel.editModeViewModel,
- modifier =
- Modifier.fillMaxWidth()
- .padding(top = { qqsPadding })
- .padding(
- horizontal = {
- QuickSettingsShade.Dimensions.Padding
- .roundToPx()
- }
- ),
- )
- } else {
- CollapsableQuickSettingsSTL()
}
}
}
}
}
- }
+
+ val frame =
+ FrameLayoutTouchPassthrough(
+ context,
+ { notificationScrimClippingParams.isEnabled },
+ { notificationScrimClippingParams.top },
+ )
+ frame.addView(
+ composeView,
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ )
+ return frame
}
/**
@@ -762,3 +779,26 @@
}
private const val EDIT_MODE_TIME_MILLIS = 500
+
+/**
+ * Ignore touches below the value returned by [clippingTopProvider], when clipping is enabled, as
+ * per [clippingEnabledProvider].
+ */
+private class FrameLayoutTouchPassthrough(
+ context: Context,
+ private val clippingEnabledProvider: () -> Boolean,
+ private val clippingTopProvider: () -> Int,
+) : FrameLayout(context) {
+ override fun isTransformedTouchPointInView(
+ x: Float,
+ y: Float,
+ child: View?,
+ outLocalPoint: PointF?,
+ ): Boolean {
+ return if (clippingEnabledProvider() && y + translationY > clippingTopProvider()) {
+ false
+ } else {
+ super.isTransformedTouchPointInView(x, y, child, outLocalPoint)
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index dc62b27..bcc2019 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4116,20 +4116,31 @@
}
@Override
- @FlaggedApi(android.app.Flags.FLAG_UI_RICH_ONGOING)
- public boolean canBePromoted(String pkg, int uid) {
+ @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING)
+ public boolean appCanBePromoted(String pkg, int uid) {
checkCallerIsSystemOrSystemUiOrShell();
- if (!android.app.Flags.uiRichOngoing()) {
+ if (!android.app.Flags.apiRichOngoing()) {
return false;
}
return mPreferencesHelper.canBePromoted(pkg, uid);
}
@Override
- @FlaggedApi(android.app.Flags.FLAG_UI_RICH_ONGOING)
+ @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING)
+ public boolean canBePromoted(String callingPkg) {
+ checkCallerIsSameApp(callingPkg);
+ if (!android.app.Flags.apiRichOngoing()) {
+ return false;
+ }
+ return mPreferencesHelper.canBePromoted(callingPkg, Binder.getCallingUid());
+ }
+
+
+ @Override
+ @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING)
public void setCanBePromoted(String pkg, int uid, boolean promote) {
checkCallerIsSystemOrSystemUiOrShell();
- if (!android.app.Flags.uiRichOngoing()) {
+ if (!android.app.Flags.apiRichOngoing()) {
return;
}
boolean changed = mPreferencesHelper.setCanBePromoted(pkg, uid, promote);
@@ -7776,7 +7787,7 @@
return false;
}
- if (android.app.Flags.uiRichOngoing()) {
+ if (android.app.Flags.apiRichOngoing()) {
// This would normally be done in fixNotification(), but we need the channel info so
// it's done a little late
if (mPreferencesHelper.canBePromoted(pkg, notificationUid)
@@ -10740,7 +10751,7 @@
}
@GuardedBy("mNotificationLock")
- @FlaggedApi(android.app.Flags.FLAG_UI_RICH_ONGOING)
+ @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING)
private @NonNull List<NotificationRecord> findAppNotificationByListLocked(
ArrayList<NotificationRecord> list, String pkg, int userId) {
List<NotificationRecord> records = new ArrayList<>();
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index fcc8d2f..fdb9f67 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -850,14 +850,14 @@
}
}
- @FlaggedApi(android.app.Flags.FLAG_UI_RICH_ONGOING)
+ @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING)
public boolean canBePromoted(String packageName, int uid) {
synchronized (mLock) {
return getOrCreatePackagePreferencesLocked(packageName, uid).canHavePromotedNotifs;
}
}
- @FlaggedApi(android.app.Flags.FLAG_UI_RICH_ONGOING)
+ @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING)
public boolean setCanBePromoted(String packageName, int uid, boolean promote) {
boolean changed = false;
synchronized (mLock) {
@@ -3065,7 +3065,7 @@
boolean migrateToPm = false;
long creationTime;
- @FlaggedApi(android.app.Flags.FLAG_UI_RICH_ONGOING)
+ @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING)
boolean canHavePromotedNotifs = false;
@UserIdInt int userId;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ff9c3e5..611e0d8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3389,18 +3389,31 @@
return true;
}
// Does it contain a device admin for any user?
- int[] users;
+ int[] allUsers = mUserManager.getUserIds();
+ int[] targetUsers;
if (userId == UserHandle.USER_ALL) {
- users = mUserManager.getUserIds();
+ targetUsers = allUsers;
} else {
- users = new int[]{userId};
+ targetUsers = new int[]{userId};
}
- for (int i = 0; i < users.length; ++i) {
- if (dpm.packageHasActiveAdmins(packageName, users[i])) {
+
+ for (int i = 0; i < targetUsers.length; ++i) {
+ if (dpm.packageHasActiveAdmins(packageName, targetUsers[i])) {
return true;
}
- if (isDeviceManagementRoleHolder(packageName, users[i])
- && dpmi.isUserOrganizationManaged(users[i])) {
+ }
+
+ // If a package is DMRH on a managed user, it should also be treated as an admin on
+ // that user. If that package is also a system package, it should also be protected
+ // on other users otherwise "uninstall updates" on an unmanaged user may break
+ // management on other users because apk version is shared between all users.
+ var packageState = snapshotComputer().getPackageStateInternal(packageName);
+ if (packageState == null) {
+ return false;
+ }
+ for (int user : packageState.isSystem() ? allUsers : targetUsers) {
+ if (isDeviceManagementRoleHolder(packageName, user)
+ && dpmi.isUserOrganizationManaged(user)) {
return true;
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 130690d..d69d678 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -16556,7 +16556,7 @@
}
@Test
- @EnableFlags(android.app.Flags.FLAG_UI_RICH_ONGOING)
+ @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
public void testSetCanBePromoted_granted() throws Exception {
mContext.getTestablePermissions().setPermission(
android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
@@ -16632,7 +16632,7 @@
}
@Test
- @EnableFlags(android.app.Flags.FLAG_UI_RICH_ONGOING)
+ @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
public void testSetCanBePromoted_granted_onlyNotifiesOnce() throws Exception {
mContext.getTestablePermissions().setPermission(
android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
@@ -16663,7 +16663,7 @@
}
@Test
- @EnableFlags(android.app.Flags.FLAG_UI_RICH_ONGOING)
+ @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
public void testSetCanBePromoted_revoked() throws Exception {
mContext.getTestablePermissions().setPermission(
android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
@@ -16728,7 +16728,7 @@
}
@Test
- @EnableFlags(android.app.Flags.FLAG_UI_RICH_ONGOING)
+ @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
public void testSetCanBePromoted_revoked_onlyNotifiesOnce() throws Exception {
mContext.getTestablePermissions().setPermission(
android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
@@ -16763,10 +16763,10 @@
}
@Test
- @EnableFlags(android.app.Flags.FLAG_UI_RICH_ONGOING)
+ @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
public void testPostPromotableNotification() throws Exception {
mBinderService.setCanBePromoted(mPkg, mUid, true);
- assertThat(mBinderService.canBePromoted(mPkg, mUid)).isTrue();
+ assertThat(mBinderService.appCanBePromoted(mPkg, mUid)).isTrue();
mContext.getTestablePermissions().setPermission(
android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
@@ -16776,7 +16776,6 @@
.setColor(Color.WHITE)
.setColorized(true)
.build();
- //assertThat(n.hasPromotableCharacteristics()).isTrue();
StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0,
n, UserHandle.getUserHandleForUid(mUid), null, 0);
@@ -16794,7 +16793,7 @@
}
@Test
- @EnableFlags(android.app.Flags.FLAG_UI_RICH_ONGOING)
+ @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
public void testPostPromotableNotification_noPermission() throws Exception {
mContext.getTestablePermissions().setPermission(
android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
@@ -16822,7 +16821,7 @@
}
@Test
- @EnableFlags(android.app.Flags.FLAG_UI_RICH_ONGOING)
+ @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
public void testPostPromotableNotification_unimportantNotification() throws Exception {
mBinderService.setCanBePromoted(mPkg, mUid, true);
mContext.getTestablePermissions().setPermission(