Android14 Settings应用添加有线网开关条目实现

Android14 Settings应用添加有线网开关条目

文章目录

一、前言

背景:

Android 原生Settings应用没有有线网开关条目;

Tv平台一般是有有线网连接的,如果没有有线网控制条目是不太方便的;

如果要在原生Settings添加有线网开关和显示有线网ip,要如何实现呢?

目前主要的商显TV中,只有我开发的方案中有些原生设置Settings 在某些方案上有修改了原生Settings的添加有线网开关控制,视源、朗国、创维、三星那些都是没修改的。

本文简单实现一下,有需要的可以参考修改。

二、适配修改

1、network_provider_settings.xml

在布局文件添加一个有线网开关UI条目控制;

这个布局文件是点击二级菜单"互联网"显示的界面主要包含条目内容:

有线网提示(接入有线网才有),飞行模式提示(开启飞行模式才有),

Wifi开关、Wifi列表、添加网络按键,网络偏好设置,已保存的网络。

Settings\res\xml\network_provider_settings.xml

复制代码
    //原本有的有线网提示
   <Preference
        android:key="connected_ethernet_network"
        android:title="@string/ethernet"
        android:summary="@string/to_switch_networks_disconnect_ethernet"
        android:icon="@drawable/ic_settings_ethernet"/>
    
    //新增的有线网开关条目
+    <SwitchPreference
+        android:key="ethernet_turn_off"
+        android:title="@string/ethernet" />

    //飞行模式提示
    <PreferenceCategory
        android:key="provider_model_mobile_network"
        android:title="@string/summary_placeholder"
        android:layout="@layout/preference_category_no_label"
        settings:isPreferenceVisible="@bool/config_show_sim_info"
        settings:controller="com.android.settings.network.NetworkMobileProviderController"/>

    //Wifi开关
    <com.android.settingslib.RestrictedSwitchPreference
        android:key="main_toggle_wifi"
        android:title="@string/wifi"
        settings:keywords="@string/keywords_wifi"
        settings:allowDividerAbove="true"/>

    //已连接的Wifi ?
    <PreferenceCategory
        android:key="connected_access_point"
        android:layout="@layout/preference_category_no_label"/>
    //保持状态的Wifi列表 ?
    <PreferenceCategory
        android:key="first_access_points"
        android:layout="@layout/preference_category_no_label"/>
    //剩余的扫描到的的Wifi列表 ?
    <PreferenceCategory
        android:key="access_points"
        android:layout="@layout/preference_category_no_label"/>

    //网络偏好设置
    <Preference
        android:key="configure_network_settings"
        android:title="@string/network_and_internet_preferences_title"
        settings:allowDividerAbove="true"
        android:fragment="com.android.settings.wifi.ConfigureWifiSettings"/>

    //已保存的网络
    <Preference
        android:key="saved_networks"
        android:title="@string/wifi_saved_access_points_label"
        android:fragment="com.android.settings.wifi.savedaccesspoints2.SavedAccessPointsWifiSettings2"/>

res/value 的资源文件:

复制代码
//英文
    <string name="to_switch_networks_disconnect_ethernet">To switch networks, disconnect ethernet</string>
//中文
    <string name="to_switch_networks_disconnect_ethernet" msgid="6615374552827587197">"如要切换网络,请拔出以太网网线"</string>

Android 原生应用没有有线网开关控制,有线网连接后,

如果正常获取到有线网ip,是有线使用有线网的,无法正常连接Wifi网络,

所以会友情提示"如要切换网络,请拔出有线网".

2、NetworkProviderSettings.java

Wifi开关和Wifi列表显示都在这个类。

复制代码
import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;

/**
 * UI for Mobile network and Wi-Fi network settings.
 */
@SearchIndexable
public class NetworkProviderSettings extends RestrictedSettingsFragment ...{


    ConnectedEthernetNetworkController mConnectedEthernetNetworkController;

+    TurnOnOffEthernetNetworkController mTurnOnOffEthernetNetworkController;


    private void addPreferences() {
...
        addConnectedEthernetNetworkController();
+        addTurnOnOffEthernetNetworkController();

    }


    //add by liwenzhi  ++++ 下面这个方法是添加的
    //主要就是开关监听,调用方法
    private void addTurnOnOffEthernetNetworkController() {
        if (mTurnOnOffEthernetNetworkController == null) {
            mTurnOnOffEthernetNetworkController =
                    new TurnOnOffEthernetNetworkController(getContext(), TurnOnOffEthernetNetworkController.KEY);
        }
        SwitchPreference  switchPreference = (SwitchPreference) findPreference("ethernet_turn_off");
        mTurnOnOffEthernetNetworkController.updateState(switchPreference);
        switchPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
            @Override
            public boolean onPreferenceChange(Preference preference, Object newValue) {
                boolean isCheck = (boolean) newValue;
                Log.i(TAG, "onPreferenceChange preference = " + preference + ", isCheck = " + isCheck);
                mTurnOnOffEthernetNetworkController.onPreferenceChange(preference, newValue);
                return true;
            }
        });
    }


    public void onStart() {
        super.onStart();
+        mTurnOnOffEthernetNetworkController.onStart(); //主要用来广播监听 + 更新有线网ip
    }

    @Override
    public void onStop() {
+        mTurnOnOffEthernetNetworkController.onStop(); //停止广播监听
    }

}

3、TurnOnOffEthernetNetworkController.java

复制代码
package com.android.settings.network;

import static com.android.settings.network.InternetUpdater.INTERNET_ETHERNET;

import android.content.Context;
import android.util.Log;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.EthernetManager;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkInfo;
import android.os.Handler;
import android.provider.Settings;
import android.text.TextUtils;

import androidx.preference.Preference;
import androidx.preference.SwitchPreference;

import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;

/**
 * PreferenceController to show the connected ethernet network turn on /off.
 * 自定义添加的有线网开关
 */
public class TurnOnOffEthernetNetworkController extends BasePreferenceController implements
        Preference.OnPreferenceChangeListener {

    private static final String TAG = "TurnOnOffEthernetNetworkController";
    private static final String NET_CHANGE_ACTION = ConnectivityManager.CONNECTIVITY_ACTION; //所有网络变化广播
    private static final String ETHERNET_STATE_CHANGE = "action.ebsw.eth.status.change"; //底层自定义有线网络插拔广播(并非共用的,是底层自己开发的)

    public static final String KEY = "ethernet_turn_off";

    private Context mContext;
    private Preference mPreference;
    private SettingsValueChangeContentObserver mContentOb; //监听 Settings ethernet_on

    public TurnOnOffEthernetNetworkController(Context context, String preferenceKey) {
        super(context, preferenceKey);
        Log.i(TAG, "TurnOnOffEthernetNetworkController preferenceKey  = " + preferenceKey);
        mContext = context;
        //注册监听Settings.Global.ETHERNET_ON 属性变化
        mContentOb = new SettingsValueChangeContentObserver();
        context.getContentResolver().registerContentObserver(Settings.System.getUriFor("ethernet_on"), true, mContentOb);//注册监听
    }


    @Override
    public String getPreferenceKey() {
        return KEY;
    }

    @Override
    public int getAvailabilityStatus() {
        return AVAILABLE;
    }

    //自定义的,非原生
    public void updateState(Preference preference) {
        Log.i(TAG, "updateState preference = " + preference);
        final boolean settingsOn = isEthernetEnabled(mContext);
        Log.i(TAG, "updateState settingsOn = " + settingsOn);
        ((SwitchPreference) preference).setChecked(settingsOn);
        mPreference = preference;
        //mPreference.setSummary("on/off:" + settingsOn); //test
        updateEthernetIp();
    }

    //自定义的,非原生
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        final boolean settingsOn = (Boolean) newValue;
        Log.i(TAG, "onPreferenceChange settingsOn = " + settingsOn);
        return enableEthernet(mContext, settingsOn);
    }

    public boolean enableEthernet(Context context, boolean enabled) {
        Log.i(TAG, "enableEthernet enabled = " + enabled);
        EthernetManager ethernetManager = (EthernetManager) context.getSystemService(Context.ETHERNET_SERVICE);
        ethernetManager.setEthernetEnabled(enabled);
        Settings.Global.putInt(context.getContentResolver(),
                "ethernet_on", enabled? EthernetManager.ETHERNET_STATE_ENABLED:EthernetManager.ETHERNET_STATE_DISABLED);
        return true;
    }

    public boolean isEthernetEnabled(Context context) {
        Log.i(TAG, "isEthernetEnabled.");
        int ethernetSate = 0;
        final ContentResolver cr = context.getContentResolver();
        try {
            ethernetSate = Settings.Global.getInt(cr, "ethernet_on", EthernetManager.ETHERNET_STATE_ENABLED);
        } catch (Exception e) {
            ethernetSate = EthernetManager.ETHERNET_STATE_DISABLED;
        }
        return ethernetSate == EthernetManager.ETHERNET_STATE_ENABLED;
    }

注意 :Settings.Global.ETHERNET_ON 属性在 Android8之后的版本好像就没有了;

如果需要全局定义可以自己在Settings.java源码中添加定义;

其实也可以不用定义,直接使用 "etherent_on"字符串就行;也是一样能监听变化能记忆能使用;

也可以使用prop属性记录有线网开关状态,不过不方便监听状态变化。

4、去除有线网提示条目。

Settings\src\com\android\settings\network\ConnectedEthernetNetworkController.java

复制代码
    @Override
    public boolean isAvailable() {
-        return mInternetType == INTERNET_ETHERNET;
+        //not to show this item ,change by liwenzhi
+        return false;
    }

代码修改可以动态设置显示或者隐藏,通过某些状态或者prop属性;

如果不想改Java代码,应该是可以在xml文件中直接去除 key="connected_ethernet_network" 条目那项。

5、效果UI

(1)修改前效果

未接入有线网的情况的显示:

这个是最普通的正常情况的显示。

接入有线网的情况下的显示:

可以看到这里就提示了让你拔掉有线网,是不是比较low。

默认情况,wifi和有线网连接是不兼容的,有线网优先级高于wifi,

所以优先连接的是有线网;如果拔出有线网,是会自动连接wifi的;

如果有需求也是可以修改系统源码,设置有线网和wifi共存,同时连接的。

(2)修改后效果

有线网开关开启并且接入有线网:

这里查看简单明了的,显示了有线网开关和有线网ip地址。

有线网开关关闭:

这里可以看到有线网关闭后,Wif是可以连接的;

如果打开有线网开关,但是未接入有线网插头,也是能连接wifi的,只是有线网那里并不显示ip地址。

三、其他

1、Android Settings应用添加有线网开关条目小结

(1)主要修改适配的代码:
复制代码
network_provider_settings.xml //有线网开关条目的添加
NetworkProviderSettings.java //有线网开关条目的关联
TurnOnOffEthernetNetworkController.java //+自定义的有线网控制显示类
ConnectedEthernetNetworkController.java //有线网默认提示是否显示

这里是添加有线网开关设置在三级目录里面,

也可以添加在二级目录里面,和Wifi、飞行模式、热点共享同级目录下;

2、关于不同Android系统版本原生Settings Wifi条目的获取代码

查看了Wifi列表获取的代码是有较大差异的:

复制代码
Android9 或者更低的版本使用的是:
List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();

Android11 或者更新的版本获取Wifi使用的是:
List<WifiEntry> wifiEntries = mWifiPickerTracker.getWifiEntries();

因为 AccessPoint 过时了,所以使用的是 WifiEntry;
AccessPoint 是系统SettingsLib包封装的对象,WifiEntry 是系统framework包的对象;

使用 WifiEntry 对象似乎是为了更容易适配Settings应用的 Preference 布局控件。

无论是AccessPoint还是WifiEntry,都是有暴露 getWifiConfiguration()方法获取都某个Wifi的配置信息WifiConfiguration对象。

我这里自定义开发的设置应用从Android7开始一直是使用 AccessPoint 那套显示和连接Wifi,没啥大问题;

也有一个方案出现过列表不显示某个已连接的隐藏Wifi的情况,直接修改的SettingsLib源码解决的。

4、Android13 有线网开关研究

Android13 的api 提供了有线网开关 EthernetManager.setEthernetEnabled(boolean),

Android9 如果要设置有线网开关,需要自己实现。

https://blog.csdn.net/wenzhi20102321/article/details/131871354

5、Android AccessPoint 已连接的wifi信息未显示处理

一个wifi列表未显示已连接的wifi信息问题记录。

本文最后又原生Settings 的Wifi列表界面显示分析,有兴趣的可以看看。

https://blog.csdn.net/wenzhi20102321/article/details/146536423

相关推荐
BingoGo20 小时前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack20 小时前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端
BingoGo2 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php
JaguarJack2 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php·服务端
JaguarJack3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
JaguarJack4 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel
郑州光合科技余经理4 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
feifeigo1234 天前
matlab画图工具
开发语言·matlab
dustcell.4 天前
haproxy七层代理
java·开发语言·前端