Anroid 9.0 主题实现方案--Runtime Resource Overlay

简单资源替换生效流程可以进行以下几步:

预制方式:

  1. 生成overlay apk;
  2. 将overlay apk push 到vendor/overlay目录下;
  3. 重启手机;
  4. 主题切换
  5. 此时若目标应用正在显示,Activity 会重新走生命周期,显示新的资源信息。

安装方式

  1. 生成overlay apk;
  2. 安装apk
  3. 重启手机;
  4. 主题切换
  5. 此时若目标应用正在显示,Activity 会重新走生命周期,显示新的资源信息。

生成overlay apk(Android studio)

假如手机预制 默认和theme1, theme2 3个主题

制作theme1主题流程如下

a. AS内新建项目,仅保留AndroidManifest.xml 和res目录下要替换的资源文件。

b. 用系统签名对overlay app 进行签名,保持签名一致。

以空调为例,车机空调包名为com.android.car.hvac,demo overlay app包名为com.abc.theme1.hvac(theme1主题 overlay apk 包名必须满足带”theme1“, 同理theme2主题overlay apk 包名必须带“theme2” )

代码结构图

android获取桌面壁纸 获取android主题资源_xml

AndroidManifest.xml

仅包含以下信息即可,其中targetPackage为要替换资源的app包名

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.abc.theme1.hvac">
    <overlay
        android:priority="9"
        android:targetPackage="com.android.car.hvac" />
</manifest>

res目录下仅保留需要替换的资源信息(values下的colors.xml , strings.xml , dimens.xml themes.xml等 和 drawables/xml目录下的资源, 不支持替换布局文件)

如colors.xml 中

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="hvac_icon_color">#00F5F5</color>
    <color name="hvac_background_color">#17ff26</color>
    <color name="hvac_fanspeed_bg_color">#ff1C21</color>
</resources>

常用adb命令

  1. 命令可以查看系统里面的overlay包以及包的状态。:

adb shell dumpsys overlay

  1. 设置每个资源包的状态,设置成enable就会立即生效,(具体命令可以到代码里面查到shellcommand)

adb exec-out cmd overlay enable com.abc.theme1.hvac

主要控制实现代码逻辑

控制模块Androidmanifest.xml 需要权限

<!-- Allows an app to set the theme overlay in /vendor/overlay
         being used.
         @hide  <p>Not for use by third-party applications.</p> -->
    <permission android:name="android.permission.MODIFY_THEME_OVERLAY"
                android:protectionLevel="signature" />
//获取每个主题的overlay 包名列表
private Map<String, List<OverlayInfo>> mOverlayInfoMap;
private List<String> mTheme1List = new ArrayList<String>(); //theme1 overlay pkgName list
private List<String> mTheme2List = new ArrayList<String>(); //theme2 overlay pkgName list

    public void getOverlayList() {
        IOverlayManager mOverlayManager  =        IOverlayManager.Stub.asInterface(ServiceManager.getService("overlay"));
        mTheme1List.clear();
        mTheme2List.clear();
        try {
            mOverlayInfoMap = mOverlayManager.getAllOverlays(0);
            for (List<OverlayInfo> overlayInfos : mOverlayInfoMap.values()) {
                for(int j = 0; j < overlayInfos.size(); j++) {
                    String overlayPackageName = overlayInfos.get(j).packageName;
                    if(overlayPackageName.contains("theme1")) {
                        mTheme1List.add(overlayPackageName);
                    } else if(overlayPackageName.contains("theme2")) {
                        mTheme2List.add(overlayPackageName);
                    }
                }
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
//设置应用选择哪一个主题
IOverlayManager mOverlayManager  =        IOverlayManager.Stub.asInterface(ServiceManager.getService("overlay"));

//setEnabledExclusive: enable 只有为true时才会起作用,
//会启用参数中的overlayPackage,禁用其他overlay package
mOverlayManager.setEnabledExclusive(overlayPackage, enable, userId);

//setEnabled: 针对参数中的overlayPackage 进行设置
mOverlayManager.setEnabled(overlayPackage, enable, userId);

android获取桌面壁纸 获取android主题资源_包名_02

设置时序图

备注

  1. 可以替换values下的colors.xml , strings.xml , dimens.xml themes.xml等 和 drawables/xml目录下的资源, 不支持替换布局文件
  2. 2s内完成替换
  3. 替换过程中添加窗口覆盖之前页面,以保证之前页面重新绘制屏幕不闪烁,当前demo 用窗口为只包含图片的View
  4. 预制主题apk 需放在目录 vendor/overlay下
  5. 主题生效逻辑为Activity 会重新启动,因此应用需关注后台应用Activity重新启动后相关信息是否和切换前相同(输入框信息默认仍然存在), 同时需要监听setting 数据库的变化更新虚浮窗口 等非Activity ;
  6. 待替换app 使用资源 路径位于 frameworks/support/car/ 的资源尚不支持替换 ==>使用frameworks/base/core/res下的资源或者应用本身内置资源