diff options
-rw-r--r-- | core/java/android/net/ConnectivityManager.java | 25 | ||||
-rw-r--r-- | core/java/android/net/IConnectivityManager.aidl | 5 | ||||
-rw-r--r-- | core/java/android/net/INetworkManagementEventObserver.aidl | 7 | ||||
-rw-r--r-- | core/java/com/android/server/net/BaseNetworkObserver.java | 5 | ||||
-rw-r--r-- | core/res/res/values-zh-rCN/strings.xml | 3 | ||||
-rw-r--r-- | core/res/res/values/bools.xml | 2 | ||||
-rw-r--r-- | core/res/res/values/strings.xml | 3 | ||||
-rwxr-xr-x | core/res/res/values/symbols.xml | 5 | ||||
-rw-r--r-- | services/core/java/com/android/server/ConnectivityService.java | 9 | ||||
-rw-r--r-- | services/core/java/com/android/server/NetworkManagementService.java | 32 | ||||
-rw-r--r-- | services/core/java/com/android/server/connectivity/Tethering.java | 225 | ||||
-rwxr-xr-x | wifi/java/android/net/wifi/WifiDevice.aidl | 32 | ||||
-rwxr-xr-x | wifi/java/android/net/wifi/WifiDevice.java | 137 |
13 files changed, 488 insertions, 2 deletions
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 8e55736..ddfca9e 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -24,6 +24,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.net.NetworkUtils; +import android.net.wifi.WifiDevice; import android.os.Binder; import android.os.Build.VERSION_CODES; import android.os.Handler; @@ -49,6 +50,7 @@ import com.android.internal.util.Protocol; import java.net.InetAddress; import java.util.concurrent.atomic.AtomicInteger; import java.util.HashMap; +import java.util.List; import libcore.net.event.NetworkEventDispatcher; @@ -273,6 +275,15 @@ public class ConnectivityManager { "android.net.conn.TETHER_STATE_CHANGED"; /** + * Broadcast intent action indicating that a Station is connected + * or disconnected. + * + * @hide + */ + public static final String TETHER_CONNECT_STATE_CHANGED = + "codeaurora.net.conn.TETHER_CONNECT_STATE_CHANGED"; + + /** * @hide * gives a String[] listing all the interfaces configured for * tethering and currently available for tethering. @@ -1658,6 +1669,20 @@ public class ConnectivityManager { } } + /** + * Get the list of Stations connected to Hotspot. + * + * @return a list of {@link WifiDevice} objects. + * {@hide} + */ + public List<WifiDevice> getTetherConnectedSta() { + try { + return mService.getTetherConnectedSta(); + } catch (RemoteException e) { + return null; + } + } + /** {@hide} */ public static final int TETHER_ERROR_NO_ERROR = 0; /** {@hide} */ diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 46c28a6..523dfe1 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -26,6 +26,7 @@ import android.net.NetworkQuotaInfo; import android.net.NetworkRequest; import android.net.NetworkState; import android.net.ProxyInfo; +import android.net.wifi.WifiDevice; import android.os.IBinder; import android.os.Messenger; import android.os.ParcelFileDescriptor; @@ -36,6 +37,8 @@ import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnInfo; import com.android.internal.net.VpnProfile; +import java.util.List; + /** * Interface that answers queries about, and allows changing, the * state of network connectivity. @@ -92,6 +95,8 @@ interface IConnectivityManager int setUsbTethering(boolean enable); + List<WifiDevice> getTetherConnectedSta(); + void reportInetCondition(int networkType, int percentage); void reportNetworkConnectivity(in Network network, boolean hasConnectivity); diff --git a/core/java/android/net/INetworkManagementEventObserver.aidl b/core/java/android/net/INetworkManagementEventObserver.aidl index b7af374..5a70ff1 100644 --- a/core/java/android/net/INetworkManagementEventObserver.aidl +++ b/core/java/android/net/INetworkManagementEventObserver.aidl @@ -92,6 +92,13 @@ interface INetworkManagementEventObserver { void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos); /** + * Message is received from network interface. + * + * @param message The message + */ + void interfaceMessageRecevied(String message); + + /** * Information about available DNS servers has been received. * * @param iface The interface on which the information was received. diff --git a/core/java/com/android/server/net/BaseNetworkObserver.java b/core/java/com/android/server/net/BaseNetworkObserver.java index 3d9fb5c..c3dcd40 100644 --- a/core/java/com/android/server/net/BaseNetworkObserver.java +++ b/core/java/com/android/server/net/BaseNetworkObserver.java @@ -63,6 +63,11 @@ public class BaseNetworkObserver extends INetworkManagementEventObserver.Stub { } @Override + public void interfaceMessageRecevied(String message) { + // default no-op + } + + @Override public void limitReached(String limitName, String iface) { // default no-op } diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 3ffb555..5f51235 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -1140,6 +1140,9 @@ <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"触摸可退出车载模式。"</string> <string name="tethered_notification_title" msgid="3146694234398202601">"网络共享或热点已启用"</string> <string name="tethered_notification_message" msgid="6857031760103062982">"触摸可进行设置。"</string> + <string name="tethered_notification_no_device_message">"没有设备已连接。"</string> + <string name="tethered_notification_one_device_message">""<xliff:g id="count">%1$s</xliff:g>"个设备已连接。"</string> + <string name="tethered_notification_multi_device_message">""<xliff:g id="count">%1$s</xliff:g>"个设备已连接。"</string> <string name="back_button_label" msgid="2300470004503343439">"上一步"</string> <string name="next_button_label" msgid="1080555104677992408">"下一步"</string> <string name="skip_button_label" msgid="1275362299471631819">"跳过"</string> diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml index 7c63950..4526f92 100644 --- a/core/res/res/values/bools.xml +++ b/core/res/res/values/bools.xml @@ -29,4 +29,6 @@ <!-- Whether to allow vertically stacked button bars. This is disabled for configurations with a small (e.g. less than 320dp) screen height. --> <bool name="allow_stacked_button_bar">false</bool> + <!-- Whether to enable softap extention feature --> + <bool name="config_softap_extention">true</bool> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index d9fa287..0b73760 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -3147,6 +3147,9 @@ <!-- Shown when the device is tethered --> <string name="tethered_notification_title">Tethering or hotspot active</string> <string name="tethered_notification_message">Touch to set up.</string> + <string name="tethered_notification_no_device_message">No connected device</string> + <string name="tethered_notification_one_device_message"><xliff:g id="count">%1$s</xliff:g> connected device</string> + <string name="tethered_notification_multi_device_message"><xliff:g id="count">%1$s</xliff:g> connected devices</string> <!-- Strings for possible PreferenceActivity Back/Next buttons --> <string name="back_button_label">Back</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 7e930c0..d00684f 100755 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1793,6 +1793,9 @@ <java-symbol type="string" name="smv_application" /> <java-symbol type="string" name="smv_process" /> <java-symbol type="string" name="tethered_notification_message" /> + <java-symbol type="string" name="tethered_notification_no_device_message" /> + <java-symbol type="string" name="tethered_notification_one_device_message" /> + <java-symbol type="string" name="tethered_notification_multi_device_message" /> <java-symbol type="string" name="tethered_notification_title" /> <java-symbol type="string" name="usb_accessory_notification_title" /> <java-symbol type="string" name="usb_mtp_notification_title" /> @@ -2322,4 +2325,6 @@ <java-symbol type="drawable" name="platlogo_m" /> + <!-- config softap extention feature --> + <java-symbol type="bool" name="config_softap_extention" /> </resources> diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 4919bed..63d8c45 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -70,6 +70,7 @@ import android.net.ProxyInfo; import android.net.RouteInfo; import android.net.UidRange; import android.net.Uri; +import android.net.wifi.WifiDevice; import android.os.Binder; import android.os.Bundle; import android.os.FileUtils; @@ -2515,6 +2516,14 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + public List<WifiDevice> getTetherConnectedSta() { + if (isTetheringSupported()) { + return mTethering.getTetherConnectedSta(); + } else { + return null; + } + } + // javadoc from interface public int tether(String iface) { ConnectivityManager.enforceTetherChangePermission(mContext); diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 433f707..ecfd042 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -170,6 +170,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub public static final int InterfaceDnsServerInfo = 615; public static final int RouteChange = 616; public static final int StrictCleartext = 617; + public static final int InterfaceMessage = 618; } static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1; @@ -520,6 +521,21 @@ public class NetworkManagementService extends INetworkManagementService.Stub } /** + * Notify our observers of a change in the data activity state of the interface + */ + private void notifyInterfaceMessage(String message) { + final int length = mObservers.beginBroadcast(); + for (int i = 0; i < length; i++) { + try { + mObservers.getBroadcastItem(i).interfaceMessageRecevied(message); + } catch (RemoteException e) { + } catch (RuntimeException e) { + } + } + mObservers.finishBroadcast(); + } + + /** * Prepare native daemon once connected, enabling modules and pushing any * existing in-memory rules. */ @@ -789,6 +805,22 @@ public class NetworkManagementService extends INetworkManagementService.Stub } throw new IllegalStateException(errorMessage); // break; + case NetdResponseCode.InterfaceMessage: + /* + * An message arrived in network interface. + * Format: "NNN IfaceMessage <3>AP-STA-CONNECTED 00:08:22:64:9d:84 + */ + if (cooked.length < 3 || !cooked[1].equals("IfaceMessage")) { + throw new IllegalStateException(errorMessage); + } + Slog.d(TAG, "onEvent: "+ raw); + if(cooked[4] != null) { + notifyInterfaceMessage(cooked[3] + " " + cooked[4]); + } else { + notifyInterfaceMessage(cooked[3]); + } + return true; + // break; case NetdResponseCode.InterfaceClassActivity: /* * An network interface class state changed (active/idle) diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index c1aaf07..6cacd7b 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -36,6 +36,7 @@ import android.net.Network; import android.net.NetworkInfo; import android.net.NetworkUtils; import android.net.RouteInfo; +import android.net.wifi.WifiDevice; import android.os.Binder; import android.os.INetworkManagementService; import android.os.Looper; @@ -64,9 +65,22 @@ import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; +import java.io.BufferedReader; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; + +import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_CHANGED_ACTION; + /** * @hide @@ -137,6 +151,17 @@ public class Tethering extends BaseNetworkObserver { private boolean mUsbTetherRequested; // true if USB tethering should be started // when RNDIS is enabled + // Once STA established connection to hostapd, it will be added + // to mL2ConnectedDeviceMap. Then after deviceinfo update from dnsmasq, + // it will be added to mConnectedDeviceMap + private HashMap<String, WifiDevice> mL2ConnectedDeviceMap = new HashMap<String, WifiDevice>(); + private HashMap<String, WifiDevice> mConnectedDeviceMap = new HashMap<String, WifiDevice>(); + private static final String dhcpLocation = "/data/misc/dhcp/dnsmasq.leases"; + + // Device name polling interval(ms) and max times + private static final int DNSMASQ_POLLING_INTERVAL = 1000; + private static final int DNSMASQ_POLLING_MAX_TIMES = 10; + public Tethering(Context context, INetworkManagementService nmService, INetworkStatsService statsService, Looper looper) { mContext = context; @@ -158,6 +183,8 @@ public class Tethering extends BaseNetworkObserver { filter.addAction(UsbManager.ACTION_USB_STATE); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); + filter.addAction(WIFI_AP_STATE_CHANGED_ACTION); + mContext.registerReceiver(mStateReceiver, filter); filter = new IntentFilter(); @@ -326,6 +353,168 @@ public class Tethering extends BaseNetworkObserver { } } + public List<WifiDevice> getTetherConnectedSta() { + Iterator it; + List<WifiDevice> TetherConnectedStaList = new ArrayList<WifiDevice>(); + + if (mContext.getResources().getBoolean(com.android.internal.R.bool.config_softap_extention)) { + it = mConnectedDeviceMap.keySet().iterator(); + while(it.hasNext()) { + String key = (String)it.next(); + WifiDevice device = (WifiDevice)mConnectedDeviceMap.get(key); + if (VDBG) { + Log.d(TAG, "getTetherConnectedSta: addr=" + key + " name=" + device.deviceName); + } + TetherConnectedStaList.add(device); + } + } + + return TetherConnectedStaList; + } + + private void sendTetherConnectStateChangedBroadcast() { + if (!getConnectivityManager().isTetheringSupported()) return; + + Intent broadcast = new Intent(ConnectivityManager.TETHER_CONNECT_STATE_CHANGED); + broadcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | + Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + + mContext.sendStickyBroadcastAsUser(broadcast, UserHandle.ALL); + + showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_wifi); + } + + private boolean readDeviceInfoFromDnsmasq(WifiDevice device) { + boolean result = false; + FileInputStream fstream = null; + String line; + + try { + fstream = new FileInputStream(dhcpLocation); + DataInputStream in = new DataInputStream(fstream); + BufferedReader br = new BufferedReader(new InputStreamReader(in)); + + while ((null != (line = br.readLine())) && (line.length() != 0)) { + String[] fields = line.split(" "); + + // 949295 00:0a:f5:6a:bf:70 192.168.43.32 android-93de88df9ec61bac * + if (fields.length > 3) { + String addr = fields[1]; + String name = fields[3]; + + if (addr.equals(device.deviceAddress)) { + device.deviceName = name; + result = true; + break; + } + } + } + } catch (IOException ex) { + Log.e(TAG, "readDeviceNameFromDnsmasq: " + ex); + } finally { + if (fstream != null) { + try { + fstream.close(); + } catch (IOException ex) {} + } + } + + return result; + } + + /* + * DnsmasqThread is used to read the Device info from dnsmasq. + */ + private static class DnsmasqThread extends Thread { + private final Tethering mTethering; + private int mInterval; + private int mMaxTimes; + private WifiDevice mDevice; + + public DnsmasqThread(Tethering tethering, WifiDevice device, + int interval, int maxTimes) { + super("Tethering"); + mTethering = tethering; + mInterval = interval; + mMaxTimes = maxTimes; + mDevice = device; + } + + public void run() { + boolean result = false; + + try { + while (mMaxTimes > 0) { + result = mTethering.readDeviceInfoFromDnsmasq(mDevice); + if (result) { + if (DBG) Log.d(TAG, "Successfully poll device info for " + mDevice.deviceAddress); + break; + } + + mMaxTimes --; + Thread.sleep(mInterval); + } + } catch (Exception ex) { + result = false; + Log.e(TAG, "Pulling " + mDevice.deviceAddress + "error" + ex); + } + + if (!result) { + if (DBG) Log.d(TAG, "Pulling timeout, suppose STA uses static ip " + mDevice.deviceAddress); + } + + // When STA uses static ip, device info will be unavaiable from dnsmasq, + // thus no matter the result is success or failure, we will broadcast the event. + // But if the device is not in L2 connected state, it means the hostapd connection is + // disconnected before dnsmasq get device info, so in this case, don't broadcast + // connection event. + WifiDevice other = mTethering.mL2ConnectedDeviceMap.get(mDevice.deviceAddress); + if (other != null && other.deviceState == WifiDevice.CONNECTED) { + mTethering.mConnectedDeviceMap.put(mDevice.deviceAddress, mDevice); + mTethering.sendTetherConnectStateChangedBroadcast(); + } else { + if (DBG) Log.d(TAG, "Device " + mDevice.deviceAddress + "already disconnected, ignoring"); + } + } + } + + public void interfaceMessageRecevied(String message) { + // if softap extension feature not enabled, do nothing + if (!mContext.getResources().getBoolean(com.android.internal.R.bool.config_softap_extention)) { + return; + } + + if (DBG) Log.d(TAG, "interfaceMessageRecevied: message=" + message); + + try { + WifiDevice device = new WifiDevice(message); + + if (device.deviceState == WifiDevice.CONNECTED) { + mL2ConnectedDeviceMap.put(device.deviceAddress, device); + + // When hostapd reported STA-connection event, it is possible that device + // info can't fetched from dnsmasq, then we start a thread to poll the + // device info, the thread will exit after device info avaiable. + // For static ip case, dnsmasq don't hold the device info, thus thread + // will exit after a timeout. + if (readDeviceInfoFromDnsmasq(device)) { + mConnectedDeviceMap.put(device.deviceAddress, device); + sendTetherConnectStateChangedBroadcast(); + } else { + if (DBG) Log.d(TAG, "Starting poll device info for " + device.deviceAddress); + new DnsmasqThread(this, device, + DNSMASQ_POLLING_INTERVAL, DNSMASQ_POLLING_MAX_TIMES).start(); + } + } else if (device.deviceState == WifiDevice.DISCONNECTED) { + mL2ConnectedDeviceMap.remove(device.deviceAddress); + mConnectedDeviceMap.remove(device.deviceAddress); + sendTetherConnectStateChangedBroadcast(); + } + } catch (IllegalArgumentException ex) { + Log.e(TAG, "WifiDevice IllegalArgument: " + ex); + } + } + public int tether(String iface) { if (DBG) Log.d(TAG, "Tethering " + iface); TetherInterfaceSM sm = null; @@ -469,8 +658,24 @@ public class Tethering extends BaseNetworkObserver { Resources r = Resources.getSystem(); CharSequence title = r.getText(com.android.internal.R.string.tethered_notification_title); - CharSequence message = r.getText(com.android.internal.R.string. - tethered_notification_message); + + CharSequence message; + int size = mConnectedDeviceMap.size(); + + if (mContext.getResources().getBoolean(com.android.internal.R.bool.config_softap_extention) + && icon == com.android.internal.R.drawable.stat_sys_tether_wifi) { + if (size == 0) { + message = r.getText(com.android.internal.R.string.tethered_notification_no_device_message); + } else if (size == 1) { + message = String.format((r.getText(com.android.internal.R.string.tethered_notification_one_device_message)).toString(), + size); + } else { + message = String.format((r.getText(com.android.internal.R.string.tethered_notification_multi_device_message)).toString(), + size); + } + } else { + message = r.getText(com.android.internal.R.string.tethered_notification_message); + } if (mTetheredNotificationBuilder == null) { mTetheredNotificationBuilder = new Notification.Builder(mContext); @@ -485,10 +690,18 @@ public class Tethering extends BaseNetworkObserver { .setContentTitle(title) .setContentText(message) .setContentIntent(pi); + if (mContext.getResources().getBoolean(com.android.internal.R.bool.config_softap_extention) + && icon == com.android.internal.R.drawable.stat_sys_tether_wifi + && size > 0) { + mTetheredNotificationBuilder.setContentText(message); + } else { + mTetheredNotificationBuilder.setContentTitle(title); + } mLastNotificationId = icon; notificationManager.notifyAsUser(null, mLastNotificationId, mTetheredNotificationBuilder.build(), UserHandle.ALL); + } private void clearTetheredNotification() { @@ -526,6 +739,14 @@ public class Tethering extends BaseNetworkObserver { } } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) { updateConfiguration(); + } else if(action.equals(WIFI_AP_STATE_CHANGED_ACTION)){ + int wifiApState = intent.getIntExtra("wifi_state", WIFI_AP_STATE_DISABLED); + if (DBG) Log.d(TAG, "WIFI_AP_STATE_CHANGED: wifiApState=" + wifiApState); + if(wifiApState == WIFI_AP_STATE_ENABLED || + wifiApState == WIFI_AP_STATE_DISABLED) { + mConnectedDeviceMap.clear(); + mL2ConnectedDeviceMap.clear(); + } } } } diff --git a/wifi/java/android/net/wifi/WifiDevice.aidl b/wifi/java/android/net/wifi/WifiDevice.aidl new file mode 100755 index 0000000..c1b186c --- /dev/null +++ b/wifi/java/android/net/wifi/WifiDevice.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package android.net.wifi; + +parcelable WifiDevice; diff --git a/wifi/java/android/net/wifi/WifiDevice.java b/wifi/java/android/net/wifi/WifiDevice.java new file mode 100755 index 0000000..163b559 --- /dev/null +++ b/wifi/java/android/net/wifi/WifiDevice.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package android.net.wifi; + +import android.os.Parcelable; +import android.os.Parcel; + +/** + * Describes information about a detected Wi-Fi STA. + * {@hide} + */ +public class WifiDevice implements Parcelable { + /** + * The device MAC address is the unique id of a Wi-Fi STA + */ + public String deviceAddress = ""; + + /** + * The device name is a readable string of a Wi-Fi STA + */ + public String deviceName = ""; + + /** + * The device state is the state of a Wi-Fi STA + */ + public int deviceState = 0; + + /** + * These definitions are for deviceState + */ + public static final int DISCONNECTED = 0; + public static final int CONNECTED = 1; + public static final int BLACKLISTED = 2; + + private static final String AP_STA_CONNECTED_STR = "AP-STA-CONNECTED"; + private static final String AP_STA_DISCONNECTED_STR = "AP-STA-DISCONNECTED"; + + /** {@hide} */ + public WifiDevice() {} + + /** + * @param string formats supported include + * + * AP-STA-CONNECTED 42:fc:89:a8:96:09 + * AP-STA-DISCONNECTED 42:fc:89:a8:96:09 + * + * Note: The events formats can be looked up in the hostapd code + * @hide + */ + public WifiDevice(String dataString) throws IllegalArgumentException { + String[] tokens = dataString.split(" "); + + if (tokens.length < 2) { + throw new IllegalArgumentException(); + } + + if (tokens[0].indexOf(AP_STA_CONNECTED_STR) != -1) { + deviceState = CONNECTED; + } else if (tokens[0].indexOf(AP_STA_DISCONNECTED_STR) != -1) { + deviceState = DISCONNECTED; + } else { + throw new IllegalArgumentException(); + } + + deviceAddress = tokens[1]; + } + + @Override + public boolean equals(Object obj) { + if (obj == null || !(obj instanceof WifiDevice)) { + return false; + } + + WifiDevice other = (WifiDevice) obj; + + if (deviceAddress == null) { + return (other.deviceAddress == null); + } else { + return deviceAddress.equals(other.deviceAddress); + } + } + + /** Implement the Parcelable interface {@hide} */ + public int describeContents() { + return 0; + } + + /** Implement the Parcelable interface {@hide} */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(deviceAddress); + dest.writeString(deviceName); + dest.writeInt(deviceState); + } + + /** Implement the Parcelable interface {@hide} */ + public static final Creator<WifiDevice> CREATOR = + new Creator<WifiDevice>() { + public WifiDevice createFromParcel(Parcel in) { + WifiDevice device = new WifiDevice(); + device.deviceAddress = in.readString(); + device.deviceName = in.readString(); + device.deviceState = in.readInt(); + return device; + } + + public WifiDevice[] newArray(int size) { + return new WifiDevice[size]; + } + }; +} |