Loading res/xml/app_and_notification.xml +15 −14 Original line number Diff line number Diff line Loading @@ -23,24 +23,25 @@ settings:initialExpandedChildrenCount="8"> <!-- the initial count should include the dynamic tiles --> <PreferenceCategory android:key="recent_apps_category" android:title="@string/recent_app_category_title" android:order="-200"> <!-- Placeholder for a list of recent apps --> <!-- See all apps button --> <Preference android:title="@string/applications_settings" android:key="all_app_info" android:fragment="com.android.settings.applications.manageapplications.ManageApplications" android:order="20"/> </PreferenceCategory> android:title="@string/applications_settings" android:order="-999" android:fragment="com.android.settings.applications.manageapplications.ManageApplications"/> <com.android.settingslib.widget.LayoutPreference android:key="recent_open_apps" android:title="@string/recent_app_category_title" android:layout="@layout/app_entities_header" android:selectable="false" android:order="-998" settings:allowDividerBelow="true" settings:controller="com.android.settings.applications.RecentAppsPreferenceController"/> <!-- Empty category to draw divider --> <PreferenceCategory android:key="all_app_info_divider" android:order="-190"/> android:key="recent_apps_divider" android:order="-997"/> <!-- Notifications (appears before manage_perms), default apps (appears after) --> <PreferenceCategory Loading src/com/android/settings/applications/AppAndNotificationDashboardFragment.java +5 −16 Original line number Diff line number Diff line Loading @@ -16,14 +16,10 @@ package com.android.settings.applications; import android.app.Activity; import android.app.Application; import android.app.settings.SettingsEnums; import android.content.Context; import android.provider.SearchIndexableResource; import androidx.fragment.app.Fragment; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.notification.EmergencyBroadcastPreferenceController; Loading Loading @@ -63,27 +59,20 @@ public class AppAndNotificationDashboardFragment extends DashboardFragment { @Override public void onAttach(Context context) { super.onAttach(context); use(SpecialAppAccessPreferenceController.class).setSession(getSettingsLifecycle()); use(RecentAppsPreferenceController.class).setFragment(this /* fragment */); } @Override protected List<AbstractPreferenceController> createPreferenceControllers(Context context) { final Activity activity = getActivity(); final Application app; if (activity != null) { app = activity.getApplication(); } else { app = null; } return buildPreferenceControllers(context, app, this); return buildPreferenceControllers(context); } private static List<AbstractPreferenceController> buildPreferenceControllers(Context context, Application app, Fragment host) { private static List<AbstractPreferenceController> buildPreferenceControllers(Context context) { final List<AbstractPreferenceController> controllers = new ArrayList<>(); controllers.add(new EmergencyBroadcastPreferenceController(context, "app_and_notif_cell_broadcast_settings")); controllers.add(new RecentAppsPreferenceController(context, app, host)); return controllers; } Loading @@ -100,7 +89,7 @@ public class AppAndNotificationDashboardFragment extends DashboardFragment { @Override public List<AbstractPreferenceController> createPreferenceControllers( Context context) { return buildPreferenceControllers(context, null, null /* host */); return buildPreferenceControllers(context); } }; } src/com/android/settings/applications/RecentAppsPreferenceController.java +99 −117 Original line number Diff line number Diff line Loading @@ -27,26 +27,28 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.os.PowerManager; import android.os.UserHandle; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.IconDrawableFactory; import android.util.Log; import android.view.View; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.applications.appinfo.AppInfoDashboardFragment; import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.applications.manageapplications.ManageApplications; import com.android.settings.core.BasePreferenceController; import com.android.settings.core.SubSettingLauncher; import com.android.settingslib.applications.AppUtils; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.utils.StringUtil; import com.android.settingslib.widget.apppreference.AppPreference; import com.android.settingslib.widget.AppEntitiesHeaderController; import com.android.settingslib.widget.AppEntityInfo; import com.android.settingslib.widget.LayoutPreference; import java.util.ArrayList; import java.util.Arrays; Loading @@ -58,22 +60,29 @@ import java.util.Map; import java.util.Set; /** * This controller displays a list of recently used apps and a "See all" button. If there is * no recently used app, "See all" will be displayed as "App info". * This controller displays up to three recently used apps. * If there is no recently used app, we only show up an "App Info" preference. */ public class RecentAppsPreferenceController extends AbstractPreferenceController implements PreferenceControllerMixin, Comparator<UsageStats> { public class RecentAppsPreferenceController extends BasePreferenceController implements Comparator<UsageStats> { private static final String TAG = "RecentAppsCtrl"; private static final String KEY_PREF_CATEGORY = "recent_apps_category"; @VisibleForTesting static final String KEY_DIVIDER = "all_app_info_divider"; static final String KEY_ALL_APP_INFO = "all_app_info"; @VisibleForTesting static final String KEY_SEE_ALL = "all_app_info"; private static final int SHOW_RECENT_APP_COUNT = 5; static final String KEY_DIVIDER = "recent_apps_divider"; private static final String TAG = "RecentAppsCtrl"; private static final Set<String> SKIP_SYSTEM_PACKAGES = new ArraySet<>(); private final Fragment mHost; @VisibleForTesting AppEntitiesHeaderController mAppEntitiesController; @VisibleForTesting LayoutPreference mRecentAppsPreference; @VisibleForTesting Preference mAllAppPref; @VisibleForTesting Preference mDivider; private final PackageManager mPm; private final UsageStatsManager mUsageStatsManager; private final ApplicationsState mApplicationsState; Loading @@ -81,12 +90,9 @@ public class RecentAppsPreferenceController extends AbstractPreferenceController private final IconDrawableFactory mIconDrawableFactory; private final PowerManager mPowerManager; private Fragment mHost; private Calendar mCal; private List<UsageStats> mStats; private PreferenceCategory mCategory; private Preference mSeeAllPref; private Preference mDivider; private boolean mHasRecentApps; static { Loading @@ -100,68 +106,67 @@ public class RecentAppsPreferenceController extends AbstractPreferenceController )); } public RecentAppsPreferenceController(Context context, Application app, Fragment host) { this(context, app == null ? null : ApplicationsState.getInstance(app), host); } @VisibleForTesting(otherwise = VisibleForTesting.NONE) RecentAppsPreferenceController(Context context, ApplicationsState appState, Fragment host) { super(context); mIconDrawableFactory = IconDrawableFactory.newInstance(context); public RecentAppsPreferenceController(Context context, String key) { super(context, key); mApplicationsState = ApplicationsState.getInstance( (Application) mContext.getApplicationContext()); mUserId = UserHandle.myUserId(); mPm = context.getPackageManager(); mPowerManager = context.getSystemService(PowerManager.class); mHost = host; mUsageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE); mApplicationsState = appState; } @Override public boolean isAvailable() { return true; mPm = mContext.getPackageManager(); mIconDrawableFactory = IconDrawableFactory.newInstance(mContext); mPowerManager = mContext.getSystemService(PowerManager.class); mUsageStatsManager = mContext.getSystemService(UsageStatsManager.class); } @Override public String getPreferenceKey() { return KEY_PREF_CATEGORY; public void setFragment(Fragment fragment) { mHost = fragment; } @Override public void updateNonIndexableKeys(List<String> keys) { PreferenceControllerMixin.super.updateNonIndexableKeys(keys); // Don't index category name into search. It's not actionable. keys.add(KEY_PREF_CATEGORY); keys.add(KEY_DIVIDER); public int getAvailabilityStatus() { reloadData(); return getDisplayableRecentAppList().isEmpty() ? AVAILABLE_UNSEARCHABLE : AVAILABLE; } @Override public void displayPreference(PreferenceScreen screen) { mCategory = screen.findPreference(getPreferenceKey()); mSeeAllPref = screen.findPreference(KEY_SEE_ALL); mDivider = screen.findPreference(KEY_DIVIDER); super.displayPreference(screen); refreshUi(mCategory.getContext()); mAllAppPref = screen.findPreference(KEY_ALL_APP_INFO); mDivider = screen.findPreference(KEY_DIVIDER); mRecentAppsPreference = (LayoutPreference) screen.findPreference(getPreferenceKey()); final View view = mRecentAppsPreference.findViewById(R.id.app_entities_header); mAppEntitiesController = AppEntitiesHeaderController.newInstance(mContext, view) .setHeaderTitleRes(R.string.recent_app_category_title) .setHeaderDetailsClickListener((View v) -> { new SubSettingLauncher(mContext) .setDestination(ManageApplications.class.getName()) .setArguments(null /* arguments */) .setTitleRes(R.string.application_info_label) .setSourceMetricsCategory(SettingsEnums.SETTINGS_APP_NOTIF_CATEGORY) .launch(); }); refreshUi(); } @Override public void updateState(Preference preference) { super.updateState(preference); refreshUi(mCategory.getContext()); refreshUi(); // Show total number of installed apps as See all's summary. new InstalledAppCounter(mContext, InstalledAppCounter.IGNORE_INSTALL_REASON, mContext.getPackageManager()) { @Override protected void onCountComplete(int num) { if (mHasRecentApps) { mSeeAllPref.setTitle(mContext.getString(R.string.see_all_apps_title, num)); mAppEntitiesController.setHeaderDetails( mContext.getString(R.string.see_all_apps_title, num)); mAppEntitiesController.apply(); } else { mSeeAllPref.setSummary(mContext.getString(R.string.apps_summary, num)); mAllAppPref.setSummary(mContext.getString(R.string.apps_summary, num)); } } }.execute(); } @Override Loading @@ -171,12 +176,12 @@ public class RecentAppsPreferenceController extends AbstractPreferenceController } @VisibleForTesting void refreshUi(Context prefContext) { void refreshUi() { reloadData(); final List<UsageStats> recentApps = getDisplayableRecentAppList(); if (recentApps != null && !recentApps.isEmpty()) { mHasRecentApps = true; displayRecentApps(prefContext, recentApps); displayRecentApps(recentApps); } else { mHasRecentApps = false; displayOnlyAppInfo(); Loading @@ -195,73 +200,50 @@ public class RecentAppsPreferenceController extends AbstractPreferenceController } private void displayOnlyAppInfo() { mCategory.setTitle(null); mDivider.setVisible(false); mSeeAllPref.setTitle(R.string.applications_settings); mSeeAllPref.setIcon(null); int prefCount = mCategory.getPreferenceCount(); for (int i = prefCount - 1; i >= 0; i--) { final Preference pref = mCategory.getPreference(i); if (!TextUtils.equals(pref.getKey(), KEY_SEE_ALL)) { mCategory.removePreference(pref); } mAllAppPref.setTitle(R.string.applications_settings); mAllAppPref.setVisible(true); mRecentAppsPreference.setVisible(false); } private void displayRecentApps(List<UsageStats> recentApps) { int showAppsCount = 0; for (UsageStats stat : recentApps) { final AppEntityInfo appEntityInfoInfo = createAppEntity(stat); if (appEntityInfoInfo != null) { mAppEntitiesController.setAppEntity(showAppsCount++, appEntityInfoInfo); } private void displayRecentApps(Context prefContext, List<UsageStats> recentApps) { mCategory.setTitle(R.string.recent_app_category_title); if (showAppsCount == AppEntitiesHeaderController.MAXIMUM_APPS) { break; } } mAppEntitiesController.apply(); mRecentAppsPreference.setVisible(true); mAllAppPref.setVisible(false); mDivider.setVisible(true); mSeeAllPref.setSummary(null); mSeeAllPref.setIcon(R.drawable.ic_chevron_right_24dp); // Rebind prefs/avoid adding new prefs if possible. Adding/removing prefs causes jank. // Build a cached preference pool final Map<String, Preference> appPreferences = new ArrayMap<>(); int prefCount = mCategory.getPreferenceCount(); for (int i = 0; i < prefCount; i++) { final Preference pref = mCategory.getPreference(i); final String key = pref.getKey(); if (!TextUtils.equals(key, KEY_SEE_ALL)) { appPreferences.put(key, pref); } } final int recentAppsCount = recentApps.size(); for (int i = 0; i < recentAppsCount; i++) { final UsageStats stat = recentApps.get(i); // Bind recent apps to existing prefs if possible, or create a new pref. } private AppEntityInfo createAppEntity(UsageStats stat) { final String pkgName = stat.getPackageName(); final ApplicationsState.AppEntry appEntry = mApplicationsState.getEntry(pkgName, mUserId); if (appEntry == null) { continue; return null; } boolean rebindPref = true; Preference pref = appPreferences.remove(pkgName); if (pref == null) { pref = new AppPreference(prefContext); rebindPref = false; } pref.setKey(pkgName); pref.setTitle(appEntry.label); pref.setIcon(mIconDrawableFactory.getBadgedIcon(appEntry.info)); pref.setSummary(StringUtil.formatRelativeTime(mContext, System.currentTimeMillis() - stat.getLastTimeUsed(), false)); pref.setOrder(i); pref.setOnPreferenceClickListener(preference -> { return new AppEntityInfo.Builder() .setIcon(mIconDrawableFactory.getBadgedIcon(appEntry.info)) .setTitle(appEntry.label) .setSummary(StringUtil.formatRelativeTime(mContext, System.currentTimeMillis() - stat.getLastTimeUsed(), false)) .setOnClickListener(v -> AppInfoBase.startAppInfoFragment(AppInfoDashboardFragment.class, R.string.application_info_label, pkgName, appEntry.info.uid, mHost, 1001 /*RequestCode*/, SettingsEnums.SETTINGS_APP_NOTIF_CATEGORY); return true; }); if (!rebindPref) { mCategory.addPreference(pref); } } // Remove unused prefs from pref cache pool for (Preference unusedPrefs : appPreferences.values()) { mCategory.removePreference(unusedPrefs); } R.string.application_info_label, pkgName, appEntry.info.uid, mHost, 1001 /*RequestCode*/, SettingsEnums.SETTINGS_APP_NOTIF_CATEGORY)) .build(); } private List<UsageStats> getDisplayableRecentAppList() { Loading Loading @@ -293,7 +275,7 @@ public class RecentAppsPreferenceController extends AbstractPreferenceController } recentApps.add(stat); count++; if (count >= SHOW_RECENT_APP_COUNT) { if (count >= AppEntitiesHeaderController.MAXIMUM_APPS) { break; } } Loading tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java +128 −141 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
res/xml/app_and_notification.xml +15 −14 Original line number Diff line number Diff line Loading @@ -23,24 +23,25 @@ settings:initialExpandedChildrenCount="8"> <!-- the initial count should include the dynamic tiles --> <PreferenceCategory android:key="recent_apps_category" android:title="@string/recent_app_category_title" android:order="-200"> <!-- Placeholder for a list of recent apps --> <!-- See all apps button --> <Preference android:title="@string/applications_settings" android:key="all_app_info" android:fragment="com.android.settings.applications.manageapplications.ManageApplications" android:order="20"/> </PreferenceCategory> android:title="@string/applications_settings" android:order="-999" android:fragment="com.android.settings.applications.manageapplications.ManageApplications"/> <com.android.settingslib.widget.LayoutPreference android:key="recent_open_apps" android:title="@string/recent_app_category_title" android:layout="@layout/app_entities_header" android:selectable="false" android:order="-998" settings:allowDividerBelow="true" settings:controller="com.android.settings.applications.RecentAppsPreferenceController"/> <!-- Empty category to draw divider --> <PreferenceCategory android:key="all_app_info_divider" android:order="-190"/> android:key="recent_apps_divider" android:order="-997"/> <!-- Notifications (appears before manage_perms), default apps (appears after) --> <PreferenceCategory Loading
src/com/android/settings/applications/AppAndNotificationDashboardFragment.java +5 −16 Original line number Diff line number Diff line Loading @@ -16,14 +16,10 @@ package com.android.settings.applications; import android.app.Activity; import android.app.Application; import android.app.settings.SettingsEnums; import android.content.Context; import android.provider.SearchIndexableResource; import androidx.fragment.app.Fragment; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.notification.EmergencyBroadcastPreferenceController; Loading Loading @@ -63,27 +59,20 @@ public class AppAndNotificationDashboardFragment extends DashboardFragment { @Override public void onAttach(Context context) { super.onAttach(context); use(SpecialAppAccessPreferenceController.class).setSession(getSettingsLifecycle()); use(RecentAppsPreferenceController.class).setFragment(this /* fragment */); } @Override protected List<AbstractPreferenceController> createPreferenceControllers(Context context) { final Activity activity = getActivity(); final Application app; if (activity != null) { app = activity.getApplication(); } else { app = null; } return buildPreferenceControllers(context, app, this); return buildPreferenceControllers(context); } private static List<AbstractPreferenceController> buildPreferenceControllers(Context context, Application app, Fragment host) { private static List<AbstractPreferenceController> buildPreferenceControllers(Context context) { final List<AbstractPreferenceController> controllers = new ArrayList<>(); controllers.add(new EmergencyBroadcastPreferenceController(context, "app_and_notif_cell_broadcast_settings")); controllers.add(new RecentAppsPreferenceController(context, app, host)); return controllers; } Loading @@ -100,7 +89,7 @@ public class AppAndNotificationDashboardFragment extends DashboardFragment { @Override public List<AbstractPreferenceController> createPreferenceControllers( Context context) { return buildPreferenceControllers(context, null, null /* host */); return buildPreferenceControllers(context); } }; }
src/com/android/settings/applications/RecentAppsPreferenceController.java +99 −117 Original line number Diff line number Diff line Loading @@ -27,26 +27,28 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.os.PowerManager; import android.os.UserHandle; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.IconDrawableFactory; import android.util.Log; import android.view.View; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.applications.appinfo.AppInfoDashboardFragment; import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.applications.manageapplications.ManageApplications; import com.android.settings.core.BasePreferenceController; import com.android.settings.core.SubSettingLauncher; import com.android.settingslib.applications.AppUtils; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.utils.StringUtil; import com.android.settingslib.widget.apppreference.AppPreference; import com.android.settingslib.widget.AppEntitiesHeaderController; import com.android.settingslib.widget.AppEntityInfo; import com.android.settingslib.widget.LayoutPreference; import java.util.ArrayList; import java.util.Arrays; Loading @@ -58,22 +60,29 @@ import java.util.Map; import java.util.Set; /** * This controller displays a list of recently used apps and a "See all" button. If there is * no recently used app, "See all" will be displayed as "App info". * This controller displays up to three recently used apps. * If there is no recently used app, we only show up an "App Info" preference. */ public class RecentAppsPreferenceController extends AbstractPreferenceController implements PreferenceControllerMixin, Comparator<UsageStats> { public class RecentAppsPreferenceController extends BasePreferenceController implements Comparator<UsageStats> { private static final String TAG = "RecentAppsCtrl"; private static final String KEY_PREF_CATEGORY = "recent_apps_category"; @VisibleForTesting static final String KEY_DIVIDER = "all_app_info_divider"; static final String KEY_ALL_APP_INFO = "all_app_info"; @VisibleForTesting static final String KEY_SEE_ALL = "all_app_info"; private static final int SHOW_RECENT_APP_COUNT = 5; static final String KEY_DIVIDER = "recent_apps_divider"; private static final String TAG = "RecentAppsCtrl"; private static final Set<String> SKIP_SYSTEM_PACKAGES = new ArraySet<>(); private final Fragment mHost; @VisibleForTesting AppEntitiesHeaderController mAppEntitiesController; @VisibleForTesting LayoutPreference mRecentAppsPreference; @VisibleForTesting Preference mAllAppPref; @VisibleForTesting Preference mDivider; private final PackageManager mPm; private final UsageStatsManager mUsageStatsManager; private final ApplicationsState mApplicationsState; Loading @@ -81,12 +90,9 @@ public class RecentAppsPreferenceController extends AbstractPreferenceController private final IconDrawableFactory mIconDrawableFactory; private final PowerManager mPowerManager; private Fragment mHost; private Calendar mCal; private List<UsageStats> mStats; private PreferenceCategory mCategory; private Preference mSeeAllPref; private Preference mDivider; private boolean mHasRecentApps; static { Loading @@ -100,68 +106,67 @@ public class RecentAppsPreferenceController extends AbstractPreferenceController )); } public RecentAppsPreferenceController(Context context, Application app, Fragment host) { this(context, app == null ? null : ApplicationsState.getInstance(app), host); } @VisibleForTesting(otherwise = VisibleForTesting.NONE) RecentAppsPreferenceController(Context context, ApplicationsState appState, Fragment host) { super(context); mIconDrawableFactory = IconDrawableFactory.newInstance(context); public RecentAppsPreferenceController(Context context, String key) { super(context, key); mApplicationsState = ApplicationsState.getInstance( (Application) mContext.getApplicationContext()); mUserId = UserHandle.myUserId(); mPm = context.getPackageManager(); mPowerManager = context.getSystemService(PowerManager.class); mHost = host; mUsageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE); mApplicationsState = appState; } @Override public boolean isAvailable() { return true; mPm = mContext.getPackageManager(); mIconDrawableFactory = IconDrawableFactory.newInstance(mContext); mPowerManager = mContext.getSystemService(PowerManager.class); mUsageStatsManager = mContext.getSystemService(UsageStatsManager.class); } @Override public String getPreferenceKey() { return KEY_PREF_CATEGORY; public void setFragment(Fragment fragment) { mHost = fragment; } @Override public void updateNonIndexableKeys(List<String> keys) { PreferenceControllerMixin.super.updateNonIndexableKeys(keys); // Don't index category name into search. It's not actionable. keys.add(KEY_PREF_CATEGORY); keys.add(KEY_DIVIDER); public int getAvailabilityStatus() { reloadData(); return getDisplayableRecentAppList().isEmpty() ? AVAILABLE_UNSEARCHABLE : AVAILABLE; } @Override public void displayPreference(PreferenceScreen screen) { mCategory = screen.findPreference(getPreferenceKey()); mSeeAllPref = screen.findPreference(KEY_SEE_ALL); mDivider = screen.findPreference(KEY_DIVIDER); super.displayPreference(screen); refreshUi(mCategory.getContext()); mAllAppPref = screen.findPreference(KEY_ALL_APP_INFO); mDivider = screen.findPreference(KEY_DIVIDER); mRecentAppsPreference = (LayoutPreference) screen.findPreference(getPreferenceKey()); final View view = mRecentAppsPreference.findViewById(R.id.app_entities_header); mAppEntitiesController = AppEntitiesHeaderController.newInstance(mContext, view) .setHeaderTitleRes(R.string.recent_app_category_title) .setHeaderDetailsClickListener((View v) -> { new SubSettingLauncher(mContext) .setDestination(ManageApplications.class.getName()) .setArguments(null /* arguments */) .setTitleRes(R.string.application_info_label) .setSourceMetricsCategory(SettingsEnums.SETTINGS_APP_NOTIF_CATEGORY) .launch(); }); refreshUi(); } @Override public void updateState(Preference preference) { super.updateState(preference); refreshUi(mCategory.getContext()); refreshUi(); // Show total number of installed apps as See all's summary. new InstalledAppCounter(mContext, InstalledAppCounter.IGNORE_INSTALL_REASON, mContext.getPackageManager()) { @Override protected void onCountComplete(int num) { if (mHasRecentApps) { mSeeAllPref.setTitle(mContext.getString(R.string.see_all_apps_title, num)); mAppEntitiesController.setHeaderDetails( mContext.getString(R.string.see_all_apps_title, num)); mAppEntitiesController.apply(); } else { mSeeAllPref.setSummary(mContext.getString(R.string.apps_summary, num)); mAllAppPref.setSummary(mContext.getString(R.string.apps_summary, num)); } } }.execute(); } @Override Loading @@ -171,12 +176,12 @@ public class RecentAppsPreferenceController extends AbstractPreferenceController } @VisibleForTesting void refreshUi(Context prefContext) { void refreshUi() { reloadData(); final List<UsageStats> recentApps = getDisplayableRecentAppList(); if (recentApps != null && !recentApps.isEmpty()) { mHasRecentApps = true; displayRecentApps(prefContext, recentApps); displayRecentApps(recentApps); } else { mHasRecentApps = false; displayOnlyAppInfo(); Loading @@ -195,73 +200,50 @@ public class RecentAppsPreferenceController extends AbstractPreferenceController } private void displayOnlyAppInfo() { mCategory.setTitle(null); mDivider.setVisible(false); mSeeAllPref.setTitle(R.string.applications_settings); mSeeAllPref.setIcon(null); int prefCount = mCategory.getPreferenceCount(); for (int i = prefCount - 1; i >= 0; i--) { final Preference pref = mCategory.getPreference(i); if (!TextUtils.equals(pref.getKey(), KEY_SEE_ALL)) { mCategory.removePreference(pref); } mAllAppPref.setTitle(R.string.applications_settings); mAllAppPref.setVisible(true); mRecentAppsPreference.setVisible(false); } private void displayRecentApps(List<UsageStats> recentApps) { int showAppsCount = 0; for (UsageStats stat : recentApps) { final AppEntityInfo appEntityInfoInfo = createAppEntity(stat); if (appEntityInfoInfo != null) { mAppEntitiesController.setAppEntity(showAppsCount++, appEntityInfoInfo); } private void displayRecentApps(Context prefContext, List<UsageStats> recentApps) { mCategory.setTitle(R.string.recent_app_category_title); if (showAppsCount == AppEntitiesHeaderController.MAXIMUM_APPS) { break; } } mAppEntitiesController.apply(); mRecentAppsPreference.setVisible(true); mAllAppPref.setVisible(false); mDivider.setVisible(true); mSeeAllPref.setSummary(null); mSeeAllPref.setIcon(R.drawable.ic_chevron_right_24dp); // Rebind prefs/avoid adding new prefs if possible. Adding/removing prefs causes jank. // Build a cached preference pool final Map<String, Preference> appPreferences = new ArrayMap<>(); int prefCount = mCategory.getPreferenceCount(); for (int i = 0; i < prefCount; i++) { final Preference pref = mCategory.getPreference(i); final String key = pref.getKey(); if (!TextUtils.equals(key, KEY_SEE_ALL)) { appPreferences.put(key, pref); } } final int recentAppsCount = recentApps.size(); for (int i = 0; i < recentAppsCount; i++) { final UsageStats stat = recentApps.get(i); // Bind recent apps to existing prefs if possible, or create a new pref. } private AppEntityInfo createAppEntity(UsageStats stat) { final String pkgName = stat.getPackageName(); final ApplicationsState.AppEntry appEntry = mApplicationsState.getEntry(pkgName, mUserId); if (appEntry == null) { continue; return null; } boolean rebindPref = true; Preference pref = appPreferences.remove(pkgName); if (pref == null) { pref = new AppPreference(prefContext); rebindPref = false; } pref.setKey(pkgName); pref.setTitle(appEntry.label); pref.setIcon(mIconDrawableFactory.getBadgedIcon(appEntry.info)); pref.setSummary(StringUtil.formatRelativeTime(mContext, System.currentTimeMillis() - stat.getLastTimeUsed(), false)); pref.setOrder(i); pref.setOnPreferenceClickListener(preference -> { return new AppEntityInfo.Builder() .setIcon(mIconDrawableFactory.getBadgedIcon(appEntry.info)) .setTitle(appEntry.label) .setSummary(StringUtil.formatRelativeTime(mContext, System.currentTimeMillis() - stat.getLastTimeUsed(), false)) .setOnClickListener(v -> AppInfoBase.startAppInfoFragment(AppInfoDashboardFragment.class, R.string.application_info_label, pkgName, appEntry.info.uid, mHost, 1001 /*RequestCode*/, SettingsEnums.SETTINGS_APP_NOTIF_CATEGORY); return true; }); if (!rebindPref) { mCategory.addPreference(pref); } } // Remove unused prefs from pref cache pool for (Preference unusedPrefs : appPreferences.values()) { mCategory.removePreference(unusedPrefs); } R.string.application_info_label, pkgName, appEntry.info.uid, mHost, 1001 /*RequestCode*/, SettingsEnums.SETTINGS_APP_NOTIF_CATEGORY)) .build(); } private List<UsageStats> getDisplayableRecentAppList() { Loading Loading @@ -293,7 +275,7 @@ public class RecentAppsPreferenceController extends AbstractPreferenceController } recentApps.add(stat); count++; if (count >= SHOW_RECENT_APP_COUNT) { if (count >= AppEntitiesHeaderController.MAXIMUM_APPS) { break; } } Loading
tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java +128 −141 File changed.Preview size limit exceeded, changes collapsed. Show changes