Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 77983718 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Remove CategoryManager from SettingsLib."

parents eea8075d 0d7b6cf4
Loading
Loading
Loading
Loading
+0 −230
Original line number Diff line number Diff line
/**
 * 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.drawer;

import android.content.ComponentName;
import android.content.Context;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;

import androidx.annotation.VisibleForTesting;

import com.android.settingslib.applications.InterestingConfigChanges;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class CategoryManager {

    public static final String SETTING_PKG = "com.android.settings";

    private static final String TAG = "CategoryManager";

    private static CategoryManager sInstance;
    private final InterestingConfigChanges mInterestingConfigChanges;

    // Tile cache (key: <packageName, activityName>, value: tile)
    private final Map<Pair<String, String>, Tile> mTileByComponentCache;

    // Tile cache (key: category key, value: category)
    private final Map<String, DashboardCategory> mCategoryByKeyMap;

    private List<DashboardCategory> mCategories;
    private String mExtraAction;

    public static CategoryManager get(Context context) {
        return get(context, null);
    }

    public static CategoryManager get(Context context, String action) {
        if (sInstance == null) {
            sInstance = new CategoryManager(context, action);
        }
        return sInstance;
    }

    CategoryManager(Context context, String action) {
        mTileByComponentCache = new ArrayMap<>();
        mCategoryByKeyMap = new ArrayMap<>();
        mInterestingConfigChanges = new InterestingConfigChanges();
        mInterestingConfigChanges.applyNewConfig(context.getResources());
        mExtraAction = action;
    }

    public synchronized DashboardCategory getTilesByCategory(Context context, String categoryKey) {
        tryInitCategories(context, SETTING_PKG);

        return mCategoryByKeyMap.get(categoryKey);
    }

    public synchronized List<DashboardCategory> getCategories(Context context) {
        tryInitCategories(context, SETTING_PKG);
        return mCategories;
    }

    public synchronized void reloadAllCategories(Context context, String settingPkg) {
        final boolean forceClearCache = mInterestingConfigChanges.applyNewConfig(
                context.getResources());
        mCategories = null;
        tryInitCategories(context, forceClearCache, settingPkg);
    }

    public synchronized void updateCategoryFromBlacklist(Set<ComponentName> tileBlacklist) {
        if (mCategories == null) {
            Log.w(TAG, "Category is null, skipping blacklist update");
        }
        for (int i = 0; i < mCategories.size(); i++) {
            DashboardCategory category = mCategories.get(i);
            for (int j = 0; j < category.getTilesCount(); j++) {
                Tile tile = category.getTile(j);
                if (tileBlacklist.contains(tile.intent.getComponent())) {
                    category.removeTile(j--);
                }
            }
        }
    }

    private synchronized void tryInitCategories(Context context, String settingPkg) {
        // Keep cached tiles by default. The cache is only invalidated when InterestingConfigChange
        // happens.
        tryInitCategories(context, false /* forceClearCache */, settingPkg);
    }

    private synchronized void tryInitCategories(Context context, boolean forceClearCache,
            String settingPkg) {
        if (mCategories == null) {
            if (forceClearCache) {
                mTileByComponentCache.clear();
            }
            mCategoryByKeyMap.clear();
            mCategories = TileUtils.getCategories(context, mTileByComponentCache,
                    mExtraAction, settingPkg);
            for (DashboardCategory category : mCategories) {
                mCategoryByKeyMap.put(category.key, category);
            }
            backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap);
            sortCategories(context, mCategoryByKeyMap);
            filterDuplicateTiles(mCategoryByKeyMap);
        }
    }

    @VisibleForTesting
    synchronized void backwardCompatCleanupForCategory(
            Map<Pair<String, String>, Tile> tileByComponentCache,
            Map<String, DashboardCategory> categoryByKeyMap) {
        // A package can use a) CategoryKey, b) old category keys, c) both.
        // Check if a package uses old category key only.
        // If yes, map them to new category key.

        // Build a package name -> tile map first.
        final Map<String, List<Tile>> packageToTileMap = new HashMap<>();
        for (Entry<Pair<String, String>, Tile> tileEntry : tileByComponentCache.entrySet()) {
            final String packageName = tileEntry.getKey().first;
            List<Tile> tiles = packageToTileMap.get(packageName);
            if (tiles == null) {
                tiles = new ArrayList<>();
                packageToTileMap.put(packageName, tiles);
            }
            tiles.add(tileEntry.getValue());
        }

        for (Entry<String, List<Tile>> entry : packageToTileMap.entrySet()) {
            final List<Tile> tiles = entry.getValue();
            // Loop map, find if all tiles from same package uses old key only.
            boolean useNewKey = false;
            boolean useOldKey = false;
            for (Tile tile : tiles) {
                if (CategoryKey.KEY_COMPAT_MAP.containsKey(tile.category)) {
                    useOldKey = true;
                } else {
                    useNewKey = true;
                    break;
                }
            }
            // Uses only old key, map them to new keys one by one.
            if (useOldKey && !useNewKey) {
                for (Tile tile : tiles) {
                    final String newCategoryKey = CategoryKey.KEY_COMPAT_MAP.get(tile.category);
                    tile.category = newCategoryKey;
                    // move tile to new category.
                    DashboardCategory newCategory = categoryByKeyMap.get(newCategoryKey);
                    if (newCategory == null) {
                        newCategory = new DashboardCategory();
                        categoryByKeyMap.put(newCategoryKey, newCategory);
                    }
                    newCategory.addTile(tile);
                }
            }
        }
    }

    /**
     * Sort the tiles injected from all apps such that if they have the same priority value,
     * they wil lbe sorted by package name.
     * <p/>
     * A list of tiles are considered sorted when their priority value decreases in a linear
     * scan.
     */
    @VisibleForTesting
    synchronized void sortCategories(Context context,
            Map<String, DashboardCategory> categoryByKeyMap) {
        for (Entry<String, DashboardCategory> categoryEntry : categoryByKeyMap.entrySet()) {
            categoryEntry.getValue().sortTiles(context.getPackageName());
        }
    }

    /**
     * Filter out duplicate tiles from category. Duplicate tiles are the ones pointing to the
     * same intent.
     */
    @VisibleForTesting
    synchronized void filterDuplicateTiles(Map<String, DashboardCategory> categoryByKeyMap) {
        for (Entry<String, DashboardCategory> categoryEntry : categoryByKeyMap.entrySet()) {
            final DashboardCategory category = categoryEntry.getValue();
            final int count = category.getTilesCount();
            final Set<ComponentName> components = new ArraySet<>();
            for (int i = count - 1; i >= 0; i--) {
                final Tile tile = category.getTile(i);
                if (tile.intent == null) {
                    continue;
                }
                final ComponentName tileComponent = tile.intent.getComponent();
                if (components.contains(tileComponent)) {
                    category.removeTile(i);
                } else {
                    components.add(tileComponent);
                }
            }
        }
    }

    /**
     * Sort priority value for tiles within a single {@code DashboardCategory}.
     *
     * @see #sortCategories(Context, Map)
     */
    private synchronized void sortCategoriesForExternalTiles(Context context,
            DashboardCategory dashboardCategory) {
        dashboardCategory.sortTiles(context.getPackageName());

    }
}
+19 −22
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;

import androidx.annotation.VisibleForTesting;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -48,6 +50,8 @@ public class TileUtils {
    private static final boolean DEBUG_TIMING = false;

    private static final String LOG_TAG = "TileUtils";
    @VisibleForTesting
    static final String SETTING_PKG = "com.android.settings";

    /**
     * Settings will search for system activities of this action and add them as a top level
@@ -200,7 +204,7 @@ public class TileUtils {
     * categories
     */
    public static List<DashboardCategory> getCategories(Context context,
            Map<Pair<String, String>, Tile> cache, String extraAction, String settingPkg) {
            Map<Pair<String, String>, Tile> cache, String extraAction) {
        final long startTime = System.currentTimeMillis();
        boolean setup = Global.getInt(context.getContentResolver(), Global.DEVICE_PROVISIONED, 0)
                != 0;
@@ -210,21 +214,17 @@ public class TileUtils {
            // TODO: Needs much optimization, too many PM queries going on here.
            if (user.getIdentifier() == ActivityManager.getCurrentUser()) {
                // Only add Settings for this user.
                getTilesForAction(context, user, SETTINGS_ACTION, cache, null, tiles, true,
                        settingPkg);
                getTilesForAction(context, user, SETTINGS_ACTION, cache, null, tiles, true);
                getTilesForAction(context, user, OPERATOR_SETTINGS, cache,
                        OPERATOR_DEFAULT_CATEGORY, tiles, false, true, settingPkg);
                        OPERATOR_DEFAULT_CATEGORY, tiles, false, true);
                getTilesForAction(context, user, MANUFACTURER_SETTINGS, cache,
                        MANUFACTURER_DEFAULT_CATEGORY, tiles, false, true, settingPkg);
                        MANUFACTURER_DEFAULT_CATEGORY, tiles, false, true);
            }
            if (setup) {
                getTilesForAction(context, user, EXTRA_SETTINGS_ACTION, cache, null, tiles, false,
                        settingPkg);
                    getTilesForAction(context, user, IA_SETTINGS_ACTION, cache, null, tiles, false,
                            settingPkg);
                getTilesForAction(context, user, EXTRA_SETTINGS_ACTION, cache, null, tiles, false);
                getTilesForAction(context, user, IA_SETTINGS_ACTION, cache, null, tiles, false);
                if (extraAction != null) {
                        getTilesForAction(context, user, extraAction, cache, null, tiles, false,
                                settingPkg);
                    getTilesForAction(context, user, extraAction, cache, null, tiles, false);
                }
            }
        }
@@ -256,19 +256,18 @@ public class TileUtils {

    private static void getTilesForAction(Context context,
            UserHandle user, String action, Map<Pair<String, String>, Tile> addedCache,
            String defaultCategory, ArrayList<Tile> outTiles, boolean requireSettings,
            String settingPkg) {
            String defaultCategory, ArrayList<Tile> outTiles, boolean requireSettings) {
        getTilesForAction(context, user, action, addedCache, defaultCategory, outTiles,
                requireSettings, requireSettings, settingPkg);
                requireSettings, requireSettings);
    }

    private static void getTilesForAction(Context context,
            UserHandle user, String action, Map<Pair<String, String>, Tile> addedCache,
            String defaultCategory, ArrayList<Tile> outTiles, boolean requireSettings,
            boolean usePriority, String settingPkg) {
            boolean usePriority) {
        Intent intent = new Intent(action);
        if (requireSettings) {
            intent.setPackage(settingPkg);
            intent.setPackage(SETTING_PKG);
        }
        getTilesForIntent(context, user, intent, addedCache, defaultCategory, outTiles,
                usePriority, true, true);
@@ -281,7 +280,6 @@ public class TileUtils {
        PackageManager pm = context.getPackageManager();
        List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(intent,
                PackageManager.GET_META_DATA, user.getIdentifier());
        Map<String, IContentProvider> providerMap = new HashMap<>();
        for (ResolveInfo resolved : results) {
            if (!resolved.system) {
                // Do not allow any app to add to settings, only system ones.
@@ -312,7 +310,7 @@ public class TileUtils {
                tile.priority = usePriority ? resolved.priority : 0;
                tile.metaData = activityInfo.metaData;
                updateTileData(context, tile, activityInfo, activityInfo.applicationInfo,
                        pm, providerMap, forceTintExternalIcon);
                        pm, forceTintExternalIcon);
                if (DEBUG) Log.d(LOG_TAG, "Adding tile " + tile.title);
                addedCache.put(key, tile);
            }
@@ -328,11 +326,10 @@ public class TileUtils {

    private static boolean updateTileData(Context context, Tile tile,
            ActivityInfo activityInfo, ApplicationInfo applicationInfo, PackageManager pm,
            Map<String, IContentProvider> providerMap, boolean forceTintExternalIcon) {
            boolean forceTintExternalIcon) {
        if (applicationInfo.isSystemApp()) {
            boolean forceTintIcon = false;
            int icon = 0;
            Pair<String, Integer> iconFromUri = null;
            CharSequence title = null;
            String summary = null;
            String keyHint = null;
+0 −342

File deleted.

Preview size limit exceeded, changes collapsed.

+3 −4
Original line number Diff line number Diff line
@@ -177,8 +177,7 @@ public class TileUtilsTest {
                event -> testAction.equals(event.getAction())), anyInt(), anyInt()))
                .thenReturn(info);

        List<DashboardCategory> categoryList = TileUtils.getCategories(
                mContext, cache, testAction, CategoryManager.SETTING_PKG);
        List<DashboardCategory> categoryList = TileUtils.getCategories(mContext, cache, testAction);
        assertThat(categoryList.get(0).getTile(0).category).isEqualTo(testCategory);
    }

@@ -193,12 +192,12 @@ public class TileUtilsTest {
        userHandleList.add(new UserHandle(ActivityManager.getCurrentUser()));
        when(mUserManager.getUserProfiles()).thenReturn(userHandleList);

        TileUtils.getCategories(mContext, cache, null /* action */, CategoryManager.SETTING_PKG);
        TileUtils.getCategories(mContext, cache, null /* action */);
        verify(mPackageManager, atLeastOnce()).queryIntentActivitiesAsUser(
                intentCaptor.capture(), anyInt(), anyInt());

        assertThat(intentCaptor.getAllValues().get(0).getPackage())
                .isEqualTo(CategoryManager.SETTING_PKG);
                .isEqualTo(TileUtils.SETTING_PKG);
    }

    @Test