前言
android 源码中一般都自带DHCP上网的,静态IP上网是没有的。这就需要我们自己添加了,
因为之前搞过6.0的静态IP功能,同样是 MTK 平台的,差异还是有点大的,
对比分析修改完成了需求,特此分享一下,避免更多的人踩坑。
如果这篇文章帮到你,欢迎点赞和转发,请注明原文地址
Android8.1
先上效果图,毕竟没图你说个锤子
动图
如图所示在 settings 中增加以太网的配置项
1、vendor\mediatek\proprietary\packages\apps\MtkSettings\res\xml\network_and_internet.xml
<com.android.settingslib.RestrictedPreference
android:key="ethernet_settings"
android:title="@string/ethernet_settings_title"
android:summary="@string/summary_placeholder"
android:icon="@drawable/ic_ethernet_cell"
android:fragment="com.android.settings.ethernet.EthernetSettings"
android:order="-17"/>
在 mobile_network_settings 和 tether_settings 之间增加如上代码
对应的 icon 资源文件是我从 SystemUI 中拷贝过来的,稍微调整了下大小,也贴给你们吧
2、vendor\mediatek\proprietary\packages\apps\MtkSettings\res\drawable\ic_ethernet_cell.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:autoMirrored="true"
android:width="24dp"
android:height="24dp"
android:viewportWidth="48"
android:viewportHeight="48"
android:tint="?android:attr/colorControlNormal">
<path
android:fillColor="#fff"
android:pathData="M15.54 13.52l-3.08-2.55L1.64 24l10.82 13.04 3.08-2.55L6.84 24l8.7-10.48zM14 26h4v-4h-4v4zm20-4h-4v4h4v-4zm-12 4h4v-4h-4v4zm13.54-15.04l-3.08 2.55L41.16 24l-8.7 10.48 3.08 2.55L46.36 24 35.54 10.96z"/>
</vector>
vendor\mediatek\proprietary\packages\apps\MtkSettings\res\values\strings.xml
<string name="ethernet_ip_settings_invalid_ip">"Please fill in the correct format."</string>
<string name="eth_ip_settings_please_complete_settings">"Network information is not complete, please fill in the complete"</string>
<string name="save_satic_ethernet">"Save"</string>
<string name="enthernet_static">"Use static settings"</string>
<string name="enthernet_ip_address">"IP address"</string>
<string name="enthernet_gateway">"gateway"</string>
<string name="enthernet_netmask">"Subnet mask"</string>
<string name="enthernet_dns1">"domain1"</string>
<string name="enthernet_dns2">"domain2"</string>
<string name="ethernet_quick_toggle_title">"Ethernet"</string>
<string name="open_ethernet">"Open Ethernet"</string>
<string name="ethernet_static_ip_settings_title">"Setting Ethernet"</string>
<string name="ethernet_settings">"Ethernet"</string>
<string name="ethernet_settings_title">"Ethernet"</string>
vendor\mediatek\proprietary\packages\apps\MtkSettings\res\values-zh-rCN\strings.xml
<string name="ethernet_ip_settings_invalid_ip">"请填写正确的格式"</string>
<string name="save_satic_ethernet">"保存"</string>
<string name="eth_ip_settings_please_complete_settings">"网络信息不完整,请填写完整"</string>
<string name="enthernet_static">"使用静态设置"</string>
<string name="enthernet_ip_address">"IP地址"</string>
<string name="enthernet_gateway">"网关"</string>
<string name="enthernet_netmask">"子网掩码"</string>
<string name="enthernet_dns1">"域名1"</string>
<string name="enthernet_dns2">"域名2"</string>
<string name="ethernet_quick_toggle_title">"以太网"</string>
<string name="open_ethernet">"打开以太网"</string>
<string name="ethernet_static_ip_settings_title">"配置以太网"</string>
<string name="ethernet_settings">"以太网"</string>
<string name="ethernet_settings_title">"以太网"</string>
3、增加对应设置的两个布局xml
vendor\mediatek\proprietary\packages\apps\MtkSettings\res\xml\ethernet_settings.xml
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/ethernet_settings">
<SwitchPreference
android:key="ethernet"
android:title="@string/ethernet_quick_toggle_title"
android:summary="@string/open_ethernet"/>
<PreferenceScreen
android:dependency="ethernet"
android:fragment="com.android.settings.ethernet.EthernetStaticIP"
android:key="ethernet_static_ip"
android:title="@string/ethernet_static_ip_settings_title" />
</PreferenceScreen>
vendor\mediatek\proprietary\packages\apps\MtkSettings\res\xml\ethernet_static_ip.xml
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/ethernet_static_ip_settings_title">
<SwitchPreference
android:key="use_static_ip"
android:title="@string/enthernet_static"
android:persistent="false"/>
<EditTextPreference
android:dependency="use_static_ip"
android:key="ip_address"
android:title="@string/enthernet_ip_address"
android:persistent="false"
android:singleLine="true"/>
<EditTextPreference
android:dependency="use_static_ip"
android:key="gateway"
android:title="@string/enthernet_gateway"
android:persistent="false"
android:singleLine="true"/>
<EditTextPreference
android:dependency="use_static_ip"
android:key="netmask"
android:title="@string/enthernet_netmask"
android:persistent="false"
android:singleLine="true" />
<EditTextPreference
android:dependency="use_static_ip"
android:key="dns1"
android:title="@string/enthernet_dns1"
android:persistent="false"
android:singleLine="true"/>
<EditTextPreference
android:dependency="use_static_ip"
android:key="dns2"
android:title="@string/enthernet_dns2"
android:persistent="false"
android:singleLine="true"/>
</PreferenceScreen>
4、增加对应两个布局的 java 控制类
vendor\mediatek\proprietary\packages\apps\MtkSettings\src\com\android\settings\ethernet\EthernetSettings.java
package com.android.settings.ethernet;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.BroadcastReceiver;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceScreen;
import android.support.v7.preference.CheckBoxPreference;
import android.support.v14.preference.SwitchPreference;
import android.provider.Settings;
import android.provider.Settings.System;
import android.provider.Settings.Secure;
import android.util.Log;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.net.InetAddress;
import android.net.EthernetManager;
import android.net.StaticIpConfiguration;
import android.net.LinkAddress;
import android.net.IpConfiguration;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.R;
public class EthernetSettings extends SettingsPreferenceFragment
implements Preference.OnPreferenceChangeListener{
private static final String TAG = "EthernetSettings";
private static final String USE_ETHERNET_SETTINGS = "ethernet";
public static final String IS_ETHERNET_OPEN = Settings.IS_ETHERNET_OPEN;
private SwitchPreference mUseEthernet;
private IntentFilter mIntentFilter;
private boolean isEthernetEnabled() {
return Settings.System.getInt(getActivity().getContentResolver(), IS_ETHERNET_OPEN,0) == 1 ? true : false;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.ethernet_settings);
mUseEthernet = (SwitchPreference) findPreference(USE_ETHERNET_SETTINGS);
mUseEthernet.setOnPreferenceChangeListener(this);
if(isEthernetEnabled()) {
mUseEthernet.setChecked(true);
} else {
mUseEthernet.setChecked(false);
}
File f = new File("sys/class/net/eth0/address");
if (f.exists()) {
mUseEthernet.setEnabled(true);
} else {
mUseEthernet.setEnabled(false);
}
}
@Override
public void onResume() {
super.onResume();
}
@Override
public int getMetricsCategory(){return MetricsEvent.ETHERNET;}
@Override
public void onPause() {
super.onPause();
}
@Override
public boolean onPreferenceChange(Preference preference, Object value) {
boolean result = true;
final String key = preference.getKey();
if (USE_ETHERNET_SETTINGS.equals(key)) {
Settings.System.putInt(getActivity().getContentResolver(), IS_ETHERNET_OPEN,
((Boolean) value) ? 1 : 0);
}
return result;
}
}
vendor\mediatek\proprietary\packages\apps\MtkSettings\src\com\android\settings\ethernet\EthernetStaticIP.java
package com.android.settings.ethernet;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ContentResolver;
import android.os.Bundle;
import android.support.v7.preference.Preference;
import android.preference.PreferenceActivity;
import android.support.v7.preference.PreferenceScreen;
import android.support.v7.preference.CheckBoxPreference;
import android.support.v7.preference.EditTextPreference;
import android.support.v14.preference.SwitchPreference;
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.util.Log;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.AdapterView;
import android.widget.Toast;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.text.TextUtils;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.Formatter;
import java.net.InetAddress;
import android.net.EthernetManager;
import android.net.StaticIpConfiguration;
import android.net.LinkAddress;
import android.net.IpConfiguration;
import android.net.IpConfiguration.IpAssignment;
import android.net.IpConfiguration.ProxySettings;
import android.net.NetworkInfo.DetailedState;
import android.content.BroadcastReceiver;
import android.content.IntentFilter;
import android.content.Context;
import android.net.NetworkInfo;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.app.AlertDialog;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.R;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
public class EthernetStaticIP extends SettingsPreferenceFragment
implements Preference.OnPreferenceChangeListener {
private static final String TAG = "EthernetStaticIP";
public static final boolean DEBUG = false;
private static void LOG(String msg) {
if ( DEBUG ) {
Log.d(TAG, msg);
}
}
/*-------------------------------------------------------*/
private static final String KEY_USE_STATIC_IP = "use_static_ip";
private static final String KEY_IP_ADDRESS = "ip_address";
private static final String KEY_GATEWAY = "gateway";
private static final String KEY_NETMASK = "netmask";
private static final String KEY_DNS1 = "dns1";
private static final String KEY_DNS2 = "dns2";
public static final String ETHERNET_USE_STATIC_IP = Settings.IS_ETHERNET_STATUC_OPEN;
private static final int MENU_ITEM_SAVE = Menu.FIRST;
private static final int MENU_ITEM_CANCEL = Menu.FIRST + 1;
private String[] mSettingNames = {
Settings.ETHERNET_STATIC_IP,
Settings.ETHERNET_STATIC_GATEWAY,
Settings.ETHERNET_STATIC_NETMASK,
Settings.ETHERNET_STATIC_DNS1,
Settings.ETHERNET_STATIC_DNS2
};
private String[] mPreferenceKeys = {
KEY_IP_ADDRESS,
KEY_GATEWAY,
KEY_NETMASK,
KEY_DNS1,
KEY_DNS2,
};
/*-------------------------------------------------------*/
private SwitchPreference mUseStaticIpSwitch;
private StaticIpConfiguration mStaticIpConfiguration;
private IpConfiguration mIpConfiguration;
private EthernetManager mEthernetManager;
private boolean isOnPause = false;
private boolean chageState = false;
public EthernetStaticIP() {
}
@Override
public void onActivityCreated(Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
addPreferencesFromResource(R.xml.ethernet_static_ip);
mUseStaticIpSwitch = (SwitchPreference)findPreference(KEY_USE_STATIC_IP);
mUseStaticIpSwitch.setOnPreferenceChangeListener(this);
for ( int i = 0; i < mPreferenceKeys.length; i++ ) {
Preference preference = findPreference(mPreferenceKeys[i] );
preference.setOnPreferenceChangeListener(this);
}
setHasOptionsMenu(true);
}
@Override
public void onResume() {
super.onResume();
if(!isOnPause) {
updateIpSettingsInfo();
}
isOnPause = false;
}
@Override
public int getMetricsCategory(){return MetricsEvent.ETHERNET_STATIC;}
@Override
public void onPause() {
isOnPause = true;
super.onPause();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.add(Menu.NONE, MENU_ITEM_SAVE, 0, R.string.save_satic_ethernet)
.setEnabled(true)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_ITEM_SAVE:
saveIpSettingsInfo();
if(isIpDataInUiComplete())
finish();
return true;
case MENU_ITEM_CANCEL:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
private void updateIpSettingsInfo() {
LOG("Static IP status updateIpSettingsInfo");
ContentResolver contentResolver = getContentResolver();
mUseStaticIpSwitch.setChecked(Settings.System.getInt(contentResolver, ETHERNET_USE_STATIC_IP, 0) != 0);
for (int i = 0; i < mSettingNames.length; i++) {
EditTextPreference preference = (EditTextPreference) findPreference(mPreferenceKeys[i]);
String settingValue = Settings.System.getString(contentResolver, mSettingNames[i]);
preference.setText(settingValue);
preference.setSummary(settingValue);
}
}
private void saveIpSettingsInfo() {
ContentResolver contentResolver = getContentResolver();
/*
if(!chageState)
return;
*/
if(!isIpDataInUiComplete())
{
Toast.makeText(getActivity(), R.string.eth_ip_settings_please_complete_settings, Toast.LENGTH_LONG).show();
return;
}
mIpConfiguration = new IpConfiguration();
mStaticIpConfiguration = new StaticIpConfiguration();
for (int i = 0; i < mSettingNames.length; i++) {
EditTextPreference preference = (EditTextPreference) findPreference(mPreferenceKeys[i]);
String text = preference.getText();
try {
switch (mPreferenceKeys[i]) {
case KEY_IP_ADDRESS:
mStaticIpConfiguration.ipAddress = new LinkAddress(InetAddress.getByName(text), 24);
break;
case KEY_GATEWAY:
mStaticIpConfiguration.gateway = InetAddress.getByName(text);
break;
case KEY_NETMASK:
mStaticIpConfiguration.domains = text;
break;
case KEY_DNS1:
mStaticIpConfiguration.dnsServers.add(InetAddress.getByName(text));
break;
case KEY_DNS2:
mStaticIpConfiguration.dnsServers.add(InetAddress.getByName(text));
break;
}
} catch (Exception e) {
e.printStackTrace();
}
if ( null == text || TextUtils.isEmpty(text) ) {
Settings.System.putString(contentResolver, mSettingNames[i], null);
}
else {
Settings.System.putString(contentResolver, mSettingNames[i], text);
}
}
mIpConfiguration.ipAssignment = IpAssignment.STATIC;
mIpConfiguration.proxySettings = ProxySettings.STATIC;
mIpConfiguration.staticIpConfiguration = mStaticIpConfiguration;
mEthernetManager = (EthernetManager) getSystemService(Context.ETHERNET_SERVICE);
if (mUseStaticIpSwitch.isChecked())
mEthernetManager.setConfiguration(mIpConfiguration);
Settings.System.putInt(contentResolver,ETHERNET_USE_STATIC_IP, mUseStaticIpSwitch.isChecked() ? 1 : 0);
// disable ethernet
boolean enable = Secure.getInt(getContentResolver(), "isEnthernetOn", 1) == 1;
LOG("notify Secure.ETHERNET_ON changed. enable = " + enable);
if(enable) {
LOG("first disable");
Secure.putInt(getContentResolver(), "isEnthernetOn", 0);
try {
Thread.sleep(500);
} catch (InterruptedException e) {}
LOG("second enable");
Secure.putInt(getContentResolver(), "isEnthernetOn", 1);
}
}
@Override
public boolean onPreferenceTreeClick(Preference preference) {
boolean result = true;
LOG("onPreferenceTreeClick() chageState = " + chageState);
chageState = true;
return result;
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean result = true;
String key = preference.getKey();
LOG("onPreferenceChange() : key = " + key);
if ( null == key ) {
return true;
}else if (key.equals(KEY_USE_STATIC_IP)) {
}else if ( key.equals(KEY_IP_ADDRESS)
|| key.equals(KEY_GATEWAY)
|| key.equals(KEY_NETMASK)
|| key.equals(KEY_DNS1)
|| key.equals(KEY_DNS2) ) {
String value = (String) newValue;
LOG("onPreferenceChange() : value = " + value);
if ( TextUtils.isEmpty(value) ) {
( (EditTextPreference)preference).setText(value);
preference.setSummary(value);
result = true;
}
else if ( !isValidIpAddress(value) ) {
LOG("onPreferenceChange() : IP address user inputed is INVALID." );
Toast.makeText(getActivity(), R.string.ethernet_ip_settings_invalid_ip, Toast.LENGTH_LONG).show();
return false;
}
else {
( (EditTextPreference)preference).setText(value);
preference.setSummary(value);
result = true;
}
}
return result;
}
private boolean isValidIpAddress(String value) {
int start = 0;
int end = value.indexOf('.');
int numBlocks = 0;
while (start < value.length()) {
if ( -1 == end ) {
end = value.length();
}
try {
int block = Integer.parseInt(value.substring(start, end));
if ((block > 255) || (block < 0)) {
Log.w(TAG, "isValidIpAddress() : invalid 'block', block = " + block);
return false;
}
} catch (NumberFormatException e) {
Log.w(TAG, "isValidIpAddress() : e = " + e);
return false;
}
numBlocks++;
start = end + 1;
end = value.indexOf('.', start);
}
return numBlocks == 4;
}
private boolean isIpDataInUiComplete() {
ContentResolver contentResolver = getContentResolver();
for (int i = 0; i < (mPreferenceKeys.length - 1); i++) {
EditTextPreference preference = (EditTextPreference) findPreference(mPreferenceKeys[i]);
String text = preference.getText();
LOG("isIpDataInUiComplete() : text = " + text);
if ( null == text || TextUtils.isEmpty(text) ) {
return false;
}
}
return true;
}
}
到这一步 Settings 的修改就完成了,就能实现上图的效果了,你可以mm push看效果了
如果你编译报错,大概是 Settings 中没有添加对应的变量,我的本来就有的,
没有的可参考下面的加一下
frameworks\base\core\java\android\provider\Settings.java
// Intent actions for Settings
// ethernet
public static final String ETHERNET_STATIC_IP = "ethernet_static_ip";
public static final String ETHERNET_STATIC_GATEWAY = "ethernet_static_gateway";
public static final String ETHERNET_STATIC_NETMASK = "ethernet_static_netmask";
public static final String ETHERNET_STATIC_DNS1 = "ethernet_static_dns1";
public static final String ETHERNET_STATIC_DNS2 = "ethernet_static_dns2";
public static final String IS_ETHERNET_OPEN = "isEthernetOpen";
public static final String IS_ETHERNET_STATUC_OPEN = "isEthernetStaticOpen";
加完后你需要先 make update-api成功后,在重新 mm 编译应该就好了
5、修改 framework 层网卡相关的控制代码
frameworks\opt\net\ethernet\java\com\android\server\ethernet\EthernetNetworkFactory.java
将原来的 startIpManager() 直接替换为如下的方法
public void startIpManager() {
if (DBG) {
Log.d(TAG, String.format("starting IpManager(%s): mNetworkInfo=%s", mIface,
mNetworkInfo));
}
LinkProperties linkProperties;
IpConfiguration config = mEthernetManager.getConfiguration();
if (config.getIpAssignment() == IpAssignment.STATIC) {
if (!setStaticIpAddress(config.getStaticIpConfiguration())) {
// We've already logged an error.
return;
}
linkProperties = config.getStaticIpConfiguration().toLinkProperties(mIface);
if (config.getProxySettings() == ProxySettings.STATIC ||
config.getProxySettings() == ProxySettings.PAC) {
// mIpManager.setHttpProxy(config.getHttpProxy());
linkProperties.setHttpProxy(config.getHttpProxy());
}
String tcpBufferSizes = mContext.getResources().getString(
com.android.internal.R.string.config_ethernet_tcp_buffers);
if (TextUtils.isEmpty(tcpBufferSizes) == false) {
linkProperties.setTcpBufferSizes(tcpBufferSizes);
}
} else {
mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr);
}
IpManager.Callback ipmCallback = new IpManager.Callback() {
@Override
public void onProvisioningSuccess(LinkProperties newLp) {
mHandler.post(() -> onIpLayerStarted(newLp));
}
@Override
public void onProvisioningFailure(LinkProperties newLp) {
mHandler.post(() -> onIpLayerStopped(newLp));
}
@Override
public void onLinkPropertiesChange(LinkProperties newLp) {
mHandler.post(() -> updateLinkProperties(newLp));
}
};
stopIpManager();
mIpManager = new IpManager(mContext, mIface, ipmCallback);
if (config.getProxySettings() == ProxySettings.STATIC ||
config.getProxySettings() == ProxySettings.PAC) {
mIpManager.setHttpProxy(config.getHttpProxy());
}
final String tcpBufferSizes = mContext.getResources().getString(
com.android.internal.R.string.config_ethernet_tcp_buffers);
if (!TextUtils.isEmpty(tcpBufferSizes)) {
mIpManager.setTcpBufferSizes(tcpBufferSizes);
}
if (config.getIpAssignment() == IpAssignment.STATIC) {
mIpManager.startProvisioning(config.getStaticIpConfiguration());
} else {
final ProvisioningConfiguration provisioningConfiguration =
mIpManager.buildProvisioningConfiguration()
.withProvisioningTimeoutMs(0)
.build();
mIpManager.startProvisioning(provisioningConfiguration);
}
}
frameworks\opt\net\ethernet\java\com\android\server\ethernet\EthernetServiceImpl.java
在 EthernetServiceImpl 中增加网卡开关和静态IP开关的监听处理
private final EthernetOpenedObserver mOpenObserver = new EthernetOpenedObserver();
private final EthernetStaticObserver mStaticObserver = new EthernetStaticObserver();
public EthernetServiceImpl(Context context) {
.....
mContext.getContentResolver().registerContentObserver(
System.getUriFor(IS_ETHERNET_OPEN), false, mOpenObserver);
mContext.getContentResolver().registerContentObserver(
System.getUriFor(ETHERNET_USE_STATIC_IP), false, mStaticObserver);
}
private void enforceChangePermission() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_NETWORK_STATE,
"EthernetService");
}
@Override
public void setConfiguration(IpConfiguration config) {
if (!mStarted.get()) {
Log.w(TAG, "System isn't ready enough to change ethernet configuration");
}
enforceChangePermission();
enforceConnectivityInternalPermission();
.....
}
private boolean isStatic()
{
return Settings.System.getInt(mContext.getContentResolver(),ETHERNET_USE_STATIC_IP,0) ==1;
}
private int getState()
{
return Settings.System.getInt(mContext.getContentResolver(), IS_ETHERNET_OPEN,0);
}
private final class EthernetOpenedObserver extends ContentObserver {
public EthernetOpenedObserver() {
super(new Handler());
}
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
super.onChange(selfChange, uri, userId);
Log.i(TAG, "EthernetServiceImpl isEthernetOpen onChange....");
if (getState() == 1) {
if (isStatic()) {
StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();
staticIpConfiguration.domains = Settings.System.getString(mContext.getContentResolver(),Settings.ETHERNET_STATIC_NETMASK);
try {
staticIpConfiguration.gateway = InetAddress.getByName(Settings.System.getString(mContext.getContentResolver(),Settings.ETHERNET_STATIC_GATEWAY));
staticIpConfiguration.ipAddress = new LinkAddress(InetAddress.getByName(Settings.System.getString(mContext.getContentResolver(),Settings.ETHERNET_STATIC_IP)), 24);
staticIpConfiguration.dnsServers.add(InetAddress.getByName(Settings.System.getString(mContext.getContentResolver(),Settings.ETHERNET_STATIC_DNS1)));
staticIpConfiguration.dnsServers.add(InetAddress.getByName(Settings.System.getString(mContext.getContentResolver(),Settings.ETHERNET_STATIC_DNS2)));
}
catch (Exception e){
e.printStackTrace();
}
mIpConfiguration.staticIpConfiguration = staticIpConfiguration;
}
mStarted.set(true);
mTracker.start(mContext, mHandler);
}
else {
mTracker.stop();
}
}
}
private final class EthernetStaticObserver extends ContentObserver {
public EthernetStaticObserver() {
super(new Handler());
}
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
super.onChange(selfChange, uri, userId);
Log.i(TAG, "EthernetServiceImpl isEthernetStaticOpen onChange....");
if (!isStatic()) {
mIpConfiguration = mEthernetConfigStore.readIpAndProxyConfigurations();
mTracker.stop();
mStarted.set(true);
mTracker.start(mContext, mHandler);
}
}
}
好了,到此就搞定了动图的效果了,开关以太网和设置静态IP上网,下面我们再来瞅瞅 6.0的有啥区别
Android6.0
效果图和上面的一样,这里就省略了,Settings 的修改和上面的一样,有两个细小的
区别就是
1、导包需要注意,EthernetSettings 和 EthernetStaticIP 中的 Preference
相关的包,在8.1中都换成了 support.v7 下面的,6.0 还是用原来的 android.preference
2、6.0 中的 MetricsLogger.ETHERNET 和 MetricsLogger.ETHERNET_STATIC
在8.1中替换为 MetricsEvent.ETHERNET 和 MetricsEvent.ETHERNET_STATIC
导包 com.android.internal.logging.MetricsLogger
frameworks/base/proto/src/metrics_constants.proto
ETHERNET = 1144;
ETHERNET_STATIC = 1145;
framework 方面的差异
EthernetServiceImpl.java 文件和 8.1 的一样,主要差别在 EthernetNetworkFactory.java
相比较而言没有 8.1 的复杂,下面贴一下完整的代码
frameworks\opt\net\ethernet\java\com\android\server\ethernet\EthernetNetworkFactory.java
class EthernetNetworkFactory {
private static final String NETWORK_TYPE = "Ethernet";
private static final String TAG = "EthernetNetworkFactory";
private static final int NETWORK_SCORE = 110;
private static final boolean DBG = true;
public static final String ETHERNET_USE_STATIC_IP = Settings.IS_ETHERNET_STATUC_OPEN;
/** Tracks interface changes. Called from NetworkManagementService. */
private InterfaceObserver mInterfaceObserver;
/** For static IP configuration */
private EthernetManager mEthernetManager;
/** To set link state and configure IP addresses. */
private INetworkManagementService mNMService;
/* To communicate with ConnectivityManager */
private NetworkCapabilities mNetworkCapabilities;
private NetworkAgent mNetworkAgent;
private LocalNetworkFactory mFactory;
private Context mContext;
/** Product-dependent regular expression of interface names we track. */
private static String mIfaceMatch = "";
/** To notify Ethernet status. */
private final RemoteCallbackList<IEthernetServiceListener> mListeners;
/** Data members. All accesses to these must be synchronized(this). */
private static String mIface = "";
private String mHwAddr;
private static boolean mLinkUp;
private NetworkInfo mNetworkInfo;
private LinkProperties mLinkProperties;
EthernetNetworkFactory(RemoteCallbackList<IEthernetServiceListener> listeners) {
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, "");
mLinkProperties = new LinkProperties();
initNetworkCapabilities();
mListeners = listeners;
}
private class LocalNetworkFactory extends NetworkFactory {
LocalNetworkFactory(String name, Context context, Looper looper) {
super(looper, context, name, new NetworkCapabilities());
}
protected void startNetwork() {
onRequestNetwork();
}
protected void stopNetwork() {
}
}
/**
* Updates interface state variables.
* Called on link state changes or on startup.
*/
private void updateInterfaceState(String iface, boolean up) {
if (!mIface.equals(iface)) {
return;
}
Log.d(TAG, "updateInterface: " + iface + " link " + (up ? "up" : "down"));
synchronized(this) {
mLinkUp = up;
mNetworkInfo.setIsAvailable(up);
if (!up) {
// Tell the agent we're disconnected. It will call disconnect().
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr);
}
updateAgent();
// set our score lower than any network could go
// so we get dropped. TODO - just unregister the factory
// when link goes down.
mFactory.setScoreFilter(up ? NETWORK_SCORE : -1);
}
}
private class InterfaceObserver extends BaseNetworkObserver {
@Override
public void interfaceLinkStateChanged(String iface, boolean up) {
updateInterfaceState(iface, up);
}
@Override
public void interfaceAdded(String iface) {
maybeTrackInterface(iface);
}
@Override
public void interfaceRemoved(String iface) {
stopTrackingInterface(iface);
}
}
private void setInterfaceUp(String iface) {
// Bring up the interface so we get link status indications.
try {
NetworkUtils.stopDhcp(iface);
mNMService.setInterfaceUp(iface);
String hwAddr = null;
InterfaceConfiguration config = mNMService.getInterfaceConfig(iface);
if (config == null) {
Log.e(TAG, "Null iterface config for " + iface + ". Bailing out.");
return;
}
synchronized (this) {
if (!isTrackingInterface()) {
setInterfaceInfoLocked(iface, config.getHardwareAddress());
mNetworkInfo.setIsAvailable(true);
mNetworkInfo.setExtraInfo(mHwAddr);
} else {
Log.e(TAG, "Interface unexpectedly changed from " + iface + " to " + mIface);
mNMService.setInterfaceDown(iface);
}
}
} catch (RemoteException e) {
Log.e(TAG, "Error upping interface " + mIface + ": " + e);
}
}
private boolean maybeTrackInterface(String iface) {
// If we don't already have an interface, and if this interface matches
// our regex, start tracking it.
if (!iface.matches(mIfaceMatch) || isTrackingInterface())
return false;
Log.d(TAG, "Started tracking interface " + iface);
setInterfaceUp(iface);
return true;
}
private void stopTrackingInterface(String iface) {
if (!iface.equals(mIface))
return;
Log.d(TAG, "Stopped tracking interface " + iface);
// TODO: Unify this codepath with stop().
synchronized (this) {
NetworkUtils.stopDhcp(mIface);
setInterfaceInfoLocked("", null);
mNetworkInfo.setExtraInfo(null);
mLinkUp = false;
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr);
updateAgent();
mNetworkAgent = null;
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, "");
mLinkProperties = new LinkProperties();
}
}
private boolean setStaticIpAddress(StaticIpConfiguration staticConfig) {
if (staticConfig!=null && staticConfig.ipAddress != null &&
staticConfig.gateway != null &&
staticConfig.dnsServers.size() > 0) {
try {
Log.i(TAG, "Applying static IPv4 configuration to " + mIface + ": " + staticConfig);
InterfaceConfiguration config = mNMService.getInterfaceConfig(mIface);
config.setLinkAddress(staticConfig.ipAddress);
mNMService.setInterfaceConfig(mIface, config);
return true;
} catch(RemoteException|IllegalStateException e) {
Log.e(TAG, "Setting static IP address failed: " + e.getMessage());
}
} else {
Log.e(TAG, "Invalid static IP configuration.");
}
return false;
}
public void updateAgent() {
synchronized (EthernetNetworkFactory.this) {
if (mNetworkAgent == null) return;
if (DBG) {
Log.i(TAG, "Updating mNetworkAgent with: " +
mNetworkCapabilities + ", " +
mNetworkInfo + ", " +
mLinkProperties);
}
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
mNetworkAgent.sendLinkProperties(mLinkProperties);
// never set the network score below 0.
mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0);
}
}
/* Called by the NetworkFactory on the handler thread. */
public void onRequestNetwork() {
// TODO: Handle DHCP renew.
Thread dhcpThread = new Thread(new Runnable() {
public void run() {
if (DBG) Log.i(TAG, "dhcpThread(" + mIface + "): mNetworkInfo=" + mNetworkInfo);
LinkProperties linkProperties;
IpConfiguration config = mEthernetManager.getConfiguration();
/* if (config.getIpAssignment() == IpAssignment.STATIC) */
if (isStatic())
{
if (!setStaticIpAddress(config.getStaticIpConfiguration())) {
// We've already logged an error.
return;
}
linkProperties = config.getStaticIpConfiguration().toLinkProperties(mIface);
} else {
mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr);
DhcpResults dhcpResults = new DhcpResults();
// TODO: Handle DHCP renewals better.
// In general runDhcp handles DHCP renewals for us, because
// the dhcp client stays running, but if the renewal fails,
// we will lose our IP address and connectivity without
// noticing.
if (!NetworkUtils.runDhcp(mIface, dhcpResults)) {
Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
// set our score lower than any network could go
// so we get dropped.
mFactory.setScoreFilter(-1);
// If DHCP timed out (as opposed to failing), the DHCP client will still be
// running, because in M we changed its timeout to infinite. Stop it now.
NetworkUtils.stopDhcp(mIface);
return;
}
linkProperties = dhcpResults.toLinkProperties(mIface);
}
if (config.getProxySettings() == ProxySettings.STATIC ||
config.getProxySettings() == ProxySettings.PAC) {
linkProperties.setHttpProxy(config.getHttpProxy());
}
String tcpBufferSizes = mContext.getResources().getString(
com.android.internal.R.string.config_ethernet_tcp_buffers);
if (TextUtils.isEmpty(tcpBufferSizes) == false) {
linkProperties.setTcpBufferSizes(tcpBufferSizes);
}
synchronized(EthernetNetworkFactory.this) {
if (mNetworkAgent != null) {
Log.e(TAG, "Already have a NetworkAgent - aborting new request");
return;
}
mLinkProperties = linkProperties;
mNetworkInfo.setIsAvailable(true);
mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr);
// Create our NetworkAgent.
mNetworkAgent = new NetworkAgent(mFactory.getLooper(), mContext,
NETWORK_TYPE, mNetworkInfo, mNetworkCapabilities, mLinkProperties,
NETWORK_SCORE) {
public void unwanted() {
synchronized(EthernetNetworkFactory.this) {
if (this == mNetworkAgent) {
NetworkUtils.stopDhcp(mIface);
mLinkProperties.clear();
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null,
mHwAddr);
updateAgent();
mNetworkAgent = null;
try {
mNMService.clearInterfaceAddresses(mIface);
} catch (Exception e) {
Log.e(TAG, "Failed to clear addresses or disable ipv6" + e);
}
} else {
Log.d(TAG, "Ignoring unwanted as we have a more modern " +
"instance");
}
}
};
};
}
}
});
dhcpThread.start();
}
/**
* Begin monitoring connectivity
*/
public synchronized void start(Context context, Handler target) {
// The services we use.
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
mNMService = INetworkManagementService.Stub.asInterface(b);
mEthernetManager = (EthernetManager) context.getSystemService(Context.ETHERNET_SERVICE);
// Interface match regex.
mIfaceMatch = context.getResources().getString(
com.android.internal.R.string.config_ethernet_iface_regex);
// Create and register our NetworkFactory.
mFactory = new LocalNetworkFactory(NETWORK_TYPE, context, target.getLooper());
mFactory.setCapabilityFilter(mNetworkCapabilities);
mFactory.setScoreFilter(-1); // this set high when we have an iface
mFactory.register();
mContext = context;
// Start tracking interface change events.
mInterfaceObserver = new InterfaceObserver();
try {
mNMService.registerObserver(mInterfaceObserver);
} catch (RemoteException e) {
Log.e(TAG, "Could not register InterfaceObserver " + e);
}
// If an Ethernet interface is already connected, start tracking that.
// Otherwise, the first Ethernet interface to appear will be tracked.
try {
final String[] ifaces = mNMService.listInterfaces();
for (String iface : ifaces) {
synchronized(this) {
if (maybeTrackInterface(iface)) {
// We have our interface. Track it.
// Note: if the interface already has link (e.g., if we
// crashed and got restarted while it was running),
// we need to fake a link up notification so we start
// configuring it. Since we're already holding the lock,
// any real link up/down notification will only arrive
// after we've done this.
if (mNMService.getInterfaceConfig(iface).hasFlag("running")) {
updateInterfaceState(iface, true);
}
break;
}
}
}
} catch (RemoteException e) {
Log.e(TAG, "Could not get list of interfaces " + e);
}
}
public synchronized void stop() {
NetworkUtils.stopDhcp(mIface);
// ConnectivityService will only forget our NetworkAgent if we send it a NetworkInfo object
// with a state of DISCONNECTED or SUSPENDED. So we can't simply clear our NetworkInfo here:
// that sets the state to IDLE, and ConnectivityService will still think we're connected.
//
// TODO: stop using explicit comparisons to DISCONNECTED / SUSPENDED in ConnectivityService,
// and instead use isConnectedOrConnecting().
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr);
mLinkUp = false;
updateAgent();
mLinkProperties = new LinkProperties();
mNetworkAgent = null;
setInterfaceInfoLocked("", null);
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, "");
mFactory.unregister();
}
private void initNetworkCapabilities() {
mNetworkCapabilities = new NetworkCapabilities();
mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET);
mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
// We have no useful data on bandwidth. Say 100M up and 100M down. :-(
mNetworkCapabilities.setLinkUpstreamBandwidthKbps(100 * 1000);
mNetworkCapabilities.setLinkDownstreamBandwidthKbps(100 * 1000);
}
public synchronized boolean isTrackingInterface() {
return !TextUtils.isEmpty(mIface);
}
/**
* Set interface information and notify listeners if availability is changed.
* This should be called with the lock held.
*/
private void setInterfaceInfoLocked(String iface, String hwAddr) {
boolean oldAvailable = isTrackingInterface();
mIface = iface;
mHwAddr = hwAddr;
boolean available = isTrackingInterface();
if (oldAvailable != available) {
int n = mListeners.beginBroadcast();
for (int i = 0; i < n; i++) {
try {
mListeners.getBroadcastItem(i).onAvailabilityChanged(available);
} catch (RemoteException e) {
// Do nothing here.
}
}
mListeners.finishBroadcast();
}
}
synchronized void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
if (isTrackingInterface()) {
pw.println("Tracking interface: " + mIface);
pw.increaseIndent();
pw.println("MAC address: " + mHwAddr);
pw.println("Link state: " + (mLinkUp ? "up" : "down"));
pw.decreaseIndent();
} else {
pw.println("Not tracking any interface");
}
pw.println();
pw.println("NetworkInfo: " + mNetworkInfo);
pw.println("LinkProperties: " + mLinkProperties);
pw.println("NetworkAgent: " + mNetworkAgent);
}
/*private boolean isStatic()*/
private boolean isStatic()
{
return Settings.System.getInt(mContext.getContentResolver(),ETHERNET_USE_STATIC_IP,0) ==1;
}
}