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

相关推荐
rqtz2 小时前
【C++指针】搭建起程序与内存深度交互的桥梁(下)
开发语言·c++·指针
AI让世界更懂你2 小时前
Python 包管理器 UV 全面介绍
开发语言·python·uv
IT猿手2 小时前
基于烟花算法(Fireworks Algorithm,FWA)及三次样条的机器人路径规划,50个场景任意选择,完整MATLAB代码
开发语言·算法·机器学习·matlab·机器人·无人机
厌世小晨宇yu.3 小时前
对Gpt关于泛型、Stream的提问
java·开发语言·gpt·ai
了一li3 小时前
2025年春招-Linux面经
开发语言·php
lllsure3 小时前
SpringMVC 拦截器(Interceptor)
java·开发语言·mysql
lsx2024063 小时前
MVC 文件夹:架构之美,开发之魂
开发语言
狂团商城小师妹4 小时前
经销商订货管理系统小程序PHP+uniapp
微信·微信小程序·小程序·uni-app·php·微信公众平台
陈陈爱java4 小时前
Java算法模板
java·开发语言·算法
郝YH是人间理想4 小时前
OpenCV基础——梯度计算、边缘检测、图像金字塔
开发语言·人工智能·python·opencv·计算机视觉