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; 21fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhangimport android.text.TextUtils; 2222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangimport android.util.ArrayMap; 235fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhangimport android.util.ArraySet; 2422a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangimport android.util.Log; 2522a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangimport android.util.Pair; 2622a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang 275adc26695fb4282125d4b6b641e04820a028d87bFan Zhangimport com.android.settingslib.applications.InterestingConfigChanges; 285adc26695fb4282125d4b6b641e04820a028d87bFan Zhang 2931f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhangimport java.util.ArrayList; 30fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhangimport java.util.Collections; 3131f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhangimport java.util.HashMap; 3222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangimport java.util.List; 3322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangimport java.util.Map; 3431f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhangimport java.util.Map.Entry; 3522a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangimport java.util.Set; 3622a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang 37fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhangimport static java.lang.String.CASE_INSENSITIVE_ORDER; 38fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang 3922a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangpublic class CategoryManager { 4022a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang 4122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang private static final String TAG = "CategoryManager"; 4222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang 4322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang private static CategoryManager sInstance; 445adc26695fb4282125d4b6b641e04820a028d87bFan Zhang private final InterestingConfigChanges mInterestingConfigChanges; 4522a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang 4622a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang // Tile cache (key: <packageName, activityName>, value: tile) 4722a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang private final Map<Pair<String, String>, Tile> mTileByComponentCache; 4822a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang 4922a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang // Tile cache (key: category key, value: category) 5022a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang private final Map<String, DashboardCategory> mCategoryByKeyMap; 5122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang 5222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang private List<DashboardCategory> mCategories; 53485df11f7770edc6c7d0f87ade5b2e0aa40e7e59Doris Ling private String mExtraAction; 5422a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang 555adc26695fb4282125d4b6b641e04820a028d87bFan Zhang public static CategoryManager get(Context context) { 56485df11f7770edc6c7d0f87ade5b2e0aa40e7e59Doris Ling return get(context, null); 57485df11f7770edc6c7d0f87ade5b2e0aa40e7e59Doris Ling } 58485df11f7770edc6c7d0f87ade5b2e0aa40e7e59Doris Ling 59485df11f7770edc6c7d0f87ade5b2e0aa40e7e59Doris Ling public static CategoryManager get(Context context, String action) { 6022a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang if (sInstance == null) { 61485df11f7770edc6c7d0f87ade5b2e0aa40e7e59Doris Ling sInstance = new CategoryManager(context, action); 6222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang } 6322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang return sInstance; 6422a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang } 6522a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang 66485df11f7770edc6c7d0f87ade5b2e0aa40e7e59Doris Ling CategoryManager(Context context, String action) { 6722a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang mTileByComponentCache = new ArrayMap<>(); 6822a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang mCategoryByKeyMap = new ArrayMap<>(); 695adc26695fb4282125d4b6b641e04820a028d87bFan Zhang mInterestingConfigChanges = new InterestingConfigChanges(); 705adc26695fb4282125d4b6b641e04820a028d87bFan Zhang mInterestingConfigChanges.applyNewConfig(context.getResources()); 71485df11f7770edc6c7d0f87ade5b2e0aa40e7e59Doris Ling mExtraAction = action; 7222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang } 7322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang 74c8a5b790fa13826b21aee97ed5d1960d785333daFan Zhang public synchronized DashboardCategory getTilesByCategory(Context context, String categoryKey) { 758f06ab0774d44c49fbb5b122b7266192c49271c0roger xue return getTilesByCategory(context, categoryKey, TileUtils.SETTING_PKG); 768f06ab0774d44c49fbb5b122b7266192c49271c0roger xue } 778f06ab0774d44c49fbb5b122b7266192c49271c0roger xue 788f06ab0774d44c49fbb5b122b7266192c49271c0roger xue public synchronized DashboardCategory getTilesByCategory(Context context, String categoryKey, 798f06ab0774d44c49fbb5b122b7266192c49271c0roger xue String settingPkg) { 808f06ab0774d44c49fbb5b122b7266192c49271c0roger xue tryInitCategories(context, settingPkg); 8122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang 8245c891b7c5fb6eab719cb9a92c38bbdb25b28ab3Fan Zhang return mCategoryByKeyMap.get(categoryKey); 8322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang } 8422a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang 85c8a5b790fa13826b21aee97ed5d1960d785333daFan Zhang public synchronized List<DashboardCategory> getCategories(Context context) { 868f06ab0774d44c49fbb5b122b7266192c49271c0roger xue return getCategories(context, TileUtils.SETTING_PKG); 878f06ab0774d44c49fbb5b122b7266192c49271c0roger xue } 888f06ab0774d44c49fbb5b122b7266192c49271c0roger xue 898f06ab0774d44c49fbb5b122b7266192c49271c0roger xue public synchronized List<DashboardCategory> getCategories(Context context, String settingPkg) { 908f06ab0774d44c49fbb5b122b7266192c49271c0roger xue tryInitCategories(context, settingPkg); 9122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang return mCategories; 9222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang } 9322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang 948f06ab0774d44c49fbb5b122b7266192c49271c0roger xue public synchronized void reloadAllCategories(Context context, String settingPkg) { 955adc26695fb4282125d4b6b641e04820a028d87bFan Zhang final boolean forceClearCache = mInterestingConfigChanges.applyNewConfig( 965adc26695fb4282125d4b6b641e04820a028d87bFan Zhang context.getResources()); 97c8a5b790fa13826b21aee97ed5d1960d785333daFan Zhang mCategories = null; 988f06ab0774d44c49fbb5b122b7266192c49271c0roger xue tryInitCategories(context, forceClearCache, settingPkg); 9922a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang } 10022a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang 101c8a5b790fa13826b21aee97ed5d1960d785333daFan Zhang public synchronized void updateCategoryFromBlacklist(Set<ComponentName> tileBlacklist) { 10222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang if (mCategories == null) { 10322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang Log.w(TAG, "Category is null, skipping blacklist update"); 10422a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang } 10522a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang for (int i = 0; i < mCategories.size(); i++) { 10622a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang DashboardCategory category = mCategories.get(i); 10722a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang for (int j = 0; j < category.tiles.size(); j++) { 10822a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang Tile tile = category.tiles.get(j); 10922a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang if (tileBlacklist.contains(tile.intent.getComponent())) { 11022a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang category.tiles.remove(j--); 11122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang } 11222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang } 11322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang } 11422a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang } 11522a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang 1168f06ab0774d44c49fbb5b122b7266192c49271c0roger xue private synchronized void tryInitCategories(Context context, String settingPkg) { 1175adc26695fb4282125d4b6b641e04820a028d87bFan Zhang // Keep cached tiles by default. The cache is only invalidated when InterestingConfigChange 1185adc26695fb4282125d4b6b641e04820a028d87bFan Zhang // happens. 1198f06ab0774d44c49fbb5b122b7266192c49271c0roger xue tryInitCategories(context, false /* forceClearCache */, settingPkg); 1205adc26695fb4282125d4b6b641e04820a028d87bFan Zhang } 1215adc26695fb4282125d4b6b641e04820a028d87bFan Zhang 1228f06ab0774d44c49fbb5b122b7266192c49271c0roger xue private synchronized void tryInitCategories(Context context, boolean forceClearCache, 1238f06ab0774d44c49fbb5b122b7266192c49271c0roger xue String settingPkg) { 12422a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang if (mCategories == null) { 1255adc26695fb4282125d4b6b641e04820a028d87bFan Zhang if (forceClearCache) { 1265adc26695fb4282125d4b6b641e04820a028d87bFan Zhang mTileByComponentCache.clear(); 1275adc26695fb4282125d4b6b641e04820a028d87bFan Zhang } 12822a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang mCategoryByKeyMap.clear(); 12922a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang mCategories = TileUtils.getCategories(context, mTileByComponentCache, 1308f06ab0774d44c49fbb5b122b7266192c49271c0roger xue false /* categoryDefinedInManifest */, mExtraAction, settingPkg); 13122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang for (DashboardCategory category : mCategories) { 13222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang mCategoryByKeyMap.put(category.key, category); 13322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang } 134914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap); 135ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling sortCategories(context, mCategoryByKeyMap); 1365fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang filterDuplicateTiles(mCategoryByKeyMap); 13722a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang } 13822a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang } 13922a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang 140914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang @VisibleForTesting 141914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang synchronized void backwardCompatCleanupForCategory( 142914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang Map<Pair<String, String>, Tile> tileByComponentCache, 143914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang Map<String, DashboardCategory> categoryByKeyMap) { 14431f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang // A package can use a) CategoryKey, b) old category keys, c) both. 14531f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang // Check if a package uses old category key only. 14631f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang // If yes, map them to new category key. 14731f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang 14831f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang // Build a package name -> tile map first. 14931f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang final Map<String, List<Tile>> packageToTileMap = new HashMap<>(); 150914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang for (Entry<Pair<String, String>, Tile> tileEntry : tileByComponentCache.entrySet()) { 15131f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang final String packageName = tileEntry.getKey().first; 15231f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang List<Tile> tiles = packageToTileMap.get(packageName); 15331f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang if (tiles == null) { 15431f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang tiles = new ArrayList<>(); 15531f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang packageToTileMap.put(packageName, tiles); 15631f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang } 15731f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang tiles.add(tileEntry.getValue()); 15831f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang } 15931f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang 16031f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang for (Entry<String, List<Tile>> entry : packageToTileMap.entrySet()) { 16131f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang final List<Tile> tiles = entry.getValue(); 16231f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang // Loop map, find if all tiles from same package uses old key only. 16331f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang boolean useNewKey = false; 16431f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang boolean useOldKey = false; 16531f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang for (Tile tile : tiles) { 16631f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang if (CategoryKey.KEY_COMPAT_MAP.containsKey(tile.category)) { 16731f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang useOldKey = true; 16831f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang } else { 16931f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang useNewKey = true; 17031f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang break; 17131f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang } 17231f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang } 17331f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang // Uses only old key, map them to new keys one by one. 17431f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang if (useOldKey && !useNewKey) { 17531f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang for (Tile tile : tiles) { 17631f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang final String newCategoryKey = CategoryKey.KEY_COMPAT_MAP.get(tile.category); 17731f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang tile.category = newCategoryKey; 17831f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang // move tile to new category. 179914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang DashboardCategory newCategory = categoryByKeyMap.get(newCategoryKey); 180914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang if (newCategory == null) { 181914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang newCategory = new DashboardCategory(); 182914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang categoryByKeyMap.put(newCategoryKey, newCategory); 183914afbfbd048721fb9ece683b9e881b79a01e34eFan Zhang } 18431f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang newCategory.tiles.add(tile); 18531f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang } 18631f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang } 18731f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang } 18831f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang } 189fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang 190fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang /** 191ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling * Sort the tiles injected from all apps such that if they have the same priority value, 192ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling * they wil lbe sorted by package name. 193fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang * <p/> 194ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling * A list of tiles are considered sorted when their priority value decreases in a linear 195fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang * scan. 196fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang */ 197fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang @VisibleForTesting 198ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling synchronized void sortCategories(Context context, 199fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang Map<String, DashboardCategory> categoryByKeyMap) { 200fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang for (Entry<String, DashboardCategory> categoryEntry : categoryByKeyMap.entrySet()) { 201ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling sortCategoriesForExternalTiles(context, categoryEntry.getValue()); 202fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang } 203fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang } 204fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang 205fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang /** 2065fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang * Filter out duplicate tiles from category. Duplicate tiles are the ones pointing to the 2075fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang * same intent. 2085fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang */ 2095fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang @VisibleForTesting 2105fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang synchronized void filterDuplicateTiles(Map<String, DashboardCategory> categoryByKeyMap) { 2115fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang for (Entry<String, DashboardCategory> categoryEntry : categoryByKeyMap.entrySet()) { 2125fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang final DashboardCategory category = categoryEntry.getValue(); 2135fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang final int count = category.tiles.size(); 2145fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang final Set<ComponentName> components = new ArraySet<>(); 2155fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang for (int i = count - 1; i >= 0; i--) { 2165fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang final Tile tile = category.tiles.get(i); 2175fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang if (tile.intent == null) { 2185fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang continue; 2195fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang } 2205fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang final ComponentName tileComponent = tile.intent.getComponent(); 2215fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang if (components.contains(tileComponent)) { 2225fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang category.tiles.remove(i); 2235fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang } else { 2245fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang components.add(tileComponent); 2255fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang } 2265fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang } 2275fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang } 2285fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang } 2295fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang 2305fa4af08c603607d7df7470dc10d3af2d2f04137Fan Zhang /** 231ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling * Sort priority value for tiles within a single {@code DashboardCategory}. 232fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang * 233ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling * @see #sortCategories(Context, Map) 234fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang */ 235ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling private synchronized void sortCategoriesForExternalTiles(Context context, 236fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang DashboardCategory dashboardCategory) { 237fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang final String skipPackageName = context.getPackageName(); 238fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang 239ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling // Sort tiles based on [priority, package within priority] 240fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang Collections.sort(dashboardCategory.tiles, (tile1, tile2) -> { 241fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang final String package1 = tile1.intent.getComponent().getPackageName(); 242fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang final String package2 = tile2.intent.getComponent().getPackageName(); 243fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang final int packageCompare = CASE_INSENSITIVE_ORDER.compare(package1, package2); 244ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling // First sort by priority 245ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling final int priorityCompare = tile2.priority - tile1.priority; 246ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling if (priorityCompare != 0) { 247ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling return priorityCompare; 248ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling } 249ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling // Then sort by package name, skip package take precedence 250fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang if (packageCompare != 0) { 251ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling if (TextUtils.equals(package1, skipPackageName)) { 252ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling return -1; 253ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling } 254ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling if (TextUtils.equals(package2, skipPackageName)) { 255ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling return 1; 256ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling } 257fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang } 258ce31159be781f5b94ed24013fcf1db7b9aa0cf4aDoris Ling return packageCompare; 259fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang }); 260fc76ab3cbf1794d2d72a92c87afc1cf9f62cc03aFan Zhang } 26122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang} 262