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);
+    }
+}
相关推荐
limingade8 小时前
手机转SIP-手机做中继网关-落地线路对接软交换呼叫中心
android·智能手机·手机转sip·手机做sip中继网关·sip中继
RainbowC08 小时前
GapBuffer高效标记管理算法
android·算法
程序员码歌9 小时前
豆包Seedream4.0深度体验:p图美化与文生图创作
android·前端·后端
、花无将10 小时前
PHP:下载、安装、配置,与apache搭建
android·php·apache
shaominjin12310 小时前
Android 约束布局(ConstraintLayout)的权重机制:用法与对比解析
android·网络
我命由我1234512 小时前
Android 对话框 - 对话框全屏显示(设置 Window 属性、使用自定义样式、继承 DialogFragment 实现、继承 Dialog 实现)
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
怪兽201413 小时前
请例举 Android 中常用布局类型,并简述其用法以及排版效率
android·面试
应用市场13 小时前
Android Bootloader启动逻辑深度解析
android
爱吃水蜜桃的奥特曼13 小时前
玩Android Harmony next版,通过项目了解harmony项目快速搭建开发
android·harmonyos
shaominjin12313 小时前
Android 中 RecyclerView 与 ListView 的深度对比:从设计到实践
android