OSDN Git Service

Add suggestions parsing to SettingsLib
authorJason Monk <jmonk@google.com>
Thu, 7 Jan 2016 21:22:53 +0000 (16:22 -0500)
committerJason Monk <jmonk@google.com>
Fri, 8 Jan 2016 14:47:35 +0000 (09:47 -0500)
Add a parser that will parse an XML of the suggestion categories
and ordering and query those categories into Tiles.

Change-Id: I3154c94e176108358163bbe36feb48e889fe00d1

packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java [new file with mode: 0644]
packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java
packages/SettingsLib/src/com/android/settingslib/drawer/ProfileSelectDialog.java
packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java [moved from packages/SettingsLib/src/com/android/settingslib/drawer/DashboardTile.java with 90% similarity]
packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java

diff --git a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
new file mode 100644 (file)
index 0000000..58a477e
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * 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);
+            }
+        }
+    }
+}
+
index 0f322cf..53be0e6 100644 (file)
@@ -43,22 +43,22 @@ public class DashboardCategory implements Parcelable {
     /**
      * 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);
     }
 
@@ -70,7 +70,7 @@ public class DashboardCategory implements Parcelable {
         return tiles.size();
     }
 
-    public DashboardTile getTile(int n) {
+    public Tile getTile(int n) {
         return tiles.get(n);
     }
 
@@ -89,7 +89,7 @@ public class DashboardCategory implements Parcelable {
         dest.writeInt(count);
 
         for (int n = 0; n < count; n++) {
-            DashboardTile tile = tiles.get(n);
+            Tile tile = tiles.get(n);
             tile.writeToParcel(dest, flags);
         }
     }
@@ -102,7 +102,7 @@ public class DashboardCategory implements Parcelable {
         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);
         }
     }
index 793e877..2fd043f 100644 (file)
@@ -30,9 +30,9 @@ public class ProfileSelectDialog extends DialogFragment implements OnClickListen
 
     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);
index 102e47a..3fc0c22 100644 (file)
@@ -49,7 +49,7 @@ public class SettingsDrawerActivity extends Activity {
     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<>();
@@ -194,7 +194,7 @@ public class SettingsDrawerActivity extends Activity {
         }
     }
 
-    public boolean openTile(DashboardTile tile) {
+    public boolean openTile(Tile tile) {
         closeDrawer();
         if (tile == null) {
             return false;
@@ -211,7 +211,7 @@ public class SettingsDrawerActivity extends Activity {
         return true;
     }
 
-    protected void onTileClicked(DashboardTile tile) {
+    protected void onTileClicked(Tile tile) {
         if (openTile(tile)) {
             finish();
         }
index 24c6ae8..72f1c56 100644 (file)
@@ -48,7 +48,7 @@ public class SettingsDrawerAdapter extends BaseAdapter {
             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;
@@ -58,7 +58,7 @@ public class SettingsDrawerAdapter extends BaseAdapter {
         notifyDataSetChanged();
     }
 
-    public DashboardTile getTile(int position) {
+    public Tile getTile(int position) {
         return mItems.get(position).tile;
     }
 
@@ -101,6 +101,6 @@ public class SettingsDrawerAdapter extends BaseAdapter {
     private static class Item {
         public Icon icon;
         public CharSequence label;
-        public DashboardTile tile;
+        public Tile tile;
     }
 }
@@ -29,7 +29,7 @@ import java.util.ArrayList;
 /**
  * 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.
@@ -79,7 +79,7 @@ public class DashboardTile implements Parcelable {
      */
     public Bundle metaData;
 
-    public DashboardTile() {
+    public Tile() {
         // Empty
     }
 
@@ -134,16 +134,16 @@ public class DashboardTile implements Parcelable {
         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];
         }
     };
 }
index 6b36680..2dfdfda 100644 (file)
@@ -1,13 +1,18 @@
 /*
  * 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;
@@ -108,9 +113,9 @@ public class TileUtils {
     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.
@@ -125,7 +130,7 @@ public class TileUtils {
             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);
@@ -170,30 +175,34 @@ public class TileUtils {
     }
 
     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 {
@@ -201,13 +210,13 @@ public class TileUtils {
             }
             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);
@@ -234,7 +243,7 @@ public class TileUtils {
         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;
@@ -252,10 +261,18 @@ public class TileUtils {
                         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) {
@@ -285,10 +302,10 @@ public class TileUtils {
         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;
         }
     };