"More Issues" card expand fails after data refresh
Bug: 234024787
Test: atest SafetyCenterActivityTest
Change-Id: If3059c8af13781951d48ab50a60bd755432b7012
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/CollapsableIssuesCardHelper.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/CollapsableIssuesCardHelper.kt
index 45d3e27..f0af622 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/CollapsableIssuesCardHelper.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/CollapsableIssuesCardHelper.kt
@@ -19,87 +19,154 @@
import android.content.Context
import android.content.Intent
import android.content.Intent.ACTION_SAFETY_CENTER
+import android.os.Bundle
+import android.safetycenter.SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK
import androidx.preference.PreferenceGroup
import com.android.permissioncontroller.R
import com.android.permissioncontroller.safetycenter.SafetyCenterConstants.EXPAND_ISSUE_GROUP_QS_FRAGMENT_KEY
+import kotlin.math.max
/**
* Helper class to hide issue cards if over a predefined limit and handle revealing hidden issue
* cards when the more issues preference is clicked
- *
- * @param context Current context
- * @param issueCardPreferences {@link List} of {@link IssueCardPreference} to add to the preference
- * fragment
- * @param expandIssueCards {@code true} if issue cards should be initially expanded, {@code false}
- * otherwise
- * @param expandPreferencesListener Listener used to inform preference fragment of expansion
*/
-class CollapsableIssuesCardHelper(
- val context: Context,
- val issueCardPreferences: List<IssueCardPreference>,
- val expandIssueCards: Boolean,
- val isQuickSettingsFragment: Boolean = false,
- val expandPreferencesListener: () -> Unit
-) {
- private val numberOfHiddenIssues = issueCardPreferences.size - MAX_SHOWN_ISSUES_COLLAPSED
- private val hasHiddenIssueCards = !expandIssueCards && numberOfHiddenIssues > 0
- private var moreIssuesCardPreference: MoreIssuesCardPreference? =
- getMoreIssuesCardPreferenceOrNull(context)
+class CollapsableIssuesCardHelper {
+ private var isQuickSettingsFragment: Boolean = false
+ private var issueCardsExpanded: Boolean = false
/**
- * Add the [IssueCardPreference] managed by this helper to the specified [ ]
+ * Sets QuickSetting specific state for use to determine correct issue section expansion state
+ * as well ass more issues card icon values
*
- * @param preferenceGroup Preference group to add preference to
+ * <p> Note the issueCardsExpanded value set here may be overridden here by calls to
+ * restoreState
+ *
+ * @param isQuickSettingsFragment {@code true} if CollapsableIssuesCardHelper is being used in
+ * quick settings fragment
+ * @param issueCardsExpanded Whether issue cards should be expanded or not when added to
+ * preference screen
*/
- fun addIssues(preferenceGroup: PreferenceGroup) {
- if (issueCardPreferences.isEmpty()) {
- return
- }
- for (i in issueCardPreferences.indices) {
- val issueCardPreference: IssueCardPreference = issueCardPreferences[i]
- if (i == MAX_SHOWN_ISSUES_COLLAPSED &&
- hasHiddenIssueCards &&
- moreIssuesCardPreference != null) {
- preferenceGroup.addPreference(moreIssuesCardPreference)
- }
- issueCardPreference.isVisible = i < MAX_SHOWN_ISSUES_COLLAPSED || expandIssueCards
- preferenceGroup.addPreference(issueCardPreference)
- }
+ fun setQuickSettingsState(isQuickSettingsFragment: Boolean, issueCardsExpanded: Boolean) {
+ this.isQuickSettingsFragment = isQuickSettingsFragment
+ this.issueCardsExpanded = issueCardsExpanded
}
- private fun getMoreIssuesCardPreferenceOrNull(context: Context): MoreIssuesCardPreference? {
- if (!hasHiddenIssueCards) {
- // Not enough issues show more issues card
- return null
+ /** Restore previously saved state from [Bundle] */
+ fun restoreState(state: Bundle?) {
+ if (state == null) {
+ return
}
- val firstHiddenIssue = issueCardPreferences[MAX_SHOWN_ISSUES_COLLAPSED]
+ // Apply the previously saved state
+ issueCardsExpanded = state.getBoolean(EXPAND_ISSUE_GROUP_SAVED_INSTANCE_STATE_KEY, false)
+ }
+
+ /** Save current state to provided [Bundle] */
+ fun saveState(outState: Bundle) =
+ outState.putBoolean(EXPAND_ISSUE_GROUP_SAVED_INSTANCE_STATE_KEY, issueCardsExpanded)
+
+ /**
+ * Add the [IssueCardPreference] managed by this helper to the specified [PreferenceGroup]
+ *
+ * @param context Current context
+ * @param issuesPreferenceGroup Preference group to add preference to
+ * @param issueCardPreferences {@link List} of {@link IssueCardPreference} to add to the
+ * preference fragment
+ */
+ fun addIssues(
+ context: Context,
+ issuesPreferenceGroup: PreferenceGroup,
+ issueCardPreferences: List<IssueCardPreference>
+ ) {
+ val moreIssuesCardPreference =
+ createMoreIssuesCardPreference(context, issuesPreferenceGroup, issueCardPreferences)
+ addIssuesToPreferenceGroupAndSetVisibility(
+ issuesPreferenceGroup,
+ issueCardPreferences,
+ moreIssuesCardPreference,
+ issueCardsExpanded)
+ }
+
+ private fun createMoreIssuesCardPreference(
+ context: Context,
+ issuesPreferenceGroup: PreferenceGroup,
+ issueCardPreferences: List<IssueCardPreference>
+ ): MoreIssuesCardPreference {
val prefIconResourceId =
if (isQuickSettingsFragment) R.drawable.ic_chevron_right else R.drawable.ic_expand_more
+ val numberOfHiddenIssue: Int = getNumberOfHiddenIssues(issueCardPreferences)
+ val firstHiddenIssueSeverityLevel: Int =
+ getFirstHiddenIssueSeverityLevel(issueCardPreferences)
+
return MoreIssuesCardPreference(
- context, prefIconResourceId, numberOfHiddenIssues, firstHiddenIssue.severityLevel) {
- expand()
+ context, prefIconResourceId, numberOfHiddenIssue, firstHiddenIssueSeverityLevel) {
+ if (isQuickSettingsFragment) {
+ goToSafetyCenter(context)
+ } else {
+ expand(issuesPreferenceGroup)
+ }
true
}
}
- private fun expand() {
- if (isQuickSettingsFragment) {
- // Navigate to Safety center with issues expanded
- val safetyCenterIntent = Intent(ACTION_SAFETY_CENTER)
- safetyCenterIntent.putExtra(EXPAND_ISSUE_GROUP_QS_FRAGMENT_KEY, true)
- context.startActivity(safetyCenterIntent)
+ private fun expand(issuesPreferenceGroup: PreferenceGroup) {
+ if (issueCardsExpanded) {
return
}
- for (preference in issueCardPreferences) {
- preference.isVisible = true
+ val numberOfPreferences = issuesPreferenceGroup.preferenceCount
+ for (i in 0 until numberOfPreferences) {
+ val preference = issuesPreferenceGroup.getPreference(i)
+ when {
+ // preferences with index under MAX_SHOWN_ISSUES_COLLAPSED are already visible
+ i < MAX_SHOWN_ISSUES_COLLAPSED -> continue
+ // "more issues" preference has index of MAX_SHOWN_ISSUES_COLLAPSED and must be
+ // hidden after expansion of issues
+ i == MAX_SHOWN_ISSUES_COLLAPSED -> preference.isVisible = false
+ // All further issue preferences must be shown
+ else -> preference.isVisible = true
+ }
}
- moreIssuesCardPreference?.isVisible = false
- // Notify host so cards can stay expanded on refresh or restart of fragment
- expandPreferencesListener()
+ issueCardsExpanded = true
+ }
+
+ private fun goToSafetyCenter(context: Context) {
+ // Navigate to Safety center with issues expanded
+ val safetyCenterIntent = Intent(ACTION_SAFETY_CENTER)
+ safetyCenterIntent.putExtra(EXPAND_ISSUE_GROUP_QS_FRAGMENT_KEY, true)
+ context.startActivity(safetyCenterIntent)
}
companion object {
+ private const val EXPAND_ISSUE_GROUP_SAVED_INSTANCE_STATE_KEY =
+ "expand_issue_group_saved_instance_state_key"
private const val MAX_SHOWN_ISSUES_COLLAPSED = 1
+
+ private fun getNumberOfHiddenIssues(issueCardPreferences: List<IssueCardPreference>): Int =
+ max(0, issueCardPreferences.size - MAX_SHOWN_ISSUES_COLLAPSED)
+
+ private fun getFirstHiddenIssueSeverityLevel(
+ issueCardPreferences: List<IssueCardPreference>
+ ): Int {
+ val firstHiddenIssue: IssueCardPreference? =
+ issueCardPreferences.getOrNull(MAX_SHOWN_ISSUES_COLLAPSED)
+ // If no first hidden issue, default to ISSUE_SEVERITY_LEVEL_OK
+ return firstHiddenIssue?.severityLevel ?: ISSUE_SEVERITY_LEVEL_OK
+ }
+
+ private fun addIssuesToPreferenceGroupAndSetVisibility(
+ issuesPreferenceGroup: PreferenceGroup,
+ issueCardPreferences: List<IssueCardPreference>,
+ moreIssuesCardPreference: MoreIssuesCardPreference,
+ issueCardsExpanded: Boolean
+ ) {
+ issueCardPreferences.forEachIndexed { index, issueCardPreference ->
+ if (index == MAX_SHOWN_ISSUES_COLLAPSED && !issueCardsExpanded) {
+ issuesPreferenceGroup.addPreference(moreIssuesCardPreference)
+ }
+ issueCardPreference.isVisible =
+ index < MAX_SHOWN_ISSUES_COLLAPSED || issueCardsExpanded
+ issuesPreferenceGroup.addPreference(issueCardPreference)
+ }
+ }
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardPreference.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardPreference.kt
index 3d5ac93..8f0ff28 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardPreference.kt
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardPreference.kt
@@ -71,7 +71,7 @@
}
override fun isSameItem(preference: Preference): Boolean {
- return preference is MoreIssuesCardPreference
+ return hasSameContents(preference)
}
override fun hasSameContents(preference: Preference): Boolean {
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterDashboardFragment.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterDashboardFragment.java
index a30e9ca..41d62c4 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterDashboardFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterDashboardFragment.java
@@ -17,7 +17,6 @@
package com.android.permissioncontroller.safetycenter.ui;
import static com.android.permissioncontroller.safetycenter.SafetyCenterConstants.EXPAND_ISSUE_GROUP_QS_FRAGMENT_KEY;
-import static com.android.permissioncontroller.safetycenter.SafetyCenterConstants.EXPAND_ISSUE_GROUP_SAVED_INSTANCE_STATE_KEY;
import static com.android.permissioncontroller.safetycenter.SafetyCenterConstants.QUICK_SETTINGS_SAFETY_CENTER_FRAGMENT;
import static java.util.Objects.requireNonNull;
@@ -53,8 +52,6 @@
import java.util.List;
import java.util.stream.Collectors;
-import kotlin.Unit;
-
/** Dashboard fragment for the Safety Center. */
public final class SafetyCenterDashboardFragment extends PreferenceFragmentCompat {
@@ -66,6 +63,8 @@
private static final String STATIC_ENTRIES_GROUP_KEY = "static_entries_group";
@Nullable private final ViewModelProvider.Factory mSafetyCenterViewModelFactoryOverride;
+ private final CollapsableIssuesCardHelper mCollapsableIssuesCardHelper =
+ new CollapsableIssuesCardHelper();
private SafetyStatusPreference mSafetyStatusPreference;
private PreferenceGroup mIssuesGroup;
@@ -74,8 +73,6 @@
private SafetyCenterViewModel mViewModel;
private boolean mIsQuickSettingsFragment;
- private boolean mExpandIssuesGroup = false;
-
public SafetyCenterDashboardFragment() {
this(null);
}
@@ -130,16 +127,15 @@
}
setPreferencesFromResource(R.xml.safety_center_dashboard, rootKey);
// Check if we've navigated from QS and issues should be expanded
- mExpandIssuesGroup =
+ boolean expandIssuesGroup =
getActivity()
.getIntent()
.getBooleanExtra(EXPAND_ISSUE_GROUP_QS_FRAGMENT_KEY, false);
- if (savedInstanceState != null) {
- mExpandIssuesGroup =
- savedInstanceState.getBoolean(
- EXPAND_ISSUE_GROUP_SAVED_INSTANCE_STATE_KEY, false);
- }
+ // Set quick settings state first and allow restored state to override if necessary
+ mCollapsableIssuesCardHelper.setQuickSettingsState(
+ mIsQuickSettingsFragment, expandIssuesGroup);
+ mCollapsableIssuesCardHelper.restoreState(savedInstanceState);
mViewModel =
new ViewModelProvider(requireActivity(), getSafetyCenterViewModelFactory())
@@ -175,7 +171,7 @@
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
- outState.putBoolean(EXPAND_ISSUE_GROUP_SAVED_INSTANCE_STATE_KEY, mExpandIssuesGroup);
+ mCollapsableIssuesCardHelper.saveState(outState);
}
private void renderSafetyCenterData(@Nullable SafetyCenterData data) {
@@ -213,17 +209,7 @@
issues.stream()
.map(issue -> new IssueCardPreference(context, mViewModel, issue))
.collect(Collectors.toUnmodifiableList());
- CollapsableIssuesCardHelper issueCardHelper =
- new CollapsableIssuesCardHelper(
- context,
- issueCardPreferenceList,
- mExpandIssuesGroup,
- mIsQuickSettingsFragment,
- () -> {
- mExpandIssuesGroup = true;
- return Unit.INSTANCE;
- });
- issueCardHelper.addIssues(mIssuesGroup);
+ mCollapsableIssuesCardHelper.addIssues(context, mIssuesGroup, issueCardPreferenceList);
}
// TODO(b/208212820): Add groups and move to separate controller