Dismiss the suspend dialog if conditions have been modified.

Whenever suspension conditions change, if there is a user-visible
suspension-related dialog, dismiss it to ensure the user is never
looking at stale information.

Bug: 169137795
Test: atest SuspendPackagesBroadcastTest#sendPackagesSuspendModifiedForUser
Test: manual (steps below)
-enable EBS, tap on suspended app to see dialog
-enable Focus mode, ensure dialog is dismissed
-tap on suspended app again to see relevent dialog,
 disable Focus mode, ensure dialog is dismissed
-tap on suspended app again to see relevant dialog,
 disable EBS, ensure dialog is dismissed correctly
-can permute enable/disable steps to further verify

Change-Id: Ib1650f910f7441498424ab4bc92185ce432ac405
This commit is contained in:
Varun Shah
2021-08-17 13:49:06 -07:00
parent 1f9a622520
commit 25e73a8b9e
5 changed files with 88 additions and 36 deletions

View File

@@ -2738,6 +2738,22 @@ public class Intent implements Parcelable, Cloneable {
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED";
/**
* Broadcast Action: One of the suspend conditions have been modified for the packages.
* <p>Includes the following extras:
* <ul>
* <li> {@link #EXTRA_CHANGED_PACKAGE_LIST} is the set of packages which have been modified
* <li> {@link #EXTRA_CHANGED_UID_LIST} is the set of uids which have been modified
* </ul>
*
* <p class="note">This is a protected intent that can only be sent
* by the system. It is only sent to registered receivers.
*
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGES_SUSPENSION_CHANGED =
"android.intent.action.PACKAGES_SUSPENSION_CHANGED";
/**
* Broadcast Action: Distracting packages have been changed.

View File

@@ -72,17 +72,19 @@ public class SuspendedAppActivity extends AlertActivity
private Resources mSuspendingAppResources;
private SuspendDialogInfo mSuppliedDialogInfo;
private Bundle mOptions;
private BroadcastReceiver mUnsuspendReceiver = new BroadcastReceiver() {
private BroadcastReceiver mSuspendModifiedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_PACKAGES_UNSUSPENDED.equals(intent.getAction())) {
final String[] unsuspended = intent.getStringArrayExtra(
if (Intent.ACTION_PACKAGES_SUSPENSION_CHANGED.equals(intent.getAction())) {
// Suspension conditions were modified, dismiss any related visible dialogs.
final String[] modified = intent.getStringArrayExtra(
Intent.EXTRA_CHANGED_PACKAGE_LIST);
if (ArrayUtils.contains(unsuspended, mSuspendedPackage)) {
if (ArrayUtils.contains(modified, mSuspendedPackage)) {
if (!isFinishing()) {
Slog.w(TAG, "Package " + mSuspendedPackage
+ " got unsuspended while the dialog was visible. Finishing.");
Slog.w(TAG, "Package " + mSuspendedPackage + " has modified"
+ " suspension conditions while dialog was visible. Finishing.");
SuspendedAppActivity.this.finish();
// TODO (b/198201994): reload the suspend dialog to show most relevant info
}
}
}
@@ -245,15 +247,16 @@ public class SuspendedAppActivity extends AlertActivity
setupAlert();
final IntentFilter unsuspendFilter = new IntentFilter(Intent.ACTION_PACKAGES_UNSUSPENDED);
registerReceiverAsUser(mUnsuspendReceiver, UserHandle.of(mUserId), unsuspendFilter, null,
null);
final IntentFilter suspendModifiedFilter =
new IntentFilter(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED);
registerReceiverAsUser(mSuspendModifiedReceiver, UserHandle.of(mUserId),
suspendModifiedFilter, null, null);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mUnsuspendReceiver);
unregisterReceiver(mSuspendModifiedReceiver);
}
private void requestDismissKeyguardIfNeeded(CharSequence dismissMessage) {

View File

@@ -15818,8 +15818,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
void sendPackagesSuspendedForUser(String[] pkgList, int[] uidList, int userId,
boolean suspended) {
void sendPackagesSuspendedForUser(String intent, String[] pkgList, int[] uidList, int userId) {
final List<List<String>> pkgsToSend = new ArrayList(pkgList.length);
final List<IntArray> uidsToSend = new ArrayList(pkgList.length);
final List<SparseArray<int[]>> allowListsToSend = new ArrayList(pkgList.length);
@@ -15860,11 +15859,8 @@ public class PackageManagerService extends IPackageManager.Stub
extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidsToSend.get(i).toArray());
final SparseArray<int[]> allowList = allowListsToSend.get(i).size() == 0
? null : allowListsToSend.get(i);
sendPackageBroadcast(
suspended ? Intent.ACTION_PACKAGES_SUSPENDED
: Intent.ACTION_PACKAGES_UNSUSPENDED,
null, extras, Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null,
userIds, null, allowList, null);
sendPackageBroadcast(intent, null, extras, Intent.FLAG_RECEIVER_REGISTERED_ONLY, null,
null, userIds, null, allowList, null);
}
}
@@ -16178,6 +16174,8 @@ public class PackageManagerService extends IPackageManager.Stub
final List<String> changedPackagesList = new ArrayList<>(packageNames.length);
final IntArray changedUids = new IntArray(packageNames.length);
final List<String> modifiedPackagesList = new ArrayList<>(packageNames.length);
final IntArray modifiedUids = new IntArray(packageNames.length);
final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
final boolean[] canSuspend = suspended ? canSuspendPackageForUserInternal(packageNames,
userId) : null;
@@ -16205,13 +16203,14 @@ public class PackageManagerService extends IPackageManager.Stub
unactionedPackages.add(packageName);
continue;
}
boolean packageUnsuspended;
final boolean packageUnsuspended;
final boolean packageModified;
synchronized (mLock) {
if (suspended) {
pkgSetting.addOrUpdateSuspension(callingPackage, dialogInfo, appExtras,
launcherExtras, userId);
packageModified = pkgSetting.addOrUpdateSuspension(callingPackage,
dialogInfo, appExtras, launcherExtras, userId);
} else {
pkgSetting.removeSuspension(callingPackage, userId);
packageModified = pkgSetting.removeSuspension(callingPackage, userId);
}
packageUnsuspended = !suspended && !pkgSetting.getSuspended(userId);
}
@@ -16219,18 +16218,29 @@ public class PackageManagerService extends IPackageManager.Stub
changedPackagesList.add(packageName);
changedUids.add(UserHandle.getUid(userId, pkgSetting.appId));
}
if (packageModified) {
modifiedPackagesList.add(packageName);
modifiedUids.add(UserHandle.getUid(userId, pkgSetting.appId));
}
}
if (!changedPackagesList.isEmpty()) {
final String[] changedPackages = changedPackagesList.toArray(
new String[changedPackagesList.size()]);
sendPackagesSuspendedForUser(changedPackages, changedUids.toArray(), userId, suspended);
final String[] changedPackages = changedPackagesList.toArray(new String[0]);
sendPackagesSuspendedForUser(
suspended ? Intent.ACTION_PACKAGES_SUSPENDED
: Intent.ACTION_PACKAGES_UNSUSPENDED,
changedPackages, changedUids.toArray(), userId);
sendMyPackageSuspendedOrUnsuspended(changedPackages, suspended, userId);
synchronized (mLock) {
scheduleWritePackageRestrictionsLocked(userId);
}
}
return unactionedPackages.toArray(new String[unactionedPackages.size()]);
// Send the suspension changed broadcast to ensure suspension state is not stale.
if (!modifiedPackagesList.isEmpty()) {
sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED,
modifiedPackagesList.toArray(new String[0]), modifiedUids.toArray(), userId);
}
return unactionedPackages.toArray(new String[0]);
}
@Override
@@ -16359,7 +16369,8 @@ public class PackageManagerService extends IPackageManager.Stub
final String[] packageArray = unsuspendedPackages.toArray(
new String[unsuspendedPackages.size()]);
sendMyPackageSuspendedOrUnsuspended(packageArray, false, userId);
sendPackagesSuspendedForUser(packageArray, unsuspendedUids.toArray(), userId, false);
sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_UNSUSPENDED,
packageArray, unsuspendedUids.toArray(), userId);
}
}

View File

@@ -455,7 +455,7 @@ public abstract class PackageSettingBase extends SettingBase {
return state.suspendParams != null && state.suspendParams.containsKey(suspendingPackage);
}
void addOrUpdateSuspension(String suspendingPackage, SuspendDialogInfo dialogInfo,
boolean addOrUpdateSuspension(String suspendingPackage, SuspendDialogInfo dialogInfo,
PersistableBundle appExtras, PersistableBundle launcherExtras, int userId) {
final PackageUserState existingUserState = modifyUserState(userId);
final PackageUserState.SuspendParams newSuspendParams =
@@ -464,21 +464,27 @@ public abstract class PackageSettingBase extends SettingBase {
if (existingUserState.suspendParams == null) {
existingUserState.suspendParams = new ArrayMap<>();
}
existingUserState.suspendParams.put(suspendingPackage, newSuspendParams);
final PackageUserState.SuspendParams oldSuspendParams =
existingUserState.suspendParams.put(suspendingPackage, newSuspendParams);
existingUserState.suspended = true;
onChanged();
return !Objects.equals(oldSuspendParams, newSuspendParams);
}
void removeSuspension(String suspendingPackage, int userId) {
boolean removeSuspension(String suspendingPackage, int userId) {
boolean wasModified = false;
final PackageUserState existingUserState = modifyUserState(userId);
if (existingUserState.suspendParams != null) {
existingUserState.suspendParams.remove(suspendingPackage);
if (existingUserState.suspendParams.remove(suspendingPackage) != null) {
wasModified = true;
}
if (existingUserState.suspendParams.size() == 0) {
existingUserState.suspendParams = null;
}
}
existingUserState.suspended = (existingUserState.suspendParams != null);
onChanged();
return wasModified;
}
void removeSuspension(Predicate<String> suspendingPackagePredicate, int userId) {

View File

@@ -79,8 +79,8 @@ class SuspendPackagesBroadcastTest {
mockAllowList(packageSetting1, allowList(10001, 10002, 10003))
mockAllowList(packageSetting2, allowList(10001, 10002, 10003))
pms.sendPackagesSuspendedForUser(
packagesToSuspend, uidsToSuspend, TEST_USER_ID, /* suspended = */ true)
pms.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENDED,
packagesToSuspend, uidsToSuspend, TEST_USER_ID)
verify(pms).sendPackageBroadcast(any(), nullable(), bundleCaptor.capture(),
anyInt(), nullable(), nullable(), any(), nullable(), any(), nullable())
@@ -97,8 +97,8 @@ class SuspendPackagesBroadcastTest {
mockAllowList(packageSetting1, allowList(10001, 10002, 10003))
mockAllowList(packageSetting2, allowList(10001, 10002, 10007))
pms.sendPackagesSuspendedForUser(
packagesToSuspend, uidsToSuspend, TEST_USER_ID, /* suspended = */ true)
pms.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENDED,
packagesToSuspend, uidsToSuspend, TEST_USER_ID)
verify(pms, times(2)).sendPackageBroadcast(any(), nullable(), bundleCaptor.capture(),
anyInt(), nullable(), nullable(), any(), nullable(), any(), nullable())
@@ -118,8 +118,8 @@ class SuspendPackagesBroadcastTest {
mockAllowList(packageSetting1, allowList(10001, 10002, 10003))
mockAllowList(packageSetting2, null)
pms.sendPackagesSuspendedForUser(
packagesToSuspend, uidsToSuspend, TEST_USER_ID, /* suspended = */ true)
pms.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENDED,
packagesToSuspend, uidsToSuspend, TEST_USER_ID)
verify(pms, times(2)).sendPackageBroadcast(any(), nullable(), bundleCaptor.capture(),
anyInt(), nullable(), nullable(), any(), nullable(), nullable(), nullable())
@@ -133,6 +133,22 @@ class SuspendPackagesBroadcastTest {
}
}
@Test
@Throws(Exception::class)
fun sendPackagesSuspendModifiedForUser() {
pms.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED,
packagesToSuspend, uidsToSuspend, TEST_USER_ID)
verify(pms).sendPackageBroadcast(
eq(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED), nullable(), bundleCaptor.capture(),
anyInt(), nullable(), nullable(), any(), nullable(), nullable(), nullable())
var modifiedPackages = bundleCaptor.value.getStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST)
var modifiedUids = bundleCaptor.value.getIntArray(Intent.EXTRA_CHANGED_UID_LIST)
assertThat(modifiedPackages).asList().containsExactly(TEST_PACKAGE_1, TEST_PACKAGE_2)
assertThat(modifiedUids).asList().containsExactly(
packageSetting1.appId, packageSetting2.appId)
}
private fun allowList(vararg uids: Int) = SparseArray<IntArray>().apply {
this.put(TEST_USER_ID, uids)
}