MTKAndroid13-Launcher3 屏蔽部分app不让显示

实现Launcher3 桌面屏蔽部分内容,不让显示


修改文件路径-实现方式

/vendor/mediatek/proprietary/packages/apps/Launcher3/src/com/android/launcher3/model/AllAppsList.java


在copyData 方法中过滤

    public AppInfo[] copyData() {
        AppInfo[] result = data.toArray(EMPTY_ARRAY);
       /* Arrays.sort(result, COMPONENT_KEY_COMPARATOR);
        return result;*/
		
	
		 List<AppInfo> updatedAppInfos = new ArrayList<>();
        for(AppInfo info:result){
            if(info.componentName!=null){
                if(info.componentName.getPackageName().equals("com.android.documentsui")){
                    Log.d(TAG,"info. filter  :"+info.componentName.getPackageName());
                }else{
                    Log.d(TAG,"info  nofilter:"+info.componentName.getPackageName());
                    updatedAppInfos.add(info);
                }
            }
        }
        AppInfo[] result1= updatedAppInfos.toArray(new AppInfo[0]);
        Arrays.sort(result1, COMPONENT_KEY_COMPARATOR);
        return result1;
    }

基础-源码模块配置

源码里面的Launcher3 有 非GMS的和GMS的,特别对于MTK、高通、展讯 手机相关平台方案,两个类型Launcher3 模块共存的。 对于 RK 、全志下的大多工控产品下,源码是没有 GMS一说的。

Launcher3 源码位置

MTK 平台 非GMS 源码路径如下:

/vendor/mediatek/proprietary/packages/apps/Launcher3

MTK 平台 GMS包 下

/vendor/google/apps/SearchLauncher
/vendor/google/overlay/gms_overlay/vendor/google/apps/SearchLauncher

在GMS 情况下,为什么会有两个 SearchLauncher, 这是系统的机制而已, gms_overlay 文件夹下的app 包会覆盖非GMS的软件包。

编译模块配置

路径:

\device\mediatek\system\common\device.mk   

配置如下参数 属性配置:

默认的Launcher3 选项配置
#PRODUCT_PACKAGES += Launcher3

如果要使用MTK的GMS 包的 Launcher ,可以配置如下

#PRODUCT_PACKAGES += MtkLauncher3QuickStep

对应的源码位置是如下两个,具体可以查阅下并进行实验:

/vendor/google/apps/SearchLauncher
/vendor/google/overlay/gms_overlay/vendor/google/apps/SearchLauncher

其实这样配置的Launcher3 本身是属于GMS的,所以发现实际跑起来的Launcher是gms包,还带有开机向导。

GMS的Launcher3 配置

GMS 情况下,配置好GMS编译环境即可, 这样就会加载 gms 文件下的所有app 包,里面就有gms 包的Launcher3

\device\mediatek\system\mssi_64_cn\SystemConfig.mk 文件下,配置BUILD_GMS = yes 

第三方Launcher需要默认为Launcher时候-系统Launcher3 的配置

实际工控产品或者消费产品非GMS产品中,客户自定义的Launcher 软件,那么如何配置默认的Launcherne ?
一般有两种解决方案:

  • 系统默认Launcher存在,在源码Framework层默认第三方Launcher为系统Launcher
  • 系统原生Launcher3 也编译到系统里面去,但是去掉Home 属性。
    如下:
    在这里插入图片描述

参考资料

Android11.0内置第三方Launcher并设置为默认,保留Launcher3并可切换
设置三方应用为默认Launcher
动态设置默认Launcher
android 13.0-launcher3中workspaceapp列表页不显示某个app图标
Android13设置默认Launcher分析

其它相关Launcher 资料相关参考:
Launcher3 相关资料参考
菜鸟成长之路-源码分析专栏
Android Launcher3 简介
Launcher3 高端定制
Launcher3 开发
Launcher3 Android Code Search在线源码查看
Launcher3 xref 在线源码查看
Launcher3 RK 源码查看
Launcher3 解析
Launcher3 AndroidP AS版本
谷歌Launcher3 Android13源码修改
Launcher3 和 Launcher3QuickStep 区别
Android14 不分Launcher3修改
Launcher3 LoaderTask 的数据加载
Android14 浅析Launcher
Android O Launcher3-Workspace加载

  • 上面参考资料都是两种Launcher情况下默认其中一个Launcher 作为默认Launcher; 我们上面分析的是保证一个Launcher 即可,系统Launcher 其实去掉了HOME属性。
  • 系统Launcher3 开发,强烈建议多了解下Launcher3 相关的基础知识,数据架子-布局加载-框架相关基本内容,方便分析代码、实现功能,有相关思路。

实现方案

源码分析

Launcher

在onCreate 方法中,有下面这段代码,见名知意 module 相关

   private LauncherModel mModel;

   @Override
    @TargetApi(Build.VERSION_CODES.S)
    protected void onCreate(Bundle savedInstanceState) {

    ...
	        mModel = app.getModel();

           if (!mModel.addCallbacksAndLoad(this)) {
            if (!internalStateHandled) {
                // If we are not binding synchronously, show a fade in animation when
                // the first page bind completes.
                mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD).setValue(0);
            }
        }
	...
	

}	


LauncherModel

addCallbacksAndLoad 方法

   /**
     * Adds a callbacks to receive model updates
     * @return true if workspace load was performed synchronously
     */
    public boolean addCallbacksAndLoad(Callbacks callbacks) {
        synchronized (mLock) {
            addCallbacks(callbacks);
            return startLoader(new Callbacks[] { callbacks });

        }
    }

startLoader

    看这个方法里面的注释:
	    // Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems
 private boolean startLoader(Callbacks[] newCallbacks) {
        // Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems
        ItemInstallQueue.INSTANCE.get(mApp.getContext())
                .pauseModelPush(ItemInstallQueue.FLAG_LOADER_RUNNING);
        synchronized (mLock) {
            // If there is already one running, tell it to stop.
            boolean wasRunning = stopLoader();
            boolean bindDirectly = mModelLoaded && !mIsLoaderTaskRunning;
            boolean bindAllCallbacks = wasRunning || !bindDirectly || newCallbacks.length == 0;
            final Callbacks[] callbacksList = bindAllCallbacks ? getCallbacks() : newCallbacks;

            if (callbacksList.length > 0) {
                // Clear any pending bind-runnables from the synchronized load process.
                for (Callbacks cb : callbacksList) {
                    MAIN_EXECUTOR.execute(cb::clearPendingBinds);
                }

                LoaderResults loaderResults = new LoaderResults(
                        mApp, mBgDataModel, mBgAllAppsList, callbacksList);
                if (bindDirectly) {
                    // Divide the set of loaded items into those that we are binding synchronously,
                    // and everything else that is to be bound normally (asynchronously).
                    loaderResults.bindWorkspace(bindAllCallbacks);
                    // For now, continue posting the binding of AllApps as there are other
                    // issues that arise from that.
                    loaderResults.bindAllApps();
                    loaderResults.bindDeepShortcuts();
                    loaderResults.bindWidgets();
                    return true;
                } else {
                    stopLoader();
                    // 数据加载 调用工作线程,规避主线程阻塞
                    mLoaderTask = new LoaderTask(
                            mApp, mBgAllAppsList, mBgDataModel, mModelDelegate, loaderResults);

                    // Always post the loader task, instead of running directly
                    // (even on same thread) so that we exit any nested synchronized blocks
                    MODEL_EXECUTOR.post(mLoaderTask);
                }
            }
        }
        return false;
    }

这里找到相关的加载App 位置了:

  loaderResults.bindWorkspace(bindAllCallbacks);
  loaderResults.bindAllApps();
  loaderResults.bindDeepShortcuts();
  loaderResults.bindWidgets();

LoaderResults

源码如下: 它是一个中间方法,暂未实质性功能,应该后面方便系统扩展和用户自己扩展了

/**
 * Helper class to handle results of {@link com.android.launcher3.model.LoaderTask}.
 */
public class LoaderResults extends BaseLoaderResults {

    public LoaderResults(LauncherAppState app, BgDataModel dataModel,
            AllAppsList allAppsList, Callbacks[] callbacks) {
        super(app, dataModel, allAppsList, callbacks, MAIN_EXECUTOR);
    }

    @Override
    public void bindDeepShortcuts() {
    }

    @Override
    public void bindWidgets() {
    }
}

BaseLoaderResults

我们看看这个类的定义:

/**
 * Stores the list of all applications for the all apps view.
 */
public class AllAppsList {

存储app 界面所有应用的集合。

在这里插入图片描述

bindAllApps

   public void bindAllApps() {
        // shallow copy
        AppInfo[] apps = mBgAllAppsList.copyData();
        int flags = mBgAllAppsList.getFlags();
        executeCallbacksTask(c -> c.bindAllApplications(apps, flags), mUiExecutor);
    }

这里看到 AppInfo[] apps = mBgAllAppsList.copyData();,下面看到的 bindAllApplications 绑定所有app ,我们最好从顶层来处理拦截 部分不想显示的应用

那就看一下 mBgAllAppsList 在哪里定义的:

    private final AllAppsList mBgAllAppsList;


  public BaseLoaderResults(LauncherAppState app, BgDataModel dataModel,
            AllAppsList allAppsList, Callbacks[] callbacksList, LooperExecutor uiExecutor) {
      。。。。
        mBgAllAppsList = allAppsList;
    。。。。
    }

所以继续找到 它的子类,上面我们说了它的子类LoadResults 只是一个中间类,再次贴出它的部分代码:

public class LoaderResults extends BaseLoaderResults {

    public LoaderResults(LauncherAppState app, BgDataModel dataModel,
            AllAppsList allAppsList, Callbacks[] callbacks) {
        super(app, dataModel, allAppsList, callbacks, MAIN_EXECUTOR);
    }


那么我们再次回到如上  LauncherModel 的startLoader 方法

 private boolean startLoader(Callbacks[] newCallbacks) {
    ........................
        synchronized (mLock) {
            // If there is already one running, tell it to stop.
            boolean wasRunning = stopLoader();
            boolean bindDirectly = mModelLoaded && !mIsLoaderTaskRunning;
            boolean bindAllCallbacks = wasRunning || !bindDirectly || newCallbacks.length == 0;
            final Callbacks[] callbacksList = bindAllCallbacks ? getCallbacks() : newCallbacks;

            if (callbacksList.length > 0) {
             ...............

                LoaderResults loaderResults = new LoaderResults(
                        mApp, mBgDataModel, mBgAllAppsList, callbacksList);
                if (bindDirectly) {
                    // Divide the set of loaded items into those that we are binding synchronously,
                    // and everything else that is to be bound normally (asynchronously).
                    loaderResults.bindWorkspace(bindAllCallbacks);
                    // For now, continue posting the binding of AllApps as there are other
                    // issues that arise from that.
                    loaderResults.bindAllApps();
                    loaderResults.bindDeepShortcuts();
                    loaderResults.bindWidgets();
                    return true;
                } else {
                    stopLoader();
                    // 数据加载 调用工作线程,规避主线程阻塞
                    mLoaderTask = new LoaderTask(
                            mApp, mBgAllAppsList, mBgDataModel, mModelDelegate, loaderResults);

                    // Always post the loader task, instead of running directly
                    // (even on same thread) so that we exit any nested synchronized blocks
                    MODEL_EXECUTOR.post(mLoaderTask);
                }
            }
        }
        return false;
    }

那就继续追 LoaderResults 构造方法里面的第三个参数  mBgAllAppsList


找到变量定义如下:

    // < only access in worker thread >
    private final AllAppsList mBgAllAppsList;


找到它初始化地方:

    LauncherModel(Context context, LauncherAppState app, IconCache iconCache, AppFilter appFilter,
            boolean isPrimaryInstance) {
        mApp = app;
        mBgAllAppsList = new AllAppsList(iconCache, appFilter);
        mModelDelegate = ModelDelegate.newInstance(context, app, mBgAllAppsList, mBgDataModel,
                isPrimaryInstance);
    }


那么接下来要分析的就是 AllAppsList

AllAppsList

如上在分析 BaseLoaderResults 类的时候 ,已经分析到了 AllAppsList ,然后在bindAllApps 方法里面找到了 mBgAllAppsList.copyData(); ,最后反推到 AllAppsList , 这里需要分析的不就是 如上提到的 copyData嘛。

  public AppInfo[] copyData() {
        AppInfo[] result = data.toArray(EMPTY_ARRAY);
        Arrays.sort(result, COMPONENT_KEY_COMPARATOR);
        return result;
    }

返回的是AppInfo 数组,那么我们过滤掉 我们不让显示的 App 不就解决了需求了嘛。 先看看 AppInfo
如类注释说明:它代表的就是一个展示在所有AppView 中的一个App . 我们可以通过它的属性类ComponentName 的包名来过滤掉我们想要隐藏的App
在这里插入图片描述

修改实现-举例说明

在第一个内容模块,已经说明了修改路径和修改方法,里面其实已经举例了修改的隐藏文件App
修改前:
在这里插入图片描述
修改之后,编译固件,开机后查看日志如下:说明修改已经起作用了。
在这里插入图片描述
最后看实际界面效果:可以看到文件app 已经被隐藏了,没有显示出来,但是这个app 是安装成功了的。
在这里插入图片描述
去系统设置看看,有木有这个app:看到是有这个app,已经安装过了的。 说明 隐藏成功了…
在这里插入图片描述

总结

  • 这个需求解决方案,完全根据代码找到并进行修改实现,思路还是很清晰的
  • 建议多看看Launcher 相关基础知识,对业务和流程分析非常有好处的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

野火少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值