From e79790b26803ee338b2fdc3404344094d7f94476 Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Wed, 2 Dec 2015 15:39:19 -0500 Subject: [PATCH] Speed up setting launch Try to avoid too many calls to the PM and cache the info we get from it to avoid too much stuff during settings launch. Change-Id: I64132cbe47cf8eac6080c8c82583b0b5eeb75a28 --- .../android/settingslib/drawer/DashboardTile.java | 7 ++ .../settingslib/drawer/SettingsDrawerActivity.java | 88 +++++++++++++++-- .../settingslib/drawer/SettingsDrawerAdapter.java | 2 +- .../com/android/settingslib/drawer/TileUtils.java | 107 ++++++++++----------- 4 files changed, 137 insertions(+), 67 deletions(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardTile.java b/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardTile.java index 6fef134f452c..347e9f742d29 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardTile.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardTile.java @@ -74,6 +74,11 @@ public class DashboardTile implements Parcelable { */ public int priority; + /** + * The metaData from the activity that defines this tile. + */ + public Bundle metaData; + public DashboardTile() { // Empty } @@ -107,6 +112,7 @@ public class DashboardTile implements Parcelable { dest.writeBundle(extras); dest.writeString(category); dest.writeInt(priority); + dest.writeBundle(metaData); } public void readFromParcel(Parcel in) { @@ -125,6 +131,7 @@ public class DashboardTile implements Parcelable { extras = in.readBundle(); category = in.readString(); priority = in.readInt(); + metaData = in.readBundle(); } DashboardTile(Parcel in) { diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java index 00dadb8d217e..581c810c7444 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java @@ -18,9 +18,15 @@ package com.android.settingslib.drawer; import android.annotation.LayoutRes; import android.annotation.Nullable; import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.res.TypedArray; +import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.widget.DrawerLayout; +import android.util.Log; import android.util.Pair; import android.view.Gravity; import android.view.LayoutInflater; @@ -33,21 +39,30 @@ import android.widget.ListView; import android.widget.Toolbar; import com.android.settingslib.R; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; public class SettingsDrawerActivity extends Activity { + protected static final boolean DEBUG_TIMING = false; + private static final String TAG = "SettingsDrawerActivity"; + + private static List sDashboardCategories; + private static HashMap, DashboardTile> sTileCache; + + private final PackageReceiver mPackageReceiver = new PackageReceiver(); + private final List mCategoryListeners = new ArrayList<>(); + private SettingsDrawerAdapter mDrawerAdapter; - // Hold on to a cache of tiles to avoid loading the info multiple times. - private final HashMap, DashboardTile> mTileCache = new HashMap<>(); - private List mDashboardCategories; private DrawerLayout mDrawerLayout; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); + long startTime = System.currentTimeMillis(); + requestWindowFeature(Window.FEATURE_NO_TITLE); super.setContentView(R.layout.settings_with_drawer); mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); @@ -62,6 +77,10 @@ public class SettingsDrawerActivity extends Activity { mDrawerLayout = null; return; } + if (sDashboardCategories == null) { + sTileCache = new HashMap<>(); + sDashboardCategories = TileUtils.getCategories(this, sTileCache); + } setActionBar(toolbar); mDrawerAdapter = new SettingsDrawerAdapter(this); ListView listView = (ListView) findViewById(R.id.left_drawer); @@ -72,6 +91,8 @@ public class SettingsDrawerActivity extends Activity { onTileClicked(mDrawerAdapter.getTile(position)); }; }); + if (DEBUG_TIMING) Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime) + + " ms"); } @Override @@ -88,7 +109,29 @@ public class SettingsDrawerActivity extends Activity { protected void onResume() { super.onResume(); - updateDrawer(); + final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); + filter.addAction(Intent.ACTION_PACKAGE_REMOVED); + filter.addAction(Intent.ACTION_PACKAGE_CHANGED); + filter.addAction(Intent.ACTION_PACKAGE_REPLACED); + filter.addDataScheme("package"); + registerReceiver(mPackageReceiver, filter); + + new CategoriesUpdater().execute(); + } + + @Override + protected void onPause() { + unregisterReceiver(mPackageReceiver); + + super.onPause(); + } + + public void addCategoryListener(CategoryListener listener) { + mCategoryListeners.add(listener); + } + + public void remCategoryListener(CategoryListener listener) { + mCategoryListeners.remove(listener); } public void openDrawer() { @@ -134,11 +177,16 @@ public class SettingsDrawerActivity extends Activity { } } - public List getDashboardCategories(boolean force) { - if (force) { - mDashboardCategories = TileUtils.getCategories(this, mTileCache); + public List getDashboardCategories() { + return sDashboardCategories; + } + + protected void onCategoriesChanged() { + updateDrawer(); + final int N = mCategoryListeners.size(); + for (int i = 0; i < N; i++) { + mCategoryListeners.get(i).onCategoriesChanged(); } - return mDashboardCategories; } public boolean openTile(DashboardTile tile) { @@ -167,4 +215,28 @@ public class SettingsDrawerActivity extends Activity { public void onProfileTileOpen() { finish(); } + + public interface CategoryListener { + void onCategoriesChanged(); + } + + private class CategoriesUpdater extends AsyncTask> { + @Override + protected List doInBackground(Void... params) { + return TileUtils.getCategories(SettingsDrawerActivity.this, sTileCache); + } + + @Override + protected void onPostExecute(List dashboardCategories) { + sDashboardCategories = dashboardCategories; + onCategoriesChanged(); + } + } + + private class PackageReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + new CategoriesUpdater().execute(); + } + } } diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java index fef716c44c57..24c6ae8356ab 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java @@ -38,7 +38,7 @@ public class SettingsDrawerAdapter extends BaseAdapter { } void updateCategories() { - List categories = mActivity.getDashboardCategories(true); + List categories = mActivity.getDashboardCategories(); mItems.clear(); for (int i = 0; i < categories.size(); i++) { Item category = new Item(); diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java index 18e8d31f59d3..6b366801e76a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java @@ -14,6 +14,7 @@ import android.app.ActivityManager; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; @@ -35,6 +36,7 @@ import java.util.Map; public class TileUtils { private static final boolean DEBUG = false; + private static final boolean DEBUG_TIMING = true; private static final String LOG_TAG = "TileUtils"; @@ -105,12 +107,9 @@ public class TileUtils { private static final String SETTING_PKG = "com.android.settings"; - public static List getCategories(Context context) { - return getCategories(context, new HashMap, DashboardTile>()); - } - public static List getCategories(Context context, HashMap, DashboardTile> cache) { + final long startTime = System.currentTimeMillis(); ArrayList tiles = new ArrayList<>(); UserManager userManager = UserManager.get(context); for (UserHandle user : userManager.getUserProfiles()) { @@ -143,6 +142,8 @@ public class TileUtils { Collections.sort(category.tiles, TILE_COMPARATOR); } Collections.sort(categories, CATEGORY_COMPARATOR); + if (DEBUG_TIMING) Log.d(LOG_TAG, "getCategories took " + + (System.currentTimeMillis() - startTime) + " ms"); return categories; } @@ -207,7 +208,9 @@ public class TileUtils { activityInfo.packageName, activityInfo.name); tile.category = categoryKey; tile.priority = requireSettings ? resolved.priority : 0; - updateTileData(context, tile); + tile.metaData = activityInfo.metaData; + updateTileData(context, tile, activityInfo, activityInfo.applicationInfo, + pm); if (DEBUG) Log.d(LOG_TAG, "Adding tile " + tile.title); addedCache.put(key, tile); @@ -231,64 +234,52 @@ public class TileUtils { return null; } - private static boolean updateTileData(Context context, DashboardTile tile) { - Intent intent = tile.intent; - if (intent != null) { - // Find the activity that is in the system image - PackageManager pm = context.getPackageManager(); - List list = tile.userHandle.size() != 0 - ? pm.queryIntentActivitiesAsUser(intent, PackageManager.GET_META_DATA, - tile.userHandle.get(0).getIdentifier()) - : pm.queryIntentActivities(intent, PackageManager.GET_META_DATA); - int listSize = list.size(); - for (int i = 0; i < listSize; i++) { - ResolveInfo resolveInfo = list.get(i); - if (resolveInfo.activityInfo.applicationInfo.isSystemApp()) { - int icon = 0; - CharSequence title = null; - String summary = null; - - // Get the activity's meta-data - try { - Resources res = pm.getResourcesForApplication( - resolveInfo.activityInfo.packageName); - Bundle metaData = resolveInfo.activityInfo.metaData; - - if (res != null && metaData != null) { - if (metaData.containsKey(META_DATA_PREFERENCE_ICON)) { - icon = metaData.getInt(META_DATA_PREFERENCE_ICON); - } - if (metaData.containsKey(META_DATA_PREFERENCE_TITLE)) { - title = metaData.getString(META_DATA_PREFERENCE_TITLE); - } - if (metaData.containsKey(META_DATA_PREFERENCE_SUMMARY)) { - summary = metaData.getString(META_DATA_PREFERENCE_SUMMARY); - } - } - } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) { - if (DEBUG) Log.d(LOG_TAG, "Couldn't find info", e); + private static boolean updateTileData(Context context, DashboardTile tile, + ActivityInfo activityInfo, ApplicationInfo applicationInfo, PackageManager pm) { + if (applicationInfo.isSystemApp()) { + int icon = 0; + CharSequence title = null; + String summary = null; + + // Get the activity's meta-data + try { + Resources res = pm.getResourcesForApplication( + applicationInfo.packageName); + Bundle metaData = activityInfo.metaData; + + if (res != null && metaData != null) { + if (metaData.containsKey(META_DATA_PREFERENCE_ICON)) { + icon = metaData.getInt(META_DATA_PREFERENCE_ICON); } - - // Set the preference title to the activity's label if no - // meta-data is found - if (TextUtils.isEmpty(title)) { - title = resolveInfo.loadLabel(pm).toString(); + if (metaData.containsKey(META_DATA_PREFERENCE_TITLE)) { + title = metaData.getString(META_DATA_PREFERENCE_TITLE); } - if (icon == 0) { - icon = resolveInfo.activityInfo.icon; + if (metaData.containsKey(META_DATA_PREFERENCE_SUMMARY)) { + summary = metaData.getString(META_DATA_PREFERENCE_SUMMARY); } - - // Set icon, title and summary for the preference - tile.icon = Icon.createWithResource(resolveInfo.activityInfo.packageName, icon); - tile.title = title; - tile.summary = summary; - // Replace the intent with this specific activity - tile.intent = new Intent().setClassName(resolveInfo.activityInfo.packageName, - resolveInfo.activityInfo.name); - - return true; } + } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) { + if (DEBUG) Log.d(LOG_TAG, "Couldn't find info", e); } + + // Set the preference title to the activity's label if no + // meta-data is found + if (TextUtils.isEmpty(title)) { + title = activityInfo.loadLabel(pm).toString(); + } + if (icon == 0) { + icon = activityInfo.icon; + } + + // Set icon, title and summary for the preference + tile.icon = Icon.createWithResource(activityInfo.packageName, icon); + tile.title = title; + tile.summary = summary; + // Replace the intent with this specific activity + tile.intent = new Intent().setClassName(activityInfo.packageName, + activityInfo.name); + + return true; } return false; -- 2.11.0