参考博客,很详细,值得一看,查看点击
车机整机开发有主题壁纸商店。需要满足动态切换资源。选择使用overlay机制实现。和手机上不同的是,使用主题后,指定的所有应用内的资源都需要替换。
video-overlay
目录结构
里面只有资源文件,无代码。需要系统签名。当然资源文件名称,要和目标项目资源名称一致。
清单文件配置
添加overlay 标签,制定目标应用包名。更多标签内容介绍,可以详细百度。这样Overlay apk 就做好了。
安装好之后,可以用命令查看 adb shell dumpsys overlay
mIsEnabled 是false ,目前还没有生效,生效和失效的adb命令:
adb shell cmd overlay enable com.example.themoverlaydemo
adb shell cmd overlay disable com.example.themoverlaydemo
启动后mIsEnabled 就会变成true。接收命令的类是OverlayManagerShellCommand,路径/homeframeworks/base/services/core/java/com/android/server/om
<string-array translatable="false" name="config_xxxxxtargetpackages">
<item>com.android.systemuiitem>
<item>com.android.launcheritem>
<item>com.xxxxx.appanelitem>
<item>com.xxxxx.themestoreitem>
<item>com.xxxxx.mediaitem>
<item>com.xxxxx.airconditionitem>
<item>com.android.systemui.pluginitem>
string-array>
frameworks/base/core/res/res/values/symbols.xml 中添加array名称
<java-symbol type="array" name="config_simbatargetpackages" />
public OverlayManagerService(@NonNull final Context context,
@NonNull final Installer installer) {
super(context);
mSettingsFile =
new AtomicFile(new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays");
mPackageManager = new PackageManagerHelper();
mUserManager = UserManagerService.getInstance();
//获取配置的目标列表
mSimbaOverlayTarget = new ArrayList<String>(Arrays.asList(context.getResources().getStringArray(
com.android.internal.R.array.config_simbatargetpackages)));
IdmapManager im = new IdmapManager(installer);
mSettings = new OverlayManagerSettings();
mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
getDefaultOverlayPackages(), new OverlayChangeListener());
//把目标设置给代理
mImpl.setROMTargetPackages(mSimbaOverlayTarget);
mInitCompleteSignal = SystemServerInitThreadPool.get().submit(() -> {
final IntentFilter packageFilter = new IntentFilter();
packageFilter.addAction(ACTION_PACKAGE_ADDED);
packageFilter.addAction(ACTION_PACKAGE_CHANGED);
packageFilter.addAction(ACTION_PACKAGE_REMOVED);
packageFilter.addDataScheme("package");
// 安装包广播
getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL,
packageFilter, null, null);
final IntentFilter userFilter = new IntentFilter();
userFilter.addAction(ACTION_USER_ADDED);
userFilter.addAction(ACTION_USER_REMOVED);
//用户广播
getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
userFilter, null, null);
restoreSettings();
mImpl.initTargetCodeBasePath();
initIfNeeded();
onSwitchUser(UserHandle.USER_SYSTEM);
publishBinderService(Context.OVERLAY_SERVICE, mService);
publishLocalService(OverlayManagerService.class, this);
}, "Init OverlayManagerService");
}
先获取配置的目标列表,然后设置给OverlayManagerServiceImpl,这个类坐了很多操作。并且上面注册了包安装的广播,和用户切换的广播。
private final class PackageReceiver extends BroadcastReceiver {
@Override
public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
//----省略
switch (intent.getAction()) {
case ACTION_PACKAGE_ADDED:
//升级和add应用包
if (replacing) {
onPackageUpgraded(packageName, userIds);
} else {
onPackageAdded(packageName, userIds);
}
break;
case ACTION_PACKAGE_CHANGED:
onPackageChanged(packageName, userIds);
break;
case ACTION_PACKAGE_REMOVED:
if (replacing) {
onPackageUpgrading(packageName, userIds);
} else {
onPackageRemoved(packageName, userIds);
}
break;
default:
// do nothing
break;
}
}
private void onPackageAdded(@NonNull final String packageName,
@NonNull final int[] userIds) {
//----省略
if (pi.isOverlayPackage()) {
//调用OverlayManagerServiceImpl
mImpl.onOverlayPackageAdded(packageName, userId);
} else {
mImpl.onTargetPackageAdded(packageName, userId);
}
}
}
}
}
我想在安装成功后就让他生效,调用到OverlayManagerServiceImpl 的onOverlayPackageAdded方法
void onOverlayPackageAdded(@NonNull final String packageName, final int userId) {
//-----省略
//通过安装的overlay apk 获取包信息
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
if (overlayPackage == null) {
Slog.w(TAG, "overlay package " + packageName + " was added, but couldn't be found");
onOverlayPackageRemoved(packageName, userId);
return;
}
//获取目标包,需要做处理,如果是自己的overlay apk 就返回配置的目标列表
final ArrayList<String> overlayTargets = getOverlayTargetList(overlayPackage);
if (isXXXXOverlayApk(packageName)) {
//如果之前设置了自己的一款主题,先disable
filterOutAndDisableOverlayForXXXXTargetApp(packageName, overlayTargets, userId);
}
for (String overlayTarget: overlayTargets) {
//遍历目标初始化生成idmap映射
mSettings.init(packageName, userId, overlayTarget,
overlayPackage.applicationInfo.getBaseCodePath(),
overlayPackage.isStaticOverlayPackage(), overlayPackage.overlayPriority,
overlayPackage.overlayCategory);
if (isXXXXOverlayApk(packageName)) {
//如果安装的是自己的主题包,就直接设置生效
mSettings.setEnabled(packageName, overlayTarget, userId, true);
}
try {
if (updateState(overlayTarget, packageName, userId, 0)) {
mListener.onOverlaysChanged(overlayTarget, userId);
}
} catch (OverlayManagerSettings.BadKeyException e) {
Slog.e(TAG, "failed to update settings", e);
mSettings.remove(packageName, userId);
}
}
}
当安装了包之后,先获取主题包信息,并获取目标列表,如果是自己开发的主题包,先取消原来的,再设置新的生效。
获取目标列表:
private ArrayList<String> getOverlayTargetList(PackageInfo overlayPackage) {
final ArrayList<String> overlayTarget = new ArrayList<>();
if (isXXXXOverlayApk(overlayPackage.packageName)) {
// 自己的主题包,就返回配置目标的列表
overlayTarget.addAll(mXXXXOverlayTarget);
} else {
overlayTarget.add(overlayPackage.overlayTarget);
}
return overlayTarget;
}
取消原来的:
private void filterOutAndDisableOverlayForXXXXTargetApp(String overlayPackageName,
ArrayList<String> simbaTargets, final int userId) {
for (String simbaTarget : simbaTargets) {
Slog.d(TAG, "filter out check target name " + simbaTarget);
List<OverlayInfo> overlayInfos = mSettings.getOverlayByTargetName(overlayPackageName, simbaTarget, userId);
if (overlayInfos == null) {
continue;
}
Slog.d(TAG, "filter out results " + overlayInfos.size());
for (OverlayInfo oi: overlayInfos) {
Slog.d(TAG, "to change disable " + oi.packageName + " - " + oi.targetPackageName + " " +oi.isEnabled());
if (oi.isEnabled()) {
mSettings.setEnabled(oi.packageName, oi.targetPackageName, userId, false);
mSettings.setState(oi.packageName, oi.targetPackageName, userId, OverlayInfo.STATE_DISABLED);
}
}
}
}
至此就大功告成。应用升级、删除这些也都需要对应的处理。原理和流程,可以看看文章最开始的链接,写的很不错,点赞。