Android Q - Settings 页面添加二级选项

简单记录下,本次修改为网络设置中添加一个以太网的选项开关。效果如下:

与Android4.4相差较大,主要修改文件为,在以下路径 packages/apps/Settings 

  • res/values-zh-rCN/strings.xml
  • res/values/config.xml
  • res/xml/network_and_internet_v2.xml
  • src/com/android/settings/network/NetworkDashboardFragment.java
  • src/com/android/settings/network/EthernetPreferenceController.java(新建)
  • src/com/android/settings/utils/ReflectUtil.java(新建)

接下来按照我修改的逻辑进行说明:

1、修改布局文件

路径:res/xml/network_and_internet_v2.xml

说明:其中 order 绝对值越大越靠上,有些我这里未给出的资源可复制其他选项的资源,或者私信或评论我发送你;修改完以下部分你就会发现已经有这个选项了。

<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="6">    //原本这里是5

...

    <!--lichang add ethernet-->
    <com.android.settingslib.RestrictedSwitchPreference
        settings:controller="com.android.settings.network.EthernetPreferenceController"
        android:key="usb_ethernet"
        android:persistent="true"
        android:icon="@drawable/ic_setting_eth"    
        android:title="@string/settings_eth_tittle"   
        android:summary="@string/settings_eth_summary"
        android:order="-25" />    

...

2、资源文件

路径:res/values-zh-rCN/strings.xml

说明:这里主要是选项标题的一些中文显示,其实我也在 res/values/strings.xml 路径下修改了,但是感觉没啥必要在写一遍。我是直接在最后添加的。

...

    <!-- lichang add ethernet -->
    <string name="settings_eth_tittle">以太网</string>
    <string name="settings_eth_summary">关闭</string>
    <string name="settings_eth_open">开启</string>
    <string name="settings_eth_close">关闭</string>

</resources>

路径:res/values/config.xml

说明:配置文件,配置功能开关;由于本次是为了添加以太网的开关选项,因此在此处添加是否显示该选项的开关。

    <!-- Whether toggle_ethernet is available or not. -->
    <bool name="config_show_toggle_ethernet">true</bool>

 3、实现开关对应的功能

路径:src/com/android/settings/network/NetworkDashboardFragment.java

说明:简单阅读代码可以发现设置页面的功能实现都是由 preference + controller 实现的,而当前文件则是网络页面 controller 的加载或者说实例化(我这么理解应该没错吧~)。

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        /*UNISOC: Modify for bug1145683, We do not want to display an advanced button if
         * linking to this screen from condition @{*/
        Bundle args = getArguments();
        if (args != null) {
            if (!args.getBoolean(ARG_SHOW_EXPAND_BUTTON, true)) {
                mChildrenCount = Integer.MAX_VALUE;
            }
        }
        if (FeatureFlagPersistent.isEnabled(context, FeatureFlags.NETWORK_INTERNET_V2)) {
            // UNISOC:Improve the function of turning on and off the Sub
            use(MultiNetworkHeaderController.class).init(getSettingsLifecycle(),
                   getFragmentManager(), mChildrenCount);
        }
        /* @} */
        use(AirplaneModePreferenceController.class).setFragment(this);
        use(EthernetPreferenceController.class).setFragment(this);    //新加
    }

路径:src/com/android/settings/network/EthernetPreferenceController.java

说明:最终的实现应该都是在 controller 里实现的,由于本次添加的是开关,于是查看了下飞行模式的 controller 并进行了部分修改。开关以太网卡的方式为修改节点,但是搁主线程里看起来非常卡顿,因此使用了线程池,虽然看起来实际开关慢了一点,但不会出现卡顿的现象。这部分代码可直接删除,然后打印 log 即可。

然后说一下这个 preference 的保存方式,修改节点的方法并不能持久保存,在关机或重启之后,会恢复为默认值,所以加了一个开机监听,在开机后将判断条件修改为关。

最后说一下保存数据的方式,说真的,我不太理解,在退出页面后数据就被重置了,不得已改成 SystemProperties 读写数据。方法贴在后面。


/*
 * Copyright (C) 2016 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.settings.network;
import android.annotation.SuppressLint;
import com.android.settings.utils.ThreadPool;
import android.content.Context;
import android.content.pm.PackageManager;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.utils.ReflectUtil;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class EthernetPreferenceController extends TogglePreferenceController {
    private static final String TAG = "EthernetPreferenceController";
    private SwitchPreference mEthernetPreference;
    private Fragment mFragment;
    private final MetricsFeatureProvider mMetricsFeatureProvider;
    private Context mContext;
    public EthernetPreferenceController(Context context, String key) {
        super(context, key);
        mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
        mContext = context;
    }
    @Override
    public boolean handlePreferenceTreeClick(Preference preference) {
        android.util.Log.d(TAG, "handlePreferenceTreeClick: " + preference.getKey());
        if (TextUtils.equals(preference.getKey(), "usb_ethernet")) {
            changeState(!isChecked());
            return true;
        }
        return false;
    }
    public void setFragment(Fragment hostFragment) {
        mFragment = hostFragment;
    }
    @Override
    @AvailabilityStatus
    public int getAvailabilityStatus() {
        return isAvailable(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
    }
    public static boolean isAvailable(Context context) {
        return context.getResources().getBoolean(R.bool.config_show_toggle_ethernet)
                && !context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
    }
    @Override
    public void displayPreference(PreferenceScreen screen) {
        super.displayPreference(screen);
        if (isAvailable()) {
            mEthernetPreference = screen.findPreference(getPreferenceKey());
            android.util.Log.d(TAG, "displayPreference: " + isChecked());
            if (isChecked())
                mEthernetPreference.setSummary(mContext.getString(R.string.settings_eth_open));
            else
                mEthernetPreference.setSummary(mContext.getString(R.string.settings_eth_close));
            mEthernetPreference.setChecked(isChecked());
        }
    }
    @Override
    public boolean setChecked(boolean isChecked) {
        return false;
    }
    public void changeState(boolean state) {
        android.util.Log.d(TAG, "changeState to be = " + state);
        if (state) {
            ReflectUtil.setProperty("persist.flyscale.ethernet", "1");
            mEthernetPreference.setSummary(mContext.getString(R.string.settings_eth_open));
            mEthernetPreference.setChecked(true);
            ThreadPool.getInstance().execute(new Runnable() {
                @Override
                public void run() {
                    write("onnet");
                }
            });
        } else {
            ReflectUtil.setProperty("persist.flyscale.ethernet", "0");
            mEthernetPreference.setSummary(mContext.getString(R.string.settings_eth_close));
            mEthernetPreference.setChecked(false);
            ThreadPool.getInstance().execute(new Runnable() {
                @Override
                public void run() {
                    write("offnet");
                }
            });
        }
        android.util.Log.d(TAG, "changeState: currentState is = " + isChecked());
    }
    @Override
    public boolean isChecked() {
        return TextUtils.equals(ReflectUtil.getProperty("persist.flyscale.ethernet", "0"), "1");
    }

   //mode{onotg,offotg,onnet,offnet}
   private static void write(String mode){
        //这里根据需要自己写实现的功能吧
    }
}

package com.android.settings.utils;
import java.lang.reflect.Method;
public final class ReflectUtil {
    public static String getProperty(String key, String defaultValue) {
        String value = defaultValue;
        try {
            Class<?> c = Class.forName("android.os.SystemProperties");
            Method get = c.getMethod("get", String.class, String.class);
            value = (String)(get.invoke(c, key, defaultValue));
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            return value;
        }
    }
    public static void setProperty(String key, String value) {
        try {
            Class<?> c = Class.forName("android.os.SystemProperties");
            Method set = c.getMethod("set", String.class, String.class);
            set.invoke(c, key, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

总之,抛开我不太理解的地方,还是相对容易的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值