1/* 2 * Copyright (C) 2016 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 17package android.net.wifi.nan; 18 19import android.os.Binder; 20import android.os.IBinder; 21import android.os.RemoteException; 22import android.util.Log; 23 24/** 25 * This class provides the primary API for managing Wi-Fi NAN operation: 26 * including discovery and data-links. Get an instance of this class by calling 27 * {@link android.content.Context#getSystemService(String) 28 * Context.getSystemService(Context.WIFI_NAN_SERVICE)}. 29 * <p> 30 * The class provides access to: 31 * <ul> 32 * <li>Configure a NAN connection and register for events. 33 * <li>Create publish and subscribe sessions. 34 * <li>Create NAN network specifier to be used to create a NAN network. 35 * </ul> 36 * 37 * @hide PROPOSED_NAN_API 38 */ 39public class WifiNanManager { 40 private static final String TAG = "WifiNanManager"; 41 private static final boolean DBG = false; 42 private static final boolean VDBG = false; // STOPSHIP if true 43 44 private IBinder mBinder; 45 46 private IWifiNanManager mService; 47 48 /** 49 * {@hide} 50 */ 51 public WifiNanManager(IWifiNanManager service) { 52 mService = service; 53 } 54 55 /** 56 * Re-connect to the Wi-Fi NAN service - enabling the application to execute 57 * {@link WifiNanManager} APIs. Application don't normally need to call this 58 * API since it is executed in the constructor. However, applications which 59 * have explicitly {@link WifiNanManager#disconnect()} need to call this 60 * function to re-connect. 61 * 62 * @param listener A listener extended from {@link WifiNanEventListener}. 63 * @param events The set of events to be delivered to the {@code listener}. 64 * OR'd event flags from {@link WifiNanEventListener 65 * NanEventListener.LISTEN*}. 66 */ 67 public void connect(WifiNanEventListener listener, int events) { 68 try { 69 if (VDBG) Log.v(TAG, "connect()"); 70 if (listener == null) { 71 throw new IllegalArgumentException("Invalid listener - must not be null"); 72 } 73 if (mBinder == null) { 74 mBinder = new Binder(); 75 } 76 mService.connect(mBinder, listener.callback, events); 77 } catch (RemoteException e) { 78 throw e.rethrowFromSystemServer(); 79 } 80 } 81 82 /** 83 * Disconnect from the Wi-Fi NAN service and destroy all outstanding 84 * operations - i.e. all publish and subscribes are terminated, any 85 * outstanding data-link is shut-down, and all requested NAN configurations 86 * are cancelled. 87 * <p> 88 * An application may then re-connect using 89 * {@link WifiNanManager#connect(WifiNanEventListener, int)} . 90 */ 91 public void disconnect() { 92 try { 93 if (VDBG) Log.v(TAG, "disconnect()"); 94 mService.disconnect(mBinder); 95 mBinder = null; 96 } catch (RemoteException e) { 97 throw e.rethrowFromSystemServer(); 98 } 99 } 100 101 /** 102 * Requests a NAN configuration, specified by {@link ConfigRequest}. Note 103 * that NAN is a shared resource and the device can only be a member of a 104 * single cluster. Thus the service may merge configuration requests from 105 * multiple applications and configure NAN differently from individual 106 * requests. 107 * <p> 108 * The {@link WifiNanEventListener#onConfigCompleted(ConfigRequest)} will be 109 * called when configuration is completed (if a listener is registered for 110 * this specific event). 111 * 112 * @param configRequest The requested NAN configuration. 113 */ 114 public void requestConfig(ConfigRequest configRequest) { 115 if (VDBG) Log.v(TAG, "requestConfig(): configRequest=" + configRequest); 116 try { 117 mService.requestConfig(configRequest); 118 } catch (RemoteException e) { 119 throw e.rethrowFromSystemServer(); 120 } 121 } 122 123 /** 124 * Request a NAN publish session. The results of the publish session 125 * operation will result in callbacks to the indicated listener: 126 * {@link WifiNanSessionListener NanSessionListener.on*}. 127 * 128 * @param publishData The {@link PublishData} specifying the contents of the 129 * publish session. 130 * @param publishSettings The {@link PublishSettings} specifying the 131 * settings for the publish session. 132 * @param listener The {@link WifiNanSessionListener} derived objects to be used 133 * for the event callbacks specified by {@code events}. 134 * @param events The list of events to be delivered to the {@code listener} 135 * object. An OR'd value of {@link WifiNanSessionListener 136 * NanSessionListener.LISTEN_*}. 137 * @return The {@link WifiNanPublishSession} which can be used to further 138 * control the publish session. 139 */ 140 public WifiNanPublishSession publish(PublishData publishData, PublishSettings publishSettings, 141 WifiNanSessionListener listener, int events) { 142 return publishRaw(publishData, publishSettings, listener, 143 events | WifiNanSessionListener.LISTEN_HIDDEN_FLAGS); 144 } 145 146 /** 147 * Same as publish(*) but does not modify the event flag 148 * 149 * @hide 150 */ 151 public WifiNanPublishSession publishRaw(PublishData publishData, 152 PublishSettings publishSettings, WifiNanSessionListener listener, int events) { 153 if (VDBG) Log.v(TAG, "publish(): data='" + publishData + "', settings=" + publishSettings); 154 155 if (publishSettings.mPublishType == PublishSettings.PUBLISH_TYPE_UNSOLICITED 156 && publishData.mRxFilterLength != 0) { 157 throw new IllegalArgumentException("Invalid publish data & settings: UNSOLICITED " 158 + "publishes (active) can't have an Rx filter"); 159 } 160 if (publishSettings.mPublishType == PublishSettings.PUBLISH_TYPE_SOLICITED 161 && publishData.mTxFilterLength != 0) { 162 throw new IllegalArgumentException("Invalid publish data & settings: SOLICITED " 163 + "publishes (passive) can't have a Tx filter"); 164 } 165 if (listener == null) { 166 throw new IllegalArgumentException("Invalid listener - must not be null"); 167 } 168 169 int sessionId; 170 171 try { 172 sessionId = mService.createSession(listener.callback, events); 173 if (DBG) Log.d(TAG, "publish: session created - sessionId=" + sessionId); 174 mService.publish(sessionId, publishData, publishSettings); 175 } catch (RemoteException e) { 176 throw e.rethrowFromSystemServer(); 177 } 178 179 return new WifiNanPublishSession(this, sessionId); 180 } 181 182 /** 183 * {@hide} 184 */ 185 public void publish(int sessionId, PublishData publishData, PublishSettings publishSettings) { 186 if (VDBG) Log.v(TAG, "publish(): data='" + publishData + "', settings=" + publishSettings); 187 188 if (publishSettings.mPublishType == PublishSettings.PUBLISH_TYPE_UNSOLICITED 189 && publishData.mRxFilterLength != 0) { 190 throw new IllegalArgumentException("Invalid publish data & settings: UNSOLICITED " 191 + "publishes (active) can't have an Rx filter"); 192 } 193 if (publishSettings.mPublishType == PublishSettings.PUBLISH_TYPE_SOLICITED 194 && publishData.mTxFilterLength != 0) { 195 throw new IllegalArgumentException("Invalid publish data & settings: SOLICITED " 196 + "publishes (passive) can't have a Tx filter"); 197 } 198 199 try { 200 mService.publish(sessionId, publishData, publishSettings); 201 } catch (RemoteException e) { 202 throw e.rethrowFromSystemServer(); 203 } 204 } 205 /** 206 * Request a NAN subscribe session. The results of the subscribe session 207 * operation will result in callbacks to the indicated listener: 208 * {@link WifiNanSessionListener NanSessionListener.on*}. 209 * 210 * @param subscribeData The {@link SubscribeData} specifying the contents of 211 * the subscribe session. 212 * @param subscribeSettings The {@link SubscribeSettings} specifying the 213 * settings for the subscribe session. 214 * @param listener The {@link WifiNanSessionListener} derived objects to be used 215 * for the event callbacks specified by {@code events}. 216 * @param events The list of events to be delivered to the {@code listener} 217 * object. An OR'd value of {@link WifiNanSessionListener 218 * NanSessionListener.LISTEN_*}. 219 * @return The {@link WifiNanSubscribeSession} which can be used to further 220 * control the subscribe session. 221 */ 222 public WifiNanSubscribeSession subscribe(SubscribeData subscribeData, 223 SubscribeSettings subscribeSettings, 224 WifiNanSessionListener listener, int events) { 225 return subscribeRaw(subscribeData, subscribeSettings, listener, 226 events | WifiNanSessionListener.LISTEN_HIDDEN_FLAGS); 227 } 228 229 /** 230 * Same as subscribe(*) but does not modify the event flag 231 * 232 * @hide 233 */ 234 public WifiNanSubscribeSession subscribeRaw(SubscribeData subscribeData, 235 SubscribeSettings subscribeSettings, WifiNanSessionListener listener, int events) { 236 if (VDBG) { 237 Log.v(TAG, "subscribe(): data='" + subscribeData + "', settings=" + subscribeSettings); 238 } 239 240 if (subscribeSettings.mSubscribeType == SubscribeSettings.SUBSCRIBE_TYPE_ACTIVE 241 && subscribeData.mRxFilterLength != 0) { 242 throw new IllegalArgumentException( 243 "Invalid subscribe data & settings: ACTIVE subscribes can't have an Rx filter"); 244 } 245 if (subscribeSettings.mSubscribeType == SubscribeSettings.SUBSCRIBE_TYPE_PASSIVE 246 && subscribeData.mTxFilterLength != 0) { 247 throw new IllegalArgumentException( 248 "Invalid subscribe data & settings: PASSIVE subscribes can't have a Tx filter"); 249 } 250 251 int sessionId; 252 253 try { 254 sessionId = mService.createSession(listener.callback, events); 255 if (DBG) Log.d(TAG, "subscribe: session created - sessionId=" + sessionId); 256 mService.subscribe(sessionId, subscribeData, subscribeSettings); 257 } catch (RemoteException e) { 258 throw e.rethrowFromSystemServer(); 259 } 260 261 return new WifiNanSubscribeSession(this, sessionId); 262 } 263 264 /** 265 * {@hide} 266 */ 267 public void subscribe(int sessionId, SubscribeData subscribeData, 268 SubscribeSettings subscribeSettings) { 269 if (VDBG) { 270 Log.v(TAG, "subscribe(): data='" + subscribeData + "', settings=" + subscribeSettings); 271 } 272 273 if (subscribeSettings.mSubscribeType == SubscribeSettings.SUBSCRIBE_TYPE_ACTIVE 274 && subscribeData.mRxFilterLength != 0) { 275 throw new IllegalArgumentException( 276 "Invalid subscribe data & settings: ACTIVE subscribes can't have an Rx filter"); 277 } 278 if (subscribeSettings.mSubscribeType == SubscribeSettings.SUBSCRIBE_TYPE_PASSIVE 279 && subscribeData.mTxFilterLength != 0) { 280 throw new IllegalArgumentException( 281 "Invalid subscribe data & settings: PASSIVE subscribes can't have a Tx filter"); 282 } 283 284 try { 285 mService.subscribe(sessionId, subscribeData, subscribeSettings); 286 } catch (RemoteException e) { 287 throw e.rethrowFromSystemServer(); 288 } 289 } 290 291 /** 292 * {@hide} 293 */ 294 public void stopSession(int sessionId) { 295 if (DBG) Log.d(TAG, "Stop NAN session #" + sessionId); 296 297 try { 298 mService.stopSession(sessionId); 299 } catch (RemoteException e) { 300 throw e.rethrowFromSystemServer(); 301 } 302 } 303 304 /** 305 * {@hide} 306 */ 307 public void destroySession(int sessionId) { 308 if (DBG) Log.d(TAG, "Destroy NAN session #" + sessionId); 309 310 try { 311 mService.destroySession(sessionId); 312 } catch (RemoteException e) { 313 throw e.rethrowFromSystemServer(); 314 } 315 } 316 317 /** 318 * {@hide} 319 */ 320 public void sendMessage(int sessionId, int peerId, byte[] message, int messageLength, 321 int messageId) { 322 try { 323 if (VDBG) { 324 Log.v(TAG, "sendMessage(): sessionId=" + sessionId + ", peerId=" + peerId 325 + ", messageLength=" + messageLength + ", messageId=" + messageId); 326 } 327 mService.sendMessage(sessionId, peerId, message, messageLength, messageId); 328 } catch (RemoteException e) { 329 throw e.rethrowFromSystemServer(); 330 } 331 } 332} 333