Merge "Add toggle for showing system apps to "show all" and storage app lists." into pi-car-dev
diff --git a/res/values/preference_keys.xml b/res/values/preference_keys.xml
index cf33c99..fc4f338 100644
--- a/res/values/preference_keys.xml
+++ b/res/values/preference_keys.xml
@@ -229,6 +229,8 @@
 
     <!-- Storage -->
     <string name="pk_storage_music_audio" translatable="false">storage_music_audio</string>
+    <string name="pk_storage_music_audio_files" translatable="false">storage_music_audio_files
+    </string>
     <string name="pk_storage_music_audio_details" translatable="false">storage_music_audio_details
     </string>
     <string name="pk_storage_other_apps" translatable="false">storage_other_apps</string>
diff --git a/src/com/android/car/settings/applications/specialaccess/AppOpsFragment.java b/src/com/android/car/settings/applications/AppListFragment.java
similarity index 73%
rename from src/com/android/car/settings/applications/specialaccess/AppOpsFragment.java
rename to src/com/android/car/settings/applications/AppListFragment.java
index 165dbb8..c56ab7b 100644
--- a/src/com/android/car/settings/applications/specialaccess/AppOpsFragment.java
+++ b/src/com/android/car/settings/applications/AppListFragment.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.car.settings.applications.specialaccess;
+package com.android.car.settings.applications;
 
 import android.os.Bundle;
 import android.widget.Button;
@@ -25,11 +25,10 @@
 import com.android.car.settings.common.SettingsFragment;
 
 /**
- * Fragment which hosts an {@link AppOpsPreferenceController} to display a list of controls to
- * allow/disallow app operations. There is a toggle in the app bar for showing/hiding system
- * applications. The semantics of what constitues a system app is left up to the controller.
+ * Fragment base class for use in cases where a list of applications is displayed with the option to
+ * show/hide system apps in the list.
  */
-public abstract class AppOpsFragment extends SettingsFragment {
+public abstract class AppListFragment extends SettingsFragment {
 
     private static final String KEY_SHOW_SYSTEM = "showSystem";
 
@@ -41,15 +40,11 @@
         return R.layout.action_bar_with_button;
     }
 
-    /** Returns the {@link AppOpsPreferenceController} via {@link #use(Class, int)} lookup. */
-    protected abstract AppOpsPreferenceController lookupAppOpsPreferenceController();
-
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         if (savedInstanceState != null) {
             mShowSystem = savedInstanceState.getBoolean(KEY_SHOW_SYSTEM, false);
-            lookupAppOpsPreferenceController().setShowSystem(mShowSystem);
         }
     }
 
@@ -60,11 +55,25 @@
         setButtonText(toggleShowSystem);
         toggleShowSystem.setOnClickListener(v -> {
             mShowSystem = !mShowSystem;
-            lookupAppOpsPreferenceController().setShowSystem(mShowSystem);
+            onToggleShowSystemApps(mShowSystem);
             setButtonText(toggleShowSystem);
         });
     }
 
+    @Override
+    public void onStart() {
+        super.onStart();
+        onToggleShowSystemApps(mShowSystem);
+    }
+
+    /** Called when a user toggles the option to show system applications in the list. */
+    protected abstract void onToggleShowSystemApps(boolean showSystem);
+
+    /** Returns {@code true} if system applications should be shown in the list. */
+    protected final boolean shouldShowSystemApps() {
+        return mShowSystem;
+    }
+
     private void setButtonText(Button button) {
         // Show text to reverse the current state.
         button.setText(mShowSystem ? R.string.hide_system : R.string.show_system);
diff --git a/src/com/android/car/settings/applications/ApplicationListItemManager.java b/src/com/android/car/settings/applications/ApplicationListItemManager.java
index 7293539..8f7f95b 100644
--- a/src/com/android/car/settings/applications/ApplicationListItemManager.java
+++ b/src/com/android/car/settings/applications/ApplicationListItemManager.java
@@ -20,6 +20,7 @@
 
 import androidx.lifecycle.Lifecycle;
 
+import com.android.car.settings.common.Logger;
 import com.android.settingslib.applications.ApplicationsState;
 
 import java.util.ArrayList;
@@ -29,6 +30,7 @@
 /**
  * Class used to load the applications installed on the system with their metadata.
  */
+// TODO: consolidate with AppEntryListManager.
 public class ApplicationListItemManager implements ApplicationsState.Callbacks {
     /**
      * Callback that is called once the list of applications are loaded.
@@ -41,6 +43,8 @@
         void onDataLoaded(ArrayList<ApplicationsState.AppEntry> apps);
     }
 
+    private static final Logger LOG = new Logger(ApplicationListItemManager.class);
+
     private final VolumeInfo mVolumeInfo;
     private final Lifecycle mLifecycle;
     private final ApplicationsState mAppState;
@@ -90,18 +94,33 @@
     /**
      * Starts the new session and start loading the list of installed applications on the device.
      * This list will be filtered out based on the {@link ApplicationsState.AppFilter} provided.
-     * Once the list is ready {@link AppListItemListener#onDataLoaded} method will be called.
+     * Once the list is ready, {@link AppListItemListener#onDataLoaded} will be called.
      *
-     * @param appFilter based on which the list of applications will be filtered before returning.
+     * @param appFilter          based on which the list of applications will be filtered before
+     *                           returning.
      * @param appEntryComparator comparator based on which the application list will be sorted.
      */
     public void startLoading(ApplicationsState.AppFilter appFilter,
             Comparator<ApplicationsState.AppEntry> appEntryComparator) {
+        if (mSession != null) {
+            LOG.w("Loading already started but restart attempted.");
+            return; // Prevent leaking sessions.
+        }
         mAppFilter = appFilter;
         mAppEntryComparator = appEntryComparator;
         mSession = mAppState.newSession(this, mLifecycle);
     }
 
+    /**
+     * Rebuilds the list of applications using the provided {@link ApplicationsState.AppFilter}.
+     * The filter will be used for all subsequent loading. Once the list is ready, {@link
+     * AppListItemListener#onDataLoaded} will be called.
+     */
+    public void rebuildWithFilter(ApplicationsState.AppFilter appFilter) {
+        mAppFilter = appFilter;
+        rebuild();
+    }
+
     @Override
     public void onPackageIconChanged() {
         rebuild();
@@ -176,8 +195,6 @@
         if (compositeFilter != null) {
             filterObj = new ApplicationsState.CompoundFilter(filterObj, compositeFilter);
         }
-        filterObj = new ApplicationsState.CompoundFilter(filterObj,
-                ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT);
         ApplicationsState.AppFilter finalFilterObj = filterObj;
         mSession.rebuild(finalFilterObj, mAppEntryComparator, /* foreground= */ false);
     }
diff --git a/src/com/android/car/settings/applications/ApplicationsSettingsFragment.java b/src/com/android/car/settings/applications/ApplicationsSettingsFragment.java
index c736e5d..0dce6be 100644
--- a/src/com/android/car/settings/applications/ApplicationsSettingsFragment.java
+++ b/src/com/android/car/settings/applications/ApplicationsSettingsFragment.java
@@ -25,13 +25,12 @@
 import android.os.storage.VolumeInfo;
 
 import com.android.car.settings.R;
-import com.android.car.settings.common.SettingsFragment;
 import com.android.settingslib.applications.ApplicationsState;
 
 /**
  * Lists all installed applications and their summary.
  */
-public class ApplicationsSettingsFragment extends SettingsFragment {
+public class ApplicationsSettingsFragment extends AppListFragment {
 
     private ApplicationListItemManager mAppListItemManager;
 
@@ -57,7 +56,7 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mAppListItemManager.startLoading(/* AppFilter= */ null, ApplicationsState.ALPHA_COMPARATOR);
+        mAppListItemManager.startLoading(getAppFilter(), ApplicationsState.ALPHA_COMPARATOR);
     }
 
     @Override
@@ -71,4 +70,14 @@
         super.onStop();
         mAppListItemManager.onFragmentStop();
     }
+
+    @Override
+    protected void onToggleShowSystemApps(boolean showSystem) {
+        mAppListItemManager.rebuildWithFilter(getAppFilter());
+    }
+
+    private ApplicationsState.AppFilter getAppFilter() {
+        return shouldShowSystemApps() ? null
+                : ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT;
+    }
 }
diff --git a/src/com/android/car/settings/applications/specialaccess/ModifySystemSettingsFragment.java b/src/com/android/car/settings/applications/specialaccess/ModifySystemSettingsFragment.java
index bd3955d..fae0522 100644
--- a/src/com/android/car/settings/applications/specialaccess/ModifySystemSettingsFragment.java
+++ b/src/com/android/car/settings/applications/specialaccess/ModifySystemSettingsFragment.java
@@ -23,11 +23,12 @@
 import androidx.annotation.XmlRes;
 
 import com.android.car.settings.R;
+import com.android.car.settings.applications.AppListFragment;
 
 /**
  * Displays apps which have requested to modify system settings and their current allowed status.
  */
-public class ModifySystemSettingsFragment extends AppOpsFragment {
+public class ModifySystemSettingsFragment extends AppListFragment {
 
     @Override
     @XmlRes
@@ -38,13 +39,15 @@
     @Override
     public void onAttach(Context context) {
         super.onAttach(context);
-        lookupAppOpsPreferenceController().init(AppOpsManager.OP_WRITE_SETTINGS,
+        use(AppOpsPreferenceController.class, R.string.pk_modify_system_settings).init(
+                AppOpsManager.OP_WRITE_SETTINGS,
                 Manifest.permission.WRITE_SETTINGS,
                 AppOpsManager.MODE_ERRORED);
     }
 
     @Override
-    protected AppOpsPreferenceController lookupAppOpsPreferenceController() {
-        return use(AppOpsPreferenceController.class, R.string.pk_modify_system_settings);
+    protected void onToggleShowSystemApps(boolean showSystem) {
+        use(AppOpsPreferenceController.class, R.string.pk_modify_system_settings).setShowSystem(
+                showSystem);
     }
 }
diff --git a/src/com/android/car/settings/applications/specialaccess/UsageAccessFragment.java b/src/com/android/car/settings/applications/specialaccess/UsageAccessFragment.java
index c44e870..266afd8 100644
--- a/src/com/android/car/settings/applications/specialaccess/UsageAccessFragment.java
+++ b/src/com/android/car/settings/applications/specialaccess/UsageAccessFragment.java
@@ -23,11 +23,12 @@
 import androidx.annotation.XmlRes;
 
 import com.android.car.settings.R;
+import com.android.car.settings.applications.AppListFragment;
 
 /**
  * Displays apps which have requested to access usage data and their current allowed status.
  */
-public class UsageAccessFragment extends AppOpsFragment {
+public class UsageAccessFragment extends AppListFragment {
 
     @Override
     @XmlRes
@@ -38,13 +39,14 @@
     @Override
     public void onAttach(Context context) {
         super.onAttach(context);
-        lookupAppOpsPreferenceController().init(AppOpsManager.OP_GET_USAGE_STATS,
+        use(AppOpsPreferenceController.class, R.string.pk_usage_access).init(
+                AppOpsManager.OP_GET_USAGE_STATS,
                 Manifest.permission.PACKAGE_USAGE_STATS,
                 AppOpsManager.MODE_IGNORED);
     }
 
     @Override
-    protected AppOpsPreferenceController lookupAppOpsPreferenceController() {
-        return use(AppOpsPreferenceController.class, R.string.pk_usage_access);
+    protected void onToggleShowSystemApps(boolean showSystem) {
+        use(AppOpsPreferenceController.class, R.string.pk_usage_access).setShowSystem(showSystem);
     }
 }
diff --git a/src/com/android/car/settings/applications/specialaccess/WifiControlFragment.java b/src/com/android/car/settings/applications/specialaccess/WifiControlFragment.java
index eff706c..87b7728 100644
--- a/src/com/android/car/settings/applications/specialaccess/WifiControlFragment.java
+++ b/src/com/android/car/settings/applications/specialaccess/WifiControlFragment.java
@@ -19,11 +19,12 @@
 import androidx.annotation.XmlRes;
 
 import com.android.car.settings.R;
+import com.android.car.settings.applications.AppListFragment;
 
 /**
  * Displays apps which have requested to control Wi-Fi settings and their current allowed status.
  */
-public class WifiControlFragment extends AppOpsFragment {
+public class WifiControlFragment extends AppListFragment {
 
     @Override
     @XmlRes
@@ -32,7 +33,8 @@
     }
 
     @Override
-    protected AppOpsPreferenceController lookupAppOpsPreferenceController() {
-        return use(WifiControlPreferenceController.class, R.string.pk_wifi_control);
+    protected void onToggleShowSystemApps(boolean showSystem) {
+        use(WifiControlPreferenceController.class, R.string.pk_wifi_control).setShowSystem(
+                showSystem);
     }
 }
diff --git a/src/com/android/car/settings/storage/StorageApplicationListPreferenceController.java b/src/com/android/car/settings/storage/StorageApplicationListPreferenceController.java
index 53ed01c..e403998 100644
--- a/src/com/android/car/settings/storage/StorageApplicationListPreferenceController.java
+++ b/src/com/android/car/settings/storage/StorageApplicationListPreferenceController.java
@@ -49,22 +49,14 @@
 
     @Override
     public void onDataLoaded(ArrayList<ApplicationsState.AppEntry> apps) {
+        getPreference().removeAll();
         for (ApplicationsState.AppEntry appEntry : apps) {
-            addOrUpdatePreference(appEntry);
+            getPreference().addPreference(
+                    createPreference(appEntry.label, appEntry.sizeStr, appEntry.icon,
+                            appEntry.info.packageName));
         }
     }
 
-    private void addOrUpdatePreference(ApplicationsState.AppEntry appEntry) {
-        Preference preference = getPreference().findPreference(appEntry.info.packageName);
-        if (preference != null) {
-            preference.setSummary(appEntry.sizeStr);
-            return;
-        }
-        getPreference().addPreference(
-                createPreference(appEntry.label, appEntry.sizeStr, appEntry.icon,
-                        appEntry.info.packageName));
-    }
-
     protected Preference createPreference(String title, String summary, Drawable icon,
             String key) {
         Preference preference = new Preference(getContext());
diff --git a/src/com/android/car/settings/storage/StorageMediaCategoryDetailFragment.java b/src/com/android/car/settings/storage/StorageMediaCategoryDetailFragment.java
index 66919d1..f7af597 100644
--- a/src/com/android/car/settings/storage/StorageMediaCategoryDetailFragment.java
+++ b/src/com/android/car/settings/storage/StorageMediaCategoryDetailFragment.java
@@ -26,14 +26,14 @@
 import android.os.storage.VolumeInfo;
 
 import com.android.car.settings.R;
+import com.android.car.settings.applications.AppListFragment;
 import com.android.car.settings.applications.ApplicationListItemManager;
-import com.android.car.settings.common.SettingsFragment;
 import com.android.settingslib.applications.ApplicationsState;
 
 /**
  * Lists all installed applications with category audio and their summary.
  */
-public class StorageMediaCategoryDetailFragment extends SettingsFragment {
+public class StorageMediaCategoryDetailFragment extends AppListFragment {
 
     private ApplicationListItemManager mAppListItemManager;
 
@@ -70,8 +70,7 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mAppListItemManager.startLoading(ApplicationsState.FILTER_AUDIO,
-                ApplicationsState.SIZE_COMPARATOR);
+        mAppListItemManager.startLoading(getAppFilter(), ApplicationsState.SIZE_COMPARATOR);
     }
 
     @Override
@@ -85,4 +84,18 @@
         super.onStop();
         mAppListItemManager.onFragmentStop();
     }
+
+    @Override
+    protected void onToggleShowSystemApps(boolean showSystem) {
+        mAppListItemManager.rebuildWithFilter(getAppFilter());
+    }
+
+    private ApplicationsState.AppFilter getAppFilter() {
+        ApplicationsState.AppFilter filter = ApplicationsState.FILTER_AUDIO;
+        if (!shouldShowSystemApps()) {
+            filter = new ApplicationsState.CompoundFilter(filter,
+                    ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT);
+        }
+        return filter;
+    }
 }
diff --git a/src/com/android/car/settings/storage/StorageMediaCategoryDetailPreferenceController.java b/src/com/android/car/settings/storage/StorageMediaCategoryDetailPreferenceController.java
index 548faa2..7c81ff7 100644
--- a/src/com/android/car/settings/storage/StorageMediaCategoryDetailPreferenceController.java
+++ b/src/com/android/car/settings/storage/StorageMediaCategoryDetailPreferenceController.java
@@ -35,7 +35,6 @@
         StorageApplicationListPreferenceController {
 
     private long mExternalAudioBytes;
-    private boolean mIsStorageAudioPreferenceAdded;
 
     public StorageMediaCategoryDetailPreferenceController(Context context,
             String preferenceKey, FragmentController fragmentController,
@@ -46,18 +45,15 @@
     @Override
     public void onDataLoaded(ArrayList<ApplicationsState.AppEntry> apps) {
         super.onDataLoaded(apps);
-        if (mIsStorageAudioPreferenceAdded) {
-            return;
-        }
         Preference preference = createPreference(
                 getContext().getString(R.string.storage_audio_files_title),
                 Long.toString(mExternalAudioBytes),
-                getContext().getDrawable(R.drawable.ic_headset), /* key= */ null);
+                getContext().getDrawable(R.drawable.ic_headset),
+                getContext().getString(R.string.pk_storage_music_audio_files));
         // remove the onClickListener which was set above with null key. This preference should
         // do nothing on click.
         preference.setOnPreferenceClickListener(null);
         getPreference().addPreference(preference);
-        mIsStorageAudioPreferenceAdded = true;
     }
 
     /**
diff --git a/src/com/android/car/settings/storage/StorageOtherCategoryDetailFragment.java b/src/com/android/car/settings/storage/StorageOtherCategoryDetailFragment.java
index ac71912..6aec796 100644
--- a/src/com/android/car/settings/storage/StorageOtherCategoryDetailFragment.java
+++ b/src/com/android/car/settings/storage/StorageOtherCategoryDetailFragment.java
@@ -24,14 +24,14 @@
 import android.os.storage.VolumeInfo;
 
 import com.android.car.settings.R;
+import com.android.car.settings.applications.AppListFragment;
 import com.android.car.settings.applications.ApplicationListItemManager;
-import com.android.car.settings.common.SettingsFragment;
 import com.android.settingslib.applications.ApplicationsState;
 
 /**
  * Lists all installed applications with no category defined and their summary.
  */
-public class StorageOtherCategoryDetailFragment extends SettingsFragment {
+public class StorageOtherCategoryDetailFragment extends AppListFragment {
 
     private ApplicationListItemManager mAppListItemManager;
 
@@ -56,8 +56,7 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mAppListItemManager.startLoading(ApplicationsState.FILTER_OTHER_APPS,
-                ApplicationsState.SIZE_COMPARATOR);
+        mAppListItemManager.startLoading(getAppFilter(), ApplicationsState.SIZE_COMPARATOR);
     }
 
     @Override
@@ -71,4 +70,18 @@
         super.onStop();
         mAppListItemManager.onFragmentStop();
     }
+
+    @Override
+    protected void onToggleShowSystemApps(boolean showSystem) {
+        mAppListItemManager.rebuildWithFilter(getAppFilter());
+    }
+
+    private ApplicationsState.AppFilter getAppFilter() {
+        ApplicationsState.AppFilter filter = ApplicationsState.FILTER_OTHER_APPS;
+        if (!shouldShowSystemApps()) {
+            filter = new ApplicationsState.CompoundFilter(filter,
+                    ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT);
+        }
+        return filter;
+    }
 }