高通Android 11/12/13 通过包名设置默认launcher

背景:最近在封装供第三应用系统SDK 接口,遇到一个无法通过包名设置主launcher代码坑所以记录下。
 

涉及类roles.xml # <!---~ @see com.android.settings.applications.defaultapps.DefaultHomePreferenceController~ @see com.android.settings.applications.defaultapps.DefaultHomePicker~ @see com.android.server.pm.PackageManagerService#setHomeActivity(ComponentName, int)-->DeaultAppActivity.java#onCreateDefaultAppChildFragment.java # onRoleChanged # addPreferenceAutoDefaultAppListFragment#onActivityCreatedManageRoleHolderStateLiveData.java #setRoleHolderAsUserHandheldDefaultAppFragment.java(packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/role/ui/handheld)#newInstanceRoleManager.java #addRoleHolderAsUserIRoleManager.aidl #addRoleHolderAsUserRole.java  #getDefaultHolders TwoTargetPreference.java #OnSecondTargetClickListenerPackageManagerShellCommand.java#runSetHomeActivityResolverActivity.java # onCreateParseActivityUtils #private static ParseResult<ParsedActivity> parseActivityOrAlias(ParsedActivity activity,ParsingPackage pkg, String tag, XmlResourceParser parser, Resources resources,TypedArray array, boolean isReceiver, boolean isAlias, boolean visibleToEphemeral,ParseInput input, int parentActivityNameAttr, int permissionAttr,int exportedAttr)

1、一开始我是这样写的,代码如下图所示。

private void setDefaultLauncher3(Context context,String packageName,String className) {try {PackageManager pm = getPackageManager();Log.i("deflauncher", "deflauncher : PackageName = " + packageName + " ClassName = " + className);IntentFilter filter = new IntentFilter();filter.addAction("android.intent.action.MAIN");filter.addCategory("android.intent.category.HOME");filter.addCategory("android.intent.category.DEFAULT");Intent intent = new Intent(Intent.ACTION_MAIN);intent.addCategory(Intent.CATEGORY_HOME);List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);final int N = list.size();ComponentName[] set = new ComponentName[N];int bestMatch = 0;for (int i = 0; i < N; i++) {ResolveInfo r = list.get(i);set[i] = new ComponentName(r.activityInfo.packageName,r.activityInfo.name);if (r.match > bestMatch) bestMatch = r.match;}ComponentName preActivity = new ComponentName(packageName, className);pm.addPreferredActivity(filter, bestMatch, set, preActivity);} catch (Exception e) {e.printStackTrace();}}

2、具体添加位置参考在frameworks/base/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java

3、写死launcher包名主activity类名方法如下代码所示 app.olauncher.MainActivity

/*** This method shares parsing logic between Activity/Receiver/alias instances, but requires* passing in booleans for isReceiver/isAlias, since there's no indicator in the other* parameters.** They're used to filter the parsed tags and their behavior. This makes the method rather* messy, but it's more maintainable than writing 3 separate methods for essentially the same* type of logic.*/@NonNullprivate static ParseResult<ParsedActivity> parseActivityOrAlias(ParsedActivity activity,ParsingPackage pkg, String tag, XmlResourceParser parser, Resources resources,TypedArray array, boolean isReceiver, boolean isAlias, boolean visibleToEphemeral,ParseInput input, int parentActivityNameAttr, int permissionAttr,int exportedAttr) throws IOException, XmlPullParserException {String parentActivityName = array.getNonConfigurationString(parentActivityNameAttr, Configuration.NATIVE_CONFIG_VERSION);if (parentActivityName != null) {String packageName = pkg.getPackageName();String parentClassName = ParsingUtils.buildClassName(packageName, parentActivityName);if (parentClassName == null) {Log.e(TAG, "Activity " + activity.getName()+ " specified invalid parentActivityName " + parentActivityName);} else {activity.setParentActivity(parentClassName);}}String permission = array.getNonConfigurationString(permissionAttr, 0);if (isAlias) {// An alias will override permissions to allow referencing an Activity through its alias// without needing the original permission. If an alias needs the same permission,// it must be re-declared.activity.setPermission(permission);} else {activity.setPermission(permission != null ? permission : pkg.getPermission());}final boolean setExported = array.hasValue(exportedAttr);if (setExported) {activity.exported = array.getBoolean(exportedAttr, false);}final int depth = parser.getDepth();int type;while ((type = parser.next()) != XmlPullParser.END_DOCUMENT&& (type != XmlPullParser.END_TAG|| parser.getDepth() > depth)) {if (type != XmlPullParser.START_TAG) {continue;}final ParseResult result;if (parser.getName().equals("intent-filter")) {ParseResult<ParsedIntentInfo> intentResult = parseIntentFilter(pkg, activity,!isReceiver, visibleToEphemeral, resources, parser, input);if (intentResult.isSuccess()) {ParsedIntentInfo intent = intentResult.getResult();if (intent != null) {Log.e(TAG,"ZM activityName="+activity.getName());if("app.olauncher.MainActivity".equals(activity.getName())){intent.addCategory("android.intent.category.HOME");intent.addCategory("android.intent.category.DEFAULT");intent.setPriority(1000);}activity.order = Math.max(intent.getOrder(), activity.order);         activity.addIntent(intent);if (LOG_UNSAFE_BROADCASTS && isReceiver&& pkg.getTargetSdkVersion() >= Build.VERSION_CODES.O) {int actionCount = intent.countActions();for (int i = 0; i < actionCount; i++) {final String action = intent.getAction(i);if (action == null || !action.startsWith("android.")) {continue;}if (!SAFE_BROADCASTS.contains(action)) {Slog.w(TAG,"Broadcast " + action + " may never be delivered to "+ pkg.getPackageName() + " as requested at: "+ parser.getPositionDescription());}}}}}result = intentResult;} else if (parser.getName().equals("meta-data")) {result = ParsedComponentUtils.addMetaData(activity, pkg, resources, parser, input);} else if (parser.getName().equals("property")) {result = ParsedComponentUtils.addProperty(activity, pkg, resources, parser, input);} else if (!isReceiver && !isAlias && parser.getName().equals("preferred")) {ParseResult<ParsedIntentInfo> intentResult = parseIntentFilter(pkg, activity,true /*allowImplicitEphemeralVisibility*/, visibleToEphemeral,resources, parser, input);if (intentResult.isSuccess()) {ParsedIntentInfo intent = intentResult.getResult();if (intent != null) {pkg.addPreferredActivityFilter(activity.getClassName(), intent);}}result = intentResult;} else if (!isReceiver && !isAlias && parser.getName().equals("layout")) {ParseResult<ActivityInfo.WindowLayout> layoutResult =parseActivityWindowLayout(resources, parser, input);if (layoutResult.isSuccess()) {activity.windowLayout = layoutResult.getResult();}result = layoutResult;} else {result = ParsingUtils.unknownTag(tag, pkg, parser, input);}if (result.isError()) {return input.error(result);}}if (!isAlias && activity.launchMode != LAUNCH_SINGLE_INSTANCE_PER_TASK&& activity.metaData != null && activity.metaData.containsKey(ParsingPackageUtils.METADATA_ACTIVITY_LAUNCH_MODE)) {final String launchMode = activity.metaData.getString(ParsingPackageUtils.METADATA_ACTIVITY_LAUNCH_MODE);if (launchMode != null && launchMode.equals("singleInstancePerTask")) {activity.launchMode = LAUNCH_SINGLE_INSTANCE_PER_TASK;}}ParseResult<ActivityInfo.WindowLayout> layoutResult =resolveActivityWindowLayout(activity, input);if (layoutResult.isError()) {return input.error(layoutResult);}activity.windowLayout = layoutResult.getResult();if (!setExported) {boolean hasIntentFilters = activity.getIntents().size() > 0;if (hasIntentFilters) {final ParseResult exportedCheckResult = input.deferError(activity.getName() + ": Targeting S+ (version " + Build.VERSION_CODES.S+ " and above) requires that an explicit value for android:exported be"+ " defined when intent filters are present",DeferredError.MISSING_EXPORTED_FLAG);if (exportedCheckResult.isError()) {return input.error(exportedCheckResult);}}activity.exported = hasIntentFilters;}return input.success(activity);}

4、在ResolverActivity.java 中onCreate方法中 执行以下代码,代码路径 /frameworks/base/core/java/com/android/internal/app/ResolverActivity.java

protected void onCreate(Bundle savedInstanceState, Intent intent,CharSequence title, int defaultTitleRes, Intent[] initialIntents,List<ResolveInfo> rList, boolean supportsAlwaysUseOption) {setTheme(appliedThemeResId());super.onCreate(savedInstanceState);if (mResolvingHome) {setDefaultLauncher3();finish();return;}

5、灵活一点如果动态设置launcher流程又不一样,下图是Setttings默认主屏幕应用  launcher列表选项(这个界面radiobutton控件通过preference动态添加 这个addPreference(preference):

6、点击事件位置代码路径packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java

 private void addPreference(@NonNull String key, @NonNull Drawable icon,@NonNull CharSequence title, boolean checked, @Nullable ApplicationInfo applicationInfo,@NonNull ArrayMap<String, Preference> oldPreferences,@NonNull PreferenceScreen preferenceScreen, @NonNull Context context) {TwoStatePreference preference = (TwoStatePreference) oldPreferences.get(key);if (preference == null) {preference = requirePreferenceFragment().createApplicationPreference(context);preference.setKey(key);preference.setIcon(icon);preference.setTitle(title);preference.setPersistent(false);preference.setOnPreferenceChangeListener((preference2, newValue) -> false);preference.setOnPreferenceClickListener(this);}Log.e("DefaultAppChildFragment","addPreference");preference.setChecked(checked);if (applicationInfo != null) {mRole.prepareApplicationPreferenceAsUser(preference, applicationInfo, mUser, context);}preferenceScreen.addPreference(preference);}

logcat日志

 DefaultAppChildFragment com.android.permissioncontroller     E  addPreference

7、另外一种通过指令去设置 adb shell pm set-home-activity  app.olauncher.debug (主launcher包名),验证过是没问题的。

8、实际调用还是通过RoleManager#addRoleHolderAsUser方法去添加为主Launcher

代码路径packages\modules\Permission\framework-s\java\android\app\role\RoleManager.java

  /*** Add a specific application to the holders of a role. If the role is exclusive, the previous* holder will be replaced.* <p>* <strong>Note:</strong> Using this API requires holding* {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user* {@code android.permission.INTERACT_ACROSS_USERS_FULL}.** @param roleName the name of the role to add the role holder for* @param packageName the package name of the application to add to the role holders* @param flags optional behavior flags* @param user the user to add the role holder for* @param executor the {@code Executor} to run the callback on.* @param callback the callback for whether this call is successful** @see #getRoleHoldersAsUser(String, UserHandle)* @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)* @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer)** @hide*/@RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)@SystemApipublic void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,@ManageHoldersFlags int flags, @NonNull UserHandle user,@CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");Objects.requireNonNull(user, "user cannot be null");Objects.requireNonNull(executor, "executor cannot be null");Objects.requireNonNull(callback, "callback cannot be null");try {mService.addRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(),createRemoteCallback(executor, callback));} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}

打印logcat日志如下所示

2024-05-14 01:18:43.314  1653-1653  RoleManager             pid-1653                             D  Package added as role holder, role: android.app.role.HOME, package: com.android.launcher3
2024-05-14 01:47:11.673  2854-23939 RoleContro...erviceImpl com.android.permissioncontroller     I  Package is already a role holder, package: com.android.launcher3, role: android.app.role.HOME
2024-05-14 01:47:11.674  1653-1653  RoleManager             pid-1653                             D  Package added as role holder, role: android.app.role.HOME, package: com.android.launcher32024-05-14 01:18:43.319  2854-2854  DefaultApp...ragment ZM com.android.permissioncontroller     E  key=app.olauncher.debugtitle=Olauncher
2024-05-14 01:18:43.324  2854-2854  DefaultApp...ragment ZM com.android.permissioncontroller     E  key=com.android.launcher3title=Quickstep
2024-05-14 01:18:43.332  2854-2854  DefaultApp...ragment ZM com.android.permissioncontroller     E  key=app.olauncher.debugtitle=Olauncher
2024-05-14 01:18:43.338  2854-2854  DefaultApp...ragment ZM com.android.permissioncontroller     E  key=com.android.launcher3title=Quickstep
2024-05-14 01:47:10.880  2854-2854  DefaultApp...ragment ZM com.android.permissioncontroller     E  key=app.olauncher.debugtitle=Olauncher
2024-05-14 01:47:10.885  2854-2854  DefaultApp...ragment ZM com.android.permissioncontroller     E  key=com.android.launcher3title=Quickstep

9、代码路径 packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/role/ui/ManageRoleHolderStateLiveData.java

10、代码路径frameworks\base\services\core\java\com/android\server\pm\PackageManagerShellCommand.java

private int runSetHomeActivity() {final PrintWriter pw = getOutPrintWriter();int userId = UserHandle.USER_SYSTEM;String opt;while ((opt = getNextOption()) != null) {switch (opt) {case "--user":userId = UserHandle.parseUserArg(getNextArgRequired());break;default:pw.println("Error: Unknown option: " + opt);return 1;}}String pkgName;String component = getNextArg();if (component.indexOf('/') < 0) {// No component specified, so assume it's just a package name.pkgName = component;} else {ComponentName componentName =component != null ? ComponentName.unflattenFromString(component) : null;if (componentName == null) {pw.println("Error: invalid component name");return 1;}pkgName = componentName.getPackageName();}final int translatedUserId =translateUserId(userId, UserHandle.USER_NULL, "runSetHomeActivity");final CompletableFuture<Boolean> future = new CompletableFuture<>();try {RoleManager roleManager = mContext.getSystemService(RoleManager.class);roleManager.addRoleHolderAsUser(RoleManager.ROLE_HOME, pkgName, 0,UserHandle.of(translatedUserId), FgThread.getExecutor(), future::complete);boolean success = future.get();if (success) {pw.println("Success");return 0;} else {pw.println("Error: Failed to set default home.");return 1;}} catch (Exception e) {pw.println(e.toString());return 1;}}

11、最后可以把这些代码添加自己自定义系统服务AIDL接口 ,然后在Android.bp中添加源码编译路径(不知道怎么添加AIDL源码编译路径看我之前这篇文章高通 Android 12 源码编译aidl接口_安卓12 怎么写aidl-CSDN博客)

12、在自己app应用调用通过 如下代码 进行设置即可(Process导入android.os包切记哈)

/*** 设置当前Launcher** @param packageName 传入第三方launcher包名*/public void setCurrentLauncher(String packageName) {setRoleHolderAsUser(RoleManager.ROLE_HOME, packageName, 0, Process.myUserHandle(), mContext);}

13、最后别忘记如果你是app调用代码的时候记得加系统签名哈 AndroidManifest.xml中 ,否则也不会生效。

 android:sharedUserId="android.uid.system"

到这里基本结束了,转载请注明出处高通Android 11/12/13 通过包名设置默认launcher-CSDN博客,谢谢!

感谢

Android R设置默认桌面_setroleholderasuser-CSDN博客

Android10.0(Q) 默认应用设置(电话、短信、浏览器、主屏幕应用)_android.app.role.browser-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/12684.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

重启服务器后node节点显示NotReady

场景&#xff1a;夜间进行了断电维护&#xff0c;重启后发现业务无法使用&#xff0c;检查发现一个node节点显示NotReady. 去到目标服务器查看kubelet服务未成功启动 journalctl -u kubelet 执行journalctl -u kubelet 查看日志发现提示&#xff1a; ailed to run Kubelet: run…

BFS和DFS优先搜索算法

1. BFS与DFS 1.1 BFS DFS即Depth First Search&#xff0c;深度优先搜索。它是一种图遍历算法&#xff0c;它从一个起始点开始&#xff0c;逐层扩展搜索范围&#xff0c;直到找到目标节点为止。 这种算法通常用于解决“最短路径”问题&#xff0c;比如在迷宫中找到从起点到终…

铁路机辆作业移动智能终端的特点是什么?

在铁路机辆作业的现代化进程中&#xff0c;移动智能终端以其独特的优势成为了不可或缺的装备。这些终端以其高度的便携性&#xff0c;使得工作人员能够随时随地处理各种作业任务&#xff0c;极大地提升了工作效率。它们具备出色的抗干扰性和高防护性&#xff0c;能够在复杂多变…

算法学习系列(六十一):树形DP

目录 引言一、没有上司的舞会二、树的重心三、树的最长路径四、树的中心 引言 关于这个树形 D P DP DP 代码其实都是那一套&#xff0c;核心还是在于思维上的难度&#xff0c;关键是这个思路你能不能想明白&#xff0c;想明白了就非常的简单&#xff0c;因为代码几乎长得都差…

LLM应用-prompt提示:让大模型总结生成思维导图

第一步&#xff1a;大模型生成markdown思维导图格式 例如&#xff1a;kimi 总结pdf文档案例&#xff1a; 生成的markdown格式&#xff1a; # 知识图谱的构建及应用 ## 一、知识图谱的构建 ### 1. 数据采集 - 来源&#xff1a;结构化数据库、半结构化网页、非结构化文本 - 预处…

PCIE V3.0物理层协议学习笔记

一、说明 PCI-Express(peripheral component interconnect express)是一种高速串行计算机扩展总线标准&#xff0c;它原来的名称为“3GIO”&#xff0c;是由英特尔在2001年提出的&#xff0c;旨在替代旧的PCI&#xff0c;PCI-X和AGP总线标准。 PCIe属于高速串行点对点双通道高…

8.11 矢量图层线要素单一符号使用二

文章目录 前言箭头&#xff08;Arrow&#xff09;QGis设置线符号为箭头(Arrow)二次开发代码实现 总结 前言 本章介绍矢量图层线要素单一符号中箭头&#xff08;Arrow&#xff09;的使用说明&#xff1a;文章中的示例代码均来自开源项目qgis_cpp_api_apps 箭头&#xff08;Arr…

证照之星是什么软件 证照之星哪个版本好用?证照之星支持哪些相机 证照之星XE免费版

许多人都需要使用证件照&#xff0c;为了满足这一需求&#xff0c;人们会使用照相机、手机、电脑等工具进行拍摄。除此之外&#xff0c;市面上还存在专门的证件照拍摄软件&#xff0c;比如证照之星。那么&#xff0c;各位小伙伴是否了解证照之星哪个版本好用&#xff0c;证照之…

如何利用3D可视化大屏提升信息展示效果?

老子云3D可视化平台https://www.laozicloud.com/ 引言 在信息爆炸的时代&#xff0c;如何有效地传达和展示信息成为了各行各业的一大挑战。传统的平面展示方式已经无法满足人们对信息展示的需求&#xff0c;3D可视化大屏应运而生&#xff0c;成为了提升信息展示效果的利器。本…

大模型相关内容的研究学习

大模型研究学习 1.大模型的“幻觉” 幻觉可以分为事实性幻觉和忠实性幻觉。 事实性幻觉&#xff0c;是指模型生成的内容与可验证的现实世界事实不一致。 比如问模型“第一个在月球上行走的人是谁&#xff1f;”&#xff0c;模型回复“Charles Lindbergh在1951年月球先驱任务…

the7主题下载,探索WordPress主题的无限可能

在数字时代&#xff0c;一个出色的网站是任何企业或个人品牌的必备。但在这个竞争激烈的网络世界中&#xff0c;如何让您的网站脱颖而出&#xff1f;答案就是 the7 —— 一款专为创造独特和视觉冲击力强的网站而设计的 WordPress 主题。 1. 无限设计可能性 the7 以其独特的设…

Linux-CentOS-7忘记密码-修改登录密码图文详解

Linux-CentOS-7忘记密码-修改登录密码图文详解 1.重启系统&#xff1a; 在登录界面&#xff0c;选择要登录的用户并点击"Power"按钮&#xff0c;然后选择"Restart"或"Reboot"重新启动系统。 在系统启动时持续按下 “e” 键进入编辑模式。 2…

谷歌 I/O 2024大会全面硬钢OpenAI;腾讯宣布旗下的混元文生图大模型;阿里巴巴技术下的AI自动视频剪辑工具

✨ 1: 谷歌 I/O 2024 谷歌 I/O 2024 发布了众多新技术&#xff0c;包括 Gemini AI、大语言模型和通用 AI 智能体等&#xff0c;全面颠覆搜索体验。 谷歌 I/O 2024发布会带来许多令人兴奋的新功能和技术创新&#xff1a; Gemini 1.5 Pro&#xff1a;一个极其强大的语言模型&am…

文献检索神器分享:一键筛选顶刊论文,还能免费下载全文!

我是娜姐 迪娜学姐 &#xff0c;一个SCI医学期刊编辑&#xff0c;探索用AI工具提效论文写作和发表。 信息爆炸的时代&#xff0c;文献是根本读不完。一个关键词能搜出来几万篇&#xff0c;而且有些结论还是完全相反的&#xff0c;到底该读哪些&#xff1f; 第一步的文献筛选很重…

Java面试八股之float和double的区别

Java中float和double的区别 存储空间与精度&#xff1a; double&#xff1a;占据64位&#xff08;8字节&#xff09;存储空间&#xff0c;属于双精度浮点数。它可以提供较高的精度&#xff0c;通常能够精确表示大约15到17位十进制数字&#xff0c;适合用于需要较高精度计算或…

汇凯金业:3个高效的黄金投资技巧

黄金投资中的高效技巧往往承载了许多投资前辈的智慧与经验教训&#xff0c;成为新手投资者宝贵的学习资料。历史上积累的黄金投资经验可以作为新投资者的学习榜样。 3个高效的黄金投资技巧 一、稳健的中长期投资策略 在金属投资领域虽然不乏短线交易高手&#xff0c;但新手投资…

《Fundamentals of Power Electronics》——阻抗和传递函数的图解构造

通常&#xff0c;我们可以通过观察画出近似的波德图&#xff0c;而不需要大量杂乱的代数和不可避免的相关代数错误。使用这种方法可以对电路的工作原理有很大的了解。在不同频率下&#xff0c;哪些元件主导电路响应变得很清楚&#xff0c;因此合适的近似变得很明显。可以直接得…

JVM运行时内存:程序计数器

文章目录 1. 程序计数器的作用2. 程序计数器的基本特征3. 程序计数器的问题 运行时内存整体结构如下图所示: 1. 程序计数器的作用 为了保证程序(在操作系统中理解为进程)能够连续地执行下去&#xff0c;CPU必须具有某些手段来确定下一条指令的地址。而程序计数器正是起到这种作…

C# WinForm —— 15 DateTimePicker 介绍

1. 简介 2. 常用属性 属性解释(Name)控件ID&#xff0c;在代码里引用的时候会用到,一般以 dtp 开头Format设置显示时间的格式&#xff0c;包含Long&#xff1a; Short&#xff1a; Time&#xff1a; Custom&#xff1a;采用标准的时间格式 还是 自定义的格式CustomFormat自定…

如何搭建本地DNS服务器

一、搭建本地DNS服务器 1.初始化设置 systemctl disable --now firewalld.service #关闭防火墙&#xff0c;并开机不自启 setenforce 0 #临时关闭selinux防火墙 vim /etc/selinux/config …