目录
device\qcom\common\rootdir\etc\init.qcom.rc
device/qcom/msm8909/msm8909.mk
device/qcom/common/device/overlay/frameworks/base/core/res/res/values/config.xml
frameworks/base/core/java/android/net/EthernetManager.java
frameworks\base\core\java\android\net\IEthernetManager.aidl
frameworks\base\core\java\android\provider\Settings.java.
frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java
frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetServiceImpl.java
frameworks/base/core/res/res/values/config.xml
frameworks/base/core/java/android/content/Intent.java
frameworks/base/core/res/res/values/symbols.xml
frameworks/base/packages/SystemUI/res/drawable/ethernet_connected.png
frameworks/base/packages/SystemUI/res/drawable/ethernet_connecting.png
frameworks/base/packages/SystemUI/res/drawable/ethernet_disconnected.png
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
packages/apps/Settings/AndroidManifest.xml
packages/apps/Settings/res/layout/eth_configure.xml
packages/apps/Settings/res/values/strings.xml
packages/apps/Settings/res/xml/ethernet_settings.xml
packages/apps/Settings/src/com/android/settings/Settings.java
packages/apps/Settings/src/com/android/settings/SettingsActivity.java
packages/apps/Settings/src/com/android/settings/ethernet/EthernetDialog.java
packages/apps/Settings/src/com/android/settings/ethernet/EthernetEnabler.java
packages/apps/Settings/src/com/android/settings/ethernet/EthernetSettings.java
packages/apps/Settings/res/drawable-hdpi/ic_settings_dock_alpha.png
packages/apps/Settings/res/drawable/ic_settings_dock.xml
写在前面
SOC:Qualcomm msm8909
Core-Board:SC20-CE QA/PJ
Base-Board:xxx
Linux Kernel:xxx
Android:7.1
本次目的
为安卓系统增加以太网功能,能够在系统设置菜单中找到以太网选项,完成以太网功能设置,并且在系统状态栏能够提示以太网网络状态。
如果您需要了解如何添加和调试相关驱动,比如这里用的RTL8152(USB转以太网芯片),可以参考我的这篇博客:
https://blog.youkuaiyun.com/uestc_ganlin/article/details/90692753
详细步骤
device的修改
device\qcom\common\rootdir\etc\init.qcom.rc
添加以下内容:
service dhcpcd_eth0 /system/bin/dhcpcd -ABDKL
class main
disabled
oneshot
service iprenew_eth0 /system/bin/dhcpcd -n
class late_start
disabled
oneshot
device/qcom/msm8909/msm8909.mk
在“PRODUCT_COPY_FILES”中加入以下内容,注意上一个值的后面不要漏掉结束“\”:
frameworks/native/data/etc/android.hardware.ethernet.xml:system/etc/permissions/android.hardware.ethernet.xml
修改完成后像这样:
# Feature definition files for msm8953
PRODUCT_COPY_FILES += \
frameworks/native/data/etc/android.hardware.sensor.accelerometer.xml:system/etc/permissions/android.hardware.sensor.accelerometer.xml \
frameworks/native/data/etc/android.hardware.sensor.compass.xml:system/etc/permissions/android.hardware.sensor.compass.xml \
frameworks/native/data/etc/android.hardware.sensor.gyroscope.xml:system/etc/permissions/android.hardware.sensor.gyroscope.xml \
frameworks/native/data/etc/android.hardware.sensor.light.xml:system/etc/permissions/android.hardware.sensor.light.xml \
frameworks/native/data/etc/android.hardware.sensor.proximity.xml:system/etc/permissions/android.hardware.sensor.proximity.xml \
frameworks/native/data/etc/android.hardware.sensor.barometer.xml:system/etc/permissions/android.hardware.sensor.barometer.xml \
frameworks/native/data/etc/android.hardware.sensor.stepcounter.xml:system/etc/permissions/android.hardware.sensor.stepcounter.xml \
frameworks/native/data/etc/android.hardware.sensor.stepdetector.xml:system/etc/permissions/android.hardware.sensor.stepdetector.xml \
frameworks/native/data/etc/android.hardware.ethernet.xml:system/etc/permissions/android.hardware.ethernet.xml
device/qcom/common/device/overlay/frameworks/base/core/res/res/values/config.xml
加入以下内容:
<item><xliff:g id="id">ethernet</xliff:g></item>
修改完后像这样:
<!-- Do not translate. Defines the slots for the right-hand side icons. That is to say, the
icons in the status bar that are not notifications. -->
<string-array name="config_statusBarIcons">
<item><xliff:g id="id">managed_profile</xliff:g></item>
<item><xliff:g id="id">ime</xliff:g></item>
<item><xliff:g id="id">sync_failing</xliff:g></item>
<item><xliff:g id="id">sync_active</xliff:g></item>
<item><xliff:g id="id">cast</xliff:g></item>
<item><xliff:g id="id">hotspot</xliff:g></item>
<item><xliff:g id="id">location</xliff:g></item>
<item><xliff:g id="id">bluetooth</xliff:g></item>
<item><xliff:g id="id">nfc</xliff:g></item>
<item><xliff:g id="id">femtoicon</xliff:g></item>
<item><xliff:g id="id">tty</xliff:g></item>
<item><xliff:g id="id">speakerphone</xliff:g></item>
<item><xliff:g id="id">zen</xliff:g></item>
<item><xliff:g id="id">mute</xliff:g></item>
<item><xliff:g id="id">volume</xliff:g></item>
<item><xliff:g id="id">wifi</xliff:g></item>
<item><xliff:g id="id">ethernet</xliff:g></item>
<item><xliff:g id="id">cdma_eri</xliff:g></item>
<item><xliff:g id="id">data_connection</xliff:g></item>
<item><xliff:g id="id">phone_evdo_signal</xliff:g></item>
<item><xliff:g id="id">phone_signal</xliff:g></item>
<item><xliff:g id="id">battery</xliff:g></item>
<item><xliff:g id="id">alarm_clock</xliff:g></item>
<item><xliff:g id="id">secure</xliff:g></item>
<item><xliff:g id="id">clock</xliff:g></item>
</string-array>
frameworks的修改
frameworks/base/core/java/android/net/EthernetManager.java
添加以下内容:
public static final int ETH_STATE_UNKNOWN = 0; //law
public static final int ETH_STATE_DISABLED = 1;
public static final int ETH_STATE_ENABLED = 2;
public void start() {
try {
mService.Trackstart();
} catch (NullPointerException | RemoteException e) {
}
}
public void stop() {
try {
mService.Trackstop();
} catch (NullPointerException | RemoteException e) {
}
}
frameworks\base\core\java\android\net\IEthernetManager.aidl
添加以下内容:
void Trackstart();//add by law
void Trackstop();
frameworks\base\core\java\android\provider\Settings.java.
添加以下内容:
/**
* law add
* {@hide}
*/
public static final String ETHERNET_ON = "ethernet_on";//add by law
frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java
添加以下依赖内容:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
在此类中增加Handler属性:
private Handler mHandler;
增加一个状态标志并创建一个广播接收:
private boolean isStatusBarReady= false;
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(TAG, "klein----BroadcastReceiver--action = " + action);
if (action.equals(Intent.ACTION_ETHERNET_STATUSBAR_READY)) {
isStatusBarReady = true;
Log.d(TAG,"statusbar is ready, update current status");
if (mLinkUp){
Log.d(TAG,"updateAgent connected");
Intent intent1 = new Intent();
intent1.setAction(Intent.ACTION_ETHERNET_CONNECTED);
mContext.sendBroadcast(intent1);
}else{
Log.d(TAG,"updateAgent disconnected");
Intent intent2 = new Intent();
intent2.setAction(Intent.ACTION_ETHERNET_DISCONNECTED);
mContext.sendBroadcast(intent2);
}
}
}
};
在“updateInterfaceState”方法中加入更新状态的逻辑:
if (up){
Log.d(TAG,"updateAgent connected");
Intent intent = new Intent();
intent.setAction(Intent.ACTION_ETHERNET_CONNECTED);
mContext.sendBroadcast(intent);
}else{
Log.d(TAG,"updateAgent disconnected");
Intent intent = new Intent();
intent.setAction(Intent.ACTION_ETHERNET_DISCONNECTED);
mContext.sendBroadcast(intent);
}
在“onRequestNetwork”方法中 “ ipProvisioningThread”线程初始化时加入判断:
//if error then stop and restart add by law
if((mContext != null) && (mHandler != null)) {
Log.d(TAG, "Setting static ip failed now restart");
stop();
start(mContext,mHandler);
}
在“start”方法中加入以下内容:
mHandler = target;//add by law
if(!iface.equals("eth0"))//add by hclydao make sure the interface is eth0
continue;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_ETHERNET_STATUSBAR_READY);
mContext.registerReceiver(mIntentReceiver, filter);
Log.d(TAG, "klein----EthernetNetworkFactory start");
完整的文件内容如下:
/*
* Copyright (C) 2014 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.server.ethernet;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.DhcpResults;
import android.net.EthernetManager;
import android.net.IEthernetServiceListener;
import android.net.InterfaceConfiguration;
import android.net.IpConfiguration;
import android.net.IpConfiguration.IpAssignment;
import android.net.IpConfiguration.ProxySettings;
import android.net.LinkProperties;
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.NetworkFactory;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.StaticIpConfiguration;
import android.net.ip.IpManager;
import android.net.ip.IpManager.ProvisioningConfiguration;
import android.net.ip.IpManager.WaitForProvisioningCallback;
import android.os.Handler;
import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.text.TextUtils;
import android.util.Log;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.net.BaseNetworkObserver;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
/**
* Manages connectivity for an Ethernet interface.
*
* Ethernet Interfaces may be present at boot time or appear after boot (e.g.,
* for Ethernet adapters connected over USB). This class currently supports
* only one interface. When an interface appears on the system (or is present
* at boot time) this class will start tracking it and bring it up, and will
* attempt to connect when requested. Any other interfaces that subsequently
* appear will be ignored until the tracked interface disappears. Only
* interfaces whose names match the <code>config_ethernet_iface_regex</code>
* regular expression are tracked.
*
* This class reports a static network score of 70 when it is tracking an
* interface and that interface's link is up, and a score of 0 otherwise.
*
* @hide
*/
class EthernetNetworkFactory {
private static final String NETWORK_TYPE = "Ethernet";
private static final String TAG = "EthernetNetworkFactory";
private static final int NETWORK_SCORE = 70;
private static final boolean DBG = true;
private Handler mHandler;
/** 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;
private IpManager mIpManager;
private Thread mIpProvisioningThread;
private boolean isStatusBarReady= false;
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(TAG, "klein----BroadcastReceiver--action = " + action);
if (action.equals(Intent.ACTION_ETHERNET_STATUSBAR_READY)) {
isStatusBarReady = true;
Log.d(TAG,"statusbar is ready, update current status");
if (mLinkUp){
Log.d(TAG,"updateAgent connected");
Intent intent1 = new Intent();
intent1.setAction(Intent.ACTION_ETHERNET_CONNECTED);
mContext.sendBroadcast(intent1);
}else{
Log.d(TAG,"updateAgent disconnected");
Intent intent2 = new Intent();
intent2.setAction(Intent.ACTION_ETHERNET_DISCONNECTED);
mContext.sendBroadcast(intent2);
}
}
}
};
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() {
}
}
private void stopIpManagerLocked() {
if (mIpManager != null) {
mIpManager.shutdown();
mIpManager = null;
}
}
private void stopIpProvisioningThreadLocked() {
stopIpManagerLocked();
if (mIpProvisioningThread != null) {
mIpProvisioningThread.interrupt();
mIpProvisioningThread = null;
}
}
/**
* 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"));
if (up){
Log.d(TAG,"updateAgent connected");
Intent intent = new Intent();
intent.setAction(Intent.ACTION_ETHERNET_CONNECTED);
mContext.sendBroadcast(intent);
}else{
Log.d(TAG,"updateAgent disconnected");
Intent intent = new Intent();
intent.setAction(Intent.ACTION_ETHERNET_DISCONNECTED);
mContext.sendBroadcast(intent);
}
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);
stopIpProvisioningThreadLocked();
}
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 {
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) {
stopIpProvisioningThreadLocked();
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.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() {
synchronized(EthernetNetworkFactory.this) {
if (mIpProvisioningThread != null) {
return;
}
}
final Thread ipProvisioningThread = new Thread(new Runnable() {
public void run() {
if (DBG) {
Log.d(TAG, String.format("starting ipProvisioningThread(%s): mNetworkInfo=%s",
mIface, mNetworkInfo));
}
LinkProperties linkProperties;
IpConfiguration config = mEthernetManager.getConfiguration();
if (config.getIpAssignment() == IpAssignment.STATIC) {
if (!setStaticIpAddress(config.getStaticIpConfiguration())) {
//if error then stop and restart add by law
if((mContext != null) && (mHandler != null)) {
Log.d(TAG, "Setting static ip failed now restart");
stop();
start(mContext,mHandler);
}
// We've already logged an error.
return;
}
linkProperties = config.getStaticIpConfiguration().toLinkProperties(mIface);
} else {
mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr);
WaitForProvisioningCallback ipmCallback = new WaitForProvisioningCallback() {
@Override
public void onLinkPropertiesChange(LinkProperties newLp) {
synchronized(EthernetNetworkFactory.this) {
if (mNetworkAgent != null && mNetworkInfo.isConnected()) {
mLinkProperties = newLp;
mNetworkAgent.sendLinkProperties(newLp);
}
}
}
};
synchronized(EthernetNetworkFactory.this) {
stopIpManagerLocked();
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);
}
final ProvisioningConfiguration provisioningConfiguration =
mIpManager.buildProvisioningConfiguration()
.withProvisioningTimeoutMs(0)
.build();
mIpManager.startProvisioning(provisioningConfiguration);
}
linkProperties = ipmCallback.waitForProvisioning();
if (linkProperties == null) {
Log.e(TAG, "IP provisioning error");
// set our score lower than any network could go
// so we get dropped.
mFactory.setScoreFilter(-1);
synchronized(EthernetNetworkFactory.this) {
stopIpManagerLocked();
}
return;
}
}
synchronized(EthernetNetworkFactory.this) {
if (mNetworkAgent != null) {
Log.e(TAG, "Already have a NetworkAgent - aborting new request");
stopIpManagerLocked();
mIpProvisioningThread = null;
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) {
stopIpManagerLocked();
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");
}
}
};
};
mIpProvisioningThread = null;
}
if (DBG) {
Log.d(TAG, String.format("exiting ipProvisioningThread(%s): mNetworkInfo=%s",
mIface, mNetworkInfo));
}
}
});
synchronized(EthernetNetworkFactory.this) {
if (mIpProvisioningThread == null) {
mIpProvisioningThread = ipProvisioningThread;
mIpProvisioningThread.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;
mHandler = target;//add by law
// 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")) {
if(!iface.equals("eth0"))//add by hclydao make sure the interface is eth0
continue;
updateInterfaceState(iface, true);
}
break;
}
}
}
} catch (RemoteException|IllegalStateException e) {
Log.e(TAG, "Could not get list of interfaces " + e);
}
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_ETHERNET_STATUSBAR_READY);
mContext.registerReceiver(mIntentReceiver, filter);
Log.d(TAG, "klein----EthernetNetworkFactory start");
}
public synchronized void stop() {
stopIpProvisioningThreadLocked();
// 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);
if (mIpManager != null) {
pw.println("IpManager:");
pw.increaseIndent();
mIpManager.dump(fd, pw, args);
pw.decreaseIndent();
}
}
}
frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetServiceImpl.java
添加以下内容:
import android.net.EthernetManager;
import android.os.Looper;
import android.provider.Settings;
int enable = Settings.Global.getInt(mContext.getContentResolver(),Settings.Global.ETHERNET_ON,0);//add by hclydao
if(enable != EthernetManager.ETH_STATE_ENABLED) {
Log.i(TAG, "Ethernet is not enable");
return;
}
//law
class TstartThread extends Thread {
public void run() {
Looper.prepare();
mTracker.start(mContext, mHandler);
mStarted.set(true);
Looper.loop();
}
}
public void Trackstart() { //add by hclydao
new TstartThread().start();
}
public void Trackstop() {
Log.i(TAG, "Stop Ethernet service");
Thread tstopthread = new Thread(new Runnable() {
public void run() {
Looper.prepare();
mTracker.stop();
mStarted.set(false);
Looper.loop();
}
});
tstopthread.start();
}
完整内容如下:
/*
* Copyright (C) 2014 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.server.ethernet;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.IEthernetManager;
import android.net.IEthernetServiceListener;
import android.net.IpConfiguration;
import android.net.IpConfiguration.IpAssignment;
import android.net.IpConfiguration.ProxySettings;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.provider.Settings;
import android.net.EthernetManager;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.os.Looper;
import android.provider.Settings;
import com.android.internal.util.IndentingPrintWriter;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* EthernetServiceImpl handles remote Ethernet operation requests by implementing
* the IEthernetManager interface.
*
* @hide
*/
public class EthernetServiceImpl extends IEthernetManager.Stub {
private static final String TAG = "EthernetServiceImpl";
private final Context mContext;
private final EthernetConfigStore mEthernetConfigStore;
private final AtomicBoolean mStarted = new AtomicBoolean(false);
private IpConfiguration mIpConfiguration;
private Handler mHandler;
private final EthernetNetworkFactory mTracker;
private final RemoteCallbackList<IEthernetServiceListener> mListeners =
new RemoteCallbackList<IEthernetServiceListener>();
public EthernetServiceImpl(Context context) {
mContext = context;
Log.i(TAG, "Creating EthernetConfigStore");
mEthernetConfigStore = new EthernetConfigStore();
mIpConfiguration = mEthernetConfigStore.readIpAndProxyConfigurations();
Log.i(TAG, "Read stored IP configuration: " + mIpConfiguration);
mTracker = new EthernetNetworkFactory(mListeners);
}
private void enforceAccessPermission() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE,
"EthernetService");
}
private void enforceConnectivityInternalPermission() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CONNECTIVITY_INTERNAL,
"ConnectivityService");
}
public void start() {
Log.i(TAG, "Starting Ethernet service");
HandlerThread handlerThread = new HandlerThread("EthernetServiceThread");
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper());
int enable = Settings.Global.getInt(mContext.getContentResolver(),Settings.Global.ETHERNET_ON,0);//add by hclydao
if(enable != EthernetManager.ETH_STATE_ENABLED) {
Log.i(TAG, "Ethernet is not enable");
return;
}
mTracker.start(mContext, mHandler);
mStarted.set(true);
}
//law
class TstartThread extends Thread {
public void run() {
Looper.prepare();
mTracker.start(mContext, mHandler);
mStarted.set(true);
Looper.loop();
}
}
public void Trackstart() { //add by hclydao
new TstartThread().start();
}
public void Trackstop() {
Log.i(TAG, "Stop Ethernet service");
Thread tstopthread = new Thread(new Runnable() {
public void run() {
Looper.prepare();
mTracker.stop();
mStarted.set(false);
Looper.loop();
}
});
tstopthread.start();
}
/**
* Get Ethernet configuration
* @return the Ethernet Configuration, contained in {@link IpConfiguration}.
*/
@Override
public IpConfiguration getConfiguration() {
enforceAccessPermission();
synchronized (mIpConfiguration) {
return new IpConfiguration(mIpConfiguration);
}
}
/**
* Set Ethernet configuration
*/
@Override
public void setConfiguration(IpConfiguration config) {
if (!mStarted.get()) {
Log.w(TAG, "System isn't ready enough to change ethernet configuration");
}
enforceConnectivityInternalPermission();
synchronized (mIpConfiguration) {
mEthernetConfigStore.writeIpAndProxyConfigurations(config);
// TODO: this does not check proxy settings, gateways, etc.
// Fix this by making IpConfiguration a complete representation of static configuration.
if (!config.equals(mIpConfiguration)) {
mIpConfiguration = new IpConfiguration(config);
mTracker.stop();
mTracker.start(mContext, mHandler);
}
}
}
/**
* Indicates whether the system currently has one or more
* Ethernet interfaces.
*/
@Override
public boolean isAvailable() {
enforceAccessPermission();
return mTracker.isTrackingInterface();
}
/**
* Addes a listener.
* @param listener A {@link IEthernetServiceListener} to add.
*/
public void addListener(IEthernetServiceListener listener) {
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}
enforceAccessPermission();
mListeners.register(listener);
}
/**
* Removes a listener.
* @param listener A {@link IEthernetServiceListener} to remove.
*/
public void removeListener(IEthernetServiceListener listener) {
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}
enforceAccessPermission();
mListeners.unregister(listener);
}
@Override
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump EthernetService from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid());
return;
}
pw.println("Current Ethernet state: ");
pw.increaseIndent();
mTracker.dump(fd, pw, args);
pw.decreaseIndent();
pw.println();
pw.println("Stored Ethernet configuration: ");
pw.increaseIndent();
pw.println(mIpConfiguration);
pw.decreaseIndent();
pw.println("Handler:");
pw.increaseIndent();
mHandler.dump(new PrintWriterPrinter(pw), "EthernetServiceImpl");
pw.decreaseIndent();
}
}
frameworks/base/core/res/res/values/config.xml
添加以下内容:
<item><xliff:g id="id">@string/status_bar_ethernet</xliff:g></item>
<string translatable="false" name="status_bar_ethernet">ethernet</string>
frameworks/base/core/java/android/content/Intent.java
加入以下内容:
/** @hide */
public static final String ACTION_ETHERNET_ON = "android.intent.action.ETHERNET_ON";
/** @hide */
public static final String ACTION_ETHERNET_CONNECTED = "android.intent.action.ETHERNET_CONNECTED";
/** @hide */
public static final String ACTION_ETHERNET_DISCONNECTED = "android.intent.action.ETHERNET_DISCONNECTED";
/** @hide */
public static final String ACTION_ETHERNET_OFF = "android.intent.action.ETHERNET_OFF";
/** @hide */
public static final String ACTION_ETHERNET_STATUSBAR_READY = "android.intent.action.ETHERNET_STATUSBAR_READY";
frameworks/base/core/res/res/values/symbols.xml
加入以下内容:
<java-symbol type="string" name="status_bar_ethernet" />
frameworks/base/packages/SystemUI/res/drawable/ethernet_connected.png
frameworks/base/packages/SystemUI/res/drawable/ethernet_connecting.png
frameworks/base/packages/SystemUI/res/drawable/ethernet_disconnected.png
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
添加以下内容:
import android.provider.Settings;
import android.net.EthernetManager;
private static final boolean DEBUG = true; //Log.isLoggable(TAG, Log.DEBUG);
private final String mSlotEthernet;
private static final int ETHERNET_ON = 1;
private static final int ETHERNET_OFF = 2;
private static final int ETHERNET_CONNECTED = 3;
private static final int ETHERNET_DISCONNECTED = 4;
private boolean mEthernetConnected = false;
在“PhoneStatusBarPolicy”中添加:
mSlotEthernet = context.getString(com.android.internal.R.string.status_bar_ethernet);
filter.addAction(Intent.ACTION_ETHERNET_ON);
filter.addAction(Intent.ACTION_ETHERNET_OFF);
filter.addAction(Intent.ACTION_ETHERNET_CONNECTED);
filter.addAction(Intent.ACTION_ETHERNET_DISCONNECTED);
mIconController.setIcon(mSlotEthernet, R.drawable.ethernet_disconnected, null);
mIconController.setIconVisibility(mSlotEthernet, false);
Log.d(TAG, "klein----PhoneStatusBarPolicy--broadcasts register ");
// listen for broadcasts
Log.d(TAG, "klein----PhoneStatusBarPolicy--tell ethernet that statusbar is ready");
Intent intent = new Intent();
intent.setAction(Intent.ACTION_ETHERNET_STATUSBAR_READY);
mContext.sendBroadcast(intent);
添加“updateEthernet” 方法:
private void updateEthernet(int mEthernetConnectedNewState) {
Log.d(TAG, "klein----updateEthernet--isEthernetConnected = " + mEthernetConnectedNewState);
int ethernetIconId = 0;
String ethernetDescription = null;
int enable = Settings.Global.getInt(mContext.getContentResolver(),Settings.Global.ETHERNET_ON,0);
boolean isEthernetOpened = (enable == EthernetManager.ETH_STATE_ENABLED);
Log.d(TAG, "klein----updateEthernet--isEthernetOpened = " + isEthernetOpened);
if ((mEthernetConnectedNewState == ETHERNET_CONNECTED)){
mEthernetConnected = true;
}else if (mEthernetConnectedNewState == ETHERNET_DISCONNECTED){
mEthernetConnected = false;
}
if (isEthernetOpened){
Log.d(TAG, "klein----set false");
mIconController.setIconVisibility(mSlotEthernet, false);
if (mEthernetConnected){
mIconController.setIcon(mSlotEthernet, R.drawable.ethernet_connected, null);
mIconController.setIconVisibility(mSlotEthernet, true);
} else {
mIconController.setIconVisibility(mSlotEthernet, false);
}
} else {
mEthernetConnected = false;
mIconController.setIconVisibility(mSlotEthernet, false);
}
}
在“BroadcastReceiver mIntentReceiver”的“onReceive”方法中增加:
else if (action.equals(Intent.ACTION_ETHERNET_ON)) {
updateEthernet(ETHERNET_ON);
}else if (action.equals(Intent.ACTION_ETHERNET_CONNECTED)) {
updateEthernet(ETHERNET_CONNECTED);
}else if (action.equals(Intent.ACTION_ETHERNET_DISCONNECTED)) {
updateEthernet(ETHERNET_DISCONNECTED);
}else if (action.equals(Intent.ACTION_ETHERNET_OFF)) {
updateEthernet(ETHERNET_OFF);
}
packages的修改
packages/apps/Settings/AndroidManifest.xml
添加以下内容:
<activity android:name="Settings$EthernetSettingsActivity"
android:label="@string/ethernet_settings"
android:taskAffinity="">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="com.android.settings.ETHERNET_SETTINGS" />
<action android:name="android.settings.ETHERNET_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.VOICE_LAUNCH" />
<category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.ethernet.EthernetSettings" />
<meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
android:resource="@string/ethernet_settings"
style="box-sizing: border-box;" />
<meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
android:value="true"
style="box-sizing: border-box;"/>
</activity>
<activity android:name="Settings$EthernetSettingsActivity"
android:label="@string/ethernet_settings"
android:taskAffinity=""
android:icon="@drawable/ic_settings_dock"
android:configChanges="orientation|keyboardHidden|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="com.android.settings.ETHERNET_SETTINGS" />
<action android:name="android.settings.ETHERNET_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.VOICE_LAUNCH" />
<category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
<intent-filter android:priority="4">
<action android:name="com.android.settings.action.SETTINGS" />
</intent-filter>
<meta-data android:name="com.android.settings.category"
android:value="com.android.settings.category.wireless" />
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.ethernet.EthernetSettings" />
<meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
android:value="true" />
</activity>
<!-- Keep compatibility with old shortcuts. -->
<activity-alias android:name=".ethernet.EthernetSettings"
android:taskAffinity="com.android.settings"
android:label="@string/ethernet_settings"
android:icon="@drawable/ic_settings_dock"
android:targetActivity="Settings$EthernetSettingsActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:exported="true">
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.wifi.EthernetSettings" />
</activity-alias>
packages/apps/Settings/res/layout/eth_configure.xml
完整文件内容如下:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="8dip"
android:orientation="vertical">
<LinearLayout
android:id="@+id/table"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
</LinearLayout>
<!-- Connection type -->
<TextView android:id="@+id/eth_con_type"
style="?android:attr/textAppearanceSmall"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dip"
android:text="@string/eth_con_type" />
<RadioGroup android:id="@+id/con_type"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<RadioButton android:id="@+id/dhcp_radio"
style="?android:attr/textAppearanceSmall"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/eth_con_type_dhcp"
></RadioButton>
<RadioButton android:id="@+id/manual_radio"
style="?android:attr/textAppearanceSmall"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/eth_con_type_manual"
></RadioButton>
</RadioGroup>
<!-- IP address -->
<LinearLayout android:id="@+id/enterprise_wrapper"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="0dip"
android:orientation="vertical">
<TextView android:id="@+id/ipaddr_text"
style="?android:attr/textAppearanceSmall"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dip"
android:text="@string/eth_ipaddr" />
<EditText android:id="@+id/ipaddr_edit"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dip"
android:singleLine="true" />
<!--
<TextView android:id="@+id/netmask_text"
style="?android:attr/textAppearanceSmall"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dip"
android:text="@string/eth_mask" />
<EditText android:id="@+id/netmask_edit"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dip"
android:singleLine="true" />
-->
<TextView android:id="@+id/prefix_text"
style="?android:attr/textAppearanceSmall"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dip"
android:text="@string/eth_network_prefix_length" />
<EditText android:id="@+id/prefix_edit"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dip"
android:singleLine="true" />
<TextView android:id="@+id/dns_text"
style="?android:attr/textAppearanceSmall"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dip"
android:text="@string/eth_dns" />
<EditText android:id="@+id/eth_dns_edit"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dip"
android:singleLine="true" />
<TextView android:id="@+id/gw_text"
style="?android:attr/textAppearanceSmall"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dip"
android:text="@string/eth_gw" />
<EditText android:id="@+id/eth_gw_edit"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dip"
android:singleLine="true" />
</LinearLayout>
</LinearLayout>
</ScrollView>
packages/apps/Settings/res/values/strings.xml
加入以下内容:
<string name="ethernet_settings">Ethernet</string>
<!-- Ethernet configuration dialog law-->
<string name="eth_config_title">Configure Ethernet device</string>
<string name="eth_setting">Ethernet</string>
<string name="eth_dev_list">Ethernet Devices:</string>
<string name="eth_con_type">Connection Type</string>
<string name="eth_con_type_dhcp">DHCP</string>
<string name="eth_con_type_manual">Static IP</string>
<string name="eth_dns">DNS address</string>
<string name="eth_gw">Gateway address</string>
<string name="eth_ipaddr">IP address</string>
<string name="eth_quick_toggle_title">Ethernet</string>
<string name="eth_quick_toggle_summary">Turn on Ethernet</string>
<string name="eth_conf_perf_title">Ethernet configuration</string>
<string name="eth_conf_summary">Configure Ethernet devices</string>
<string name="eth_mask">Netmask</string>
<string name="eth_toggle_summary_off">Turn off Ethernet</string>
<string name="eth_toggle_summary_on">Turn on Ethernet</string>
<string name="eth_settings_error">Failed to set: Please enter the valid characters 0~255</string>
<string name="eth_settings_empty">can\'t be empty</string>
<!-- Label for the <a target=_blank href="http://www.07net01.com/tags-Network-0.html" target="_blank" class="infotextkey" style="box-sizing: border-box; background-color: transparent; color: rgb(66, 139, 202);">Network</a> prefix of the network [CHAR LIMIT=25]-->
<string name="eth_network_prefix_length">Network prefix length</string>
packages/apps/Settings/res/xml/ethernet_settings.xml
完整的内容如下:
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 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.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/ethernet_settings"
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings">
<Preference
android:title="@string/eth_conf_perf_title"
android:summary="@string/eth_conf_summary"
android:key="ETHERNET_CONFIG"
android:persistent="true" />
</PreferenceScreen>
packages/apps/Settings/src/com/android/settings/Settings.java
添加如下内容:
public static class EthernetSettingsActivity extends SettingsActivity { /*empty */ }
packages/apps/Settings/src/com/android/settings/SettingsActivity.java
添加以下内容:
import com.android.settings.ethernet.EthernetSettings;
在“String[] SETTINGS_FOR_RESTRICTED”中加入:
Settings.EthernetSettingsActivity.class.getName(),
在“String[] ENTRY_FRAGMENTS”中加入:
EthernetSettings.class.getName(),//add by law
在“doUpdateTilesList”方法中加入:
setTileEnabled(new ComponentName(packageName,
Settings.EthernetSettingsActivity.class.getName()),
pm.hasSystemFeature(PackageManager.FEATURE_WIFI), isAdmin, pm);
packages/apps/Settings/src/com/android/settings/ethernet/EthernetDialog.java
新增此文件:
/*
* Copyright (C) 2010 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.ethernet;
import com.android.settings.R;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioButton;
import android.util.Slog;
import android.view.inputmethod.InputMethodManager;
import android.net.IpConfiguration;
import android.net.IpConfiguration.IpAssignment;
import android.net.IpConfiguration.ProxySettings;
import android.os.Environment;
import android.util.SparseArray;
import android.net.StaticIpConfiguration;
import android.net.EthernetManager;
import java.net.InetAddress;
import java.net.Inet4Address;
import java.util.Iterator;
import android.text.TextUtils;
import android.net.LinkAddress;
import android.net.NetworkUtils;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import com.android.settings.Utils;
import android.widget.Toast;
import android.net.EthernetManager;
import android.provider.Settings;
class EthernetDialog extends AlertDialog implements DialogInterface.OnClickListener, DialogInterface.OnShowListener,
DialogInterface.OnDismissListener{
private final String TAG = "EthConfDialog";
private static final boolean localLOGV = true;
/* This value comes from "wifi_ip_settings" resource array */
private static final int DHCP = 0;
private static final int STATIC_IP = 1;
private IpAssignment mIpAssignment = IpAssignment.DHCP;
private StaticIpConfiguration mStaticIpConfiguration = null;
private View mView;
private RadioButton mConTypeDhcp;
private RadioButton mConTypeManual;
private EditText mIpaddr;
private EditText mDns;
private EditText mGw;
//private EditText mMask;
private EditText mprefix;
private Context mContext;
private EthernetManager mEthManager;
private ConnectivityManager mCM;
public EthernetDialog(Context context,EthernetManager EthManager,ConnectivityManager cm) {
super(context);
Slog.d(TAG, "klein----EthernetDialog");
mContext = context;
mEthManager = EthManager;
mCM = cm;
buildDialogContent(context);
setOnShowListener(this);
setOnDismissListener(this);
}
public void onShow(DialogInterface dialog) {
if (localLOGV) Slog.d(TAG, "onShow");
UpdateInfo();
// soft keyboard pops up on the disabled EditText. Hide it.
InputMethodManager imm = (InputMethodManager)mContext.getSystemService(
Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(),
InputMethodManager.HIDE_IMPLICIT_ONLY);
}
public void onDismiss(DialogInterface dialog) {
if (localLOGV) Slog.d(TAG, "onDismiss");
}
public void UpdateInfo() {
int enable = Settings.Global.getInt(mContext.getContentResolver(),Settings.Global.ETHERNET_ON,0);//add by hclydao
if(enable == EthernetManager.ETH_STATE_ENABLED) {
//if(mEthManager.isAvailable()) {
IpConfiguration ipinfo = mEthManager.getConfiguration();
if(ipinfo != null) {
if(ipinfo.ipAssignment == IpAssignment.DHCP) {
mConTypeDhcp.setChecked(true);
mIpaddr.setEnabled(false);
mDns.setEnabled(false);
mGw.setEnabled(false);
//mMask.setEnabled(true);
mprefix.setEnabled(false);
mDns.setText("");
mGw.setText("");
mprefix.setText("");
mIpaddr.setText("");
if(mCM != null) {
LinkProperties lp = mCM.getLinkProperties(ConnectivityManager.TYPE_ETHERNET);
if(lp != null) {
mIpaddr.setText(formatIpAddresses(lp));
}
}
} else {
mConTypeManual.setChecked(true);
mIpaddr.setEnabled(true);
mDns.setEnabled(true);
mGw.setEnabled(true);
//mMask.setEnabled(true);
mprefix.setEnabled(true);
StaticIpConfiguration staticConfig = ipinfo.getStaticIpConfiguration();
if (staticConfig != null) {
if (staticConfig.ipAddress != null) {
mIpaddr.setText(staticConfig.ipAddress.getAddress().getHostAddress());
mprefix.setText(Integer.toString(staticConfig.ipAddress.getNetworkPrefixLength()));
}
if (staticConfig.gateway != null) {
mGw.setText(staticConfig.gateway.getHostAddress());
}
Iterator<InetAddress> dnsIterator = staticConfig.dnsServers.iterator();
if (dnsIterator.hasNext()) {
mDns.setText(dnsIterator.next().getHostAddress());
}
}
}
}
}
}
public int buildDialogContent(Context context) {
this.setTitle(R.string.eth_config_title);
this.setView(mView = getLayoutInflater().inflate(R.layout.eth_configure, null));
mConTypeDhcp = (RadioButton) mView.findViewById(R.id.dhcp_radio);
mConTypeManual = (RadioButton) mView.findViewById(R.id.manual_radio);
mIpaddr = (EditText)mView.findViewById(R.id.ipaddr_edit);
mprefix = (EditText)mView.findViewById(R.id.prefix_edit);
// mMask = (EditText)mView.findViewById(R.id.netmask_edit);
mDns = (EditText)mView.findViewById(R.id.eth_dns_edit);
mGw = (EditText)mView.findViewById(R.id.eth_gw_edit);
mConTypeDhcp.setChecked(true);
mConTypeManual.setChecked(false);
mIpaddr.setEnabled(false);
// mMask.setEnabled(false);
mprefix.setEnabled(false);
mDns.setEnabled(false);
mGw.setEnabled(false);
mConTypeManual.setOnClickListener(new RadioButton.OnClickListener() {
public void onClick(View v) {
mIpaddr.setEnabled(true);
mDns.setEnabled(true);
mGw.setEnabled(true);
//mMask.setEnabled(true);
mprefix.setEnabled(true);
mIpAssignment = IpAssignment.STATIC;
if(TextUtils.isEmpty(mIpaddr.getText().toString()))
mIpaddr.setText("192.168.1.15");
if(TextUtils.isEmpty(mDns.getText().toString()))
mDns.setText("192.168.1.1");
if(TextUtils.isEmpty(mGw.getText().toString()))
mGw.setText("192.168.1.1");
if(TextUtils.isEmpty(mprefix.getText().toString()))
mprefix.setText("24");
}
});
mConTypeDhcp.setOnClickListener(new RadioButton.OnClickListener() {
public void onClick(View v) {
mIpaddr.setEnabled(false);
mDns.setEnabled(false);
mGw.setEnabled(false);
//mMask.setEnabled(false);
mprefix.setEnabled(false);
mIpAssignment = IpAssignment.DHCP;
mDns.setText("");
mGw.setText("");
mprefix.setText("");
mIpaddr.setText("");
}
});
this.setInverseBackgroundForced(true);
this.setButton(BUTTON_POSITIVE, context.getText(R.string.menu_save), this);
this.setButton(BUTTON_NEGATIVE, context.getText(R.string.menu_cancel), this);
UpdateInfo();
return 0;
}
private String formatIpAddresses(LinkProperties prop) {
if (prop == null) return null;
Iterator<InetAddress> iter = prop.getAllAddresses().iterator();
// If there are no entries, return null
if (!iter.hasNext()) return null;
// Concatenate all available addresses, comma separated
String addresses = "";
while (iter.hasNext()) {
addresses += iter.next().getHostAddress();
if (iter.hasNext()) addresses += "\n";
}
return addresses;
}
private Inet4Address getIPv4Address(String text) {
try {
return (Inet4Address) NetworkUtils.numericToInetAddress(text);
} catch (IllegalArgumentException|ClassCastException e) {
return null;
}
}
private int validateIpConfigFields(StaticIpConfiguration staticIpConfiguration) {
String ipAddr = mIpaddr.getText().toString();
Inet4Address inetAddr = getIPv4Address(ipAddr);
if (inetAddr == null) {
return 2;
}
/*
String netmask = mMask.getText().toString();
if (TextUtils.isEmpty(netmask))
return 11;
Inet4Address netmas = getIPv4Address(netmask);
if (netmas == null) {
return 12;
}
int nmask = NetworkUtils.inetAddressToInt(netmas);
int prefixlength = NetworkUtils.netmaskIntToPrefixLength(nmask);
*/
int networkPrefixLength = -1;
try {
networkPrefixLength = Integer.parseInt(mprefix.getText().toString());
if (networkPrefixLength < 0 || networkPrefixLength > 32) {
return 3;
}
staticIpConfiguration.ipAddress = new LinkAddress(inetAddr, networkPrefixLength);
} catch (NumberFormatException e) {
// Set the hint as default after user types in ip address
}
String gateway = mGw.getText().toString();
InetAddress gatewayAddr = getIPv4Address(gateway);
if (gatewayAddr == null) {
return 4;
}
staticIpConfiguration.gateway = gatewayAddr;
String dns = mDns.getText().toString();
InetAddress dnsAddr = null;
dnsAddr = getIPv4Address(dns);
if (dnsAddr == null) {
return 5;
}
staticIpConfiguration.dnsServers.add(dnsAddr);
return 0;
}
private void handle_saveconf() {
if (mConTypeDhcp.isChecked()) {
Slog.i(TAG,"mode dhcp");
mEthManager.setConfiguration(new IpConfiguration(mIpAssignment, ProxySettings.NONE,
null, null));
} else {
Slog.i(TAG,"mode static ip");
if(isIpAddress(mIpaddr.getText().toString())
&& isIpAddress(mGw.getText().toString())
&& isIpAddress(mDns.getText().toString())) {
if(TextUtils.isEmpty(mIpaddr.getText().toString())
|| TextUtils.isEmpty(mprefix.getText().toString())
|| TextUtils.isEmpty(mGw.getText().toString())
|| TextUtils.isEmpty(mDns.getText().toString())) {
Toast.makeText(mContext, R.string.eth_settings_empty, Toast.LENGTH_LONG).show();
return ;
}
mStaticIpConfiguration = new StaticIpConfiguration();
int result = validateIpConfigFields(mStaticIpConfiguration);
if (result != 0) {
Toast.makeText(mContext, " error id is " + result, Toast.LENGTH_LONG).show();
return ;
} else {
mEthManager.setConfiguration( new IpConfiguration(mIpAssignment, ProxySettings.NONE,
mStaticIpConfiguration, null));
}
} else
Toast.makeText(mContext, R.string.eth_settings_error, Toast.LENGTH_LONG).show();
}
}
private boolean isIpAddress(String value) {
int start = 0;
int end = value.indexOf('.');
int numBlocks = 0;
while (start < value.length()) {
if (end == -1) {
end = value.length();
}
try {
int block = Integer.parseInt(value.substring(start, end));
if ((block > 255) || (block < 0)) {
return false;
}
} catch (NumberFormatException e) {
return false;
}
numBlocks++;
start = end + 1;
end = value.indexOf('.', start);
}
return numBlocks == 4;
}
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case BUTTON_POSITIVE:
handle_saveconf();
break;
case BUTTON_NEGATIVE:
//Don't need to do anything
break;
default:
}
}
}
packages/apps/Settings/src/com/android/settings/ethernet/EthernetEnabler.java
新增此文件:
/*
* Copyright (C) 2010 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.
*/
/*
* developed by hclydao@gmail.com
*/
package com.android.settings.ethernet;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceScreen;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.preference.CheckBoxPreference;
import java.util.ArrayList;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.R;
import com.android.settings.widget.SwitchBar;
import com.android.settings.SettingsActivity;
import android.widget.Switch;
import android.util.Slog;
import android.net.EthernetManager;
import android.provider.Settings;
public class EthernetEnabler implements SwitchBar.OnSwitchChangeListener {
private final String TAG = "EthernetEnabler";
private Context mContext;
private SwitchBar mSwitchBar;
private boolean mListeningToOnSwitchChange = false;
private EthernetDialog mEthDialog = null;
private EthernetManager mEthManager;
public void setConfigDialog(EthernetDialog Dialog) {
mEthDialog = Dialog;
}
public EthernetEnabler(Context context, SwitchBar switchBar,EthernetManager ethernetManager) {
mContext = context;
mSwitchBar = switchBar;
mEthManager = ethernetManager;
setupSwitchBar();
}
public void resume(Context context) {
mContext = context;
if (!mListeningToOnSwitchChange) {
mSwitchBar.addOnSwitchChangeListener(this);
mListeningToOnSwitchChange = true;
}
}
public void pause() {
if (mListeningToOnSwitchChange) {
mSwitchBar.removeOnSwitchChangeListener(this);
mListeningToOnSwitchChange = false;
}
}
public void setupSwitchBar() {
if (!mListeningToOnSwitchChange) {
mSwitchBar.addOnSwitchChangeListener(this);
mListeningToOnSwitchChange = true;
}
mSwitchBar.show();
int enable = Settings.Global.getInt(mContext.getContentResolver(),Settings.Global.ETHERNET_ON,0);//add by hclydao
if(enable == EthernetManager.ETH_STATE_ENABLED) {
mSwitchBar.setChecked(true);
Log.d(TAG,"setupSwitchBar on");
Intent intent = new Intent();
intent.setAction(Intent.ACTION_ETHERNET_ON);
mContext.sendBroadcast(intent);
} else {
mSwitchBar.setChecked(false);
Log.d(TAG,"setupSwitchBar off");
Intent intent = new Intent();
intent.setAction(Intent.ACTION_ETHERNET_OFF);
mContext.sendBroadcast(intent);
}
}
public void teardownSwitchBar() {
if (mListeningToOnSwitchChange) {
mSwitchBar.removeOnSwitchChangeListener(this);
mListeningToOnSwitchChange = false;
}
mSwitchBar.hide();
}
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
Log.d(TAG,"klein--isChecked = " + isChecked);
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.ETHERNET_ON,
isChecked ? EthernetManager.ETH_STATE_ENABLED : EthernetManager.ETH_STATE_DISABLED);
if(isChecked) {
//if(mEthDialog != null)
//mEthDialog.show();
} else {
Log.d(TAG,"klein--onSwitchChanged off");
Intent intent = new Intent();
intent.setAction(Intent.ACTION_ETHERNET_OFF);
mContext.sendBroadcast(intent);
if(mEthManager != null)
mEthManager.stop();
}
if(isChecked){
Log.d(TAG,"klein--onSwitchChanged on");
Intent intent = new Intent();
intent.setAction(Intent.ACTION_ETHERNET_ON);
mContext.sendBroadcast(intent);
if(mEthManager != null){
mEthManager.start();
}
}
}
}
packages/apps/Settings/src/com/android/settings/ethernet/EthernetSettings.java
新增此文件:
/*
* Copyright (C) 2010 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.
*/
/*
* developed by hclydao@gmail.com
*/
package com.android.settings.ethernet;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.support.v7.preference.AndroidResources;
import android.support.v7.preference.DialogPreference;
import android.support.v7.preference.EditTextPreference;
import android.support.v7.preference.ListPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceGroupAdapter;
import android.support.v7.preference.PreferenceManager;
import android.support.v7.preference.PreferenceRecyclerViewAccessibilityDelegate;
import android.support.v7.preference.PreferenceScreen;
import android.support.v7.preference.PreferenceViewHolder;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.preference.CheckBoxPreference;
import java.util.ArrayList;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.R;
import com.android.settings.widget.SwitchBar;
import com.android.settings.SettingsActivity;
import android.widget.Switch;
import android.app.Activity;
import android.app.ActivityManager;
import android.net.EthernetManager;
import android.content.Context;
import android.net.ConnectivityManager;
import android.util.Slog;
import android.widget.Toast;
import android.os.Looper;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
public class EthernetSettings extends SettingsPreferenceFragment implements
Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener{
private static final String TAG = "EthernetSettings";
private EthernetEnabler mEthEnabler;
private static final String KEY_CONF_ETH = "ETHERNET_CONFIG";
private EthernetDialog mEthDialog = null;
private Preference mEthConfigPref;
private ConnectivityManager mCM;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.ethernet_settings);
mEthConfigPref = (Preference)findPreference(KEY_CONF_ETH);
mEthConfigPref.setOnPreferenceChangeListener(this);
mEthConfigPref.setOnPreferenceClickListener(this);
}
@Override
public void onStart() {
super.onStart();
// On/off switch is hidden for Setup Wizard (returns null)
mEthEnabler = createEthernetEnabler();
mCM = (ConnectivityManager)getActivity().getSystemService(
Context.CONNECTIVITY_SERVICE);
mEthDialog = new EthernetDialog(getActivity(),(EthernetManager)getSystemService(Context.ETHERNET_SERVICE),mCM);
mEthEnabler.setConfigDialog(mEthDialog);
}
@Override
public void onResume() {
final Activity activity = getActivity();
super.onResume();
if (mEthEnabler != null) {
mEthEnabler.resume(activity);
}
}
@Override
public void onPause() {
super.onPause();
if (mEthEnabler != null) {
mEthEnabler.pause();
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (mEthEnabler != null) {
mEthEnabler.teardownSwitchBar();
}
}
/**
* @return new WifiEnabler or null (as overridden by WifiSettingsForSetupWizard)
*/
/* package */
EthernetEnabler createEthernetEnabler() {
final SettingsActivity activity = (SettingsActivity) getActivity();
return new EthernetEnabler(activity, activity.getSwitchBar(),(EthernetManager)getSystemService(Context.ETHERNET_SERVICE));
}
public boolean onPreferenceChange(Preference preference, Object objValue) {
return true;
}
/**
* klein.zhou@quectel.com
* onPreferenceTreeClick
*/
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
Log.d(TAG, "leave empty");
return false;
}
/**
* klein.zhou@quectel.com
* onPreferenceClick
*/
public boolean onPreferenceClick(Preference preference){
Log.d(TAG, "klein---onPreferenceClick");
if (preference == mEthConfigPref) {
final SettingsActivity activity = (SettingsActivity) getActivity();
if(activity.getSwitchBar().isChecked()) {
if(mEthDialog != null){
mEthDialog.show();
}
} else {
Toast.makeText(getActivity(), "please turn on ethernet",
Toast.LENGTH_LONG).show();
}
}
return false;
}
@Override
protected int getMetricsCategory(){
return MetricsEvent.WIFI;
}
}
packages/apps/Settings/res/drawable-hdpi/ic_settings_dock_alpha.png
新增此文件:
packages/apps/Settings/res/drawable/ic_settings_dock.xml
新增此文件:
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/ic_settings_dock_alpha"
android:tint="?android:attr/colorAccent" />
重新编译
修改完上述文件后重新编译系统固件,使用新的固件启动系统,尝试相关操作。
本次小结
这个人很懒,什么也没有留下!