1 /******************************************************************
3 * Copyright 2015 Samsung Electronics All Rights Reserved.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 ******************************************************************/
20 package org.iotivity.service.easysetup.mediator.ip;
22 import java.io.BufferedReader;
23 import java.io.FileReader;
24 import java.io.IOException;
25 import java.lang.reflect.Method;
26 import java.net.InetAddress;
27 import java.util.ArrayList;
29 import android.content.Context;
30 import android.net.wifi.WifiConfiguration;
31 import android.net.wifi.WifiManager;
32 import android.os.Handler;
33 import android.util.Log;
35 import org.iotivity.service.easysetup.mediator.EnrolleeInfo;
36 import org.iotivity.service.easysetup.mediator.EnrolleeOnBoardingInfo;
37 import org.iotivity.service.easysetup.mediator.IOnBoardingStatus;
40 * WiFiSoftAPManager provides wrapper methods for accessing Android Soft Access Point functionality.
41 * This is a convenient class, providing Android "WiFiManager" kind of equivalent class for Soft AP.
43 * Note: Android doesn't provide public APIs for Soft Access Point feature access.
44 * This class provides only reference implementation to use the Soft AP and it uses Java reflection
45 * for access Soft Access point features.
48 public class WiFiSoftAPManager {
49 private final WifiManager mWifiManager;
50 private Context context;
51 static ArrayList<EnrolleeOnBoardingInfo> appNotification =
52 new ArrayList<EnrolleeOnBoardingInfo>();
53 IOnBoardingStatus finishListener = null;
55 public enum WIFI_AP_STATE {
56 WIFI_AP_STATE_DISABLING,
57 WIFI_AP_STATE_DISABLED,
58 WIFI_AP_STATE_ENABLING,
59 WIFI_AP_STATE_ENABLED,
63 public WiFiSoftAPManager(Context context) {
64 this.context = context;
65 mWifiManager = (WifiManager) this.context
66 .getSystemService(Context.WIFI_SERVICE);
70 * Utility API to check the validity of the MAC Address read from the ARP cache
72 private boolean CheckIfValidMacAddress(String macAddr)
74 if(macAddr.matches("..:..:..:..:..:.."))
84 * The API is used for checking the device entry in the list maintained for the device
86 * If device entry is not found in the list, app is notified.
87 * If the device entry is found in the device, as application is already notified it will
90 private synchronized boolean CheckForDeviceEntryAndNotify(String ipAddr,
91 String macAddr, boolean isReachable)
93 final EnrolleeInfo result = new EnrolleeInfo();
94 boolean deviceAddedToList = false;
96 if (appNotification.size() > 0) {
97 for (EnrolleeOnBoardingInfo ipDeviceOnBoardingNotification : appNotification) {
98 EnrolleeOnBoardingInfo ipEnrolleeDevice = (EnrolleeOnBoardingInfo)ipDeviceOnBoardingNotification;
99 boolean macAddressComparison = ipEnrolleeDevice.getHWAddr().equalsIgnoreCase(
100 macAddr) ? true : false;
102 if (macAddressComparison) {
103 deviceAddedToList = true;
105 if (ipDeviceOnBoardingNotification
106 .isAdditionNotified()
109 } else if (ipDeviceOnBoardingNotification
114 result.setIpAddr(ipAddr);
115 result.setHWAddr(macAddr);
116 result.setReachable(isReachable);
119 .remove(ipDeviceOnBoardingNotification);
122 .add(new EnrolleeOnBoardingInfo(ipAddr, macAddr, "", isReachable,
126 .add(new EnrolleeOnBoardingInfo(ipAddr, macAddr, "", isReachable,
130 NotifyApplication(result);
135 if (!deviceAddedToList) {
138 .add(new EnrolleeOnBoardingInfo(ipAddr, macAddr, "", isReachable, false,
142 .add(new EnrolleeOnBoardingInfo(ipAddr, macAddr, "", isReachable, true,
146 result.setIpAddr(ipAddr);
147 result.setHWAddr(macAddr);
148 result.setReachable(isReachable);
150 NotifyApplication(result);
156 .add(new EnrolleeOnBoardingInfo(ipAddr, macAddr, "", isReachable, false,
160 .add(new EnrolleeOnBoardingInfo(ipAddr, macAddr, "", isReachable, true,
164 result.setIpAddr(ipAddr);
165 result.setHWAddr(macAddr);
166 result.setReachable(isReachable);
168 NotifyApplication(result);
175 * Start WiFi Soft AccessPoint mode with the specified configuration.
176 * If the Soft AP is already running, this API call will update the new configuration.
178 * Note: Starting Wi-Fi Soft Access Point will disable the Wi-Fi normal operation.
182 * SSID, security and channel details as part of WifiConfiguration
183 * @return {@code true} if the operation succeeds, {@code false} otherwise
185 public boolean setWifiApEnabled(WifiConfiguration wifiConfig,
188 // Stopping Wi-Fi mode
190 mWifiManager.setWifiEnabled(false);
193 Method method = mWifiManager.getClass().getMethod(
194 "setWifiApEnabled", WifiConfiguration.class, boolean.class);
195 return (Boolean) method.invoke(mWifiManager, wifiConfig, enabled);
196 } catch (Exception e) {
197 Log.e(this.getClass().toString(), "", e);
203 * Fetch the current state of the Wi-Fi Soft AP
205 * @return {@link WIFI_AP_STATE}
207 public WIFI_AP_STATE getWifiApState() {
209 Method method = mWifiManager.getClass().getMethod("getWifiApState");
211 int currentWiFiState = ((Integer) method.invoke(mWifiManager));
213 return WIFI_AP_STATE.class.getEnumConstants()[currentWiFiState];
214 } catch (Exception e) {
215 Log.e(this.getClass().toString(), "", e);
216 return WIFI_AP_STATE.WIFI_AP_STATE_FAILED;
221 * Fetch the current Wi-Fi AP Configuration.
223 * @return AP details in {@link WifiConfiguration}
225 public WifiConfiguration getWifiApConfiguration() {
227 Method method = mWifiManager.getClass().getMethod(
228 "getWifiApConfiguration");
229 return (WifiConfiguration) method.invoke(mWifiManager);
230 } catch (Exception e) {
231 Log.e(this.getClass().toString(), "", e);
237 * Set/Update the Wi-Fi AP Configuration.
239 * @return {@code true} if the operation succeeds, {@code false} otherwise
241 public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
243 Method method = mWifiManager.getClass().getMethod(
244 "setWifiApConfiguration", WifiConfiguration.class);
245 return (Boolean) method.invoke(mWifiManager, wifiConfig);
246 } catch (Exception e) {
247 Log.e(this.getClass().toString(), "", e);
253 * Gets a list of the Soft AP clients connected to the Wi-Fi Soft Access point
255 * @param finishListener
256 * Interface called when the scan method finishes
257 * @param reachableTimeout
258 * Reachable Timeout in miliseconds
260 public void getClientList(IOnBoardingStatus finishListener, final int reachableTimeout) {
261 this.finishListener = finishListener;
262 Runnable runnable = new Runnable() {
265 BufferedReader bufferedReader = null;
268 // Note : This is a reference implementation for getting the list of Enrollee's
269 // connected to the Soft AP.
270 // There is no Android API for getting list of connected devices to the Soft AP.
271 // The connected device information is fetched from Arp cache for Soft AP and
272 // it is maintained in the file "/proc/net/arp"
273 bufferedReader = new BufferedReader(new FileReader("/proc/net/arp"));
276 while ((line = bufferedReader.readLine()) != null) {
277 //ARP entries are splitted using Regex for getting the IP and MAC Address
279 String[] arpEntry = line.split(" +");
281 if ((arpEntry != null) && (arpEntry.length >= 4)) {
282 String ipAddr = arpEntry[0];
283 String macAddr = arpEntry[3];
286 // Checking if the string is matching MAC Address is matching the
287 // standard MAC address format.
288 // If the entry is not matching with MAC address format,
290 if (CheckIfValidMacAddress(macAddr)) {
291 boolean isReachable = InetAddress.getByName(
295 Log.i("exec statement", ipAddr);
296 Log.i("Return Value", " " + isReachable);
298 // Checking if the app notification entries are available in the
299 // list for the current device
300 // API returns true is there is a notification to the application.
301 // API returns false if there is no entry or if device is
303 if(CheckForDeviceEntryAndNotify(ipAddr, macAddr, isReachable))
310 } catch (Exception e) {
311 Log.e(this.getClass().toString(), e.toString());
314 bufferedReader.close();
315 } catch (IOException e) {
316 Log.e(this.getClass().toString(), e.getMessage());
322 Thread mythread = new Thread(runnable);
326 void NotifyApplication(final EnrolleeInfo result) {
327 // Get a handler that can be used to post to the main thread
328 Handler mainHandler = new Handler(context.getMainLooper());
329 Runnable myRunnable = new Runnable() {
332 finishListener.deviceOnBoardingStatus(result);
335 mainHandler.post(myRunnable);