2 * ***************************************************************
4 * Copyright 2015 Samsung Electronics All Rights Reserved.
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
20 * ****************************************************************
23 package org.iotivity.service.easysetup.mediator.ip;
25 import java.io.BufferedReader;
26 import java.io.FileReader;
27 import java.io.IOException;
28 import java.lang.reflect.Method;
29 import java.net.InetAddress;
30 import java.util.ArrayList;
32 import android.content.Context;
33 import android.net.wifi.WifiConfiguration;
34 import android.net.wifi.WifiManager;
35 import android.os.Handler;
36 import android.util.Log;
38 import org.iotivity.service.easysetup.mediator.EnrolleeInfo;
39 import org.iotivity.service.easysetup.mediator.EnrolleeOnBoardingInfo;
40 import org.iotivity.service.easysetup.mediator.IOnBoardingStatus;
43 * WiFiSoftAPManager provides wrapper methods for accessing Android Soft Access Point functionality.
44 * This is a convenient class, providing Android "WiFiManager" kind of equivalent class for Soft AP.
46 * Note: Android doesn't provide public APIs for Soft Access Point feature access.
47 * This class provides only reference implementation to use the Soft AP and it uses Java reflection
48 * for access Soft Access point features.
51 public class WiFiSoftAPManager {
52 private static final String TAG = WiFiSoftAPManager.class.getName();
53 private final WifiManager mWifiManager;
54 private Context context;
55 static ArrayList<EnrolleeOnBoardingInfo> appNotification =
56 new ArrayList<EnrolleeOnBoardingInfo>();
57 IOnBoardingStatus finishListener = null;
59 public enum WIFI_AP_STATE {
60 WIFI_AP_STATE_DISABLING,
61 WIFI_AP_STATE_DISABLED,
62 WIFI_AP_STATE_ENABLING,
63 WIFI_AP_STATE_ENABLED,
67 public WiFiSoftAPManager(Context context) {
68 this.context = context;
69 mWifiManager = (WifiManager) this.context
70 .getSystemService(Context.WIFI_SERVICE);
74 * Utility API to check the validity of the MAC Address read from the ARP cache
76 private boolean CheckIfValidMacAddress(String macAddr) {
77 if (macAddr.matches("..:..:..:..:..:..")) {
85 * The API is used for checking the device entry in the list maintained for the device
87 * If device entry is not found in the list, app is notified.
88 * If the device entry is found in the device, as application is already notified it will
91 private synchronized boolean CheckForDeviceEntryAndNotify(String ipAddr,
92 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.
181 * @param wifiConfig SSID, security and channel details as part of WifiConfiguration
182 * @return {@code true} if the operation succeeds, {@code false} otherwise
184 public boolean setWifiApEnabled(WifiConfiguration wifiConfig,
187 appNotification.clear();
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 Interface called when the scan method finishes
256 * @param reachableTimeout Reachable Timeout in miliseconds
258 public void getClientList(IOnBoardingStatus finishListener, final int reachableTimeout) {
259 this.finishListener = finishListener;
260 Runnable runnable = new Runnable() {
262 Log.i(TAG, "Scanning enrolling device in the network" );
264 BufferedReader bufferedReader = null;
267 // Note : This is a reference implementation for getting the list of Enrollee's
268 // connected to the Soft AP.
269 // There is no Android API for getting list of connected devices to the Soft AP.
270 // The connected device information is fetched from Arp cache for Soft AP and
271 // it is maintained in the file "/proc/net/arp"
272 bufferedReader = new BufferedReader(new FileReader("/proc/net/arp"));
275 while ((line = bufferedReader.readLine()) != null) {
276 //ARP entries are splitted using Regex for getting the IP and MAC Address
278 String[] arpEntry = line.split(" +");
280 if ((arpEntry != null) && (arpEntry.length >= 4)) {
281 String ipAddr = arpEntry[0];
282 String macAddr = arpEntry[3];
285 // Checking if the string is matching MAC Address is matching the
286 // standard MAC address format.
287 // If the entry is not matching with MAC address format,
289 if (CheckIfValidMacAddress(macAddr)) {
290 boolean isReachable = InetAddress.getByName(
294 Log.i("exec statement", ipAddr);
295 Log.i("Return Value", " " + isReachable);
297 // Checking if the app notification entries are available in the
298 // list for the current device
299 // API returns true is there is a notification to the application.
300 // API returns false if there is no entry or if device is
302 if (CheckForDeviceEntryAndNotify(ipAddr, macAddr, isReachable)) {
308 } catch (Exception e) {
309 Log.e(this.getClass().toString(), e.toString());
312 bufferedReader.close();
313 } catch (IOException e) {
314 Log.e(this.getClass().toString(), e.getMessage());
320 Thread mythread = new Thread(runnable);
324 void NotifyApplication(final EnrolleeInfo result) {
325 // Get a handler that can be used to post to the main thread
327 Handler mainHandler = new Handler(context.getMainLooper());
328 Runnable myRunnable = new Runnable() {
331 finishListener.deviceOnBoardingStatus(result);
334 mainHandler.post(myRunnable);
336 Log.i(TAG, "Scanning is finished with result, IP : " + result.getIpAddr() + "Notifying to Application");
337 finishListener.deviceOnBoardingStatus(result);