mTrackingInterfaces =
59 | new ConcurrentHashMap<>();
60 | private final Handler mHandler;
61 | private final Context mContext;
62 |
63 | public EthernetNetworkFactory(Handler handler, Context context, NetworkCapabilities filter) {
64 | super(handler.getLooper(), context, NETWORK_TYPE, filter);
65 |
66 | if (DBG) {
67 | Log.d(TAG, "EthernetNetworkFactory new");
68 | }
69 | mHandler = handler;
70 | mContext = context;
71 |
72 | setScoreFilter(NETWORK_SCORE);
73 | }
74 |
75 | @Override
76 | public boolean acceptRequest(NetworkRequest request, int score) {
77 | if (DBG) {
78 | Log.d(TAG, "acceptRequest, request: " + request + ", score: " + score);
79 | }
80 |
81 | return networkForRequest(request) != null;
82 | }
83 |
84 | @Override
85 | protected void needNetworkFor(NetworkRequest networkRequest, int score) {
86 | NetworkInterfaceState network = networkForRequest(networkRequest);
87 |
88 | if (network == null) {
89 | Log.e(TAG, "needNetworkFor, failed to get a network for start" + networkRequest);
90 | return;
91 | }
92 |
93 | if (++network.refCount == 1) {
94 | Log.d(TAG, "+needNetworkFor, " + networkRequest);
95 |
96 | network.start();
97 | }
98 | }
99 |
100 | @Override
101 | protected void releaseNetworkFor(NetworkRequest networkRequest) {
102 | NetworkInterfaceState network = networkForRequest(networkRequest);
103 | if (network == null) {
104 | Log.e(TAG, "needNetworkFor, failed to get a network for stop" + networkRequest);
105 | return;
106 | }
107 |
108 | if (--network.refCount == 1) {
109 | Log.d(TAG, "-needNetworkFor, " + networkRequest);
110 | network.stop();
111 | }
112 | }
113 |
114 | /**
115 | * Returns an array of available interface names. The array is sorted: unrestricted interfaces
116 | * goes first, then sorted by name.
117 | */
118 | String[] getAvailableInterfaces(boolean includeRestricted) {
119 | return mTrackingInterfaces.values()
120 | .stream()
121 | .filter(iface -> !iface.isRestricted() || includeRestricted)
122 | .sorted((iface1, iface2) -> {
123 | int r = Boolean.compare(iface1.isRestricted(), iface2.isRestricted());
124 | return r == 0 ? iface1.name.compareTo(iface2.name) : r;
125 | })
126 | .map(iface -> iface.name)
127 | .toArray(String[]::new);
128 | }
129 |
130 | void addInterface(String ifaceName, String hwAddress, NetworkCapabilities capabilities,
131 | IpConfiguration ipConfiguration) {
132 | if (mTrackingInterfaces.containsKey(ifaceName)) {
133 | Log.e(TAG, "Interface with name " + ifaceName + " already exists.");
134 | return;
135 | }
136 |
137 | if (DBG) {
138 | Log.d(TAG, "addInterface, iface: " + ifaceName + ", capabilities: " + capabilities);
139 | }
140 |
141 | NetworkInterfaceState iface = new NetworkInterfaceState(
142 | ifaceName, hwAddress, mHandler, mContext, capabilities);
143 | iface.setIpConfig(ipConfiguration);
144 | mTrackingInterfaces.put(ifaceName, iface);
145 |
146 | updateCapabilityFilter();
147 | }
148 |
149 | private void updateCapabilityFilter() {
150 | NetworkCapabilities capabilitiesFilter = new NetworkCapabilities();
151 | capabilitiesFilter.clearAll();
152 |
153 | for (NetworkInterfaceState iface: mTrackingInterfaces.values()) {
154 | capabilitiesFilter.combineCapabilities(iface.mCapabilities);
155 | }
156 |
157 | if (DBG) Log.d(TAG, "updateCapabilityFilter: " + capabilitiesFilter);
158 | setCapabilityFilter(capabilitiesFilter);
159 | }
160 |
161 | void removeInterface(String interfaceName) {
162 | NetworkInterfaceState iface = mTrackingInterfaces.remove(interfaceName);
163 | if (DBG) {
164 | Log.d(TAG, "removeInterface iface=" + iface + " interfaceName=" + interfaceName);
165 | }
166 | if (iface != null) {
167 | iface.stop();
168 | }
169 |
170 | updateCapabilityFilter();
171 | }
172 |
173 | /** Returns true if state has been modified */
174 | boolean updateInterfaceLinkState(String ifaceName, boolean up) {
175 | if (!mTrackingInterfaces.containsKey(ifaceName)) {
176 | return false;
177 | }
178 |
179 | if (DBG) {
180 | Log.d(TAG, "updateInterfaceLinkState, iface: " + ifaceName + ", up: " + up);
181 | }
182 |
183 | NetworkInterfaceState iface = mTrackingInterfaces.get(ifaceName);
184 | return iface.updateLinkState(up);
185 | }
186 |
187 | boolean hasInterface(String interfacName) {
188 | return mTrackingInterfaces.containsKey(interfacName);
189 | }
190 |
191 | void updateIpConfiguration(String iface, IpConfiguration ipConfiguration) {
192 | NetworkInterfaceState network = mTrackingInterfaces.get(iface);
193 | if (network != null) {
194 | network.setIpConfig(ipConfiguration);
195 | }
196 | }
197 |
198 | private NetworkInterfaceState networkForRequest(NetworkRequest request) {
199 | String requestedIface = null;
200 |
201 | NetworkSpecifier specifier = request.networkCapabilities.getNetworkSpecifier();
202 | if (specifier instanceof StringNetworkSpecifier) {
203 | requestedIface = ((StringNetworkSpecifier) specifier).specifier;
204 | }
205 |
206 | NetworkInterfaceState network = null;
207 | if (!TextUtils.isEmpty(requestedIface)) {
208 | NetworkInterfaceState n = mTrackingInterfaces.get(requestedIface);
209 | if (n != null && n.statisified(request.networkCapabilities)) {
210 | network = n;
211 | }
212 | } else {
213 | for (NetworkInterfaceState n : mTrackingInterfaces.values()) {
214 | if (n.statisified(request.networkCapabilities)) {
215 | network = n;
216 | break;
217 | }
218 | }
219 | }
220 |
221 | if (DBG) {
222 | Log.i(TAG, "networkForRequest, request: " + request + ", network: " + network);
223 | }
224 |
225 | return network;
226 | }
227 |
228 | private static class NetworkInterfaceState {
229 | final String name;
230 |
231 | private final String mHwAddress;
232 | private final NetworkCapabilities mCapabilities;
233 | private final Handler mHandler;
234 | private final Context mContext;
235 | private final NetworkInfo mNetworkInfo;
236 |
237 | private static String sTcpBufferSizes = null; // Lazy initialized.
238 |
239 | private boolean mLinkUp;
240 | private LinkProperties mLinkProperties = new LinkProperties();
241 |
242 | private IpClient mIpClient;
243 | private NetworkAgent mNetworkAgent;
244 | private IpConfiguration mIpConfig;
245 |
246 | long refCount = 0;
247 |
248 | private final IpClient.Callback mIpClientCallback = new IpClient.Callback() {
249 | @Override
250 | public void onProvisioningSuccess(LinkProperties newLp) {
251 | mHandler.post(() -> onIpLayerStarted(newLp));
252 | }
253 |
254 | @Override
255 | public void onProvisioningFailure(LinkProperties newLp) {
256 | mHandler.post(() -> onIpLayerStopped(newLp));
257 | }
258 |
259 | @Override
260 | public void onLinkPropertiesChange(LinkProperties newLp) {
261 | mHandler.post(() -> updateLinkProperties(newLp));
262 | }
263 | };
264 |
265 | NetworkInterfaceState(String ifaceName, String hwAddress, Handler handler, Context context,
266 | NetworkCapabilities capabilities) {
267 | name = ifaceName;
268 | mCapabilities = capabilities;
269 | mHandler = handler;
270 | mContext = context;
271 |
272 | mHwAddress = hwAddress;
273 | mNetworkInfo = new NetworkInfo(TYPE_ETHERNET, 0, NETWORK_TYPE, "");
274 | mNetworkInfo.setExtraInfo(mHwAddress);
275 | mNetworkInfo.setIsAvailable(true);
276 | }
277 |
278 | void setIpConfig(IpConfiguration ipConfig) {
279 |
280 | this.mIpConfig = ipConfig;
281 | }
282 |
283 | boolean statisified(NetworkCapabilities requestedCapabilities) {
284 | return requestedCapabilities.satisfiedByNetworkCapabilities(mCapabilities);
285 | }
286 |
287 | boolean isRestricted() {
288 | return mCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
289 | }
290 |
291 | private void start() {
292 | if (mIpClient != null) {
293 | if (DBG) Log.d(TAG, "IpClient already started");
294 | return;
295 | }
296 | if (DBG) {
297 | Log.d(TAG, String.format("starting IpClient(%s): mNetworkInfo=%s", name,
298 | mNetworkInfo));
299 | }
300 |
301 | mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddress);
302 |
303 | mIpClient = new IpClient(mContext, name, mIpClientCallback);
304 |
305 | if (sTcpBufferSizes == null) {
306 | sTcpBufferSizes = mContext.getResources().getString(
307 | com.android.internal.R.string.config_ethernet_tcp_buffers);
308 | }
309 |
310 | provisionIpClient(mIpClient, mIpConfig, sTcpBufferSizes);
311 |
312 | }
313 |
314 | void onIpLayerStarted(LinkProperties linkProperties) {
315 | if (mNetworkAgent != null) {
316 | Log.e(TAG, "Already have a NetworkAgent - aborting new request");
317 | stop();
318 | return;
319 | }
320 | mLinkProperties = linkProperties;
321 | mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddress);
322 | mNetworkInfo.setIsAvailable(true);
323 |
324 | // Create our NetworkAgent.
325 | mNetworkAgent = new NetworkAgent(mHandler.getLooper(), mContext,
326 | NETWORK_TYPE, mNetworkInfo, mCapabilities, mLinkProperties,
327 | NETWORK_SCORE) {
328 | public void unwanted() {
329 | if (this == mNetworkAgent) {
330 | stop();
331 | } else if (mNetworkAgent != null) {
332 | Log.d(TAG, "Ignoring unwanted as we have a more modern " +
333 | "instance");
334 | } // Otherwise, we've already called stop.
335 | }
336 | };
337 | }
338 |
339 | void onIpLayerStopped(LinkProperties linkProperties) {
340 | // This cannot happen due to provisioning timeout, because our timeout is 0. It can only
341 | // happen if we're provisioned and we lose provisioning.
342 | Log.e(TAG, "onIpLayerStopped");
343 | stop();
344 | start();
345 | }
346 |
347 | void updateLinkProperties(LinkProperties linkProperties) {
348 | mLinkProperties = linkProperties;
349 | if (mNetworkAgent != null) {
350 | mNetworkAgent.sendLinkProperties(linkProperties);
351 | }
352 | }
353 |
354 | /** Returns true if state has been modified */
355 | boolean updateLinkState(boolean up) {
356 | if (mLinkUp == up) return false;
357 | mLinkUp = up;
358 |
359 | Log.e(TAG, "updateLinkState");
360 | stop();
361 | if (up) {
362 | start();
363 | }
364 |
365 | return true;
366 | }
367 |
368 | void stop() {
369 | if (mIpClient != null) {
370 | mIpClient.shutdown();
371 | mIpClient.awaitShutdown();
372 | mIpClient = null;
373 | }
374 |
375 | // ConnectivityService will only forget our NetworkAgent if we send it a NetworkInfo object
376 | // with a state of DISCONNECTED or SUSPENDED. So we can't simply clear our NetworkInfo here:
377 | // that sets the state to IDLE, and ConnectivityService will still think we're connected.
378 | //
379 | mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddress);
380 | if (mNetworkAgent != null) {
381 | updateAgent();
382 | mNetworkAgent = null;
383 | }
384 | clear();
385 | }
386 |
387 | private void updateAgent() {
388 | if (mNetworkAgent == null) return;
389 | if (DBG) {
390 | Log.i(TAG, "Updating mNetworkAgent with: " +
391 | mCapabilities + ", " +
392 | mNetworkInfo + ", " +
393 | mLinkProperties);
394 | }
395 | mNetworkAgent.sendNetworkCapabilities(mCapabilities);
396 | mNetworkAgent.sendNetworkInfo(mNetworkInfo);
397 | mNetworkAgent.sendLinkProperties(mLinkProperties);
398 | // never set the network score below 0.
399 | mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0);
400 | }
401 |
402 | private void clear() {
403 | mLinkProperties.clear();
404 | mNetworkInfo.setDetailedState(DetailedState.IDLE, null, null);
405 | mNetworkInfo.setIsAvailable(false);
406 | }
407 |
408 | private static void provisionIpClient(IpClient ipClient, IpConfiguration config,
409 | String tcpBufferSizes) {
410 | if (config.getProxySettings() == ProxySettings.STATIC ||
411 | config.getProxySettings() == ProxySettings.PAC) {
412 | ipClient.setHttpProxy(config.getHttpProxy());
413 | }
414 |
415 | if (!TextUtils.isEmpty(tcpBufferSizes)) {
416 | ipClient.setTcpBufferSizes(tcpBufferSizes);
417 | }
418 |
419 | final ProvisioningConfiguration provisioningConfiguration;
420 | if (config.getIpAssignment() == IpAssignment.STATIC) {
421 | provisioningConfiguration = IpClient.buildProvisioningConfiguration()
422 | .withStaticConfiguration(config.getStaticIpConfiguration())
423 | .build();
424 | } else {
425 | provisioningConfiguration = IpClient.buildProvisioningConfiguration()
426 | .withProvisioningTimeoutMs(0)
427 | .build();
428 | }
429 |
430 | ipClient.startProvisioning(provisioningConfiguration);
431 | }
432 |
433 | @Override
434 | public String toString() {
435 | return getClass().getSimpleName() + "{ "
436 | + "iface: " + name + ", "
437 | + "up: " + mLinkUp + ", "
438 | + "hwAddress: " + mHwAddress + ", "
439 | + "networkInfo: " + mNetworkInfo + ", "
440 | + "networkAgent: " + mNetworkAgent + ", "
441 | + "ipClient: " + mIpClient + ","
442 | + "linkProperties: " + mLinkProperties
443 | + "}";
444 | }
445 | }
446 |
447 | void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
448 | super.dump(fd, pw, args);
449 | pw.println(getClass().getSimpleName());
450 | pw.println("Tracking interfaces:");
451 | pw.increaseIndent();
452 | for (String iface: mTrackingInterfaces.keySet()) {
453 | NetworkInterfaceState ifaceState = mTrackingInterfaces.get(iface);
454 | pw.println(iface + ":" + ifaceState);
455 | pw.increaseIndent();
456 | final IpClient ipClient = ifaceState.mIpClient;
457 | if (ipClient != null) {
458 | ipClient.dump(fd, pw, args);
459 | } else {
460 | pw.println("IpClient is null");
461 | }
462 | pw.decreaseIndent();
463 | }
464 | pw.decreaseIndent();
465 | }
466 | }
467 |
--------------------------------------------------------------------------------
/frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetTracker.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.android.server.ethernet;
18 |
19 | import android.annotation.Nullable;
20 | import android.content.Context;
21 | import android.net.IEthernetServiceListener;
22 | import android.net.InterfaceConfiguration;
23 | import android.net.IpConfiguration;
24 | import android.net.IpConfiguration.IpAssignment;
25 | import android.net.IpConfiguration.ProxySettings;
26 | import android.net.LinkAddress;
27 | import android.net.NetworkCapabilities;
28 | import android.net.StaticIpConfiguration;
29 | import android.os.Handler;
30 | import android.os.IBinder;
31 | import android.os.INetworkManagementService;
32 | import android.os.RemoteCallbackList;
33 | import android.os.RemoteException;
34 | import android.os.ServiceManager;
35 | import android.text.TextUtils;
36 | import android.util.ArrayMap;
37 | import android.util.Log;
38 | import android.provider.Settings;
39 |
40 | import com.android.internal.annotations.VisibleForTesting;
41 | import com.android.internal.util.IndentingPrintWriter;
42 | import com.android.server.net.BaseNetworkObserver;
43 |
44 | import java.io.FileDescriptor;
45 | import java.net.InetAddress;
46 | import java.util.ArrayList;
47 | import java.util.concurrent.ConcurrentHashMap;
48 |
49 | /**
50 | * Tracks Ethernet interfaces and manages interface configurations.
51 | *
52 | * Interfaces may have different {@link android.net.NetworkCapabilities}. This mapping is defined
53 | * in {@code config_ethernet_interfaces}. Notably, some interfaces could be marked as restricted by
54 | * not specifying {@link android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED} flag.
55 | * Interfaces could have associated {@link android.net.IpConfiguration}.
56 | * Ethernet Interfaces may be present at boot time or appear after boot (e.g., for Ethernet adapters
57 | * connected over USB). This class supports multiple interfaces. When an interface appears on the
58 | * system (or is present at boot time) this class will start tracking it and bring it up. Only
59 | * interfaces whose names match the {@code config_ethernet_iface_regex} regular expression are
60 | * tracked.
61 | *
62 | *
All public or package private methods must be thread-safe unless stated otherwise.
63 | */
64 | final class EthernetTracker {
65 | private final static String TAG = EthernetTracker.class.getSimpleName();
66 | private final static boolean DBG = EthernetNetworkFactory.DBG;
67 |
68 | /** Product-dependent regular expression of interface names we track. */
69 | private final String mIfaceMatch;
70 |
71 | /** Mapping between {iface name | mac address} -> {NetworkCapabilities} */
72 | private final ConcurrentHashMap mNetworkCapabilities =
73 | new ConcurrentHashMap<>();
74 | private final ConcurrentHashMap mIpConfigurations =
75 | new ConcurrentHashMap<>();
76 |
77 | private final INetworkManagementService mNMService;
78 | private final Handler mHandler;
79 | private final EthernetNetworkFactory mFactory;
80 | private final EthernetConfigStore mConfigStore;
81 | private InterfaceObserver mInterfaceObserver;
82 | private boolean mEnabled;
83 |
84 | private final RemoteCallbackList mListeners =
85 | new RemoteCallbackList<>();
86 |
87 | private volatile IpConfiguration mIpConfigForDefaultInterface;
88 |
89 | EthernetTracker(Context context, Handler handler) {
90 | if (DBG) {
91 | Log.d(TAG, "EthernetTracker new");
92 | }
93 | mHandler = handler;
94 |
95 | // The services we use.
96 | IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
97 | mNMService = INetworkManagementService.Stub.asInterface(b);
98 |
99 | // Interface match regex.
100 | mIfaceMatch = context.getResources().getString(
101 | com.android.internal.R.string.config_ethernet_iface_regex);
102 |
103 | // Read default Ethernet interface configuration from resources
104 | final String[] interfaceConfigs = context.getResources().getStringArray(
105 | com.android.internal.R.array.config_ethernet_interfaces);
106 | for (String strConfig : interfaceConfigs) {
107 | parseEthernetConfig(strConfig);
108 | }
109 |
110 | mConfigStore = new EthernetConfigStore();
111 |
112 | NetworkCapabilities nc = createNetworkCapabilities(true /* clear default capabilities */);
113 | mFactory = new EthernetNetworkFactory(handler, context, nc);
114 | mFactory.register();
115 | }
116 |
117 | void start() {
118 | if (DBG) {
119 | Log.d(TAG, "EthernetTracker start");
120 | }
121 | mConfigStore.read();
122 |
123 | // Default interface is just the first one we want to track.
124 | mIpConfigForDefaultInterface = mConfigStore.getIpConfigurationForDefaultInterface();
125 | final ArrayMap configs = mConfigStore.getIpConfigurations();
126 | for (int i = 0; i < configs.size(); i++) {
127 | mIpConfigurations.put(configs.keyAt(i), configs.valueAt(i));
128 | }
129 |
130 | mInterfaceObserver = new InterfaceObserver();
131 | try {
132 | mNMService.registerObserver(mInterfaceObserver);
133 | } catch (RemoteException e) {
134 | Log.e(TAG, "Could not register InterfaceObserver " + e);
135 | }
136 |
137 | mEnabled = true;
138 | mHandler.post(this::trackAvailableInterfaces);
139 | }
140 |
141 | void enable(){
142 | if (DBG) {
143 | Log.d(TAG, "EthernetTracker enable");
144 | }
145 |
146 | //mFactory.register();
147 |
148 | mEnabled = true;
149 | mHandler.post(this::trackAvailableInterfaces);
150 | if(isTrackingInterface(Settings.Global.INTERFACE_ETH0)){
151 | updateInterfaceState(Settings.Global.INTERFACE_ETH0,true);
152 | }
153 |
154 | if(isTrackingInterface(Settings.Global.INTERFACE_ETH1)){
155 | updateInterfaceState(Settings.Global.INTERFACE_ETH1,true);
156 | }
157 | }
158 |
159 | void disable(){
160 | if (DBG) {
161 | Log.d(TAG, "EthernetTracker disable");
162 | }
163 | updateInterfaceState(Settings.Global.INTERFACE_ETH0,false);
164 | updateInterfaceState(Settings.Global.INTERFACE_ETH1,false);
165 |
166 | //mFactory.unregister();
167 | mEnabled = false;
168 |
169 | }
170 |
171 | void updateIpConfiguration(String iface, IpConfiguration ipConfiguration) {
172 | if (DBG) {
173 | Log.i(TAG, "updateIpConfiguration, iface: " + iface + ", cfg: " + ipConfiguration);
174 | }
175 |
176 | mConfigStore.write(iface, ipConfiguration);
177 | mIpConfigurations.put(iface, ipConfiguration);
178 |
179 | mHandler.post(() -> mFactory.updateIpConfiguration(iface, ipConfiguration));
180 | }
181 |
182 | IpConfiguration getIpConfiguration(String iface) {
183 | return mIpConfigurations.get(iface);
184 | }
185 |
186 | boolean isTrackingInterface(String iface) {
187 | return mFactory.hasInterface(iface);
188 | }
189 |
190 | String[] getInterfaces(boolean includeRestricted) {
191 | return mFactory.getAvailableInterfaces(includeRestricted);
192 | }
193 |
194 | /**
195 | * Returns true if given interface was configured as restricted (doesn't have
196 | * NET_CAPABILITY_NOT_RESTRICTED) capability. Otherwise, returns false.
197 | */
198 | boolean isRestrictedInterface(String iface) {
199 | final NetworkCapabilities nc = mNetworkCapabilities.get(iface);
200 | return nc != null && !nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
201 | }
202 |
203 | void addListener(IEthernetServiceListener listener, boolean canUseRestrictedNetworks) {
204 | mListeners.register(listener, new ListenerInfo(canUseRestrictedNetworks));
205 | }
206 |
207 | void removeListener(IEthernetServiceListener listener) {
208 | mListeners.unregister(listener);
209 | }
210 |
211 | private void removeInterface(String iface) {
212 | mFactory.removeInterface(iface);
213 | }
214 |
215 | private void addInterface(String iface) {
216 | InterfaceConfiguration config = null;
217 | // Bring up the interface so we get link status indications.
218 | try {
219 | mNMService.setInterfaceUp(iface);
220 | config = mNMService.getInterfaceConfig(iface);
221 | } catch (RemoteException | IllegalStateException e) {
222 | // Either the system is crashing or the interface has disappeared. Just ignore the
223 | // error; we haven't modified any state because we only do that if our calls succeed.
224 | Log.e(TAG, "Error upping interface " + iface, e);
225 | }
226 |
227 | if (config == null) {
228 | Log.e(TAG, "Null interface config for " + iface + ". Bailing out.");
229 | return;
230 | }
231 |
232 | final String hwAddress = config.getHardwareAddress();
233 |
234 | NetworkCapabilities nc = mNetworkCapabilities.get(iface);
235 | if (nc == null) {
236 | // Try to resolve using mac address
237 | nc = mNetworkCapabilities.get(hwAddress);
238 | if (nc == null) {
239 | nc = createDefaultNetworkCapabilities();
240 | }
241 | }
242 | IpConfiguration ipConfiguration = mIpConfigurations.get(iface);
243 | if (ipConfiguration == null) {
244 | ipConfiguration = createDefaultIpConfiguration();
245 | }
246 |
247 | Log.d(TAG, "Started tracking interface " + iface);
248 | mFactory.addInterface(iface, hwAddress, nc, ipConfiguration);
249 |
250 | if(iface.equals(Settings.Global.INTERFACE_ETH0)){
251 | return;
252 | }
253 |
254 | if(iface.equals(Settings.Global.INTERFACE_ETH1)){
255 | return;
256 | }
257 | // Note: if the interface already has link (e.g., if we crashed and got
258 | // restarted while it was running), we need to fake a link up notification so we
259 | // start configuring it.
260 | if (config.hasFlag("running")) {
261 | updateInterfaceState(iface, true);
262 | }
263 | }
264 |
265 | private void updateInterfaceState(String iface, boolean up) {
266 | if(!mEnabled && up){
267 | return;
268 | }
269 | boolean modified = mFactory.updateInterfaceLinkState(iface, up);
270 | if (modified) {
271 | boolean restricted = isRestrictedInterface(iface);
272 | int n = mListeners.beginBroadcast();
273 | for (int i = 0; i < n; i++) {
274 | try {
275 | if (restricted) {
276 | ListenerInfo listenerInfo = (ListenerInfo) mListeners.getBroadcastCookie(i);
277 | if (!listenerInfo.canUseRestrictedNetworks) {
278 | continue;
279 | }
280 | }
281 | mListeners.getBroadcastItem(i).onAvailabilityChanged(iface, up);
282 | } catch (RemoteException e) {
283 | // Do nothing here.
284 | }
285 | }
286 | mListeners.finishBroadcast();
287 | }
288 | }
289 |
290 | private void maybeTrackInterface(String iface) {
291 | if (DBG) Log.i(TAG, "maybeTrackInterface " + iface);
292 | // If we don't already track this interface, and if this interface matches
293 | // our regex, start tracking it.
294 | if (!iface.matches(mIfaceMatch) || mFactory.hasInterface(iface)) {
295 | return;
296 | }
297 |
298 | if (mIpConfigForDefaultInterface != null) {
299 | updateIpConfiguration(iface, mIpConfigForDefaultInterface);
300 | mIpConfigForDefaultInterface = null;
301 | }
302 |
303 | addInterface(iface);
304 | }
305 |
306 | private void trackAvailableInterfaces() {
307 | try {
308 | final String[] ifaces = mNMService.listInterfaces();
309 | for (String iface : ifaces) {
310 | maybeTrackInterface(iface);
311 | }
312 | } catch (RemoteException | IllegalStateException e) {
313 | Log.e(TAG, "Could not get list of interfaces " + e);
314 | }
315 | }
316 |
317 |
318 | private class InterfaceObserver extends BaseNetworkObserver {
319 |
320 | @Override
321 | public void interfaceLinkStateChanged(String iface, boolean up) {
322 | if (DBG) {
323 | Log.i(TAG, "interfaceLinkStateChanged, iface: " + iface + ", up: " + up);
324 | }
325 | mHandler.post(() -> updateInterfaceState(iface, up));
326 | }
327 |
328 | @Override
329 | public void interfaceAdded(String iface) {
330 | mHandler.post(() -> maybeTrackInterface(iface));
331 | }
332 |
333 | @Override
334 | public void interfaceRemoved(String iface) {
335 | mHandler.post(() -> removeInterface(iface));
336 | }
337 | }
338 |
339 | private static class ListenerInfo {
340 |
341 | boolean canUseRestrictedNetworks = false;
342 |
343 | ListenerInfo(boolean canUseRestrictedNetworks) {
344 | this.canUseRestrictedNetworks = canUseRestrictedNetworks;
345 | }
346 | }
347 |
348 | private void parseEthernetConfig(String configString) {
349 | String[] tokens = configString.split(";");
350 | String name = tokens[0];
351 | String capabilities = tokens.length > 1 ? tokens[1] : null;
352 | NetworkCapabilities nc = createNetworkCapabilities(
353 | !TextUtils.isEmpty(capabilities) /* clear default capabilities */, capabilities);
354 | mNetworkCapabilities.put(name, nc);
355 |
356 | if (tokens.length > 2 && !TextUtils.isEmpty(tokens[2])) {
357 | IpConfiguration ipConfig = parseStaticIpConfiguration(tokens[2]);
358 | mIpConfigurations.put(name, ipConfig);
359 | }
360 | }
361 |
362 | private static NetworkCapabilities createDefaultNetworkCapabilities() {
363 | NetworkCapabilities nc = createNetworkCapabilities(false /* clear default capabilities */);
364 | nc.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
365 | nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
366 | nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
367 | nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
368 | nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED);
369 |
370 | return nc;
371 | }
372 |
373 | private static NetworkCapabilities createNetworkCapabilities(boolean clearDefaultCapabilities) {
374 | return createNetworkCapabilities(clearDefaultCapabilities, null);
375 | }
376 |
377 | private static NetworkCapabilities createNetworkCapabilities(
378 | boolean clearDefaultCapabilities, @Nullable String commaSeparatedCapabilities) {
379 |
380 | NetworkCapabilities nc = new NetworkCapabilities();
381 | if (clearDefaultCapabilities) {
382 | nc.clearAll(); // Remove default capabilities.
383 | }
384 | nc.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET);
385 | nc.setLinkUpstreamBandwidthKbps(100 * 1000);
386 | nc.setLinkDownstreamBandwidthKbps(100 * 1000);
387 |
388 | if (!TextUtils.isEmpty(commaSeparatedCapabilities)) {
389 | for (String strNetworkCapability : commaSeparatedCapabilities.split(",")) {
390 | if (!TextUtils.isEmpty(strNetworkCapability)) {
391 | nc.addCapability(Integer.valueOf(strNetworkCapability));
392 | }
393 | }
394 | }
395 |
396 | return nc;
397 | }
398 |
399 | /**
400 | * Parses static IP configuration.
401 | *
402 | * @param staticIpConfig represents static IP configuration in the following format: {@code
403 | * ip= gateway= dns=
404 | * domains=}
405 | */
406 | @VisibleForTesting
407 | static IpConfiguration parseStaticIpConfiguration(String staticIpConfig) {
408 | StaticIpConfiguration ipConfig = new StaticIpConfiguration();
409 |
410 | for (String keyValueAsString : staticIpConfig.trim().split(" ")) {
411 | if (TextUtils.isEmpty(keyValueAsString)) continue;
412 |
413 | String[] pair = keyValueAsString.split("=");
414 | if (pair.length != 2) {
415 | throw new IllegalArgumentException("Unexpected token: " + keyValueAsString
416 | + " in " + staticIpConfig);
417 | }
418 |
419 | String key = pair[0];
420 | String value = pair[1];
421 |
422 | switch (key) {
423 | case "ip":
424 | ipConfig.ipAddress = new LinkAddress(value);
425 | break;
426 | case "domains":
427 | ipConfig.domains = value;
428 | break;
429 | case "gateway":
430 | ipConfig.gateway = InetAddress.parseNumericAddress(value);
431 | break;
432 | case "dns": {
433 | ArrayList dnsAddresses = new ArrayList<>();
434 | for (String address: value.split(",")) {
435 | dnsAddresses.add(InetAddress.parseNumericAddress(address));
436 | }
437 | ipConfig.dnsServers.addAll(dnsAddresses);
438 | break;
439 | }
440 | default : {
441 | throw new IllegalArgumentException("Unexpected key: " + key
442 | + " in " + staticIpConfig);
443 | }
444 | }
445 | }
446 | return new IpConfiguration(IpAssignment.STATIC, ProxySettings.NONE, ipConfig, null);
447 | }
448 |
449 | private static IpConfiguration createDefaultIpConfiguration() {
450 | return new IpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, null, null);
451 | }
452 |
453 | private void postAndWaitForRunnable(Runnable r) {
454 | mHandler.runWithScissors(r, 2000L /* timeout */);
455 | }
456 |
457 | void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
458 | postAndWaitForRunnable(() -> {
459 | pw.println(getClass().getSimpleName());
460 | pw.println("Ethernet interface name filter: " + mIfaceMatch);
461 | pw.println("Listeners: " + mListeners.getRegisteredCallbackCount());
462 | pw.println("IP Configurations:");
463 | pw.increaseIndent();
464 | for (String iface : mIpConfigurations.keySet()) {
465 | pw.println(iface + ": " + mIpConfigurations.get(iface));
466 | }
467 | pw.decreaseIndent();
468 | pw.println();
469 |
470 | pw.println("Network Capabilities:");
471 | pw.increaseIndent();
472 | for (String iface : mNetworkCapabilities.keySet()) {
473 | pw.println(iface + ": " + mNetworkCapabilities.get(iface));
474 | }
475 | pw.decreaseIndent();
476 | pw.println();
477 |
478 | mFactory.dump(fd, pw, args);
479 | });
480 | }
481 | }
482 |
--------------------------------------------------------------------------------
/packages/apps/Settings/src/com/android/settings/ethernet/EthernetDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2020 SIMCOM Corp.
3 | *
4 | * The main interface to control ethernet setting param.
5 | * Athor: Mr. Tsao Bo, SIMCOM.
6 | * Restructured on 2020.11.10, for USB ethernet( A.K.A, eth1 ) connection.
7 | *
8 | */
9 |
10 | package com.android.settings.ethernet;
11 |
12 | import com.android.settings.R;
13 | import com.android.settings.ethernet.ip.IPView;
14 |
15 | import android.app.AlertDialog;
16 | import android.content.Context;
17 | import android.content.DialogInterface;
18 | import android.os.Bundle;
19 | import android.view.View;
20 | import android.widget.Button;
21 | import android.widget.EditText;
22 | import android.widget.CompoundButton;
23 | import android.widget.RadioButton;
24 | import android.util.Log;
25 | import android.view.inputmethod.InputMethodManager;
26 | import android.net.IpConfiguration;
27 | import android.net.IpConfiguration.IpAssignment;
28 | import android.net.IpConfiguration.ProxySettings;
29 | import android.os.Environment;
30 | import android.util.SparseArray;
31 | import android.net.StaticIpConfiguration;
32 | import android.net.EthernetManager;
33 | import android.text.TextUtils;
34 | import android.net.LinkAddress;
35 | import android.net.NetworkUtils;
36 | import android.net.ConnectivityManager;
37 | import android.net.LinkProperties;
38 | import android.os.RemoteException;
39 | import com.android.settings.Utils;
40 | import android.widget.Toast;
41 | import android.net.EthernetManager;
42 | import android.provider.Settings.Global;
43 | import com.zanshang.wifi.ExtraWifiService;
44 | import android.provider.Settings;
45 | import android.widget.Button;
46 |
47 |
48 | import java.net.InetAddress;
49 | import java.net.Inet4Address;
50 | import java.net.UnknownHostException;
51 | import java.util.Iterator;
52 | import java.util.regex.Pattern;
53 |
54 |
55 | class EthernetDialog extends AlertDialog implements DialogInterface.OnClickListener, DialogInterface.OnShowListener,
56 | DialogInterface.OnDismissListener{
57 | private final String TAG = "EthernetDialog";
58 | private static final boolean localLOGV = true;
59 |
60 |
61 | private View mView;
62 | private RadioButton mIpTypeDhcp;
63 | private RadioButton mIpTypeManual;
64 | private RadioButton eth0Radio;
65 | private RadioButton eth1Radio;
66 |
67 | private StaticIpViews mStaticIpViews;
68 | private RJ45StaticIpViews mRJ45StaticIpViews;
69 | private UsbCardStaticIpViews mUsbCardStaticIpViews;
70 |
71 |
72 | private Context mContext;
73 | private EthernetManager mEthManager;
74 | private ConnectivityManager mCM;
75 |
76 | public EthernetDialog(Context context,EthernetManager EthManager,ConnectivityManager cm) {
77 | super(context);
78 | mContext = context;
79 | mEthManager = EthManager;
80 | mCM = cm;
81 |
82 | createDialogContent();
83 |
84 | setOnShowListener(this);
85 | setOnDismissListener(this);
86 |
87 | }
88 |
89 | public void onShow(DialogInterface dialog) {
90 | if (localLOGV) Log.d(TAG, "onShow");
91 |
92 | UpdateViewContent();
93 |
94 | // soft keyboard pops up on the disabled EditText. Hide it.
95 | InputMethodManager imm = (InputMethodManager)mContext.getSystemService(
96 | Context.INPUT_METHOD_SERVICE);
97 | imm.hideSoftInputFromWindow(mView.getWindowToken(),
98 | InputMethodManager.HIDE_IMPLICIT_ONLY);
99 |
100 | /* Tsao Bo:The reason we listen click event on postive_button's View rather than the button */
101 | /* is because we'd like to manually handle the dialog dismiss.*/
102 | Button positive_button = getButton(BUTTON_POSITIVE);
103 | positive_button.setOnClickListener(new View.OnClickListener() {
104 | @Override
105 | public void onClick(View v) {
106 | handle_saveconf();
107 | }
108 | });
109 | }
110 |
111 | public void onClick(DialogInterface dialog, int which){
112 |
113 | }
114 |
115 | public void onDismiss(DialogInterface dialog) {
116 | if (localLOGV) Log.d(TAG, "onDismiss");
117 | }
118 |
119 | private void createDialogContent() {
120 | this.setTitle(R.string.eth_config_title);
121 | this.setView(mView = getLayoutInflater().inflate(R.layout.ethernet_configure, null));
122 |
123 | eth0Radio = (RadioButton) mView.findViewById(R.id.eth0_radio);
124 | eth1Radio = (RadioButton) mView.findViewById(R.id.eth1_radio);
125 |
126 | mIpTypeDhcp = (RadioButton) mView.findViewById(R.id.dhcp_radio);
127 | mIpTypeManual = (RadioButton) mView.findViewById(R.id.manual_radio);
128 |
129 | IPView Ipaddr = (IPView)mView.findViewById(R.id.ipaddr_edit);
130 | IPView NetMask = (IPView)mView.findViewById(R.id.mask_edit);
131 | IPView Gw = (IPView)mView.findViewById(R.id.eth_gw_edit);
132 | IPView Dns1 = (IPView)mView.findViewById(R.id.eth_dns_edit1);
133 | IPView Dns2 = (IPView)mView.findViewById(R.id.eth_dns_edit2);
134 |
135 | mRJ45StaticIpViews = new RJ45StaticIpViews(Ipaddr,NetMask,Gw,Dns1,Dns2);
136 | mUsbCardStaticIpViews = new UsbCardStaticIpViews(Ipaddr,NetMask,Gw,Dns1,Dns2);
137 |
138 | String ifaceType = getInterfaceSetting();
139 | if(ifaceType.equals(Settings.Global.INTERFACE_ETH0)){
140 | mStaticIpViews = mRJ45StaticIpViews;
141 | }else{
142 | mStaticIpViews = mUsbCardStaticIpViews;
143 | }
144 | mStaticIpViews.disableAllViews();
145 |
146 | setButton(BUTTON_POSITIVE, mContext.getText(R.string.menu_save), (DialogInterface.OnClickListener)null);
147 | setButton(BUTTON_NEGATIVE, mContext.getText(R.string.menu_cancel), this);
148 |
149 | updateRadioButtonState();
150 |
151 | setInverseBackgroundForced(true);
152 |
153 |
154 | eth0Radio.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
155 | @Override
156 | public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
157 | Log.i("eth0Radio","onCheckedChanged isChecked:"+isChecked);
158 | if(isChecked){
159 | mStaticIpViews = mRJ45StaticIpViews;
160 |
161 | setInterfaceSetting(Settings.Global.INTERFACE_ETH0);
162 |
163 | updateIpTypeRadioButtonState();
164 | mStaticIpViews.clearAllViews();
165 | mStaticIpViews.loadSettings();
166 | }
167 | }
168 | });
169 |
170 | eth1Radio.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
171 | @Override
172 | public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
173 | Log.i("eth1Radio","onCheckedChanged isChecked:"+isChecked);
174 | if(isChecked){
175 | mStaticIpViews = mUsbCardStaticIpViews;
176 |
177 | setInterfaceSetting(Settings.Global.INTERFACE_ETH1);
178 |
179 | updateIpTypeRadioButtonState();
180 | mStaticIpViews.clearAllViews();
181 | mStaticIpViews.loadSettings();
182 | }
183 | }
184 | });
185 |
186 | mIpTypeDhcp.setOnClickListener(new RadioButton.OnClickListener() {
187 | public void onClick(View v) {
188 | mStaticIpViews.setIpTypeSetting(Settings.Global.TYPE_DHCP);
189 |
190 | mStaticIpViews.disableAllViews();
191 | mStaticIpViews.clearAllViews();
192 | }
193 | });
194 |
195 | mIpTypeManual.setOnClickListener(new RadioButton.OnClickListener() {
196 | public void onClick(View v) {
197 | mStaticIpViews.setIpTypeSetting(Settings.Global.TYPE_STATIC);
198 |
199 | mStaticIpViews.enableAllViews();
200 | mStaticIpViews.clearAllViews();
201 | mStaticIpViews.loadSettings();
202 | }
203 | });
204 |
205 | UpdateViewContent();
206 |
207 | }
208 |
209 | private void UpdateViewContent() {
210 | int enable = Global.getInt(mContext.getContentResolver(), Global.ETHERNET_ON, EthernetManager.ETHERNET_STATE_UNKNOWN);
211 | if (localLOGV) Log.d(TAG, "UpdateViewContent enable=" + enable);
212 |
213 | if(enable == EthernetManager.ETHERNET_STATE_ENABLED) {
214 | String ifaceType = getInterfaceSetting();
215 |
216 | IpConfiguration ipinfo = mEthManager.getConfiguration(ifaceType);
217 |
218 | if((ipinfo.ipAssignment == IpAssignment.DHCP) ||(ipinfo.ipAssignment == IpAssignment.UNASSIGNED) ) {
219 | mIpTypeDhcp.setChecked(true);
220 | mStaticIpViews.disableAllViews();
221 | mStaticIpViews.clearAllViews();
222 | } else {
223 | mIpTypeManual.setChecked(true);
224 | mStaticIpViews.enableAllViews();
225 |
226 | StaticIpConfiguration staticConfig = ipinfo.getStaticIpConfiguration();
227 | Log.d(TAG, "UpdateViewContent staticConfig=" + staticConfig);
228 |
229 | mStaticIpViews.updateViews(staticConfig);
230 | }
231 | }
232 | }
233 |
234 | private String updateIfaceTypeRadioButtonState(){
235 | String ifaceType = getInterfaceSetting();
236 | if(ifaceType.equals(Settings.Global.INTERFACE_ETH0)){
237 | eth0Radio.setChecked(true);
238 | }else if(ifaceType.equals(Settings.Global.INTERFACE_ETH1)){
239 | eth1Radio.setChecked(true);
240 | }
241 | return ifaceType;
242 | }
243 |
244 | private String updateIpTypeRadioButtonState(){
245 | String ipType = mStaticIpViews.getIpTypeSetting();
246 | if(ipType.equals(Settings.Global.TYPE_DHCP)){
247 | mIpTypeDhcp.setChecked(true);
248 | mIpTypeManual.setChecked(false);
249 | }else if(ipType.equals(Settings.Global.TYPE_STATIC)){
250 | mIpTypeDhcp.setChecked(false);
251 | mIpTypeManual.setChecked(true);
252 | }
253 |
254 | return ipType;
255 | }
256 | private void updateRadioButtonState(){
257 | updateIfaceTypeRadioButtonState();
258 |
259 | updateIpTypeRadioButtonState();
260 | }
261 |
262 | private String getInterfaceSetting(){
263 | String ifaceType = Settings.Global.getString(mContext.getContentResolver(), Settings.Global.ETHERNET_IFACE_TYPE);
264 |
265 | return ifaceType;
266 | }
267 |
268 | private boolean setInterfaceSetting(String iface){
269 | return Settings.Global.putString(mContext.getContentResolver(), Settings.Global.ETHERNET_IFACE_TYPE, iface);
270 |
271 | }
272 |
273 | private void handle_saveconf() {
274 | IpAssignment ipAssignment = (mIpTypeDhcp.isChecked() ? IpAssignment.DHCP:IpAssignment.STATIC);
275 |
276 | String iface;
277 | if(eth0Radio.isChecked()){
278 | iface = Settings.Global.INTERFACE_ETH0;
279 | }else{
280 | iface = Settings.Global.INTERFACE_ETH1;
281 | }
282 |
283 | if(IpAssignment.DHCP == ipAssignment){
284 | mEthManager.setConfiguration(iface,new IpConfiguration(ipAssignment, ProxySettings.NONE,
285 | null, null));
286 | dismiss();
287 | }else{
288 | StaticIpConfiguration staticIpConfiguration = mStaticIpViews.generateStaticIpConfiguration();
289 |
290 | if(staticIpConfiguration == null){
291 | Toast.makeText(mContext, R.string.eth_settings_error, Toast.LENGTH_SHORT).show();
292 | }else{
293 | mEthManager.setConfiguration(iface,new IpConfiguration(ipAssignment, ProxySettings.NONE,
294 | staticIpConfiguration, null));
295 | Log.d(TAG,"mode static ip ++ staticIpConfiguration=" + staticIpConfiguration);
296 |
297 | mStaticIpViews.saveSettings();
298 | dismiss();
299 | }
300 |
301 | }
302 |
303 | }
304 |
305 |
306 | private abstract class StaticIpViews{
307 | private final String TAG = "StaticIpViews";
308 |
309 | protected IPView mIpaddr;
310 | protected IPView mNetMask;
311 | protected IPView mGw;
312 | protected IPView mDns1;
313 | protected IPView mDns2;
314 |
315 |
316 | public StaticIpViews(IPView ipaddr, IPView netMask, IPView gateway, IPView dns1, IPView dns2){
317 | mIpaddr = ipaddr;
318 | mNetMask = netMask;
319 | mGw = gateway;
320 | mDns1 = dns1;
321 | mDns2 = dns2;
322 | }
323 |
324 | public void updateViews(StaticIpConfiguration staticIpConfig ){
325 | if (staticIpConfig != null) {
326 | if (staticIpConfig.ipAddress != null) {
327 | mIpaddr.setIp(staticIpConfig.ipAddress.getAddress().getHostAddress());
328 |
329 | String prefix=interMask2String(staticIpConfig.ipAddress.getPrefixLength());
330 | Log.d(TAG, "updateViews prefix=" + prefix);
331 | mNetMask.setIp(prefix);
332 | }
333 |
334 | if (staticIpConfig.gateway != null) {
335 | mGw.setIp(staticIpConfig.gateway.getHostAddress());
336 | }
337 |
338 | Iterator dnsIterator = staticIpConfig.dnsServers.iterator();
339 | if(dnsIterator.hasNext()){
340 | InetAddress ia = dnsIterator.next();
341 | mDns1.setIp(ia.getHostAddress());
342 | }
343 | if(dnsIterator.hasNext()){
344 | InetAddress ia = dnsIterator.next();
345 | mDns2.setIp(ia.getHostAddress());
346 | }
347 |
348 | }
349 | }
350 |
351 | public void enableAllViews(){
352 | setAllViewsEnabled(true);
353 | }
354 |
355 | public void disableAllViews(){
356 | setAllViewsEnabled(false);
357 | }
358 |
359 | private void setAllViewsEnabled(boolean enabled){
360 | mIpaddr.setEnabled(enabled);
361 | mNetMask.setEnabled(enabled);
362 | mGw.setEnabled(enabled);
363 | mDns1.setEnabled(enabled);
364 | mDns2.setEnabled(enabled);
365 | }
366 |
367 | public void clearAllViews(){
368 | mIpaddr.clear();
369 | mNetMask.clear();
370 | mGw.clear();
371 | mDns1.clear();
372 | mDns2.clear();
373 | }
374 |
375 | public abstract void saveSettings();
376 |
377 | public abstract void loadSettings();
378 |
379 | public abstract String getIpTypeSetting();
380 |
381 | public abstract boolean setIpTypeSetting(String ipType);
382 |
383 | public void readSettingsToIPView(IPView ipv, String settingString){
384 | String data = Global.getString(mContext.getContentResolver(), settingString);
385 | if(data != null && isIpAddress(data)) {
386 | ipv.setIp(data);
387 | }
388 | }
389 |
390 | public StaticIpConfiguration generateStaticIpConfiguration(){
391 |
392 | String ipaddr = mIpaddr.getText();
393 | String netMask = mNetMask.getText();
394 | String gateway = mGw.getText();
395 | String dns1 = mDns1.getText();
396 | String dns2 = mDns2.getText();
397 |
398 | InvalidInputHandler invalidInputHandler = new InvalidInputHandler();
399 | StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();
400 |
401 | if (TextUtils.isEmpty(ipaddr)) {
402 | invalidInputHandler.addResult(ConfigErrorCodeEnum.CONFIG_STR_EMPTY);
403 | }else{
404 | Inet4Address inetAddr = getIPv4Address(ipaddr);
405 |
406 | if (inetAddr == null || inetAddr.equals(Inet4Address.ANY)) {
407 | invalidInputHandler.addResult(ConfigErrorCodeEnum.CONFIG_INVAILD_IP);
408 | }else{
409 |
410 | int networkPrefixLength = -1;
411 | try {
412 | networkPrefixLength = maskStr2InetMask(netMask);
413 | staticIpConfiguration.ipAddress = new LinkAddress(inetAddr, networkPrefixLength);
414 | } catch (NumberFormatException e) {
415 | // Set the hint as default after user types in ip address
416 | invalidInputHandler.addResult(ConfigErrorCodeEnum.CONFI_ERROR);
417 | } catch (IllegalArgumentException e) {
418 | invalidInputHandler.addResult(ConfigErrorCodeEnum.CONFI_ERROR);
419 | }
420 | }
421 | }
422 |
423 | if (!TextUtils.isEmpty(gateway)) {
424 | InetAddress gatewayAddr = getIPv4Address(gateway);
425 | if (gatewayAddr == null) {
426 | invalidInputHandler.addResult(ConfigErrorCodeEnum.CONFIG_INVAILD_GATEWAY);
427 | }
428 | if (gatewayAddr.isMulticastAddress()) {
429 | invalidInputHandler.addResult(ConfigErrorCodeEnum.CONFIG_INVAILD_GATEWAY);
430 | }
431 | staticIpConfiguration.gateway = gatewayAddr;
432 | }
433 |
434 | InetAddress dnsAddr = null;
435 | if (dns1 != null && !TextUtils.isEmpty(dns1)) {
436 | dnsAddr = getIPv4Address(dns1);
437 | if (dnsAddr == null) {
438 | invalidInputHandler.addResult(ConfigErrorCodeEnum.CONFIG_INVAILD_DNS);
439 | }
440 | staticIpConfiguration.dnsServers.add(dnsAddr);
441 | }
442 |
443 | if (dns2 != null && !TextUtils.isEmpty(dns2)) {
444 | dnsAddr = getIPv4Address(dns2);
445 | if (dnsAddr == null) {
446 | invalidInputHandler.addResult(ConfigErrorCodeEnum.CONFIG_INVAILD_DNS);
447 | }
448 | staticIpConfiguration.dnsServers.add(dnsAddr);
449 | }
450 |
451 | Log.d(TAG, "generateStaticIpConfiguration result=" + invalidInputHandler.getResults());
452 | if(0 == invalidInputHandler.getResults()){
453 | return staticIpConfiguration;
454 | }else{
455 | return null;
456 | }
457 | }
458 |
459 | public String interMask2String(int prefixLength) {
460 | String netMask = null;
461 | int inetMask = prefixLength;
462 |
463 | int part = inetMask / 8;
464 | int remainder = inetMask % 8;
465 | int sum = 0;
466 |
467 | for (int i = 8; i > 8 - remainder; i--) {
468 | sum = sum + (int) Math.pow(2, i - 1);
469 | }
470 |
471 | if (part == 0) {
472 | netMask = sum + ".0.0.0";
473 | } else if (part == 1) {
474 | netMask = "255." + sum + ".0.0";
475 | } else if (part == 2) {
476 | netMask = "255.255." + sum + ".0";
477 | } else if (part == 3) {
478 | netMask = "255.255.255." + sum;
479 | } else if (part == 4) {
480 | netMask = "255.255.255.255";
481 | }
482 |
483 | return netMask;
484 | }
485 |
486 | /*
487 | * convert subMask string to prefix length
488 | */
489 | public int maskStr2InetMask(String maskStr) {
490 | StringBuffer sb ;
491 | String str;
492 | int inetmask = 0;
493 | int count = 0;
494 | /*
495 | * check the subMask format
496 | */
497 | Pattern pattern = Pattern.compile("(^((\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])$)|^(\\d|[1-2]\\d|3[0-2])$");
498 | if (pattern.matcher(maskStr).matches() == false) {
499 | Log.e(TAG,"subMask is error");
500 | return 0;
501 | }
502 |
503 | String[] ipSegment = maskStr.split("\\.");
504 | for(int n =0; n 255) || (block < 0)) {
540 | return false;
541 | }
542 | } catch (NumberFormatException e) {
543 | return false;
544 | }
545 |
546 | numBlocks++;
547 |
548 | start = end + 1;
549 | end = value.indexOf('.', start);
550 | }
551 | return numBlocks == 4;
552 | }
553 |
554 | }
555 |
556 | private class RJ45StaticIpViews extends StaticIpViews{
557 | public RJ45StaticIpViews (IPView ipaddr, IPView netMask, IPView gateway, IPView dns1, IPView dns2){
558 | super(ipaddr,netMask,gateway,dns1,dns2);
559 | }
560 |
561 | @Override
562 | public void saveSettings(){
563 | Global.putString(mContext.getContentResolver(), Global.RJ45_STATIC_IP,
564 | mIpaddr.getText());
565 | Global.putString(mContext.getContentResolver(), Global.RJ45_STATIC_NETMASK,
566 | mNetMask.getText().toString());
567 | Global.putString(mContext.getContentResolver(), Global.RJ45_STATIC_GATEWAY,
568 | mGw.getText());
569 | Global.putString(mContext.getContentResolver(), Global.RJ45_STATIC_DNS1,
570 | mDns1.getText());
571 | Global.putString(mContext.getContentResolver(), Global.RJ45_STATIC_DNS2,
572 | mDns2.getText());
573 | }
574 |
575 | @Override
576 | public void loadSettings(){
577 | String ipType = getIpTypeSetting();
578 | if (localLOGV) Log.d(TAG, "ipType =" + ipType );
579 |
580 | if(ipType.equals(Settings.Global.TYPE_STATIC)){
581 | readSettingsToIPView(mIpaddr,Global.RJ45_STATIC_IP);
582 | readSettingsToIPView(mNetMask,Global.RJ45_STATIC_NETMASK);
583 | readSettingsToIPView(mGw,Global.RJ45_STATIC_GATEWAY);
584 | readSettingsToIPView(mDns1,Global.RJ45_STATIC_DNS1);
585 | readSettingsToIPView(mDns2,Global.RJ45_STATIC_DNS2);
586 | enableAllViews();
587 | }else{
588 | disableAllViews();
589 | clearAllViews();
590 | }
591 | }
592 |
593 | @Override
594 | public String getIpTypeSetting(){
595 | String ipType = Settings.Global.getString(mContext.getContentResolver(), Settings.Global.ETHERNET_IP_TYPE_ETH0);
596 |
597 | return ipType;
598 | }
599 |
600 | @Override
601 | public boolean setIpTypeSetting(String ipType){
602 | return Settings.Global.putString(mContext.getContentResolver(), Settings.Global.ETHERNET_IP_TYPE_ETH0, ipType);
603 | }
604 |
605 | }
606 |
607 | private class UsbCardStaticIpViews extends StaticIpViews{
608 | public UsbCardStaticIpViews (IPView ipaddr, IPView netMask, IPView gateway, IPView dns1, IPView dns2){
609 | super(ipaddr,netMask,gateway,dns1,dns2);
610 | }
611 |
612 | @Override
613 | public void saveSettings(){
614 | Global.putString(mContext.getContentResolver(), Global.USB_CARD_STATIC_IP,
615 | mIpaddr.getText());
616 | Global.putString(mContext.getContentResolver(), Global.USB_CARD_STATIC_NETMASK,
617 | mNetMask.getText().toString());
618 | Global.putString(mContext.getContentResolver(), Global.USB_CARD_STATIC_GATEWAY,
619 | mGw.getText());
620 | Global.putString(mContext.getContentResolver(), Global.USB_CARD_STATIC_DNS1,
621 | mDns1.getText());
622 | Global.putString(mContext.getContentResolver(), Global.USB_CARD_STATIC_DNS2,
623 | mDns2.getText());
624 | }
625 |
626 | @Override
627 | public void loadSettings(){
628 | String ipType = getIpTypeSetting();
629 | if (localLOGV) Log.d(TAG, "ipType =" + ipType );
630 |
631 | if(ipType.equals(Settings.Global.TYPE_STATIC)){
632 | readSettingsToIPView(mIpaddr,Global.USB_CARD_STATIC_IP);
633 | readSettingsToIPView(mNetMask,Global.USB_CARD_STATIC_NETMASK);
634 | readSettingsToIPView(mGw,Global.USB_CARD_STATIC_GATEWAY);
635 | readSettingsToIPView(mDns1,Global.USB_CARD_STATIC_DNS1);
636 | readSettingsToIPView(mDns2,Global.USB_CARD_STATIC_DNS2);
637 | enableAllViews();
638 | }else{
639 | disableAllViews();
640 | clearAllViews();
641 | }
642 |
643 | }
644 |
645 | @Override
646 | public String getIpTypeSetting(){
647 | String ipType = Settings.Global.getString(mContext.getContentResolver(), Settings.Global.ETHERNET_IP_TYPE_ETH1);
648 |
649 | return ipType;
650 | }
651 |
652 | @Override
653 | public boolean setIpTypeSetting(String ipType){
654 | return Settings.Global.putString(mContext.getContentResolver(), Settings.Global.ETHERNET_IP_TYPE_ETH1, ipType);
655 | }
656 | }
657 |
658 | private class InvalidInputHandler{
659 |
660 | public static final int STR_EMPTY_MASK = ~0x01;
661 | private int mResults;
662 |
663 | public InvalidInputHandler(){
664 | mResults = ConfigErrorCodeEnum.CONFIG_OK.getCode();
665 | }
666 |
667 | public void addResult(ConfigErrorCodeEnum resultEnum){
668 | mResults |=resultEnum.getCode();
669 | }
670 |
671 | public int getResults(){
672 | return mResults;
673 | }
674 |
675 | public void popupIndication(){
676 |
677 | }
678 |
679 | }
680 |
681 |
682 | public static enum ConfigErrorCodeEnum{
683 | CONFIG_OK(0,0),
684 | CONFIG_STR_EMPTY(0x01, R.string.eth_settings_empty),
685 | CONFIG_INVAILD_IP(0x02, R.string.eth_settings_invalid_ip_address),
686 | CONFIG_INVAILD_GATEWAY(0x04, R.string.eth_settings_invalid_gateway),
687 | CONFIG_INVAILD_DNS(0x08, R.string.eth_settings_invalid_dns),
688 | CONFI_ERROR(0x10, R.string.eth_settings_error);
689 |
690 | private int mCode;
691 | private int mTextId;
692 |
693 | private ConfigErrorCodeEnum(int code, int textId){
694 | mCode = code;
695 | mTextId = textId;
696 | }
697 |
698 | public int getCode(){
699 | return mCode;
700 | }
701 |
702 | public static int getTextIdByCode(int code ){
703 | int rTextId = 0;
704 | for(ConfigErrorCodeEnum errorCode:values()){
705 | if(errorCode.mCode == code){
706 | rTextId = errorCode.mTextId;
707 | break;
708 | }
709 | }
710 |
711 | return rTextId;
712 | }
713 | }
714 |
715 |
716 | }
717 |
--------------------------------------------------------------------------------