Android 10 之前的暗藏形式:
con.getPackageManager().setComponentEnabledSetting(new ComponentName(con,activityAliasName,PackageManager.COMPONENT_ENABLED_STATE_DISABLED,PackageManager.DONT_KILL_APP);
Android 10 之后,该暗藏图标形式生效,暗藏胜利后仍然会在桌面上保留其图标,点击后会跳转到利用详情页。具体查看官网 API 更新阐明:getActivityList)。
那这就很好受了,在我看来,目前设计的并不太正当,能不能暗藏应该由用户决定,而不是强制不容许暗藏,不过目前官网也设置了管制开关,能够批改零碎设置来去掉该限度,只不过须要 adb 或能批改零碎设置的 APP 或 ROOT 权限能力批改。接下来就是具体分析了。
具体分析
-
getActivityList
//frameworks/base/core/java/android/content/pm/LauncherApps.java public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {logErrorForInvalidProfileAccess(user); try {return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(), packageName, user), user); } catch (RemoteException re) {throw re.rethrowFromSystemServer(); } }
-
getLauncherActivities
//frameworks/base/services/core/java/com/android/server/pm/LauncherAppsService.java @Override public ParceledListSlice<LauncherActivityInfoInternal> getLauncherActivities(String callingPackage, String packageName, UserHandle user) throws RemoteException { // 查问蕴含 ACTION_MAIN 和 CATEGORY_LAUNCHER 的 activity ParceledListSlice<LauncherActivityInfoInternal> launcherActivities = queryActivitiesForUser(callingPackage, new Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_LAUNCHER) .setPackage(packageName), user); // 检测零碎设置(零碎设置管制开关管制是否走新版限度逻辑)if (Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED, 1) == 0) {return launcherActivities;} // 没有找到入口 activity if (launcherActivities == null) { // Cannot access profile, so we don't even return any hidden apps. return null; } final int callingUid = injectBinderCallingUid(); final long ident = injectClearCallingIdentity(); try { // 托管配置文件能够暗藏 APP if (mUm.getUserInfo(user.getIdentifier()).isManagedProfile()) { // Managed profile should not show hidden apps return launcherActivities; } // 设施管理员能够暗藏 APP if (mDpm.getDeviceOwnerComponentOnAnyUser() != null) { // Device owner devices should not show hidden apps return launcherActivities; } final ArrayList<LauncherActivityInfoInternal> result = new ArrayList<>(launcherActivities.getList()); if (packageName != null) { // If this hidden app should not be shown, return the original list. // Otherwise, inject hidden activity that forwards user to app details page. // 可能是如果大于 0,示意有无效的启动入口,则不必注入暗藏的 APP 详情页入口 if (result.size() > 0) {return launcherActivities;} final ApplicationInfo appInfo = mPackageManagerInternal.getApplicationInfo(packageName, /* flags= */ 0, callingUid, user.getIdentifier()); // 依据 APP 信息进行判断是否注入暗藏 APP 详情页入口 if (shouldShowSyntheticActivity(user, appInfo)) { LauncherActivityInfoInternal info = getHiddenAppActivityInfo(packageName, callingUid, user); if (info != null) {result.add(info); } } return new ParceledListSlice<>(result); } final HashSet<String> visiblePackages = new HashSet<>(); for (LauncherActivityInfoInternal info : result) {visiblePackages.add(info.getActivityInfo().packageName); } final List<ApplicationInfo> installedPackages = mPackageManagerInternal.getInstalledApplications(/* flags= */ 0, user.getIdentifier(), callingUid); for (ApplicationInfo applicationInfo : installedPackages) {if (!visiblePackages.contains(applicationInfo.packageName)) {if (!shouldShowSyntheticActivity(user, applicationInfo)) {continue;} LauncherActivityInfoInternal info = getHiddenAppActivityInfo(applicationInfo.packageName, callingUid, user); if (info != null) {result.add(info); } } } return new ParceledListSlice<>(result); } finally {injectRestoreCallingIdentity(ident); } }
-
shouldShowSyntheticActivity
//frameworks/base/services/core/java/com/android/server/pm/LauncherAppsService.java private boolean shouldShowSyntheticActivity(UserHandle user, ApplicationInfo appInfo) { // 没有 app 信息,是零碎 APP 或者更新的零碎 APP,则不增加暗藏详情页入口 if (appInfo == null || appInfo.isSystemApp() || appInfo.isUpdatedSystemApp()) {return false;} // 是管理员 APP 也不必增加该入口 if (isManagedProfileAdmin(user, appInfo.packageName)) {return false;} final AndroidPackage pkg = mPackageManagerInternal.getPackage(appInfo.packageName); if (pkg == null) { // Should not happen, but we shouldn't be failing if it does return false; } // If app does not have any default enabled launcher activity or any permissions, // the app can legitimately have no icon so we do not show the synthetic activity. return requestsPermissions(pkg) && hasDefaultEnableLauncherActivity(appInfo.packageName); }
依据以上源码,能够发现该机制有个全局设置开关,并且有多种状况能够不受该机制限度。因而总结出如下解决方案:
-
若是你的 APP 有 adb 权限或 ROOT 权限,能够间接批改这个全局开关,批改命令如下:
adb shell settings put global show_hidden_icon_apps_enabled 0
- 或者你的 APP 有设施管理员权限
- 或者你的 APP 是零碎 APP
- 或者你的 APP 没有任何默认启动入口
- 或者你的 APP 没有申请任何权限
- 或者你的 APP 波及到 Managed profile(这个具体不太分明怎么用)
- 或者你的 APP 是 Xposed 模块,能够间接注入零碎服务拦挡相干 API,或者注入能够批改零碎设置的 APP(比方:设置)间接批改这个开关
- 或者你是零碎源码开发者,能够间接批改该处代码即可
- 其它更多还未摸索出的形式 (比方利用某些逻辑破绽)……..
参考
- Android hide/unhide app icon programmatically
转自:https://blog.csdn.net/qq_2691…