summaryrefslogtreecommitdiff
path: root/service/java/com/android/safetycenter/SafetyCenterDataTracker.java
diff options
context:
space:
mode:
Diffstat (limited to 'service/java/com/android/safetycenter/SafetyCenterDataTracker.java')
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterDataTracker.java122
1 files changed, 105 insertions, 17 deletions
diff --git a/service/java/com/android/safetycenter/SafetyCenterDataTracker.java b/service/java/com/android/safetycenter/SafetyCenterDataTracker.java
index fe0b6768c..cd2fdf94d 100644
--- a/service/java/com/android/safetycenter/SafetyCenterDataTracker.java
+++ b/service/java/com/android/safetycenter/SafetyCenterDataTracker.java
@@ -24,9 +24,11 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.PendingIntent;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
import android.icu.text.ListFormatter;
import android.icu.text.MessageFormat;
import android.icu.util.ULocale;
@@ -72,7 +74,6 @@ import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
-import java.util.Set;
import javax.annotation.concurrent.NotThreadSafe;
@@ -88,7 +89,9 @@ final class SafetyCenterDataTracker {
private static final String TAG = "SafetyCenterDataTracker";
- private static final String ANDROID_LOCK_SCREEN_SOURCES_ID = "AndroidLockScreenSources";
+ private static final String ANDROID_LOCK_SCREEN_SOURCES_GROUP_ID = "AndroidLockScreenSources";
+ private static final String ANDROID_LOCK_SCREEN_SOURCE_ID = "AndroidLockScreen";
+ private static final int ANDROID_LOCK_SCREEN_ICON_ACTION_REQ_CODE = 86;
private static final SafetyCenterIssuesBySeverityDescending
SAFETY_CENTER_ISSUES_BY_SEVERITY_DESCENDING =
@@ -301,11 +304,17 @@ final class SafetyCenterDataTracker {
}
/**
- * Clears all safety source errors received so far, this is useful e.g. when starting a new
- * broadcast.
+ * Clears all safety source errors received so far for the given {@link UserProfileGroup}, this
+ * is useful e.g. when starting a new broadcast.
*/
- void clearSafetySourceErrors() {
- mSafetySourceErrors.clear();
+ void clearSafetySourceErrors(@NonNull UserProfileGroup userProfileGroup) {
+ // Loop in reverse index order to be able to remove entries while iterating.
+ for (int i = mSafetySourceErrors.size() - 1; i >= 0; i--) {
+ SafetySourceKey sourceKey = mSafetySourceErrors.valueAt(i);
+ if (userProfileGroup.contains(sourceKey.getUserId())) {
+ mSafetySourceErrors.removeAt(i);
+ }
+ }
}
/**
@@ -478,6 +487,13 @@ final class SafetyCenterDataTracker {
}
}
// Loop in reverse index order to be able to remove entries while iterating.
+ for (int i = mSafetySourceErrors.size() - 1; i >= 0; i--) {
+ SafetySourceKey sourceKey = mSafetySourceErrors.valueAt(i);
+ if (sourceKey.getUserId() == userId) {
+ mSafetySourceErrors.removeAt(i);
+ }
+ }
+ // Loop in reverse index order to be able to remove entries while iterating.
for (int i = mSafetyCenterIssueCache.size() - 1; i >= 0; i--) {
SafetyCenterIssueKey issueKey = mSafetyCenterIssueCache.keyAt(i);
if (issueKey.getUserId() == userId) {
@@ -705,7 +721,7 @@ final class SafetyCenterDataTracker {
int safetyCenterOverallSeverityLevel = SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK;
int safetyCenterEntriesSeverityLevel = SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK;
List<SafetyCenterIssue> safetyCenterIssues = new ArrayList<>();
- Set<Integer> allCurrentIssueCategories = new ArraySet<>();
+ ArraySet<Integer> allCurrentIssueCategories = new ArraySet<>();
List<SafetyCenterEntryOrGroup> safetyCenterEntryOrGroups = new ArrayList<>();
List<SafetyCenterStaticEntryGroup> safetyCenterStaticEntryGroups = new ArrayList<>();
SafetyCenterOverallStatusErrorState safetyCenterOverallStatusErrorState =
@@ -779,7 +795,7 @@ final class SafetyCenterDataTracker {
@SafetyCenterStatus.OverallSeverityLevel
private int addSafetyCenterIssues(
@NonNull List<SafetyCenterIssue> safetyCenterIssues,
- @NonNull Set<Integer> allCurrentIssueCategories,
+ @NonNull ArraySet<Integer> allCurrentIssueCategories,
@NonNull SafetySourcesGroup safetySourcesGroup,
@NonNull UserProfileGroup userProfileGroup) {
int safetyCenterIssuesOverallSeverityLevel = SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK;
@@ -826,7 +842,7 @@ final class SafetyCenterDataTracker {
@SafetyCenterStatus.OverallSeverityLevel
private int addSafetyCenterIssues(
@NonNull List<SafetyCenterIssue> safetyCenterIssues,
- @NonNull Set<Integer> allCurrentIssueCategories,
+ @NonNull ArraySet<Integer> allCurrentIssueCategories,
@NonNull SafetySource safetySource,
@UserIdInt int userId) {
SafetySourceKey key = SafetySourceKey.of(safetySource.getId(), userId);
@@ -995,7 +1011,7 @@ final class SafetyCenterDataTracker {
break;
}
}
- } else if (safetySourcesGroup.getId().equals(ANDROID_LOCK_SCREEN_SOURCES_ID)
+ } else if (safetySourcesGroup.getId().equals(ANDROID_LOCK_SCREEN_SOURCES_GROUP_ID)
&& TextUtils.isEmpty(groupSummary)) {
List<CharSequence> titles = new ArrayList<>();
for (int i = 0; i < entries.size(); i++) {
@@ -1098,12 +1114,16 @@ final class SafetyCenterDataTracker {
.setSeverityUnspecifiedIconType(severityUnspecifiedIconType)
.setPendingIntent(pendingIntent);
SafetySourceStatus.IconAction iconAction = safetySourceStatus.getIconAction();
- if (iconAction != null) {
- builder.setIconAction(
- new SafetyCenterEntry.IconAction(
- toSafetyCenterEntryIconActionType(iconAction.getIconType()),
- iconAction.getPendingIntent()));
+ if (iconAction == null) {
+ return builder.build();
}
+ PendingIntent iconActionPendingIntent =
+ toIconActionPendingIntent(
+ safetySource.getId(), iconAction.getPendingIntent());
+ builder.setIconAction(
+ new SafetyCenterEntry.IconAction(
+ toSafetyCenterEntryIconActionType(iconAction.getIconType()),
+ iconActionPendingIntent));
return builder.build();
}
return toDefaultSafetyCenterEntry(
@@ -1343,16 +1363,84 @@ final class SafetyCenterDataTracker {
// TODO(b/222838784): Validate that the intent action is available.
+ return toPendingIntent(context, 0, new Intent(intentAction));
+ }
+
+ @NonNull
+ private static PendingIntent toPendingIntent(
+ @NonNull Context packageContext, int requestCode, @NonNull Intent intent) {
// This call is required for getIntentSender() to be allowed to send as another package.
final long identity = Binder.clearCallingIdentity();
try {
return PendingIntent.getActivity(
- context, 0, new Intent(intentAction), PendingIntent.FLAG_IMMUTABLE);
+ packageContext, requestCode, intent, PendingIntent.FLAG_IMMUTABLE);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
+ /**
+ * Potentially overrides the Settings IconAction PendingIntent for the AndroidLockScreen source.
+ *
+ * <p>This is done because of a bug in the Settings app where the PendingIntent created ends up
+ * referencing the one from the main entry. The reason for this is that PendingIntent instances
+ * are cached and keyed by an object which does not take into account the underlying intent
+ * extras; and these two intents only differ by the extras that they set. We fix this issue by
+ * recreating the desired Intent and PendingIntent here, using a specific request code for the
+ * PendingIntent to ensure a new instance is created (the key does take into account the request
+ * code).
+ */
+ @NonNull
+ private PendingIntent toIconActionPendingIntent(
+ @NonNull String sourceId, @NonNull PendingIntent pendingIntent) {
+ if (!ANDROID_LOCK_SCREEN_SOURCE_ID.equals(sourceId)) {
+ return pendingIntent;
+ }
+ if (!SafetyCenterFlags.getReplaceLockScreenIconAction()) {
+ return pendingIntent;
+ }
+ String settingsPackageName = pendingIntent.getCreatorPackage();
+ int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
+ Context packageContext = toPackageContextAsUser(settingsPackageName, userId);
+ if (packageContext == null) {
+ return pendingIntent;
+ }
+ Resources settingsResources = packageContext.getResources();
+ int hasSettingsFixedIssueResourceId =
+ settingsResources.getIdentifier(
+ "config_isSafetyCenterLockScreenPendingIntentFixed",
+ "bool",
+ settingsPackageName);
+ if (hasSettingsFixedIssueResourceId != Resources.ID_NULL) {
+ boolean hasSettingsFixedIssue =
+ settingsResources.getBoolean(hasSettingsFixedIssueResourceId);
+ if (hasSettingsFixedIssue) {
+ return pendingIntent;
+ }
+ }
+ Intent intent =
+ new Intent(Intent.ACTION_MAIN)
+ .setComponent(
+ new ComponentName(
+ settingsPackageName, settingsPackageName + ".SubSettings"))
+ .putExtra(
+ ":settings:show_fragment",
+ settingsPackageName + ".security.screenlock.ScreenLockSettings")
+ .putExtra(":settings:source_metrics", 1917)
+ .putExtra("page_transition_type", 0);
+ PendingIntent offendingPendingIntent = toPendingIntent(packageContext, 0, intent);
+ if (!offendingPendingIntent.equals(pendingIntent)) {
+ return pendingIntent;
+ }
+ // If creating that PendingIntent with request code 0 returns the same value as the
+ // PendingIntent that was sent to Safety Center, then we’re most likely hitting the caching
+ // issue described in this method’s documentation.
+ // i.e. the intent action and component of the cached PendingIntent are the same, but the
+ // extras are actually different so we should ensure we create a brand new PendingIntent by
+ // changing the request code.
+ return toPendingIntent(packageContext, ANDROID_LOCK_SCREEN_ICON_ACTION_REQ_CODE, intent);
+ }
+
@Nullable
private Context toPackageContextAsUser(@NonNull String packageName, @UserIdInt int userId) {
// This call requires the INTERACT_ACROSS_USERS permission.
@@ -1496,7 +1584,7 @@ final class SafetyCenterDataTracker {
private String getSafetyCenterStatusTitle(
@SafetyCenterStatus.OverallSeverityLevel int overallSeverityLevel,
@SafetyCenterStatus.RefreshStatus int refreshStatus,
- @NonNull Set<Integer> allCurrentIssueCategories,
+ @NonNull ArraySet<Integer> allCurrentIssueCategories,
boolean hasSettingsToReview) {
String refreshStatusTitle = getSafetyCenterRefreshStatusTitle(refreshStatus);
if (refreshStatusTitle != null) {