Android 动态设置默认Launcher(默认应用 电话-短信-浏览器-主屏幕应用))
Android 动态设置默认Launcher(默认应用 电话-短信-浏览器-主屏幕应用))
文章目录
- 场景需求
- 参考资料
- 思路
- 期待效果
- 实现方案
- 源码流程分析和思路实现
- DefaultAppActivity
- HandheldDefaultAppFragment
- HandheldDefaultAppPreferenceFragment
- DefaultAppChildFragment
- DefaultAppViewModel
- ManageRoleHolderStateLiveData
- 小结
- RoleManager
- addRoleHolderAsUser
- IRoleManager aidl 接口
- RoleService addRoleHolderAsUser
- RoleControllerManager
- RoleControllerService
- IRoleController
- RoleControllerServiceImpl
- addRoleHolderInternal
- RoleManager addRoleHolderFromController
- RoleService
- addRoleHolderFromController
- getOrCreateUserState
- RoleUserState ->addRoleHolder
- scheduleWriteFileLocked
- writeFile
- RolesPersistenceImpl ->writeForUser
- getFile 方法
- roles.xml
- 小结
- Launcher 指定默认流程总结
- 指定其它默认App 方案
- 总结
- 扩展知识
- adb 命令来动态设置默认的Launcher
- adb 命令实现思考
场景需求
-
客需项目中,客户需要有自己Launcher 形态出现
Android系统本身有自己的Launcher,目前看到的基本上都是Launcher3,几年前还看到Launcher2. 目前接触到的原生Launcher基本都是Launcher3,客户需要有自己Launcher 形态出现 -
客户在定制自己产品时候有自己默认Launcher,或者整个产品形态要么只有自己一个Launcher 要么客需Launcher和系统Launcher3,但是Launcher3 从不显示
-
在已经成型的产品中,可能多个Launcher存在,客户需要在已有产品的基础上,动态切换自己默认的Launcher。 很多白牌产品,借用已有的产品形态,更换Launcher 就是一个新的产品,最重要的是实际商业中不需要备货一说
备注: 默认电话、短信、浏览器和主屏 一样的思路,代码都完全一样,参数不一样而已。
参考资料
Setting 里面切换不同Launcher
高通Android 8.1/9/10/11/12/13 通过包名设置默认launcher
android 10 设置app为默认浏览器
Android11 设置第三方Launcher并默认 与 如何预置apk
本来是分析 默认Launcher 的,实际实验发现 默认电话、短信、桌面、浏览器 是一样的思路,索性放在一起,以默认Launcher为例进行总结说明。
思路
从设置默认主屏幕地方入手,设置->Launcher应用->主屏幕应用选择-> 桌面应用切换
然后进行源码分析,实现的具体方案是怎样的。
如下,实际设置中切换的入口
期待效果
能在应用层实现这个效果,一个界面动态切换不同的Launcher
可以adb 命令实现这个功能
在效果一的基础上,可以考虑集成到framework层,对外提供接口,应用调用framework层接口也可以。
如下测试图,验证过,三个按钮实现切换。
实现方案
对 RoleManager 类的 addRoleHolderAsUser 方法,进行反射实现。
路径:/packages/modules/Permission/framework-s/java/android/app/role/RoleManager.java
实际控制方法 如下反射实现:
val roleManager: RoleManager =
ContextProvider.get().context.getSystemService<RoleManager>(RoleManager::class.java)
val executor: Executor = ContextProvider.get().context.getMainExecutor()
val callback =
Consumer<Boolean> { successful: Boolean ->
if (successful) {
Log.i(TAG, " 成功了==> Package " + "added" + " as role holder, role: " + "测试Home 桌面" + ", package: " + "com.nd.android.pandahome2")
} else {
Log.i(TAG, " 失败了==> Package " + "added" + " as role holder, role: " + "测试Home 桌面" + ", package: " + "com.nd.android.pandahome2")
}
}
val addRoleHolderAsUser = roleManager.javaClass.getMethod(
"addRoleHolderAsUser",
String::class.java, String::class.java, Int::class.java,
UserHandle::class.java,Executor::class.java,Consumer::class.java
)
addRoleHolderAsUser.isAccessible = true
val userHandle = NavigationHelper.newInstance(
UserHandle::class.java, arrayOf<Class<*>?>(
Int::class.javaPrimitiveType
), 0
) as UserHandle
addRoleHolderAsUser.invoke(roleManager, "android.app.role.HOME", "com.nd.android.pandahome2",
1,userHandle,executor,callback)
}
源码流程分析和思路实现
如上 思路 说明部分,以设置进入Launcher 选择为切入点,进行分析,下面主要涉及到的内和方法。
类 | 相关调用 |
---|---|
DefaultAppActivity | fragment = AutoDefaultAppFragment.newInstance(roleName, user); |
HandheldDefaultAppFragment | HandheldDefaultAppPreferenceFragment.newInstance(mRoleName, mUser); |
HandheldDefaultAppPreferenceFragment | DefaultAppChildFragment.newInstance(mRoleName,mUser); |
DefaultAppChildFragment | onPreferenceClick ->setDefaultApp(packageName); -> mViewModel.setDefaultApp |
DefaultAppViewModel | setDefaultApp |
ManageRoleHolderStateLiveData | setRoleHolderAsUser |
RoleManager | addRoleHolderAsUser |
IRoleManager | aidl 接口功能定义 addRoleHolderAsUser |
RoleService | addRoleHolderAsUser |
RoleControllerManager | onAddRoleHolder |
RoleControllerService | onAddRoleHolder |
IRoleController | IRoleController.aidl 文件 |
RoleControllerServiceImpl | onAddRoleHolder ->addRoleHolderInternal |
RoleManager | addRoleHolderFromController |
RoleService | addRoleHolderFromController |
RoleUserState | addRoleHolder->scheduleWriteFileLocked->writeFile |
RolesPersistence | writeForUser |
RolesPersistenceImpl | writeForUser |
DefaultAppActivity
路径:/packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppActivity.java
com.google.android.permissioncontroller/com.android.permissioncontroller.role.ui.DefaultAppActivity
从包名路径就可以看到,这是一个包,看看实际源码结构,看着是一个软件包 如下,实际发现安卓系统结构里面又没有这个包名的包。导入工程分析
结合界面,就是要分析 桌面应用选择点击动作,看看如下截图,发现它只是一个入口,啥也没有。 进入到HandheldDefaultAppFragment 看看
HandheldDefaultAppFragment
实际代码截图如下,也是几行代码,它也是一个入口而已
HandheldDefaultAppPreferenceFragment
实际代码截图如下,发现它也还是一个简单的类,入口而已
DefaultAppChildFragment
看代码截图,和点击事件有点像的就是 就是 onPreferenceClick 方法了。 继续分析源码
DefaultAppViewModel
看看类注释,就是默认APP 的功能, setDefaultApp 方法也是设置包名作为默认app 的功能,
/**
* {@link ViewModel} for a default app.
*/
public class DefaultAppViewModel extends AndroidViewModel {
/**
* Set an application as the default app.
*
* @param packageName the package name of the application
*/
public void setDefaultApp(@NonNull String packageName) {
if (mManageRoleHolderStateLiveData.getValue() != ManageRoleHolderStateLiveData.STATE_IDLE) {
Log.i(LOG_TAG, "Trying to set default app while another request is on-going");
return;
}
mManageRoleHolderStateLiveData.setRoleHolderAsUser(mRole.getName(), packageName, true, 0,
mUser, getApplication());
}
ManageRoleHolderStateLiveData
居然是一个 LiveData, 订阅机制。 这也是为什么 更改默认之后全局通知的原因吧,看方法参数解释也是 角色、包名、flag、user 等,说明跟角色、权限类型相关的。
/**
* Set whether an application is a holder of a role, and update the state accordingly. Will
* be no-op if the current state is not {@link #STATE_IDLE}.
*
* @param roleName the name of the role
* @param packageName the package name of the application
* @param add whether to add or remove the application as a role holder
* @param flags optional behavior flags
* @param user the user to manage the role holder for
* @param context the {@code Context} to retrieve system services
*/
public void setRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
boolean add, int flags, @NonNull UserHandle user, @NonNull Context context) {
if (getValue() != STATE_IDLE) {
Log.e(LOG_TAG, "Already (tried) managing role holders, requested role: " + roleName
+ ", requested package: " + packageName);
return;
}
if (DEBUG) {
Log.i(LOG_TAG, (add ? "Adding" : "Removing") + " package as role holder, role: "
+ roleName + ", package: " + packageName);
}
mLastPackageName = packageName;
mLastAdd = add;
mLastFlags = flags;
mLastUser = user;
setValue(STATE_WORKING);
RoleManager roleManager = context.getSystemService(RoleManager.class);
Executor executor = context.getMainExecutor();
Consumer<Boolean> callback = successful -> {
if (successful) {
if (DEBUG) {
Log.i(LOG_TAG, "Package " + (add ? "added" : "removed")
+ " as role holder, role: " + roleName + ", package: " + packageName);
}
setValue(STATE_SUCCESS);
} else {
if (DEBUG) {
Log.i(LOG_TAG, "Failed to " + (add ? "add" : "remove")
+ " package as role holder, role: " + roleName + ", package: "
+ packageName);
}
setValue(STATE_FAILURE);
}
};
if (add) {
roleManager.addRoleHolderAsUser(roleName, packageName, flags, user, executor, callback);
} else {
roleManager.removeRoleHolderAsUser(roleName, packageName, flags, user, executor,
callback);
}
}
小结
上面通过界面到业务代码分析,发现都是设置默认App 入口,经过来4个类的入口调用 直到 ManageRoleHolderStateLiveData 类里面调用到 RoleManager 的 addRoleHolderAsUser 方法,才进入框架层面
RoleManager
路径:
/packages/modules/Permission/framework-s/java/android/app/role/RoleManager.java
看类注释说明如下: 提供权限roles 管理的功能,对外通过getService 获取它
/**
* This class provides information about and manages roles.
* <p>
* A role is a unique name within the system associated with certain privileges. The list of
.....
*/
@SystemService(Context.ROLE_SERVICE)
public final class RoleManager {
..............
}
addRoleHolderAsUser
上面关联到的方法,看看源码说明,
- 从方法注释上看就是权限添加的功能,如果已经存在 权限,那么添加后会被替换replaced
- 看到注释上面,这个方法是一个隐藏的方法了
/**
* 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)
@SystemApi
public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
@ManageHoldersFlags int flags, @NonNull UserHandle user,
@CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
........
try {
mService.addRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(),
createRemoteCallback(executor, callback));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
关注mService 是什么,看当前类定义地方,
@NonNull
private final IRoleManager mService;
/**
* Create a new instance of this class.
*
* @param context the {@link Context}
* @param service the {@link IRoleManager} service
*
* @hide
*/
public RoleManager(@NonNull Context context, @NonNull IRoleManager service) {
mContext = context;
mService = service;
}
IRoleManager aidl 接口
IRoleManager 源码路径和源码如下:它只是一个接口定义,一般情况下 这个aidl 在一个服务里面引用,服务来实现 aidl 接口,实现对应的功能。
这里通过 grep 来看看 ,找到了
packages/modules/Permission/service/java/com/android/role/RoleService.java
packages/modules/Permission/service/java/com/android/role/RoleShellCommand.java
这里先关注 RoleService
RoleService addRoleHolderAsUser
直接看相关代码
private class Stub extends IRoleManager.Stub {
....................
@NonNull
@Override
public List<String> getRoleHoldersAsUser(@NonNull String roleName, @UserIdInt int userId) {
enforceCrossUserPermission(userId, false, "getRoleHoldersAsUser");
..........
}
@Override
public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
@RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
@NonNull RemoteCallback callback) {
..............
getOrCreateController(userId).onAddRoleHolder(roleName, packageName, flags,
callback);
}
...........
}
@NonNull
private RoleControllerManager getOrCreateController(@UserIdInt int userId) {
synchronized (mLock) {
RoleControllerManager controller = mControllers.get(userId);
if (controller == null) {
Context systemContext = getContext();
Context context;
try {
context = systemContext.createPackageContextAsUser(
systemContext.getPackageName(), 0, UserHandle.of(userId));
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(e);
}
controller = RoleControllerManager.createWithInitializedRemoteServiceComponentName(
ForegroundThread.getHandler(), context);
mControllers.put(userId, controller);
}
return controller;
}
}
上面两个方法可以理解为 :
RoleService 类的方法 addRoleHolderAsUser 实际上执行的是 RoleControllerManager 的对象调用了 onAddRoleHolder 方法
RoleControllerManager
路径:/packages/modules/Permission/framework-s/java/android/app/role/RoleControllerManager.java
直接看源码,方法注释让我们关注 RoleControllerService 的 onAddRoleHolder 方法
/**
* @see RoleControllerService#onAddRoleHolder(String, String, int)
*
* @hide
*/
public void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
@RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
AndroidFuture<Bundle> future = new AndroidFuture<>();
service.onAddRoleHolder(roleName, packageName, flags,
new RemoteCallback(future::complete));
return future;
});
propagateCallback(operation, "onAddRoleHolder", callback);
}
RoleControllerService
承接上文,这里看 onAddRoleHolder 方法源码
先看类注释说明
@Deprecated
@SystemApi
public abstract class RoleControllerService extends Service {
再看方法说明及注释
private void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
@RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
boolean successful = onAddRoleHolder(roleName, packageName, flags);
callback.sendResult(successful ? Bundle.EMPTY : null);
}
/**
* Add a specific application to the holders of a role. If the role is exclusive, the previous
* holder will be replaced.
* <p>
* Implementation should enforce the role requirements and grant or revoke the relevant
* privileges of roles.
*
* @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
*
* @return whether this call was successful
*
* @see RoleManager#addRoleHolderAsUser(String, String, int, UserHandle, Executor,
* RemoteCallback)
*/
@WorkerThread
public abstract boolean onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
@RoleManager.ManageHoldersFlags int flags);
这里发现 RoleControllerService 是个服务,但也是一个抽象的类。 最终共调用到 onAddRoleHolder,需要子类来实现的。
回归到 RoleControllerManager 源码分析,mRemoteService 调用,其实是集合 mRemoteService 里面获取的。
private final ServiceConnector<IRoleController> mRemoteService;
那也就是 要看看 IRoleController 是什么,发现图也是一个aidl 接口。
IRoleController
路径 :
packages/modules/Permission/framework-s/java/android/app/role/IRoleController.aidl
源码如下:
但是 搜索发现一个问题,如下截图看看:你会发现实现类其实就是上面分析的RoleControllerService , 再进一步找到实现类 RoleControllerServiceImpl,那就看实现类里面的oAddRoleHolder 方法
RoleControllerServiceImpl
看一下 onAddRoleHolder 方法
@Override
@WorkerThread
public boolean onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
int flags) {
。。。。。。。。。。。。。。。
Role role = Roles.get(this).get(roleName);
。。。。。。。。。。。。。。。。。。
boolean dontKillApp = hasFlag(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP);
added = addRoleHolderInternal(role, packageName, dontKillApp,
role.shouldOverrideUserWhenGranting(), added);
if (!added) {
return false;
}
role.onHolderAddedAsUser(packageName, Process.myUserHandle(), this);
role.onHolderChangedAsUser(Process.myUserHandle(), this);
return true;
}
关注下 addRoleHolderInternal方法
addRoleHolderInternal
代码如下 ,
@WorkerThread
private boolean addRoleHolderInternal(@NonNull Role role, @NonNull String packageName,
boolean overrideUserSetAndFixedPermissions) {
return addRoleHolderInternal(role, packageName, false, overrideUserSetAndFixedPermissions,
false);
}
@WorkerThread
private boolean addRoleHolderInternal(@NonNull Role role, @NonNull String packageName,
boolean dontKillApp, boolean overrideUserSetAndFixedPermissions, boolean added) {
role.grant(packageName, dontKillApp, overrideUserSetAndFixedPermissions, this);
String roleName = role.getName();
if (!added) {
added = mRoleManager.addRoleHolderFromController(roleName, packageName);
}
if (!added) {
Log.e(LOG_TAG, "Failed to add role holder in RoleManager, package: " + packageName
+ ", role: " + roleName);
}
return added;
}
继续跟踪代码:
mRoleManager.addRoleHolderFromController(roleName, packageName);
RoleManager addRoleHolderFromController
这里直接贴出源码
/**
* Add a specific application to the holders of a role, only modifying records inside
* {@link RoleManager}. Should only be called from
* {@link android.app.role.RoleControllerService}.
* <p>
* <strong>Note:</strong> Using this API requires holding
* {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}.
*
* @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
*
* @return whether the operation was successful, and will also be {@code true} if a matching
* role holder is already found.
*
* @see #getRoleHolders(String)
* @see #removeRoleHolderFromController(String, String)
*
* @deprecated This is only usable by the role controller service, which is an internal
* implementation detail inside role.
*
* @hide
*/
@Deprecated
@RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
@SystemApi
public boolean addRoleHolderFromController(@NonNull String roleName,
@NonNull String packageName) {
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
try {
return mService.addRoleHolderFromController(roleName, packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
这里又要开始追踪 mService 了 。
看构造方法:
/**
* Create a new instance of this class.
*
* @param context the {@link Context}
* @param service the {@link IRoleManager} service
*
* @hide
*/
public RoleManager(@NonNull Context context, @NonNull IRoleManager service) {
mContext = context;
mService = service;
}
追踪 mService 定义:
@NonNull
private final IRoleManager mService;
上面再追踪 IRoleManager 时候,已经分析了这是一个aidl 接口调用,最终实现是 RoleService。
所以上面的 mService.addRoleHolderFromController(roleName, packageName); 最总到
RoleService -> addRoleHolderFromController
RoleService
addRoleHolderFromController
源码如下:
@Override
public boolean addRoleHolderFromController(@NonNull String roleName,
@NonNull String packageName) {
getContext().enforceCallingOrSelfPermission(
RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
"addRoleHolderFromController");
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
int userId = UserHandleCompat.getUserId(Binder.getCallingUid());
return getOrCreateUserState(userId).addRoleHolder(roleName, packageName);
}
getOrCreateUserState
private RoleUserState getOrCreateUserState(@UserIdInt int userId) {
synchronized (mLock) {
RoleUserState userState = mUserStates.get(userId);
if (userState == null) {
userState = new RoleUserState(userId, mPlatformHelper, this);
mUserStates.put(userId, userState);
}
return userState;
}
}
这个方法返回的实例是什么,RoleUserState ,那不就是调用功能 RoleUserState 的 addRoleHolder 方法了嘛
RoleUserState ->addRoleHolder
/**
* Add a holder to a role.
*
* @param roleName the name of the role to add the holder to
* @param packageName the package name of the new holder
*
* @return {@code false} if and only if the role is not found
*/
@CheckResult
public boolean addRoleHolder(@NonNull String roleName, @NonNull String packageName) {
boolean changed;
synchronized (mLock) {
......
changed = roleHolders.add(packageName);
if (changed) {
scheduleWriteFileLocked();
}
}
if (changed) {
mCallback.onRoleHoldersChanged(roleName, mUserId);
}
return true;
}
scheduleWriteFileLocked
/**
* Schedule writing the state to file.
*/
@GuardedBy("mLock")
private void scheduleWriteFileLocked() {
if (mDestroyed) {
return;
}
if (!mWriteScheduled) {
mWriteHandler.postDelayed(this::writeFile, WRITE_DELAY_MILLIS);
mWriteScheduled = true;
}
}
writeFile
@WorkerThread
private void writeFile() {
RolesState roles;
synchronized (mLock) {
if (mDestroyed) {
return;
}
mWriteScheduled = false;
roles = new RolesState(mVersion, mPackagesHash,
(Map<String, Set<String>>) (Map<String, ?>) snapshotRolesLocked());
}
mPersistence.writeForUser(roles, UserHandle.of(mUserId));
}
继续跟踪 mPersistence,如下定义:
private final RolesPersistence mPersistence = RolesPersistence.createInstance();
如下 看RolesPersistence 源码,是一个接口,那么就找实现类:RolesPersistenceImpl
RolesPersistenceImpl ->writeForUser
终于到头了,这里看到XML 解析并写文件
getFile 方法
@NonNull
private static File getFile(@NonNull UserHandle user) {
ApexEnvironment apexEnvironment = ApexEnvironment.getApexEnvironment(APEX_MODULE_NAME);
File dataDirectory = apexEnvironment.getDeviceProtectedDataDirForUser(user);
return new File(dataDirectory, ROLES_FILE_NAME);
}
看看 这个类的参数定义:
public class RolesPersistenceImpl implements RolesPersistence {
private static final String LOG_TAG = RolesPersistenceImpl.class.getSimpleName();
private static final String APEX_MODULE_NAME = "com.android.permission";
private static final String ROLES_FILE_NAME = "roles.xml";
那么我继续看看 roles.xml 是什么
roles.xml
位置
./vendor/mediatek/proprietary/packages/apps/PermissionController/res/xml/roles.xml
./vendor/mediatek/proprietary/packages/apps/PermissionController/tests/mocking/main_res/xml/roles.xml
这里举例HOME 相关的Launcher 部分,方便分析:
<role
name="android.app.role.HOME"
behavior="HomeRoleBehavior"
description="@string/role_home_description"
exclusive="true"
label="@string/role_home_label"
overrideUserWhenGranting="true"
requestDescription="@string/role_home_request_description"
requestTitle="@string/role_home_request_title"
searchKeywords="@string/role_home_search_keywords"
shortLabel="@string/role_home_short_label">
<!-- Also used by HomeRoleBehavior.getFallbackHolder(). -->
<required-components>
<activity>
<intent-filter>
<action name="android.intent.action.MAIN" />
<category name="android.intent.category.HOME" />
</intent-filter>
</activity>
</required-components>
<preferred-activities>
<preferred-activity>
<activity>
<intent-filter>
<action name="android.intent.action.MAIN" />
<category name="android.intent.category.HOME" />
</intent-filter>
</activity>
<intent-filter>
<action name="android.intent.action.MAIN" />
<category name="android.intent.category.HOME" />
</intent-filter>
</preferred-activity>
</preferred-activities>
</role>
看name 属性,不就是 如上分析RoleManager 里面 如下方法的role 参数值嘛:
roleManager.addRoleHolderAsUser(roleName, packageName, flags, user, executor, callback);
小结
Launcher 指定默认流程总结
所以,整套流程分析下来,设置默认App,这里HomeLauncher 举例,核心逻辑就是给包名一个role 权限,然后写入到文件,最后同步一次,通知系统。
指定其它默认App 方案
通过Launcher 的举例,默认其它App 作为默认的逻辑,比如默认浏览器、打电话、短信… 等,看一下 roles.xml 文件中定义的role name 是什么。 最终实现方案如上通过反射传递 packageName 和 role Name 不就可以了嘛。
总结
- 如上分析了一整套默认Launcher 的代码逻辑业务,同理对于默认浏览器、短信、打电话等完全适用。
- 通过反射实现 想要的功能,反射RoleManager 类,的addRoleHolderAsUser 方法比较合适,而且有回调。 整个流程里面发现其它类的调用并不合适
扩展知识
上面 动态实现了自己想要的功能,可以集成到framework层的服务里面对外提供接口来用,也可以最简单方式 让应用端直接反射实现。 那么有木有可能adb 命令来实现上面的需求呢?
adb 命令来动态设置默认的Launcher
实现方案如下:
pm set-home-activity com.zeasn.whale.saas.touch[需要设置Launcher的包名]
adb 命令实现思考
adb 为什么可以实现? 我们在上面分析了几个aidl 接口串来串去,其实adb 命令系统提供了支持。
如下截图 部分源码分享:
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;
}
}
其实最终调用的也是 RoleManager 的 addRoleHolderAsUser 方法来实现的。