122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang/**
222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang * Copyright (C) 2016 The Android Open Source Project
322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang *
422a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang * Licensed under the Apache License, Version 2.0 (the "License");
522a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang * you may not use this file except in compliance with the License.
622a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang * You may obtain a copy of the License at
722a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang *
8c8a5b790fa13826b21aee97ed5d1960d785333daFan Zhang * http://www.apache.org/licenses/LICENSE-2.0
922a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang *
1022a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang * Unless required by applicable law or agreed to in writing, software
1122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang * distributed under the License is distributed on an "AS IS" BASIS,
1222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang * See the License for the specific language governing permissions and
1422a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang * limitations under the License.
1522a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang */
1622a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangpackage com.android.settingslib.drawer;
1722a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
1822a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangimport android.content.ComponentName;
1922a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangimport android.content.Context;
20914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhangimport android.support.annotation.VisibleForTesting;
2122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangimport android.util.ArrayMap;
225fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhangimport android.util.ArraySet;
2322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangimport android.util.Log;
2422a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangimport android.util.Pair;
2522a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
265adc26695fb4282125d4b6b641e04820a028d87bFan Zhangimport com.android.settingslib.applications.InterestingConfigChanges;
275adc26695fb4282125d4b6b641e04820a028d87bFan Zhang
2831f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhangimport java.util.ArrayList;
2931f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhangimport java.util.HashMap;
3022a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangimport java.util.List;
3122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangimport java.util.Map;
3231f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhangimport java.util.Map.Entry;
3322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangimport java.util.Set;
3422a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
35fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhangimport static java.lang.String.CASE_INSENSITIVE_ORDER;
36fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang
3722a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangpublic class CategoryManager {
3822a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
3922a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    private static final String TAG = "CategoryManager";
4022a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
4122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    private static CategoryManager sInstance;
425adc26695fb4282125d4b6b641e04820a028d87bFan Zhang    private final InterestingConfigChanges mInterestingConfigChanges;
4322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
4422a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    // Tile cache (key: <packageName, activityName>, value: tile)
4522a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    private final Map<Pair<String, String>, Tile> mTileByComponentCache;
4622a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
4722a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    // Tile cache (key: category key, value: category)
4822a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    private final Map<String, DashboardCategory> mCategoryByKeyMap;
4922a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
5022a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    private List<DashboardCategory> mCategories;
51485df11f7770edc6c7d0f87ade5b2e0aa40e7e59Doris Ling    private String mExtraAction;
5222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
535adc26695fb4282125d4b6b641e04820a028d87bFan Zhang    public static CategoryManager get(Context context) {
54485df11f7770edc6c7d0f87ade5b2e0aa40e7e59Doris Ling        return get(context, null);
55485df11f7770edc6c7d0f87ade5b2e0aa40e7e59Doris Ling    }
56485df11f7770edc6c7d0f87ade5b2e0aa40e7e59Doris Ling
57485df11f7770edc6c7d0f87ade5b2e0aa40e7e59Doris Ling    public static CategoryManager get(Context context, String action) {
5822a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        if (sInstance == null) {
59485df11f7770edc6c7d0f87ade5b2e0aa40e7e59Doris Ling            sInstance = new CategoryManager(context, action);
6022a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        }
6122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        return sInstance;
6222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    }
6322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
64485df11f7770edc6c7d0f87ade5b2e0aa40e7e59Doris Ling    CategoryManager(Context context, String action) {
6522a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        mTileByComponentCache = new ArrayMap<>();
6622a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        mCategoryByKeyMap = new ArrayMap<>();
675adc26695fb4282125d4b6b641e04820a028d87bFan Zhang        mInterestingConfigChanges = new InterestingConfigChanges();
685adc26695fb4282125d4b6b641e04820a028d87bFan Zhang        mInterestingConfigChanges.applyNewConfig(context.getResources());
69485df11f7770edc6c7d0f87ade5b2e0aa40e7e59Doris Ling        mExtraAction = action;
7022a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    }
7122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
72c8a5b790fa13826b21aee97ed5d1960d785333daFan Zhang    public synchronized DashboardCategory getTilesByCategory(Context context, String categoryKey) {
738f06ab0774d44c49fbb5b122b7266192c49271c0roger xue        return getTilesByCategory(context, categoryKey, TileUtils.SETTING_PKG);
748f06ab0774d44c49fbb5b122b7266192c49271c0roger xue    }
758f06ab0774d44c49fbb5b122b7266192c49271c0roger xue
768f06ab0774d44c49fbb5b122b7266192c49271c0roger xue    public synchronized DashboardCategory getTilesByCategory(Context context, String categoryKey,
778f06ab0774d44c49fbb5b122b7266192c49271c0roger xue            String settingPkg) {
788f06ab0774d44c49fbb5b122b7266192c49271c0roger xue        tryInitCategories(context, settingPkg);
7922a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
8045c891b7c5fb6eab719cb9a92c38bbdb25b28ab3Fan Zhang        return mCategoryByKeyMap.get(categoryKey);
8122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    }
8222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
83c8a5b790fa13826b21aee97ed5d1960d785333daFan Zhang    public synchronized List<DashboardCategory> getCategories(Context context) {
848f06ab0774d44c49fbb5b122b7266192c49271c0roger xue        return getCategories(context, TileUtils.SETTING_PKG);
858f06ab0774d44c49fbb5b122b7266192c49271c0roger xue    }
868f06ab0774d44c49fbb5b122b7266192c49271c0roger xue
878f06ab0774d44c49fbb5b122b7266192c49271c0roger xue    public synchronized List<DashboardCategory> getCategories(Context context, String settingPkg) {
888f06ab0774d44c49fbb5b122b7266192c49271c0roger xue        tryInitCategories(context, settingPkg);
8922a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        return mCategories;
9022a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    }
9122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
928f06ab0774d44c49fbb5b122b7266192c49271c0roger xue    public synchronized void reloadAllCategories(Context context, String settingPkg) {
935adc26695fb4282125d4b6b641e04820a028d87bFan Zhang        final boolean forceClearCache = mInterestingConfigChanges.applyNewConfig(
945adc26695fb4282125d4b6b641e04820a028d87bFan Zhang                context.getResources());
95c8a5b790fa13826b21aee97ed5d1960d785333daFan Zhang        mCategories = null;
968f06ab0774d44c49fbb5b122b7266192c49271c0roger xue        tryInitCategories(context, forceClearCache, settingPkg);
9722a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    }
9822a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
99c8a5b790fa13826b21aee97ed5d1960d785333daFan Zhang    public synchronized void updateCategoryFromBlacklist(Set<ComponentName> tileBlacklist) {
10022a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        if (mCategories == null) {
10122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang            Log.w(TAG, "Category is null, skipping blacklist update");
10222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        }
10322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        for (int i = 0; i < mCategories.size(); i++) {
10422a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang            DashboardCategory category = mCategories.get(i);
105b8d2cd41e9472d6f860f35ee9a073b89ba9507f0Doris Ling            for (int j = 0; j < category.getTilesCount(); j++) {
106b8d2cd41e9472d6f860f35ee9a073b89ba9507f0Doris Ling                Tile tile = category.getTile(j);
10722a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang                if (tileBlacklist.contains(tile.intent.getComponent())) {
108b8d2cd41e9472d6f860f35ee9a073b89ba9507f0Doris Ling                    category.removeTile(j--);
10922a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang                }
11022a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang            }
11122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        }
11222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    }
11322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
1148f06ab0774d44c49fbb5b122b7266192c49271c0roger xue    private synchronized void tryInitCategories(Context context, String settingPkg) {
1155adc26695fb4282125d4b6b641e04820a028d87bFan Zhang        // Keep cached tiles by default. The cache is only invalidated when InterestingConfigChange
1165adc26695fb4282125d4b6b641e04820a028d87bFan Zhang        // happens.
1178f06ab0774d44c49fbb5b122b7266192c49271c0roger xue        tryInitCategories(context, false /* forceClearCache */, settingPkg);
1185adc26695fb4282125d4b6b641e04820a028d87bFan Zhang    }
1195adc26695fb4282125d4b6b641e04820a028d87bFan Zhang
1208f06ab0774d44c49fbb5b122b7266192c49271c0roger xue    private synchronized void tryInitCategories(Context context, boolean forceClearCache,
1218f06ab0774d44c49fbb5b122b7266192c49271c0roger xue            String settingPkg) {
12222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        if (mCategories == null) {
1235adc26695fb4282125d4b6b641e04820a028d87bFan Zhang            if (forceClearCache) {
1245adc26695fb4282125d4b6b641e04820a028d87bFan Zhang                mTileByComponentCache.clear();
1255adc26695fb4282125d4b6b641e04820a028d87bFan Zhang            }
12622a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang            mCategoryByKeyMap.clear();
12722a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang            mCategories = TileUtils.getCategories(context, mTileByComponentCache,
1288f06ab0774d44c49fbb5b122b7266192c49271c0roger xue                    false /* categoryDefinedInManifest */, mExtraAction, settingPkg);
12922a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang            for (DashboardCategory category : mCategories) {
13022a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang                mCategoryByKeyMap.put(category.key, category);
13122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang            }
132914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang            backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap);
133ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling            sortCategories(context, mCategoryByKeyMap);
1345fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang            filterDuplicateTiles(mCategoryByKeyMap);
13522a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        }
13622a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    }
13722a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
138914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang    @VisibleForTesting
139914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang    synchronized void backwardCompatCleanupForCategory(
140914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang            Map<Pair<String, String>, Tile> tileByComponentCache,
141914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang            Map<String, DashboardCategory> categoryByKeyMap) {
14231f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang        // A package can use a) CategoryKey, b) old category keys, c) both.
14331f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang        // Check if a package uses old category key only.
14431f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang        // If yes, map them to new category key.
14531f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang
14631f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang        // Build a package name -> tile map first.
14731f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang        final Map<String, List<Tile>> packageToTileMap = new HashMap<>();
148914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang        for (Entry<Pair<String, String>, Tile> tileEntry : tileByComponentCache.entrySet()) {
14931f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            final String packageName = tileEntry.getKey().first;
15031f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            List<Tile> tiles = packageToTileMap.get(packageName);
15131f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            if (tiles == null) {
15231f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                tiles = new ArrayList<>();
15331f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                packageToTileMap.put(packageName, tiles);
15431f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            }
15531f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            tiles.add(tileEntry.getValue());
15631f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang        }
15731f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang
15831f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang        for (Entry<String, List<Tile>> entry : packageToTileMap.entrySet()) {
15931f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            final List<Tile> tiles = entry.getValue();
16031f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            // Loop map, find if all tiles from same package uses old key only.
16131f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            boolean useNewKey = false;
16231f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            boolean useOldKey = false;
16331f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            for (Tile tile : tiles) {
16431f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                if (CategoryKey.KEY_COMPAT_MAP.containsKey(tile.category)) {
16531f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                    useOldKey = true;
16631f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                } else {
16731f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                    useNewKey = true;
16831f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                    break;
16931f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                }
17031f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            }
17131f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            // Uses only old key, map them to new keys one by one.
17231f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            if (useOldKey && !useNewKey) {
17331f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                for (Tile tile : tiles) {
17431f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                    final String newCategoryKey = CategoryKey.KEY_COMPAT_MAP.get(tile.category);
17531f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                    tile.category = newCategoryKey;
17631f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                    // move tile to new category.
177914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang                    DashboardCategory newCategory = categoryByKeyMap.get(newCategoryKey);
178914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang                    if (newCategory == null) {
179914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang                        newCategory = new DashboardCategory();
180914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang                        categoryByKeyMap.put(newCategoryKey, newCategory);
181914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang                    }
182b8d2cd41e9472d6f860f35ee9a073b89ba9507f0Doris Ling                    newCategory.addTile(tile);
18331f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                }
18431f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            }
18531f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang        }
18631f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang    }
187fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang
188fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang    /**
189ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling     * Sort the tiles injected from all apps such that if they have the same priority value,
190ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling     * they wil lbe sorted by package name.
191fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang     * <p/>
192ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling     * A list of tiles are considered sorted when their priority value decreases in a linear
193fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang     * scan.
194fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang     */
195fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang    @VisibleForTesting
196ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling    synchronized void sortCategories(Context context,
197fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang            Map<String, DashboardCategory> categoryByKeyMap) {
198fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang        for (Entry<String, DashboardCategory> categoryEntry : categoryByKeyMap.entrySet()) {
199b8d2cd41e9472d6f860f35ee9a073b89ba9507f0Doris Ling            categoryEntry.getValue().sortTiles(context.getPackageName());
200fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang        }
201fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang    }
202fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang
203fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang    /**
2045fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang     * Filter out duplicate tiles from category. Duplicate tiles are the ones pointing to the
2055fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang     * same intent.
2065fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang     */
2075fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang    @VisibleForTesting
2085fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang    synchronized void filterDuplicateTiles(Map<String, DashboardCategory> categoryByKeyMap) {
2095fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang        for (Entry<String, DashboardCategory> categoryEntry : categoryByKeyMap.entrySet()) {
2105fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang            final DashboardCategory category = categoryEntry.getValue();
211b8d2cd41e9472d6f860f35ee9a073b89ba9507f0Doris Ling            final int count = category.getTilesCount();
2125fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang            final Set<ComponentName> components = new ArraySet<>();
2135fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang            for (int i = count - 1; i >= 0; i--) {
214b8d2cd41e9472d6f860f35ee9a073b89ba9507f0Doris Ling                final Tile tile = category.getTile(i);
2155fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang                if (tile.intent == null) {
2165fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang                    continue;
2175fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang                }
2185fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang                final ComponentName tileComponent = tile.intent.getComponent();
2195fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang                if (components.contains(tileComponent)) {
220b8d2cd41e9472d6f860f35ee9a073b89ba9507f0Doris Ling                    category.removeTile(i);
2215fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang                } else {
2225fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang                    components.add(tileComponent);
2235fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang                }
2245fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang            }
2255fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang        }
2265fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang    }
2275fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang
2285fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang    /**
229ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling     * Sort priority value for tiles within a single {@code DashboardCategory}.
230fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang     *
231ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling     * @see #sortCategories(Context, Map)
232fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang     */
233ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling    private synchronized void sortCategoriesForExternalTiles(Context context,
234fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang            DashboardCategory dashboardCategory) {
235b8d2cd41e9472d6f860f35ee9a073b89ba9507f0Doris Ling        dashboardCategory.sortTiles(context.getPackageName());
236fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang
237fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang    }
23822a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang}
239