Android13 Launcher3 App列表隐藏单个或多个apk

1 需求概述

       当业务需求要求要主页面不显示特定的一个或多个apk时,我们需要在launcher中隐藏此apk。本文以隐藏 Aqua Mail,Calculator,FileCommander三个apk为例来详细讲解。

2 实现功能核心类

  代码路径

 packages\apps\Launcher3\src\com\android\launcher3\model\LoaderTask.java

packages\apps\Launcher3\quickstep\src\com\android\launcher3\appprediction\PredictionRowView.java

3 核心代码分析

 3.1 LoaderTask加载allapps流程

    加载apk列表是在LoaderTask中进行加载的,我们只需要在加载所有apk列表的地方,屏蔽我们业务需要的apk即可实现此功能。看run()方法

public void run() {
        synchronized (this) {
            // Skip fast if we are already stopped.
            if (mStopped) {
                return;
            }
        }

        Object traceToken = TraceHelper.INSTANCE.beginSection(TAG);
        TimingLogger logger = new TimingLogger(TAG, "run");
        LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger();
        try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
            List<ShortcutInfo> allShortcuts = new ArrayList<>();
            Trace.beginSection("LoadWorkspace");
            try {
                loadWorkspace(allShortcuts, memoryLogger);
            } finally {
                Trace.endSection();
            }
            logASplit(logger, "loadWorkspace");

            // Sanitize data re-syncs widgets/shortcuts based on the workspace loaded from db.
            // sanitizeData should not be invoked if the workspace is loaded from a db different
            // from the main db as defined in the invariant device profile.
            // (e.g. both grid preview and minimal device mode uses a different db)
            if (mApp.getInvariantDeviceProfile().dbFile.equals(mDbName)) {
                verifyNotStopped();
                sanitizeData();
                logASplit(logger, "sanitizeData");
            }

            verifyNotStopped();
            mResults.bindWorkspace(true /* incrementBindId */);
            logASplit(logger, "bindWorkspace");

            mModelDelegate.workspaceLoadComplete();
            // Notify the installer packages of packages with active installs on the first screen.
            sendFirstScreenActiveInstallsBroadcast();
            logASplit(logger, "sendFirstScreenActiveInstallsBroadcast");

            // Take a break
            waitForIdle();
            logASplit(logger, "step 1 complete");
            verifyNotStopped();

            // second step
            Trace.beginSection("LoadAllApps");
            List<LauncherActivityInfo> allActivityList;
            try {
               allActivityList = loadAllApps();
            } finally {
                Trace.endSection();
            }
            logASplit(logger, "loadAllApps");

            verifyNotStopped();
            mResults.bindAllApps();
            logASplit(logger, "bindAllApps");

            verifyNotStopped();
            IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler();
            setIgnorePackages(updateHandler);
            updateHandler.updateIcons(allActivityList,
                    LauncherActivityCachingLogic.newInstance(mApp.getContext()),
                    mApp.getModel()::onPackageIconsUpdated);
            logASplit(logger, "update icon cache");

            if (FeatureFlags.ENABLE_DEEP_SHORTCUT_ICON_CACHE.get()) {
                verifyNotStopped();
                logASplit(logger, "save shortcuts in icon cache");
                updateHandler.updateIcons(allShortcuts, new ShortcutCachingLogic(),
                        mApp.getModel()::onPackageIconsUpdated);
            }

            // Take a break
            waitForIdle();
            logASplit(logger, "step 2 complete");
            verifyNotStopped();

            // third step
            List<ShortcutInfo> allDeepShortcuts = loadDeepShortcuts();
            logASplit(logger, "loadDeepShortcuts");

            verifyNotStopped();
            mResults.bindDeepShortcuts();
            logASplit(logger, "bindDeepShortcuts");

            if (FeatureFlags.ENABLE_DEEP_SHORTCUT_ICON_CACHE.get()) {
                verifyNotStopped();
                logASplit(logger, "save deep shortcuts in icon cache");
                updateHandler.updateIcons(allDeepShortcuts,
                        new ShortcutCachingLogic(), (pkgs, user) -> { });
            }

            // Take a break
            waitForIdle();
            logASplit(logger, "step 3 complete");
            verifyNotStopped();

            // fourth step
            List<ComponentWithLabelAndIcon> allWidgetsList =
                    mBgDataModel.widgetsModel.update(mApp, null);
            logASplit(logger, "load widgets");

            verifyNotStopped();
            mResults.bindWidgets();
            logASplit(logger, "bindWidgets");
            verifyNotStopped();

            updateHandler.updateIcons(allWidgetsList,
                    new ComponentWithIconCachingLogic(mApp.getContext(), true),
                    mApp.getModel()::onWidgetLabelsUpdated);
            logASplit(logger, "save widgets in icon cache");

            // fifth step
            if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
                loadFolderNames();
            }

            verifyNotStopped();
            updateHandler.finish();
            logASplit(logger, "finish icon update");

            mModelDelegate.modelLoadComplete();
            transaction.commit();
            memoryLogger.clearLogs();
        } catch (CancellationException e) {
            // Loader stopped, ignore
            logASplit(logger, "Cancelled");
        } catch (Exception e) {
            memoryLogger.printLogs();
            throw e;
        } finally {
            logger.dumpToLog();
        }
        TraceHelper.INSTANCE.endSection(traceToken);
    }

在此方法里面跟下去,找到loadAllApps(),这里就是具体执行加载所有apk的方法了,继续跟踪

private List<LauncherActivityInfo> loadAllApps() {
        final List<UserHandle> profiles = mUserCache.getUserProfiles();
        List<LauncherActivityInfo> allActivityList = new ArrayList<>();
        // Clear the list of apps
        mBgAllAppsList.clear();

        List<IconRequestInfo<AppInfo>> iconRequestInfos = new ArrayList<>();
        for (UserHandle user : profiles) {
            // Query for the set of apps
            final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
            // Fail if we don't have any apps
            // TODO: Fix this. Only fail for the current user.
            if (apps == null || apps.isEmpty()) {
                return allActivityList;
            }
            boolean quietMode = mUserManagerState.isUserQuiet(user);
            // Create the ApplicationInfos
            for (int i = 0; i < apps.size(); i++) {
                LauncherActivityInfo app = apps.get(i);
                AppInfo appInfo = new AppInfo(app, user, quietMode);

                boolean isHideApk = HideApkUtils.getInstall().isHidedApkPackageName(app.getComponentName().getPackageName());
                if(isHideApk){
                    continue;
                }
                iconRequestInfos.add(new IconRequestInfo<>(
                        appInfo, app, /* useLowResIcon= */ false));
                mBgAllAppsList.add(
                        appInfo, app, !FeatureFlags.ENABLE_BULK_ALL_APPS_ICON_LOADING.get());
            }
            allActivityList.addAll(apps);
        }


        if (FeatureFlags.PROMISE_APPS_IN_ALL_APPS.get()) {
            // get all active sessions and add them to the all apps list
            for (PackageInstaller.SessionInfo info :
                    mSessionHelper.getAllVerifiedSessions()) {
                AppInfo promiseAppInfo = mBgAllAppsList.addPromiseApp(
                        mApp.getContext(),
                        PackageInstallInfo.fromInstallingState(info),
                        !FeatureFlags.ENABLE_BULK_ALL_APPS_ICON_LOADING.get());

                if (promiseAppInfo != null) {
                    iconRequestInfos.add(new IconRequestInfo<>(
                            promiseAppInfo,
                            /* launcherActivityInfo= */ null,
                            promiseAppInfo.usingLowResIcon()));
                }
            }
        }

        if (FeatureFlags.ENABLE_BULK_ALL_APPS_ICON_LOADING.get()) {
            Trace.beginSection("LoadAllAppsIconsInBulk");
            try {
                mIconCache.getTitlesAndIconsInBulk(iconRequestInfos);
                iconRequestInfos.forEach(iconRequestInfo ->
                        mBgAllAppsList.updateSectionName(iconRequestInfo.itemInfo));
            } finally {
                Trace.endSection();
            }
        }

        mBgAllAppsList.setFlags(FLAG_QUIET_MODE_ENABLED,
                mUserManagerState.isAnyProfileQuietModeEnabled());
        mBgAllAppsList.setFlags(FLAG_HAS_SHORTCUT_PERMISSION,
                hasShortcutsPermission(mApp.getContext()));
        mBgAllAppsList.setFlags(FLAG_QUIET_MODE_CHANGE_PERMISSION,
                mApp.getContext().checkSelfPermission("android.permission.MODIFY_QUIET_MODE")
                        == PackageManager.PERMISSION_GRANTED);

        mBgAllAppsList.getAndResetChangeFlag();
        return allActivityList;
    }

这里面就是加载所有apk逻辑了,我们只需要添加我们需要隐藏的业务逻辑即可。

    // Create the ApplicationInfos
    for (int i = 0; i < apps.size(); i++) {
        LauncherActivityInfo app = apps.get(i);
        AppInfo appInfo = new AppInfo(app, user, quietMode);

        boolean isHideApk =   HideApkUtils.getInstall().isHidedApkPackageName(app.getComponentName().getPackageName());
        if(isHideApk){
            continue;
        }
        iconRequestInfos.add(new IconRequestInfo<>(
                appInfo, app, /* useLowResIcon= */ false));
        mBgAllAppsList.add(
                appInfo, app, !FeatureFlags.ENABLE_BULK_ALL_APPS_ICON_LOADING.get());
    }
    allActivityList.addAll(apps);
}

标红的即我们加的业务逻辑,此功能就实现了。但是需要注意的是,在配每一屏显示与Hotseat显示的apk列表中,不要把我们需要隐藏的apk加入这表中即可(如何配置每一屏显示的apk与Hotseat显示的apk,请看系列文章会详细讲解)

以下是HideApkUtils.java类

package com.android.launcher3.util;

import java.util.LinkedList;
import java.util.List;

/**
 * by Hogan 2023.3.17
 * 功能:隐藏指定的apk列表
 */

public class HideApkUtils {

    private static final List<String> mHiddenPackageMap = new LinkedList<>();

    private HideApkUtils() {
        addHideAppList();
    }

    //需要隐藏的apk包名,添加到这里
    private void addHideAppList() {
        mHiddenPackageMap.add("org.kman.AquaMail");
        mHiddenPackageMap.add("com.google.android.calculator");
        mHiddenPackageMap.add("com.mobisystems.fileman");
 //       mHiddenPackageMap.add("com.mobisystems.office");
//        mHiddenPackageMap.add("com.hht.factory");
    }

    private static class HideApkUtilsHolder {
        private static final HideApkUtils INSTALL = new HideApkUtils();
    }

    public static HideApkUtils getInstall() {
        return HideApkUtilsHolder.INSTALL;
    }

    public boolean isHidedApkPackageName(String apkPkg) {
        return mHiddenPackageMap.contains(apkPkg);
    }
}

 3.2  PredictionRowView 加载显示搜索框下的搜索预测行视图流程

   1. 找到setPredictedApps()方法,此方法是用于设置预测选项的内容并更新视图的:

    

    public void setPredictedApps(List<ItemInfo> items) {
        if (!FeatureFlags.ENABLE_APP_PREDICTIONS_WHILE_VISIBLE.get()
                && !mActivityContext.isBindingItems()
                && isShown()
                && getWindowVisibility() == View.VISIBLE) {
            mPendingPredictedItems = items;
            return;
        }
        applyPredictedApps(items);
    }

   在这个方法里面调用了 applyPredictedApps()方法

    private void applyPredictedApps(List<ItemInfo> items) {
        List<ItemInfo> itemInfoList =new ArrayList<>();

        for(int i=0;i<items.size();i++){
            String pkg = items.get(i).getTargetPackage();
            boolean isHideApk = HideApkUtils.getInstall().isHidedApkPackageName(pkg);
            if(isHideApk){
                continue;
            }
            itemInfoList.add(items.get(i));
        }
        mPendingPredictedItems = null;
        mPredictedApps.clear();
        mPredictedApps.addAll(itemInfoList.stream()
                .filter(itemInfo -> itemInfo instanceof WorkspaceItemInfo)
                .map(itemInfo -> (WorkspaceItemInfo) itemInfo).collect(Collectors.toList()));
        applyPredictionApps();
    }

这正是加载搜索预测apk,我们可以在这里加上业务逻辑代码即可:

private void applyPredictedApps(List<ItemInfo> items) {
    List<ItemInfo> itemInfoList =new ArrayList<>();

    for(int i=0;i<items.size();i++){
        String pkg = items.get(i).getTargetPackage();
        boolean isHideApk = HideApkUtils.getInstall().isHidedApkPackageName(pkg);
        if(isHideApk){
            continue;
        }
        itemInfoList.add(items.get(i));
    }
    mPendingPredictedItems = null;
    mPredictedApps.clear();
    mPredictedApps.addAll(itemInfoList.stream()
            .filter(itemInfo -> itemInfo instanceof WorkspaceItemInfo)
            .map(itemInfo -> (WorkspaceItemInfo) itemInfo).collect(Collectors.toList()));
    applyPredictionApps();
}

标红的代码就是加入修改之处。

4 完成业务效果图

    4.1 未隐藏前图,红线标注为需要隐藏的apk

 

4.2 隐藏后的效果图

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值