Add a component to load category/tiles by key.
And switch between using SettingDrawerActivity.getDashboardCategories()
and the new CategoryManager in different conditions.
Test: SettingsRoboTests for regression. Will write tests for new feature
soon once we are set on the data structure.
Bug: 31781480
Change-Id: I864e5aea869071df63ca89002fb378c235d0a1fe
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
new file mode 100644
index 0000000..9821fb8
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settingslib.drawer;
+
+public final class CategoryKey {
+
+ // Activities in this category shows up in Settings homepage.
+ public static final String CATEGORY_HOMEPAGE = "com.android.settings.category.homepage";
+
+ // Top level categor.
+ public static final String CATEGORY_NETWORK = "com.android.settings.category.wireless";
+ public static final String CATEGORY_DEVICE = "com.android.settings.category.device";
+ public static final String CATEGORY_APPS = "com.android.settings.category.apps";
+ public static final String CATEGORY_BATTERY = "com.android.settings.category.battery";
+ public static final String CATEGORY_DISPLAY = "com.android.settings.category.display";
+ public static final String CATEGORY_SOUND = "com.android.settings.category.sound";
+ public static final String CATEGORY_STORAGE = "com.android.settings.category.storage";
+ public static final String CATEGORY_SECURITY = "com.android.settings.category.security";
+ public static final String CATEGORY_ACCOUNT = "com.android.settings.category.accounts";
+ public static final String CATEGORY_SYSTEM = "com.android.settings.category.system";
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java
new file mode 100644
index 0000000..a8f286d
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java
@@ -0,0 +1,108 @@
+/**
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settingslib.drawer;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.settingslib.applications.InterestingConfigChanges;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class CategoryManager {
+
+ private static final String TAG = "CategoryManager";
+
+ private static CategoryManager sInstance;
+
+ private final InterestingConfigChanges mInterestingConfigChanges;
+
+ // Tile cache (key: <packageName, activityName>, value: tile)
+ private final Map<Pair<String, String>, Tile> mTileByComponentCache;
+
+ // Tile cache (key: category key, value: category)
+ private final Map<String, DashboardCategory> mCategoryByKeyMap;
+
+ private List<DashboardCategory> mCategories;
+
+ public static CategoryManager get() {
+ if (sInstance == null) {
+ sInstance = new CategoryManager();
+ }
+ return sInstance;
+ }
+
+ CategoryManager() {
+ mInterestingConfigChanges = new InterestingConfigChanges();
+ mTileByComponentCache = new ArrayMap<>();
+ mCategoryByKeyMap = new ArrayMap<>();
+ }
+
+ public DashboardCategory getTilesByCategory(Context context, String categoryKey) {
+ tryInitCategories(context);
+
+ final DashboardCategory category = mCategoryByKeyMap.get(categoryKey);
+ if (category == null) {
+ throw new IllegalStateException("Can't find category with key " + categoryKey);
+ }
+ return category;
+ }
+
+ public List<DashboardCategory> getCategories(Context context) {
+ tryInitCategories(context);
+ return mCategories;
+ }
+
+ public void reloadAllCategoriesForConfigChange(Context context) {
+ if (mInterestingConfigChanges.applyNewConfig(context.getResources())) {
+ mCategories = null;
+ tryInitCategories(context);
+ }
+ }
+
+ public void updateCategoryFromBlacklist(Set<ComponentName> tileBlacklist) {
+ if (mCategories == null) {
+ Log.w(TAG, "Category is null, skipping blacklist update");
+ }
+ for (int i = 0; i < mCategories.size(); i++) {
+ DashboardCategory category = mCategories.get(i);
+ for (int j = 0; j < category.tiles.size(); j++) {
+ Tile tile = category.tiles.get(j);
+ if (tileBlacklist.contains(tile.intent.getComponent())) {
+ category.tiles.remove(j--);
+ }
+ }
+ }
+ }
+
+ private void tryInitCategories(Context context) {
+ if (mCategories == null) {
+ mTileByComponentCache.clear();
+ mCategoryByKeyMap.clear();
+ mCategories = TileUtils.getCategories(context, mTileByComponentCache,
+ false /* categoryDefinedInManifest */);
+ for (DashboardCategory category : mCategories) {
+ mCategoryByKeyMap.put(category.key, category);
+ }
+ }
+ }
+
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java b/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java
index 53be0e6..3fc999f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java
@@ -16,15 +16,20 @@
package com.android.settingslib.drawer;
+import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import android.util.Log;
import java.util.ArrayList;
import java.util.List;
public class DashboardCategory implements Parcelable {
+ private static final String TAG = "DashboardCategory";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
/**
* Title of the category that is shown to the user.
*/
@@ -74,6 +79,22 @@
return tiles.get(n);
}
+ public boolean containsComponent(ComponentName component) {
+ for (Tile tile : tiles) {
+ if (TextUtils.equals(tile.intent.getComponent().getClassName(),
+ component.getClassName())) {
+ if (DEBUG) {
+ Log.d(TAG, "category " + key + "contains component" + component);
+ }
+ return true;
+ }
+ }
+ if (DEBUG) {
+ Log.d(TAG, "category " + key + " does not contain component" + component);
+ }
+ return false;
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index 05585e53e..50867eb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -33,7 +33,6 @@
import android.provider.Settings;
import android.support.annotation.VisibleForTesting;
import android.support.v4.widget.DrawerLayout;
-import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
@@ -64,12 +63,9 @@
public static final String EXTRA_SHOW_MENU = "show_drawer_menu";
- private static List<DashboardCategory> sDashboardCategories;
- private static HashMap<Pair<String, String>, Tile> sTileCache;
// Serves as a temporary list of tiles to ignore until we heard back from the PM that they
// are disabled.
private static ArraySet<ComponentName> sTileBlacklist = new ArraySet<>();
- private static InterestingConfigChanges sConfigTracker;
private final PackageReceiver mPackageReceiver = new PackageReceiver();
private final List<CategoryListener> mCategoryListeners = new ArrayList<>();
@@ -80,6 +76,15 @@
private boolean mShowingMenu;
private UserManager mUserManager;
+ // Remove below after new IA
+ @Deprecated
+ private static List<DashboardCategory> sDashboardCategories;
+ @Deprecated
+ private static HashMap<Pair<String, String>, Tile> sTileCache;
+ @Deprecated
+ private static InterestingConfigChanges sConfigTracker;
+ // Remove above after new IA
+
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -105,7 +110,9 @@
mDrawerLayout = null;
return;
}
- getDashboardCategories();
+ if (!isDashboardFeatureEnabled()) {
+ getDashboardCategories();
+ }
setActionBar(toolbar);
mDrawerAdapter = new SettingsDrawerAdapter(this);
ListView listView = (ListView) findViewById(R.id.left_drawer);
@@ -144,7 +151,11 @@
filter.addDataScheme("package");
registerReceiver(mPackageReceiver, filter);
- new CategoriesUpdater().execute();
+ if (isDashboardFeatureEnabled()) {
+ new CategoriesUpdateTask().execute();
+ } else {
+ new CategoriesUpdater().execute();
+ }
}
final Intent intent = getIntent();
if (intent != null) {
@@ -173,23 +184,23 @@
if (componentName == null) {
return false;
}
- // Look for a tile that has the same component as incoming intent
- final List<DashboardCategory> categories = getDashboardCategories();
- for (DashboardCategory category : categories) {
- for (Tile tile : category.tiles) {
- if (TextUtils.equals(tile.intent.getComponent().getClassName(),
- componentName.getClassName())) {
- if (DEBUG) {
- Log.d(TAG, "intent is for top level tile: " + tile.title);
- }
+ if (isDashboardFeatureEnabled()) {
+ final DashboardCategory homepageCategories = CategoryManager.get()
+ .getTilesByCategory(this, CategoryKey.CATEGORY_HOMEPAGE);
+ return homepageCategories.containsComponent(componentName);
+ } else {
+ // Look for a tile that has the same component as incoming intent
+ final List<DashboardCategory> categories = getDashboardCategories();
+ for (DashboardCategory category : categories) {
+ if (category.containsComponent(componentName)) {
return true;
}
}
+ if (DEBUG) {
+ Log.d(TAG, "Intent is not for top level settings " + intent);
+ }
+ return false;
}
- if (DEBUG) {
- Log.d(TAG, "Intent is not for top level settings " + intent);
- }
- return false;
}
public void addCategoryListener(CategoryListener listener) {
@@ -255,7 +266,11 @@
return;
}
// TODO: Do this in the background with some loading.
- mDrawerAdapter.updateCategories();
+ if (isDashboardFeatureEnabled()) {
+ mDrawerAdapter.updateHomepageCategories();
+ } else {
+ mDrawerAdapter.updateCategories();
+ }
if (mDrawerAdapter.getCount() != 0) {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
} else {
@@ -343,13 +358,6 @@
}
}
- public HashMap<Pair<String, String>, Tile> getTileCache() {
- if (sTileCache == null) {
- getDashboardCategories();
- }
- return sTileCache;
- }
-
public void onProfileTileOpen() {
finish();
}
@@ -368,7 +376,11 @@
? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
- new CategoriesUpdater().execute();
+ if (isDashboardFeatureEnabled()) {
+ new CategoriesUpdateTask().execute();
+ } else {
+ new CategoriesUpdater().execute();
+ }
}
}
@@ -376,6 +388,10 @@
void onCategoriesChanged();
}
+ /**
+ * @deprecated remove after new IA
+ */
+ @Deprecated
private class CategoriesUpdater extends AsyncTask<Void, Void, List<DashboardCategory>> {
@Override
protected List<DashboardCategory> doInBackground(Void... params) {
@@ -408,10 +424,39 @@
}
}
+ private class CategoriesUpdateTask extends AsyncTask<Void, Void, Void> {
+
+ private final CategoryManager mCategoryManager;
+
+ public CategoriesUpdateTask() {
+ mCategoryManager = CategoryManager.get();
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ mCategoryManager.reloadAllCategoriesForConfigChange(SettingsDrawerActivity.this);
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ mCategoryManager.updateCategoryFromBlacklist(sTileBlacklist);
+ onCategoriesChanged();
+ }
+ }
+
+ protected boolean isDashboardFeatureEnabled() {
+ return false;
+ }
+
private class PackageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- new CategoriesUpdater().execute();
+ if (isDashboardFeatureEnabled()) {
+ new CategoriesUpdateTask().execute();
+ } else {
+ 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 1d6197a..e1216a1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
@@ -37,6 +37,10 @@
mActivity = activity;
}
+ /**
+ * @deprecated Remove after new IA
+ */
+ @Deprecated
void updateCategories() {
List<DashboardCategory> categories = mActivity.getDashboardCategories();
mItems.clear();
@@ -64,6 +68,27 @@
notifyDataSetChanged();
}
+ public void updateHomepageCategories() {
+ DashboardCategory category =
+ CategoryManager.get().getTilesByCategory(mActivity, CategoryKey.CATEGORY_HOMEPAGE);
+ mItems.clear();
+ // Spacer.
+ mItems.add(null);
+ Item tile = new Item();
+ tile.label = mActivity.getString(R.string.home);
+ tile.icon = Icon.createWithResource(mActivity, R.drawable.home);
+ mItems.add(tile);
+ for (int j = 0; j < category.tiles.size(); j++) {
+ tile = new Item();
+ Tile dashboardTile = category.tiles.get(j);
+ tile.label = dashboardTile.title;
+ tile.icon = dashboardTile.icon;
+ tile.tile = dashboardTile;
+ mItems.add(tile);
+ }
+ notifyDataSetChanged();
+ }
+
public Tile getTile(int position) {
return mItems.get(position) != null ? mItems.get(position).tile : null;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index e70cc29..81f0e84 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -94,6 +94,13 @@
private static final String EXTRA_CATEGORY_KEY = "com.android.settings.category";
/**
+ * The key used to get the category from metadata of activities of action
+ * {@link #EXTRA_SETTINGS_ACTION}
+ * The value must be one of constants defined in {@code CategoryKey}.
+ */
+ private static final String EXTRA_IA_CATEGORY_KEY = "com.android.settings.iacategory";
+
+ /**
* Name of the meta-data item that should be set in the AndroidManifest.xml
* to specify the icon that should be displayed for the preference.
*/
@@ -113,8 +120,24 @@
private static final String SETTING_PKG = "com.android.settings";
+ /**
+ * Build a list of DashboardCategory. Each category must be defined in manifest.
+ * eg: .Settings$DeviceSettings
+ * @deprecated
+ */
+ @Deprecated
public static List<DashboardCategory> getCategories(Context context,
- HashMap<Pair<String, String>, Tile> cache) {
+ Map<Pair<String, String>, Tile> cache) {
+ return getCategories(context, cache, true /*categoryDefinedInManifest*/);
+ }
+
+ /**
+ * Build a list of DashboardCategory.
+ * @param categoryDefinedInManifest If true, an dummy activity must exists in manifest to
+ * represent this category (eg: .Settings$DeviceSettings)
+ */
+ public static List<DashboardCategory> getCategories(Context context,
+ Map<Pair<String, String>, Tile> cache, boolean categoryDefinedInManifest) {
final long startTime = System.currentTimeMillis();
boolean setup = Global.getInt(context.getContentResolver(), Global.DEVICE_PROVISIONED, 0)
!= 0;
@@ -134,11 +157,12 @@
getTilesForAction(context, user, EXTRA_SETTINGS_ACTION, cache, null, tiles, false);
}
}
+
HashMap<String, DashboardCategory> categoryMap = new HashMap<>();
for (Tile tile : tiles) {
DashboardCategory category = categoryMap.get(tile.category);
if (category == null) {
- category = createCategory(context, tile.category);
+ category = createCategory(context, tile.category, categoryDefinedInManifest);
if (category == null) {
Log.w(LOG_TAG, "Couldn't find category " + tile.category);
continue;
@@ -157,9 +181,21 @@
return categories;
}
- private static DashboardCategory createCategory(Context context, String categoryKey) {
+ /**
+ * Create a new DashboardCategory from key.
+ *
+ * @param context Context to query intent
+ * @param categoryKey The category key
+ * @param categoryDefinedInManifest If true, an dummy activity must exists in manifest to
+ * represent this category (eg: .Settings$DeviceSettings)
+ */
+ private static DashboardCategory createCategory(Context context, String categoryKey,
+ boolean categoryDefinedInManifest) {
DashboardCategory category = new DashboardCategory();
category.key = categoryKey;
+ if (!categoryDefinedInManifest) {
+ return category;
+ }
PackageManager pm = context.getPackageManager();
List<ResolveInfo> results = pm.queryIntentActivities(new Intent(categoryKey), 0);
if (results.size() == 0) {
@@ -204,14 +240,19 @@
ActivityInfo activityInfo = resolved.activityInfo;
Bundle metaData = activityInfo.metaData;
String categoryKey = defaultCategory;
- if (checkCategory && ((metaData == null) || !metaData.containsKey(EXTRA_CATEGORY_KEY))
- && categoryKey == null) {
+ if (metaData != null && categoryKey == null) {
+ // categoryKey is null, try to get it from metadata.
+ if (metaData.containsKey(EXTRA_IA_CATEGORY_KEY)) {
+ categoryKey = metaData.getString(EXTRA_IA_CATEGORY_KEY);
+ } else if (metaData.containsKey(EXTRA_CATEGORY_KEY)) {
+ categoryKey = metaData.getString(EXTRA_CATEGORY_KEY);
+ }
+ }
+ if (checkCategory && categoryKey == null) {
Log.w(LOG_TAG, "Found " + resolved.activityInfo.name + " for intent "
+ intent + " missing metadata "
+ (metaData == null ? "" : EXTRA_CATEGORY_KEY));
continue;
- } else {
- categoryKey = metaData.getString(EXTRA_CATEGORY_KEY);
}
Pair<String, String> key = new Pair<String, String>(activityInfo.packageName,
activityInfo.name);
@@ -238,16 +279,6 @@
}
}
- private static DashboardCategory getCategory(List<DashboardCategory> target,
- String categoryKey) {
- for (DashboardCategory category : target) {
- if (categoryKey.equals(category.key)) {
- return category;
- }
- }
- return null;
- }
-
private static boolean updateTileData(Context context, Tile tile,
ActivityInfo activityInfo, ApplicationInfo applicationInfo, PackageManager pm) {
if (applicationInfo.isSystemApp()) {