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.core.ip;
25 import java.io.BufferedReader;
26 import java.io.FileInputStream;
27 import java.io.IOException;
28 import java.io.InputStreamReader;
29 import java.lang.reflect.Method;
30 import java.net.InetAddress;
31 import java.util.ArrayList;
33 import android.content.Context;
34 import android.net.wifi.WifiConfiguration;
35 import android.net.wifi.WifiManager;
36 import android.util.Log;
38 import org.iotivity.service.easysetup.core.EnrolleeInfo;
39 import org.iotivity.service.easysetup.core.EnrolleeOnBoardingInfo;
40 import org.iotivity.service.easysetup.core.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 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)
99 ipDeviceOnBoardingNotification;
100 boolean macAddressComparison = ipEnrolleeDevice.getHWAddr().equalsIgnoreCase(
101 macAddr) ? true : false;
103 if (macAddressComparison) {
104 deviceAddedToList = true;
106 if (ipDeviceOnBoardingNotification
107 .isAdditionNotified()
110 } else if (ipDeviceOnBoardingNotification
115 result.setIpAddr(ipAddr);
116 result.setHWAddr(macAddr);
117 result.setReachable(isReachable);
120 .remove(ipDeviceOnBoardingNotification);
123 .add(new EnrolleeOnBoardingInfo(ipAddr, macAddr, "",
127 //This case will happen during the transition from connected to
128 // disconneted. This case need not be notified to application.
129 // Notifying this state will cause failure of OnBoarding
131 NotifyApplication(result);
136 if (!deviceAddedToList) {
139 .add(new EnrolleeOnBoardingInfo(ipAddr, macAddr, "", isReachable, false,
142 result.setIpAddr(ipAddr);
143 result.setHWAddr(macAddr);
144 result.setReachable(isReachable);
146 NotifyApplication(result);
148 //This case will happen for the first time device is listed, but reachability
149 // is false. This case need not be notified to application. Notifying this
150 // state will cause failure of OnBoarding
157 .add(new EnrolleeOnBoardingInfo(ipAddr, macAddr, "", isReachable, false,
159 result.setIpAddr(ipAddr);
160 result.setHWAddr(macAddr);
161 result.setReachable(isReachable);
163 NotifyApplication(result);
165 //This case will happen for the first time device is listed, but
166 // reachability is false. This case need not be notified to
167 // application. Notifying this state will cause failure of OnBoarding
176 * Start WiFi Soft AccessPoint mode with the specified configuration.
177 * If the Soft AP is already running, this API call will update the new configuration.
179 * Note: Starting Wi-Fi Soft Access Point will disable the Wi-Fi normal operation.
182 * @param wifiConfig 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 appNotification.clear();
189 // Stopping Wi-Fi mode
191 mWifiManager.setWifiEnabled(false);
194 Method method = mWifiManager.getClass().getMethod(
195 "setWifiApEnabled", WifiConfiguration.class, boolean.class);
196 return (Boolean) method.invoke(mWifiManager, wifiConfig, enabled);
197 } catch (Exception e) {
198 Log.e(this.getClass().toString(), "", e);
204 * Gets a list of the Soft AP clients connected to the Wi-Fi Soft Access point
206 * @param finishListener Interface called when the scan method finishes
207 * @param reachableTimeout Reachable Timeout in miliseconds
209 public synchronized void getClientList(IOnBoardingStatus finishListener, final int
211 this.finishListener = finishListener;
212 //Clearing the scan list for providing u
213 appNotification.clear();
214 Runnable runnable = new Runnable() {
216 Log.i(TAG, "Scanning enrolling device in the network");
218 BufferedReader bufferedReader = null;
221 // Note : This is a reference implementation for getting the list of Enrollee's
222 // connected to the Soft AP.
223 // There is no Android API for getting list of connected devices to the Soft AP.
224 // The connected device information is fetched from Arp cache for Soft AP and
225 // it is maintained in the file "/proc/net/arp"
226 // This holds an ASCII readable dump of the kernel ARP table used
227 // for address resolutions. It will show both dynamically learned
228 // and preprogrammed ARP entries. The format is:
229 // IP address HW type Flags HW address Mask Device
230 // 192.168.0.50 0x1 0x2 00:50:BF:25:68:F3 * eth0
231 // 192.168.0.250 0x1 0xc 00:00:00:00:00:00 * eth0
232 bufferedReader = new BufferedReader(new InputStreamReader(
233 new FileInputStream("/proc/net/arp"), "UTF-8"));
235 while ((line = bufferedReader.readLine()) != null) {
236 //ARP entries are splitted using Regex for getting the IP and MAC Address
238 String[] arpEntry = line.split(" +");
240 if ((arpEntry != null) && (arpEntry.length >= 4)) {
241 String ipAddr = arpEntry[0];
242 String macAddr = arpEntry[3];
245 // Checking if the string is matching MAC Address is matching the
246 // standard MAC address format.
247 // If the entry is not matching with MAC address format,
249 if (CheckIfValidMacAddress(macAddr)) {
250 boolean isReachable = InetAddress.getByName(
254 Log.i("exec statement", ipAddr);
255 Log.i("Return Value", " " + isReachable);
257 // Checking if the app notification entries are available in the
258 // list for the current device
259 // API returns true is there is a notification to the application.
260 // API returns false if there is no entry or if device is
262 if (CheckForDeviceEntryAndNotify(ipAddr, macAddr, isReachable)) {
268 } catch (Exception e) {
269 Log.e(this.getClass().toString(), e.toString());
272 bufferedReader.close();
273 } catch (IOException e) {
274 Log.e(this.getClass().toString(), e.getMessage());
280 Thread mythread = new Thread(runnable);
284 void NotifyApplication(final EnrolleeInfo result) {
285 // Get a handler that can be used to post to the main thread
287 Handler mainHandler = new Handler(context.getMainLooper());
288 Runnable myRunnable = new Runnable() {
291 finishListener.deviceOnBoardingStatus(result);
294 mainHandler.post(myRunnable);
296 Log.i(TAG, "Scanning is finished with result, IP : " + result.getIpAddr() + "Notifying " +
298 finishListener.deviceOnBoardingStatus(result);