有一些 工具应用 或者 测试应用,其实是预置到系统中的,但是肯定不能让它们在桌面( Launcher )中显示出来。所以提供 rom 的时候一般会有这种需求:隐藏指定应用图标。
这里有两个方案(无论以下哪种方案,均可以在 设置 -> 应用和通知 -> 所有应用 中查看到被隐藏的应用,解决方案):
【方案一】:在编译这个被指定的应用的时候,在该应用功能清单 AndroidManifest.xml 中入口 Activity 节点下,去掉:<category android:name=”android.intent.category.LAUNCHER” />,添加上:<action android:name=”android.settings.XXXXX_XXXXX_SETTINGS” /> 和 <category android:name=”android.intent.category.DEFAULT” /> (去掉 <category android:name=”android.intent.category.LAUNCHER” /> 之后,编译出来的应用安装到设备上就不会再有桌面 icon;之所以添加了 <action android:name=”android.settings.XXXXX_XXXXX_SETTINGS” /> 和 <category android:name=”android.intent.category.DEFAULT” /> 是想可以用 intent 携带 action 的方式可以启动起这个 Activity)。
【方案二】:在 Launcher3 应用中做一些修改。当Launcher3 中加载显示系统中所有应用的 icon 的时候做判断:当应用的包名是指定的需要隐藏的应用的时候,不在 Launcher3 中加载该应用 icon (有坑:需要多处修改)。
因为方案一比较简单,不用在这里做过多的解释,下面说以下方案二的具体实现过程,以及最后,说一下方案一和方案二分别在什么情况下使用。
首先,在 Launcher 源码中有一个类叫做 LoaderTask.java ,对于这个类的官方描述如下:
Runnable for the thread that loads the contents of the launcher:
– workspace icons
– widgets
– all apps icons
– deep shortcuts within apps
简而言之:Launcher3 中桌面应用 icon、小部件 等快捷方式的加载,都是在这个Runnable 的实现类中去做的。
在这个类中找到方法:loadAllApps() 方法,修改如下:
private void loadAllApps() {
final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
final List<UserHandle> profiles = mUserManager.getUserProfiles();
// Clear the list of apps
mBgAllAppsList.clear();
for (UserHandle user : profiles) {
// Query for the set of apps
final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
if (DEBUG_LOADERS) {
Log.d(TAG, "getActivityList took "
+ (SystemClock.uptimeMillis() - qiaTime) + "ms for user " + user);
Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user);
}
// Fail if we don't have any apps
// TODO: Fix this. Only fail for the current user.
if (apps == null || apps.isEmpty()) {
return;
}
boolean quietMode = mUserManager.isQuietModeEnabled(user);
// Create the ApplicationInfos
for (int i = 0; i < apps.size(); i++) {
LauncherActivityInfo app = apps.get(i);
//关键代码
//Modify by hgd,does not show some apps in launcher.
if (!appNeedHideInLauncher(app.getComponentName().getPackageName())){
// This builds the icon bitmaps.
mBgAllAppsList.add(new AppInfo(app, user, quietMode), app);
}
//end Modify by hgd
}
ManagedProfileHeuristic.onAllAppsLoaded(mApp.getContext(), apps, user);
}
//code...
}
可以看到关键代码部分即对当前应用的包名做判断,具体方法是:
/**
* Check if app need hide in launcher.
* @param packageName package name of app.
* @return
*/
private boolean appNeedHideInLauncher(String packageName){
boolean needHideInLauncher = false;
if (APP_XXXXX_PACKAGE_NAME.equals(packageName) ||
APP_XXXXXX_PACKAGE_NAME.equals(packageName)){
needHideInLauncher = true;
}
return needHideInLauncher;
}
修改了这处,即可实现在Launcher3 首次加载所有应用图标的时候,不加载指定应用的icon 到桌面。但是,到这里还没算完成。我们的设备是支持儿童模式的,有时候会发现在儿童模式和非儿童模式之间进行切换的时候,已经被隐藏掉的应用还会显示出来,经过代码跟踪,找到还需要在 PackageUpdatedTask.java 中的 execute()方法中的 case OP_UPDATE: 中做一下和上面一样的判断:当应用的包名是指定的需要隐藏的应用的时候,不在 Launcher3 中加载该应用 icon。
这两个方案怎么选择其实一目了然:当我们可以touch 到 Launcher3 源码的情况下,最好还是在Launcher3 中进行修改,这样最保险;如果我们不能修改 Launcher3 的代码,那么我们可以选择方案一,并且最好是在这个指定的需要隐藏的应用的入口Activity 节点下添加一个约定好的 action,这样虽然这个应用图标在 Launcher3 中不可见,但是我们仍然可以通过其他应用的 intent 携带着这个约定好的 action 把这个隐藏了图标的应用启动起来。
参考:
https://blog.csdn.net/yxdspirit/article/details/78793179
https://blog.csdn.net/u010784887/article/details/51598719