--- /dev/null
+/*
+ * 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;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Xml;
+import android.view.InflateException;
+import com.android.settingslib.drawer.Tile;
+import com.android.settingslib.drawer.TileUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class SuggestionParser {
+
+ private static final String TAG = "SuggestionParser";
+
+ private final Context mContext;
+ private final List<SuggestionCategory> mSuggestionList;
+ private final ArrayMap<Pair<String, String>, Tile> addCache = new ArrayMap<>();
+
+ public SuggestionParser(Context context, int orderXml) {
+ mContext = context;
+ mSuggestionList = (List<SuggestionCategory>) new SuggestionOrderInflater(mContext)
+ .parse(orderXml);
+ }
+
+ public List<Tile> getSuggestions() {
+ List<Tile> suggestions = new ArrayList<>();
+ final int N = mSuggestionList.size();
+ for (int i = 0; i < N; i++) {
+ readSuggestions(mSuggestionList.get(i), suggestions);
+ }
+ return suggestions;
+ }
+
+ private void readSuggestions(SuggestionCategory category, List<Tile> suggestions) {
+ int countBefore = suggestions.size();
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(category.category);
+ if (category.pkg != null) {
+ intent.setPackage(category.pkg);
+ }
+ TileUtils.getTilesForIntent(mContext, new UserHandle(UserHandle.myUserId()), intent,
+ addCache, null, suggestions, true, false);
+ if (!category.multiple && suggestions.size() > (countBefore + 1)) {
+ // If there are too many, remove them all and only re-add the one with the highest
+ // priority.
+ Tile item = suggestions.remove(suggestions.size() - 1);
+ while (suggestions.size() > countBefore) {
+ Tile last = suggestions.remove(suggestions.size() - 1);
+ if (last.priority > item.priority) {
+ item = last;
+ }
+ }
+ suggestions.add(item);
+ }
+ }
+
+ private static class SuggestionCategory {
+ public String category;
+ public String pkg;
+ public boolean multiple;
+ }
+
+ private static class SuggestionOrderInflater {
+ private static final String TAG_LIST = "optional-steps";
+ private static final String TAG_ITEM = "step";
+
+ private static final String ATTR_CATEGORY = "category";
+ private static final String ATTR_PACKAGE = "package";
+ private static final String ATTR_MULTIPLE = "multiple";
+
+ private final Context mContext;
+
+ public SuggestionOrderInflater(Context context) {
+ mContext = context;
+ }
+
+ public Object parse(int resource) {
+ XmlPullParser parser = mContext.getResources().getXml(resource);
+ final AttributeSet attrs = Xml.asAttributeSet(parser);
+ try {
+ // Look for the root node.
+ int type;
+ do {
+ type = parser.next();
+ } while (type != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT);
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new InflateException(parser.getPositionDescription()
+ + ": No start tag found!");
+ }
+
+ // Temp is the root that was found in the xml
+ Object xmlRoot = onCreateItem(parser.getName(), attrs);
+
+ // Inflate all children under temp
+ rParse(parser, xmlRoot, attrs);
+ return xmlRoot;
+ } catch (XmlPullParserException | IOException e) {
+ Log.w(TAG, "Problem parser resource " + resource, e);
+ return null;
+ }
+ }
+
+ /**
+ * Recursive method used to descend down the xml hierarchy and instantiate
+ * items, instantiate their children.
+ */
+ private void rParse(XmlPullParser parser, Object parent, final AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+ final int depth = parser.getDepth();
+
+ int type;
+ while (((type = parser.next()) != XmlPullParser.END_TAG ||
+ parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ final String name = parser.getName();
+
+ Object item = onCreateItem(name, attrs);
+ onAddChildItem(parent, item);
+ rParse(parser, item, attrs);
+ }
+ }
+
+ protected void onAddChildItem(Object parent, Object child) {
+ if (parent instanceof List<?> && child instanceof SuggestionCategory) {
+ ((List<SuggestionCategory>) parent).add((SuggestionCategory) child);
+ } else {
+ throw new IllegalArgumentException("Parent was not a list");
+ }
+ }
+
+ protected Object onCreateItem(String name, AttributeSet attrs) {
+ if (name.equals(TAG_LIST)) {
+ return new ArrayList<SuggestionCategory>();
+ } else if (name.equals(TAG_ITEM)) {
+ SuggestionCategory category = new SuggestionCategory();
+ category.category = attrs.getAttributeValue(null, ATTR_CATEGORY);
+ category.pkg = attrs.getAttributeValue(null, ATTR_PACKAGE);
+ String multiple = attrs.getAttributeValue(null, ATTR_MULTIPLE);
+ category.multiple = !TextUtils.isEmpty(multiple) && Boolean.parseBoolean(multiple);
+ return category;
+ } else {
+ throw new IllegalArgumentException("Unknown item " + name);
+ }
+ }
+ }
+}
+
/**
* List of the category's children
*/
- public List<DashboardTile> tiles = new ArrayList<DashboardTile>();
+ public List<Tile> tiles = new ArrayList<Tile>();
public DashboardCategory() {
// Empty
}
- public void addTile(DashboardTile tile) {
+ public void addTile(Tile tile) {
tiles.add(tile);
}
- public void addTile(int n, DashboardTile tile) {
+ public void addTile(int n, Tile tile) {
tiles.add(n, tile);
}
- public void removeTile(DashboardTile tile) {
+ public void removeTile(Tile tile) {
tiles.remove(tile);
}
return tiles.size();
}
- public DashboardTile getTile(int n) {
+ public Tile getTile(int n) {
return tiles.get(n);
}
dest.writeInt(count);
for (int n = 0; n < count; n++) {
- DashboardTile tile = tiles.get(n);
+ Tile tile = tiles.get(n);
tile.writeToParcel(dest, flags);
}
}
final int count = in.readInt();
for (int n = 0; n < count; n++) {
- DashboardTile tile = DashboardTile.CREATOR.createFromParcel(in);
+ Tile tile = Tile.CREATOR.createFromParcel(in);
tiles.add(tile);
}
}
private static final String ARG_SELECTED_TILE = "selectedTile";
- private DashboardTile mSelectedTile;
+ private Tile mSelectedTile;
- public static void show(FragmentManager manager, DashboardTile tile) {
+ public static void show(FragmentManager manager, Tile tile) {
ProfileSelectDialog dialog = new ProfileSelectDialog();
Bundle args = new Bundle();
args.putParcelable(ARG_SELECTED_TILE, tile);
private static final String TAG = "SettingsDrawerActivity";
private static List<DashboardCategory> sDashboardCategories;
- private static HashMap<Pair<String, String>, DashboardTile> sTileCache;
+ private static HashMap<Pair<String, String>, Tile> sTileCache;
private final PackageReceiver mPackageReceiver = new PackageReceiver();
private final List<CategoryListener> mCategoryListeners = new ArrayList<>();
}
}
- public boolean openTile(DashboardTile tile) {
+ public boolean openTile(Tile tile) {
closeDrawer();
if (tile == null) {
return false;
return true;
}
- protected void onTileClicked(DashboardTile tile) {
+ protected void onTileClicked(Tile tile) {
if (openTile(tile)) {
finish();
}
mItems.add(category);
for (int j = 0; j < dashboardCategory.tiles.size(); j++) {
Item tile = new Item();
- DashboardTile dashboardTile = dashboardCategory.tiles.get(j);
+ Tile dashboardTile = dashboardCategory.tiles.get(j);
tile.label = dashboardTile.title;
tile.icon = dashboardTile.icon;
tile.tile = dashboardTile;
notifyDataSetChanged();
}
- public DashboardTile getTile(int position) {
+ public Tile getTile(int position) {
return mItems.get(position).tile;
}
private static class Item {
public Icon icon;
public CharSequence label;
- public DashboardTile tile;
+ public Tile tile;
}
}
/**
* Description of a single dashboard tile that the user can select.
*/
-public class DashboardTile implements Parcelable {
+public class Tile implements Parcelable {
/**
* Title of the tile that is shown to the user.
*/
public Bundle metaData;
- public DashboardTile() {
+ public Tile() {
// Empty
}
metaData = in.readBundle();
}
- DashboardTile(Parcel in) {
+ Tile(Parcel in) {
readFromParcel(in);
}
- public static final Creator<DashboardTile> CREATOR = new Creator<DashboardTile>() {
- public DashboardTile createFromParcel(Parcel source) {
- return new DashboardTile(source);
+ public static final Creator<Tile> CREATOR = new Creator<Tile>() {
+ public Tile createFromParcel(Parcel source) {
+ return new Tile(source);
}
- public DashboardTile[] newArray(int size) {
- return new DashboardTile[size];
+ public Tile[] newArray(int size) {
+ return new Tile[size];
}
};
}
/*
* Copyright (C) 2015 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
+ * 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.
+ * 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.app.ActivityManager;
private static final String SETTING_PKG = "com.android.settings";
public static List<DashboardCategory> getCategories(Context context,
- HashMap<Pair<String, String>, DashboardTile> cache) {
+ HashMap<Pair<String, String>, Tile> cache) {
final long startTime = System.currentTimeMillis();
- ArrayList<DashboardTile> tiles = new ArrayList<>();
+ ArrayList<Tile> tiles = new ArrayList<>();
UserManager userManager = UserManager.get(context);
for (UserHandle user : userManager.getUserProfiles()) {
// TODO: Needs much optimization, too many PM queries going on here.
getTilesForAction(context, user, EXTRA_SETTINGS_ACTION, cache, null, tiles, false);
}
HashMap<String, DashboardCategory> categoryMap = new HashMap<>();
- for (DashboardTile tile : tiles) {
+ for (Tile tile : tiles) {
DashboardCategory category = categoryMap.get(tile.category);
if (category == null) {
category = createCategory(context, tile.category);
}
private static void getTilesForAction(Context context,
- UserHandle user, String action, Map<Pair<String, String>, DashboardTile> addedCache,
- String defaultCategory, ArrayList<DashboardTile> outTiles, boolean requireSettings) {
- PackageManager pm = context.getPackageManager();
+ UserHandle user, String action, Map<Pair<String, String>, Tile> addedCache,
+ String defaultCategory, ArrayList<Tile> outTiles, boolean requireSettings) {
Intent intent = new Intent(action);
+ if (requireSettings) {
+ intent.setPackage(SETTING_PKG);
+ }
+ getTilesForIntent(context, user, intent, addedCache, defaultCategory, outTiles,
+ requireSettings, true);
+ }
+
+ public static void getTilesForIntent(Context context, UserHandle user, Intent intent,
+ Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles,
+ boolean usePriority, boolean checkCategory) {
+ PackageManager pm = context.getPackageManager();
List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(intent,
PackageManager.GET_META_DATA, user.getIdentifier());
for (ResolveInfo resolved : results) {
- if (requireSettings) {
- if (!SETTING_PKG.equals(resolved.activityInfo.applicationInfo.packageName)) {
- continue;
- }
- } else {
- if (!resolved.system) {
- // Do not allow any app to add to settings, only system ones.
- continue;
- }
+ if (!resolved.system) {
+ // Do not allow any app to add to settings, only system ones.
+ continue;
}
ActivityInfo activityInfo = resolved.activityInfo;
Bundle metaData = activityInfo.metaData;
String categoryKey = defaultCategory;
- if (((metaData == null) || !metaData.containsKey(EXTRA_CATEGORY_KEY))
+ if (checkCategory && ((metaData == null) || !metaData.containsKey(EXTRA_CATEGORY_KEY))
&& categoryKey == null) {
- Log.w(LOG_TAG, "Found " + resolved.activityInfo.name + " for action "
- + action + " missing metadata "
+ Log.w(LOG_TAG, "Found " + resolved.activityInfo.name + " for intent "
+ + intent + " missing metadata "
+ (metaData == null ? "" : EXTRA_CATEGORY_KEY));
continue;
} else {
}
Pair<String, String> key = new Pair<String, String>(activityInfo.packageName,
activityInfo.name);
- DashboardTile tile = addedCache.get(key);
+ Tile tile = addedCache.get(key);
if (tile == null) {
- tile = new DashboardTile();
+ tile = new Tile();
tile.intent = new Intent().setClassName(
activityInfo.packageName, activityInfo.name);
tile.category = categoryKey;
- tile.priority = requireSettings ? resolved.priority : 0;
+ tile.priority = usePriority ? resolved.priority : 0;
tile.metaData = activityInfo.metaData;
updateTileData(context, tile, activityInfo, activityInfo.applicationInfo,
pm);
return null;
}
- private static boolean updateTileData(Context context, DashboardTile tile,
+ private static boolean updateTileData(Context context, Tile tile,
ActivityInfo activityInfo, ApplicationInfo applicationInfo, PackageManager pm) {
if (applicationInfo.isSystemApp()) {
int icon = 0;
icon = metaData.getInt(META_DATA_PREFERENCE_ICON);
}
if (metaData.containsKey(META_DATA_PREFERENCE_TITLE)) {
- title = metaData.getString(META_DATA_PREFERENCE_TITLE);
+ if (metaData.get(META_DATA_PREFERENCE_TITLE) instanceof Integer) {
+ title = res.getString(metaData.getInt(META_DATA_PREFERENCE_TITLE));
+ } else {
+ title = metaData.getString(META_DATA_PREFERENCE_TITLE);
+ }
}
if (metaData.containsKey(META_DATA_PREFERENCE_SUMMARY)) {
- summary = metaData.getString(META_DATA_PREFERENCE_SUMMARY);
+ if (metaData.get(META_DATA_PREFERENCE_SUMMARY) instanceof Integer) {
+ summary = res.getString(metaData.getInt(META_DATA_PREFERENCE_SUMMARY));
+ } else {
+ summary = metaData.getString(META_DATA_PREFERENCE_SUMMARY);
+ }
}
}
} catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) {
return false;
}
- private static final Comparator<DashboardTile> TILE_COMPARATOR =
- new Comparator<DashboardTile>() {
+ private static final Comparator<Tile> TILE_COMPARATOR =
+ new Comparator<Tile>() {
@Override
- public int compare(DashboardTile lhs, DashboardTile rhs) {
+ public int compare(Tile lhs, Tile rhs) {
return rhs.priority - lhs.priority;
}
};