android通过广播设置默认启动器

摘要:android允许用户选择默认的启动器,满足各类业务使用场景。如果不加launcher属性,只要是有activity界面的app均能设置为默认启动器。本文通过广播的方式,内部调用设置默认启动器的流程,并且可以选择是否直接启动来实现。

1.预研

博主使用的是sprd平台/android 10的代码,通过对于原生设置默认启动器的代码追踪,定位实现方案放在PermissionController中。
PermissionController官方文档

2.定义广播并添加收发权限

java 复制代码
Index: packages/apps/PermissionController/AndroidManifest.xml
===================================================================
--- packages/apps/PermissionController/AndroidManifest.xml	(版本 1951)
+++ packages/apps/PermissionController/AndroidManifest.xml	(版本 1965)
@@ -307,6 +307,13 @@
         <receiver android:name="com.android.packageinstaller.incident.ApprovalReceiver"
             android:exported="false" />
 
+        <receiver android:name="com.android.permissioncontroller.role.service.SetDefaultHomeAppReceiver"
+                  android:exported="true">
+           <intent-filter>
+                <action android:name="android.intent.action.SET_DEFAULT_HOME_APP" />
+            </intent-filter>
+        </receiver>
+
     </application>
 
 </manifest>

后台允许广播收发权限可以自行定位代码,此处仅做记录。

java 复制代码
Index: frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
===================================================================
--- frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java	(版本 1951)
+++ frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java	(版本 1965)
@@ -90,6 +90,8 @@
     
sBackgroundActionWhiteListArraySet.add("android.intent.action.SET_DEFAULT_HOME_APP");
     }

3.方案实现

设置前判断app是否已安装,是否符合默认启动器规则。

设置完成后通过boolean extra决定是否直接启动。

java 复制代码
Index: packages/apps/PermissionController/src/com/android/packageinstaller/role/service/SetDefaultHomeAppReceiver.java
===================================================================
--- packages/apps/PermissionController/src/com/android/packageinstaller/role/service/SetDefaultHomeAppReceiver.java	(不存在的)
+++ packages/apps/PermissionController/src/com/android/packageinstaller/role/service/SetDefaultHomeAppReceiver.java	(版本 1965)
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.permissioncontroller.role.service;
+
+import android.app.Application;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Process;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import com.android.packageinstaller.role.model.Role;
+import com.android.packageinstaller.role.model.Roles;
+import com.android.packageinstaller.role.ui.DefaultAppViewModel;
+
+import java.util.List;
+
+/**
+ * {@link BroadcastReceiver} to reset default home app.
+ */
+public class SetDefaultHomeAppReceiver extends BroadcastReceiver {
+
+    private static final String TAG = "SetDefaultHomeAppReceiver";
+
+    private DefaultAppViewModel mViewModel;
+
+    @Override
+    public void onReceive(@NonNull Context context, @NonNull Intent intent) {
+        String action = intent.getAction();
+
+        String packageName = intent.getStringExtra("packageName");
+        if (packageName == null) {
+            Log.d(TAG, "onReceive::invalid parameter!");
+            return;
+        }
+        if (!isPackageExist(context, packageName)) {
+            Log.d(TAG, "onReceive::package: " + packageName + " is not exist!");
+            return;
+        }
+        if (!isHomeApp(context, packageName)) {
+            Log.d(TAG, "onReceive::package: " + packageName + " is not home app!");
+            return;
+        }
+        Log.d(TAG, "onReceive::set default home app: " + packageName);
+        Role role = Roles.get(context).get("android.app.role.HOME");
+        CharSequence confirmationMessage = role.getConfirmationMessage(packageName, context);
+        if (confirmationMessage != null) {
+            // do nothing.
+        } else {
+            Application application = (Application) context.getApplicationContext();
+            mViewModel = new DefaultAppViewModel(role, Process.myUserHandle(), application);
+            setDefaultApp(packageName);
+
+            if (intent.getBooleanExtra("startActivity", true)) {
+                launchHomeActivityByPackageName(context, packageName);
+            }
+        }
+    }
+
+    private void setDefaultApp(@NonNull String packageName) {
+        mViewModel.setDefaultApp(packageName);
+    }
+
+    public boolean isPackageExist(Context context, String targetPackage) {
+        PackageManager packageManager = context.getPackageManager();
+        try {
+            packageManager.getPackageInfo(targetPackage, PackageManager.GET_ACTIVITIES);
+            return true;
+        } catch (PackageManager.NameNotFoundException e) {
+            return false;
+        }
+    }
+
+    public boolean isHomeApp(Context context, String packageName) {
+        Intent homeIntent = new Intent(Intent.ACTION_MAIN);
+        homeIntent.addCategory(Intent.CATEGORY_HOME);
+        homeIntent.addCategory(Intent.CATEGORY_DEFAULT);
+ 
+        PackageManager pm = context.getPackageManager();
+        List<ResolveInfo> resolveInfos = pm.queryIntentActivities(homeIntent, PackageManager.MATCH_DEFAULT_ONLY);
+        for (ResolveInfo resolveInfo : resolveInfos) {
+            if (resolveInfo.activityInfo.packageName.equals(packageName)) {
+                return true;
+            }
+        } 
+        return false;
+    }
+
+    private void launchHomeActivityByPackageName(Context context, String packageName) {
+        PackageManager packageManager = context.getPackageManager();
+        Intent homeIntent = new Intent(Intent.ACTION_MAIN);
+        homeIntent.addCategory(Intent.CATEGORY_HOME);
+ 
+        List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(homeIntent, 0);
+        for (ResolveInfo resolveInfo : resolveInfos) {
+            if (resolveInfo.activityInfo.packageName.equals(packageName)) {
+                ActivityInfo activityInfo = resolveInfo.activityInfo;
+                ComponentName componentName = new ComponentName(activityInfo.applicationInfo.packageName, activityInfo.name);
+                Intent intent = new Intent(Intent.ACTION_MAIN);
+                intent.addCategory(Intent.CATEGORY_LAUNCHER);
+                intent.setComponent(componentName);
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                context.startActivity(intent);
+                return;
+            }
+        }
+
+        Log.d(TAG, "No home activity found for package: " + packageName);
+    }
+}
相关推荐
杨哥带你写代码2 小时前
汽车资讯新动力:Spring Boot技术革新
android·spring boot·后端
飞凌嵌入式2 小时前
飞凌嵌入式RK3576核心板已适配Android 14系统
android·人工智能·飞凌嵌入式
wink-1724 小时前
Android系统设置页面更改语言 权限 主题导致app崩溃
android
徐浪老师5 小时前
基于 MATLAB 的模拟退火算法详解及实现
android·ide·android studio
明川5 小时前
Android 性能优化:内存优化(理论篇)
android·前端·性能优化
粤M温同学6 小时前
Android 使用Retrofit 以纯二进制文件流上传文件
android·retrofit
yi诺千金8 小时前
Android U 多任务启动分屏——SystemUI流程(更新中)
android
Winston Wood9 小时前
Linux中火焰图和eBPF的关系
android·linux·运维·服务器·性能优化