CategoryManager.java revision 31f4c5444490cd7db7c9089e9ca3e8a2904c6d5b
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;
2022a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangimport android.util.ArrayMap;
2122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangimport android.util.Log;
2222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangimport android.util.Pair;
2322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
245adc26695fb4282125d4b6b641e04820a028d87bFan Zhangimport com.android.settingslib.applications.InterestingConfigChanges;
255adc26695fb4282125d4b6b641e04820a028d87bFan Zhang
2631f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhangimport java.util.ArrayList;
2731f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhangimport java.util.HashMap;
2822a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangimport java.util.List;
2922a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangimport java.util.Map;
3031f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhangimport java.util.Map.Entry;
3122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangimport java.util.Set;
3222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
3322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhangpublic class CategoryManager {
3422a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
3522a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    private static final String TAG = "CategoryManager";
3622a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
3722a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    private static CategoryManager sInstance;
385adc26695fb4282125d4b6b641e04820a028d87bFan Zhang    private final InterestingConfigChanges mInterestingConfigChanges;
3922a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
4022a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    // Tile cache (key: <packageName, activityName>, value: tile)
4122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    private final Map<Pair<String, String>, Tile> mTileByComponentCache;
4222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
4322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    // Tile cache (key: category key, value: category)
4422a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    private final Map<String, DashboardCategory> mCategoryByKeyMap;
4522a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
4622a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    private List<DashboardCategory> mCategories;
4722a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
485adc26695fb4282125d4b6b641e04820a028d87bFan Zhang    public static CategoryManager get(Context context) {
4922a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        if (sInstance == null) {
505adc26695fb4282125d4b6b641e04820a028d87bFan Zhang            sInstance = new CategoryManager(context);
5122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        }
5222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        return sInstance;
5322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    }
5422a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
555adc26695fb4282125d4b6b641e04820a028d87bFan Zhang    CategoryManager(Context context) {
5622a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        mTileByComponentCache = new ArrayMap<>();
5722a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        mCategoryByKeyMap = new ArrayMap<>();
585adc26695fb4282125d4b6b641e04820a028d87bFan Zhang        mInterestingConfigChanges = new InterestingConfigChanges();
595adc26695fb4282125d4b6b641e04820a028d87bFan Zhang        mInterestingConfigChanges.applyNewConfig(context.getResources());
6022a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    }
6122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
62c8a5b790fa13826b21aee97ed5d1960d785333daFan Zhang    public synchronized DashboardCategory getTilesByCategory(Context context, String categoryKey) {
6322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        tryInitCategories(context);
6422a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
6545c891b7c5fb6eab719cb9a92c38bbdb25b28ab3Fan Zhang        return mCategoryByKeyMap.get(categoryKey);
6622a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    }
6722a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
68c8a5b790fa13826b21aee97ed5d1960d785333daFan Zhang    public synchronized List<DashboardCategory> getCategories(Context context) {
6922a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        tryInitCategories(context);
7022a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        return mCategories;
7122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    }
7222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
73c8a5b790fa13826b21aee97ed5d1960d785333daFan Zhang    public synchronized void reloadAllCategories(Context context) {
745adc26695fb4282125d4b6b641e04820a028d87bFan Zhang        final boolean forceClearCache = mInterestingConfigChanges.applyNewConfig(
755adc26695fb4282125d4b6b641e04820a028d87bFan Zhang                context.getResources());
76c8a5b790fa13826b21aee97ed5d1960d785333daFan Zhang        mCategories = null;
775adc26695fb4282125d4b6b641e04820a028d87bFan Zhang        tryInitCategories(context, forceClearCache);
7822a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    }
7922a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
80c8a5b790fa13826b21aee97ed5d1960d785333daFan Zhang    public synchronized void updateCategoryFromBlacklist(Set<ComponentName> tileBlacklist) {
8122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        if (mCategories == null) {
8222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang            Log.w(TAG, "Category is null, skipping blacklist update");
8322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        }
8422a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        for (int i = 0; i < mCategories.size(); i++) {
8522a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang            DashboardCategory category = mCategories.get(i);
8622a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang            for (int j = 0; j < category.tiles.size(); j++) {
8722a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang                Tile tile = category.tiles.get(j);
8822a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang                if (tileBlacklist.contains(tile.intent.getComponent())) {
8922a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang                    category.tiles.remove(j--);
9022a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang                }
9122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang            }
9222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        }
9322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    }
9422a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
95c8a5b790fa13826b21aee97ed5d1960d785333daFan Zhang    private synchronized void tryInitCategories(Context context) {
965adc26695fb4282125d4b6b641e04820a028d87bFan Zhang        // Keep cached tiles by default. The cache is only invalidated when InterestingConfigChange
975adc26695fb4282125d4b6b641e04820a028d87bFan Zhang        // happens.
985adc26695fb4282125d4b6b641e04820a028d87bFan Zhang        tryInitCategories(context, false /* forceClearCache */);
995adc26695fb4282125d4b6b641e04820a028d87bFan Zhang    }
1005adc26695fb4282125d4b6b641e04820a028d87bFan Zhang
1015adc26695fb4282125d4b6b641e04820a028d87bFan Zhang    private synchronized void tryInitCategories(Context context, boolean forceClearCache) {
10222a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        if (mCategories == null) {
1035adc26695fb4282125d4b6b641e04820a028d87bFan Zhang            if (forceClearCache) {
1045adc26695fb4282125d4b6b641e04820a028d87bFan Zhang                mTileByComponentCache.clear();
1055adc26695fb4282125d4b6b641e04820a028d87bFan Zhang            }
10622a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang            mCategoryByKeyMap.clear();
10722a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang            mCategories = TileUtils.getCategories(context, mTileByComponentCache,
10822a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang                    false /* categoryDefinedInManifest */);
10922a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang            for (DashboardCategory category : mCategories) {
11022a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang                mCategoryByKeyMap.put(category.key, category);
11122a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang            }
11231f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            backwardCompatCleanupForCategory();
11322a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang        }
11422a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang    }
11522a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang
11631f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang    private synchronized void backwardCompatCleanupForCategory() {
11731f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang        // A package can use a) CategoryKey, b) old category keys, c) both.
11831f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang        // Check if a package uses old category key only.
11931f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang        // If yes, map them to new category key.
12031f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang
12131f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang        // Build a package name -> tile map first.
12231f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang        final Map<String, List<Tile>> packageToTileMap = new HashMap<>();
12331f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang        for (Entry<Pair<String, String>, Tile> tileEntry : mTileByComponentCache.entrySet()) {
12431f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            final String packageName = tileEntry.getKey().first;
12531f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            List<Tile> tiles = packageToTileMap.get(packageName);
12631f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            if (tiles == null) {
12731f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                tiles = new ArrayList<>();
12831f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                packageToTileMap.put(packageName, tiles);
12931f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            }
13031f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            tiles.add(tileEntry.getValue());
13131f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang        }
13231f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang
13331f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang        for (Entry<String, List<Tile>> entry : packageToTileMap.entrySet()) {
13431f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            final List<Tile> tiles = entry.getValue();
13531f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            // Loop map, find if all tiles from same package uses old key only.
13631f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            boolean useNewKey = false;
13731f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            boolean useOldKey = false;
13831f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            for (Tile tile : tiles) {
13931f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                if (CategoryKey.KEY_COMPAT_MAP.containsKey(tile.category)) {
14031f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                    useOldKey = true;
14131f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                } else {
14231f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                    useNewKey = true;
14331f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                    break;
14431f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                }
14531f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            }
14631f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            // Uses only old key, map them to new keys one by one.
14731f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            if (useOldKey && !useNewKey) {
14831f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                for (Tile tile : tiles) {
14931f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                    final String newCategoryKey = CategoryKey.KEY_COMPAT_MAP.get(tile.category);
15031f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                    tile.category = newCategoryKey;
15131f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                    // move tile to new category.
15231f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                    final DashboardCategory newCategory = mCategoryByKeyMap.get(newCategoryKey);
15331f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                    newCategory.tiles.add(tile);
15431f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang                }
15531f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang            }
15631f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang        }
15731f4c5444490cd7db7c9089e9ca3e8a2904c6d5bFan Zhang    }
15822a56d775d047a1926f2a6d9c855c802d561d487Fan Zhang}
159