欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android9.0 Settings 修改踩坑记录

程序员文章站 2022-03-13 20:21:00
问题现象 上图展示的很清楚,当系统语言为中文时,PreferenceScreen 中的折叠项 summary 描述重复显示的 bug,系统语言为英文时正常。 修改历程 先搜索 当前显示了 字符串,还真找到了 prebuilts\sdk\current\support\v7\preference\re ......

问题现象

Android9.0 Settings 修改踩坑记录

上图展示的很清楚,当系统语言为中文时,preferencescreen 中的折叠项 summary 描述重复显示的 bug,系统语言为英文时正常。

修改历程

先搜索 当前显示了 字符串,还真找到了

prebuilts\sdk\current\support\v7\preference\res\values-zh-rcn\values-zh-rcn.xml

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:ns1="urn:oasis:names:tc:xliff:document:1.2">
    <string msgid="3265458434114353660" name="expand_button_title">"高级"</string>
    <string msgid="5255557321652385027" name="summary_collapsed_preference_list">"当前显示了 <ns1:g id="current_items">%1$s</ns1:g> 项(已添加 <ns1:g id="added_items">%2$s</ns1:g> 项)"</string>
    <string msgid="2082379519172883894" name="v7_preference_off">"关闭"</string>
    <string msgid="7922757586228621900" name="v7_preference_on">"开启"</string>
</resources>

再接着搜索 summary_collapsed_preference_list,又找到如下的地方

Android9.0 Settings 修改踩坑记录

看着 androidtest 相关的可以忽略,直接看 collapsiblepreferencegroupcontroller.java
frameworks\support\preference\src\main\java\androidx\preference\collapsiblepreferencegroupcontroller.java

private void setsummary(list<preference> collapsedpreferences) {
            charsequence summary = null;
            final list<preferencegroup> parents = new arraylist<>();

            for (preference preference : collapsedpreferences) {
                final charsequence title = preference.gettitle();
                if (preference instanceof preferencegroup && !textutils.isempty(title)) {
                    parents.add((preferencegroup) preference);
                }
                if (parents.contains(preference.getparent())) {
                    if (preference instanceof preferencegroup) {
                        parents.add((preferencegroup) preference);
                    }
                    continue;
                }
                if (!textutils.isempty(title)) {
                    if (summary == null) {
                        summary = title;
                    } else {
                        summary = getcontext().getstring(
                                r.string.summary_collapsed_preference_list, summary, title);
                    }
                }
            }
            setsummary(summary);
        }

哈,这下证实了 bug 的由来,summary_collapsed_preference_list 字符串经过格式化 for 循环的叠加自然会出现 当前显示了 当前显示了 当前显示了....

那就简单了,把 summary_collapsed_preference_list 对应的中文字符串修改了就行呗,但是事情没有那么简单,经过修改重新编译测试 bug 依旧,然后又继续搜索,

在 out 目录下还发现了另一个 当前显示了 字符串,文件内容和 prebuilts 下的是一模一样的,但是文件时间却是 2018-05-25 06:04

Android9.0 Settings 修改踩坑记录

这就很诡异了,感觉此路不通啊,那好吧,乖乖去捋一捋源码吧

经过简单的分析,找到 settings 中的 highlightablepreferencegroupadapter

vendor\mediatek\proprietary\packages\apps\mtksettings\src\com\android\settings\widget\highlightablepreferencegroupadapter.java

import android.support.v7.preference.preferencegroup;
import android.support.v7.preference.preferencegroupadapter;
import android.support.v7.preference.preferencescreen;
import android.support.v7.preference.preferenceviewholder;
import android.support.v7.widget.recyclerview;
import android.text.textutils;
import android.util.log;
import android.util.typedvalue;
import android.view.view;

import com.android.settings.r;
import com.android.settings.settingspreferencefragment;

public class highlightablepreferencegroupadapter extends preferencegroupadapter {

可以看到继承的是 preferencegroupadapter,而且还是 v7 包下面的,继续搜索 preferencegroupadapter.java

Android9.0 Settings 修改踩坑记录

https://segmentfault.com/a/1190000020956652

对比 8.1 和 9.0 一看,9.0 已经没有 v7 包支持了,而是改用 androidx 替代,具体介绍可看 preference组件探究之base,support及androidx对比

难怪我们上面修改 summary_collapsed_preference_list 没用,上面调用的类 collapsiblepreferencegroupcontroller 也是在 androidx 包下,查看 settings 下的 mk

local_static_android_libraries := \
    android-slices-builders \
    android-slices-core \
    android-slices-view \
    android-support-compat \
    android-support-v4 \
    android-support-v13 \
    android-support-v7-appcompat \
    android-support-v7-cardview \
    android-support-v7-preference \
    android-support-v7-recyclerview \
    android-support-v14-preference \

android-support-v7-preference 导入静态库,而源码中并没有对应的目录,已经替代为 androidx,悲催了,这下想改资源文件解决bug看来是不行了。

看了下 android10.0 下 settings 的 mk,发现已经全部替换为 androidx

android.mk

local_static_android_libraries := \
    androidx-constraintlayout_constraintlayout \
    androidx.slice_slice-builders \
    androidx.slice_slice-core \
    androidx.slice_slice-view \
    androidx.core_core \
    androidx.appcompat_appcompat \
    androidx.cardview_cardview \
    androidx.preference_preference \
    androidx.recyclerview_recyclerview \
    com.google.android.material_material \
    setupcompat \
    setupdesign

解决办法

通过进一步分析,找到一个关键字段 initialexpandedchildrencount

vendor\mediatek\proprietary\packages\apps\mtksettings\res\xml\network_and_internet.xml

<preferencescreen
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:settings="http://schemas.android.com/apk/res-auto"
    android:key="network_and_internet_screen"
    android:title="@string/network_dashboard_title"
    settings:initialexpandedchildrencount="5">

该字段在 preferencegroup 中获取并赋值,用来区分当前 preference 要显示的数量,剩余的需要折叠显示

frameworks\support\preference\src\main\java\androidx\preference\preferencegroup.java

public preferencegroup(context context, attributeset attrs, int defstyleattr, int defstyleres) {
        super(context, attrs, defstyleattr, defstyleres);

        mpreferencelist = new arraylist<>();

        final typedarray a = context.obtainstyledattributes(
                attrs, r.styleable.preferencegroup, defstyleattr, defstyleres);

        morderingasadded =
                typedarrayutils.getboolean(a, r.styleable.preferencegroup_orderingfromxml,
                        r.styleable.preferencegroup_orderingfromxml, true);

        if (a.hasvalue(r.styleable.preferencegroup_initialexpandedchildrencount)) {
            setinitialexpandedchildrencount((typedarrayutils.getint(
                    a, r.styleable.preferencegroup_initialexpandedchildrencount,
                    r.styleable.preferencegroup_initialexpandedchildrencount, integer.max_value)));
        }
        a.recycle();
    }

最终在 collapsiblepreferencegroupcontroller 中读取该字段,判断是否需要添加 expandbutton 即高级折叠下拉按钮

所以我们只需要将 initialexpandedchildrencount 设置成最大即可,preference 将不再折叠,当然这是一种偷懒的做法,这样会失去原来的用户体验

vendor\mediatek\proprietary\packages\apps\mtksettings\src\com\android\settings\widget\highlightablepreferencegroupadapter.java

/**
     * tries to override initial expanded child count.
     * <p/>
     * initial expanded child count will be ignored if:
     * 1. fragment contains request to highlight a particular row.
     * 2. count value is invalid.
     */
    public static void adjustinitialexpandedchildcount(settingspreferencefragment host) {
        log.e("highlightablepreferencegroupadapter"," adjustinitialexpandedchildcount()");
        if (host == null) {
            return;
        }
        final preferencescreen screen = host.getpreferencescreen();
        if (screen == null) {
            return;
        }
        final bundle arguments = host.getarguments();
        if (arguments != null) {
            final string highlightkey = arguments.getstring(extra_fragment_arg_key);
            if (!textutils.isempty(highlightkey)) {
                // has highlight row - expand everything
                screen.setinitialexpandedchildrencount(integer.max_value);
                return;
            }
        }

        final int initialcount = host.getinitialexpandedchildcount();
        //cczheng add for expand everything preference s
        log.e("highlightablepreferencegroupadapter","initialcount="+initialcount);
        if (true) {
            screen.setinitialexpandedchildrencount(integer.max_value);
            return;
        }
        //e 
        if (initialcount <= 0) {
            return;
        }
        screen.setinitialexpandedchildrencount(initialcount);
    }