摘要:android允许用户选择默认的启动器,满足各类业务使用场景。如果不加launcher属性,只要是有activity界面的app均能设置为默认启动器。本文通过广播的方式,内部调用设置默认启动器的流程,并且可以选择是否直接启动来实现。
1.预研
博主使用的是sprd平台/android 10的代码,通过对于原生设置默认启动器的代码追踪,定位实现方案放在PermissionController中。
PermissionController官方文档
2.定义广播并添加收发权限
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>
后台允许广播收发权限可以自行定位代码,此处仅做记录。
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决定是否直接启动。
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);
+ }
+}