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 17 package com.googlecode.android_scripting.facade.wifi; 18 19 import android.app.Service; 20 import android.content.Context; 21 import android.net.ConnectivityManager; 22 import android.net.wifi.nan.ConfigRequest; 23 import android.net.wifi.nan.PublishData; 24 import android.net.wifi.nan.PublishSettings; 25 import android.net.wifi.nan.SubscribeData; 26 import android.net.wifi.nan.SubscribeSettings; 27 import android.net.wifi.nan.TlvBufferUtils; 28 import android.net.wifi.nan.WifiNanEventListener; 29 import android.net.wifi.nan.WifiNanManager; 30 import android.net.wifi.nan.WifiNanSession; 31 import android.net.wifi.nan.WifiNanSessionListener; 32 import android.os.Bundle; 33 import android.os.HandlerThread; 34 import android.os.Looper; 35 import android.os.RemoteException; 36 37 import com.googlecode.android_scripting.facade.EventFacade; 38 import com.googlecode.android_scripting.facade.FacadeManager; 39 import com.googlecode.android_scripting.jsonrpc.RpcReceiver; 40 import com.googlecode.android_scripting.rpc.Rpc; 41 import com.googlecode.android_scripting.rpc.RpcParameter; 42 43 import org.json.JSONException; 44 import org.json.JSONObject; 45 46 /** 47 * WifiNanManager functions. 48 */ 49 public class WifiNanManagerFacade extends RpcReceiver { 50 private final Service mService; 51 private final EventFacade mEventFacade; 52 53 private WifiNanManager mMgr; 54 private WifiNanSession mSession; 55 private HandlerThread mNanFacadeThread; 56 private ConnectivityManager mConnMgr; 57 getFilterData(JSONObject j)58 private static TlvBufferUtils.TlvConstructor getFilterData(JSONObject j) throws JSONException { 59 if (j == null) { 60 return null; 61 } 62 63 TlvBufferUtils.TlvConstructor constructor = new TlvBufferUtils.TlvConstructor(0, 1); 64 constructor.allocate(255); 65 66 if (j.has("int0")) { 67 constructor.putShort(0, (short) j.getInt("int0")); 68 } 69 70 if (j.has("int1")) { 71 constructor.putShort(0, (short) j.getInt("int1")); 72 } 73 74 if (j.has("data0")) { 75 constructor.putString(0, j.getString("data0")); 76 } 77 78 if (j.has("data1")) { 79 constructor.putString(0, j.getString("data1")); 80 } 81 82 return constructor; 83 } 84 getConfigRequest(JSONObject j)85 private static ConfigRequest getConfigRequest(JSONObject j) throws JSONException { 86 if (j == null) { 87 return null; 88 } 89 90 ConfigRequest.Builder builder = new ConfigRequest.Builder(); 91 92 if (j.has("Support5gBand")) { 93 builder.setSupport5gBand(j.getBoolean("Support5gBand")); 94 } 95 if (j.has("MasterPreference")) { 96 builder.setMasterPreference(j.getInt("MasterPreference")); 97 } 98 if (j.has("ClusterLow")) { 99 builder.setClusterLow(j.getInt("ClusterLow")); 100 } 101 if (j.has("ClusterHigh")) { 102 builder.setClusterHigh(j.getInt("ClusterHigh")); 103 } 104 105 return builder.build(); 106 } 107 getPublishData(JSONObject j)108 private static PublishData getPublishData(JSONObject j) throws JSONException { 109 if (j == null) { 110 return null; 111 } 112 113 PublishData.Builder builder = new PublishData.Builder(); 114 115 if (j.has("ServiceName")) { 116 builder.setServiceName(j.getString("ServiceName")); 117 } 118 119 if (j.has("ServiceSpecificInfo")) { 120 String ssi = j.getString("ServiceSpecificInfo"); 121 builder.setServiceSpecificInfo(ssi.getBytes(), ssi.length()); 122 } 123 124 if (j.has("TxFilter")) { 125 TlvBufferUtils.TlvConstructor constructor = getFilterData(j.getJSONObject("TxFilter")); 126 builder.setTxFilter(constructor.getArray(), constructor.getActualLength()); 127 } 128 129 if (j.has("RxFilter")) { 130 TlvBufferUtils.TlvConstructor constructor = getFilterData(j.getJSONObject("RxFilter")); 131 builder.setRxFilter(constructor.getArray(), constructor.getActualLength()); 132 } 133 134 return builder.build(); 135 } 136 getPublishSettings(JSONObject j)137 private static PublishSettings getPublishSettings(JSONObject j) throws JSONException { 138 if (j == null) { 139 return null; 140 } 141 142 PublishSettings.Builder builder = new PublishSettings.Builder(); 143 144 if (j.has("PublishType")) { 145 builder.setPublishType(j.getInt("PublishType")); 146 } 147 if (j.has("PublishCount")) { 148 builder.setPublishCount(j.getInt("PublishCount")); 149 } 150 if (j.has("TtlSec")) { 151 builder.setTtlSec(j.getInt("TtlSec")); 152 } 153 154 return builder.build(); 155 } 156 getSubscribeData(JSONObject j)157 private static SubscribeData getSubscribeData(JSONObject j) throws JSONException { 158 if (j == null) { 159 return null; 160 } 161 162 SubscribeData.Builder builder = new SubscribeData.Builder(); 163 164 if (j.has("ServiceName")) { 165 builder.setServiceName(j.getString("ServiceName")); 166 } 167 168 if (j.has("ServiceSpecificInfo")) { 169 String ssi = j.getString("ServiceSpecificInfo"); 170 builder.setServiceSpecificInfo(ssi); 171 } 172 173 if (j.has("TxFilter")) { 174 TlvBufferUtils.TlvConstructor constructor = getFilterData(j.getJSONObject("TxFilter")); 175 builder.setTxFilter(constructor.getArray(), constructor.getActualLength()); 176 } 177 178 if (j.has("RxFilter")) { 179 TlvBufferUtils.TlvConstructor constructor = getFilterData(j.getJSONObject("RxFilter")); 180 builder.setRxFilter(constructor.getArray(), constructor.getActualLength()); 181 } 182 183 return builder.build(); 184 } 185 getSubscribeSettings(JSONObject j)186 private static SubscribeSettings getSubscribeSettings(JSONObject j) throws JSONException { 187 if (j == null) { 188 return null; 189 } 190 191 SubscribeSettings.Builder builder = new SubscribeSettings.Builder(); 192 193 if (j.has("SubscribeType")) { 194 builder.setSubscribeType(j.getInt("SubscribeType")); 195 } 196 if (j.has("SubscribeCount")) { 197 builder.setSubscribeCount(j.getInt("SubscribeCount")); 198 } 199 if (j.has("TtlSec")) { 200 builder.setTtlSec(j.getInt("TtlSec")); 201 } 202 203 return builder.build(); 204 } 205 WifiNanManagerFacade(FacadeManager manager)206 public WifiNanManagerFacade(FacadeManager manager) { 207 super(manager); 208 mService = manager.getService(); 209 210 mNanFacadeThread = new HandlerThread("nanFacadeThread"); 211 mNanFacadeThread.start(); 212 213 mMgr = (WifiNanManager) mService.getSystemService(Context.WIFI_NAN_SERVICE); 214 mMgr.connect(new NanEventListenerPostsEvents(mNanFacadeThread.getLooper()), 215 WifiNanEventListener.LISTEN_CONFIG_COMPLETED 216 | WifiNanEventListener.LISTEN_CONFIG_FAILED 217 | WifiNanEventListener.LISTEN_NAN_DOWN 218 | WifiNanEventListener.LISTEN_IDENTITY_CHANGED); 219 220 mConnMgr = (ConnectivityManager) mService.getSystemService(Context.CONNECTIVITY_SERVICE); 221 222 mEventFacade = manager.getReceiver(EventFacade.class); 223 } 224 225 @Override shutdown()226 public void shutdown() { 227 } 228 229 @Rpc(description = "Start NAN.") wifiNanEnable(@pcParametername = "nanConfig") JSONObject nanConfig)230 public void wifiNanEnable(@RpcParameter(name = "nanConfig") JSONObject nanConfig) 231 throws RemoteException, JSONException { 232 mMgr.requestConfig(getConfigRequest(nanConfig)); 233 } 234 235 @Rpc(description = "Stop NAN.") wifiNanDisable()236 public void wifiNanDisable() throws RemoteException, JSONException { 237 mMgr.disconnect(); 238 } 239 240 @Rpc(description = "Publish.") wifiNanPublish(@pcParametername = "publishData") JSONObject publishData, @RpcParameter(name = "publishSettings") JSONObject publishSettings, @RpcParameter(name = "listenerId") Integer listenerId)241 public void wifiNanPublish(@RpcParameter(name = "publishData") JSONObject publishData, 242 @RpcParameter(name = "publishSettings") JSONObject publishSettings, 243 @RpcParameter(name = "listenerId") Integer listenerId) 244 throws RemoteException, JSONException { 245 mSession = mMgr.publish(getPublishData(publishData), getPublishSettings(publishSettings), 246 new NanSessionListenerPostsEvents(mNanFacadeThread.getLooper(), listenerId), 247 WifiNanSessionListener.LISTEN_PUBLISH_FAIL 248 | WifiNanSessionListener.LISTEN_PUBLISH_TERMINATED 249 | WifiNanSessionListener.LISTEN_SUBSCRIBE_FAIL 250 | WifiNanSessionListener.LISTEN_SUBSCRIBE_TERMINATED 251 | WifiNanSessionListener.LISTEN_MATCH 252 | WifiNanSessionListener.LISTEN_MESSAGE_SEND_SUCCESS 253 | WifiNanSessionListener.LISTEN_MESSAGE_SEND_FAIL 254 | WifiNanSessionListener.LISTEN_MESSAGE_RECEIVED); 255 } 256 257 @Rpc(description = "Subscribe.") wifiNanSubscribe(@pcParametername = "subscribeData") JSONObject subscribeData, @RpcParameter(name = "subscribeSettings") JSONObject subscribeSettings, @RpcParameter(name = "listenerId") Integer listenerId)258 public void wifiNanSubscribe(@RpcParameter(name = "subscribeData") JSONObject subscribeData, 259 @RpcParameter(name = "subscribeSettings") JSONObject subscribeSettings, 260 @RpcParameter(name = "listenerId") Integer listenerId) 261 throws RemoteException, JSONException { 262 263 mSession = mMgr.subscribe(getSubscribeData(subscribeData), 264 getSubscribeSettings(subscribeSettings), 265 new NanSessionListenerPostsEvents(mNanFacadeThread.getLooper(), listenerId), 266 WifiNanSessionListener.LISTEN_PUBLISH_FAIL 267 | WifiNanSessionListener.LISTEN_PUBLISH_TERMINATED 268 | WifiNanSessionListener.LISTEN_SUBSCRIBE_FAIL 269 | WifiNanSessionListener.LISTEN_SUBSCRIBE_TERMINATED 270 | WifiNanSessionListener.LISTEN_MATCH 271 | WifiNanSessionListener.LISTEN_MESSAGE_SEND_SUCCESS 272 | WifiNanSessionListener.LISTEN_MESSAGE_SEND_FAIL 273 | WifiNanSessionListener.LISTEN_MESSAGE_RECEIVED); 274 } 275 276 @Rpc(description = "Send peer-to-peer NAN message") wifiNanSendMessage( @pcParametername = "peerId", description = "The ID of the peer being communicated " + "with. Obtained from a previous message or match session.") Integer peerId, @RpcParameter(name = "message") String message, @RpcParameter(name = "messageId", description = "Arbitrary handle used for " + "identification of the message in the message status callbacks") Integer messageId)277 public void wifiNanSendMessage( 278 @RpcParameter(name = "peerId", description = "The ID of the peer being communicated " 279 + "with. Obtained from a previous message or match session.") Integer peerId, 280 @RpcParameter(name = "message") String message, 281 @RpcParameter(name = "messageId", description = "Arbitrary handle used for " 282 + "identification of the message in the message status callbacks") 283 Integer messageId) 284 throws RemoteException { 285 mSession.sendMessage(peerId, message.getBytes(), message.length(), messageId); 286 } 287 288 private class NanEventListenerPostsEvents extends WifiNanEventListener { NanEventListenerPostsEvents(Looper looper)289 public NanEventListenerPostsEvents(Looper looper) { 290 super(looper); 291 } 292 293 @Override onConfigCompleted(ConfigRequest configRequest)294 public void onConfigCompleted(ConfigRequest configRequest) { 295 Bundle mResults = new Bundle(); 296 mResults.putParcelable("configRequest", configRequest); 297 mEventFacade.postEvent("WifiNanOnConfigCompleted", mResults); 298 } 299 300 @Override onConfigFailed(ConfigRequest failedConfig, int reason)301 public void onConfigFailed(ConfigRequest failedConfig, int reason) { 302 Bundle mResults = new Bundle(); 303 mResults.putParcelable("failedConfig", failedConfig); 304 mResults.putInt("reason", reason); 305 mEventFacade.postEvent("WifiNanOnConfigFailed", mResults); 306 } 307 308 @Override onNanDown(int reason)309 public void onNanDown(int reason) { 310 Bundle mResults = new Bundle(); 311 mResults.putInt("reason", reason); 312 mEventFacade.postEvent("WifiNanOnNanDown", mResults); 313 } 314 315 @Override onIdentityChanged()316 public void onIdentityChanged() { 317 Bundle mResults = new Bundle(); 318 mEventFacade.postEvent("WifiNanOnIdentityChanged", mResults); 319 } 320 } 321 322 private class NanSessionListenerPostsEvents extends WifiNanSessionListener { 323 private int mListenerId; 324 NanSessionListenerPostsEvents(Looper looper, int listenerId)325 public NanSessionListenerPostsEvents(Looper looper, int listenerId) { 326 super(looper); 327 mListenerId = listenerId; 328 } 329 330 @Override onPublishFail(int reason)331 public void onPublishFail(int reason) { 332 Bundle mResults = new Bundle(); 333 mResults.putInt("listenerId", mListenerId); 334 mResults.putInt("reason", reason); 335 mEventFacade.postEvent("WifiNanSessionOnPublishFail", mResults); 336 } 337 338 @Override onPublishTerminated(int reason)339 public void onPublishTerminated(int reason) { 340 Bundle mResults = new Bundle(); 341 mResults.putInt("listenerId", mListenerId); 342 mResults.putInt("reason", reason); 343 mEventFacade.postEvent("WifiNanSessionOnPublishTerminated", mResults); 344 } 345 346 @Override onSubscribeFail(int reason)347 public void onSubscribeFail(int reason) { 348 Bundle mResults = new Bundle(); 349 mResults.putInt("listenerId", mListenerId); 350 mResults.putInt("reason", reason); 351 mEventFacade.postEvent("WifiNanSessionOnSubscribeFail", mResults); 352 } 353 354 @Override onSubscribeTerminated(int reason)355 public void onSubscribeTerminated(int reason) { 356 Bundle mResults = new Bundle(); 357 mResults.putInt("listenerId", mListenerId); 358 mResults.putInt("reason", reason); 359 mEventFacade.postEvent("WifiNanSessionOnSubscribeTerminated", mResults); 360 } 361 362 @Override onMatch(int peerId, byte[] serviceSpecificInfo, int serviceSpecificInfoLength, byte[] matchFilter, int matchFilterLength)363 public void onMatch(int peerId, byte[] serviceSpecificInfo, 364 int serviceSpecificInfoLength, byte[] matchFilter, int matchFilterLength) { 365 Bundle mResults = new Bundle(); 366 mResults.putInt("listenerId", mListenerId); 367 mResults.putInt("peerId", peerId); 368 mResults.putInt("serviceSpecificInfoLength", serviceSpecificInfoLength); 369 mResults.putByteArray("serviceSpecificInfo", serviceSpecificInfo); // TODO: base64 370 mResults.putInt("matchFilterLength", matchFilterLength); 371 mResults.putByteArray("matchFilter", matchFilter); // TODO: base64 372 mEventFacade.postEvent("WifiNanSessionOnMatch", mResults); 373 } 374 375 @Override onMessageSendSuccess(int messageId)376 public void onMessageSendSuccess(int messageId) { 377 Bundle mResults = new Bundle(); 378 mResults.putInt("listenerId", mListenerId); 379 mResults.putInt("messageId", messageId); 380 mEventFacade.postEvent("WifiNanSessionOnMessageSendSuccess", mResults); 381 } 382 383 @Override onMessageSendFail(int messageId, int reason)384 public void onMessageSendFail(int messageId, int reason) { 385 Bundle mResults = new Bundle(); 386 mResults.putInt("listenerId", mListenerId); 387 mResults.putInt("messageId", messageId); 388 mResults.putInt("reason", reason); 389 mEventFacade.postEvent("WifiNanSessionOnMessageSendFail", mResults); 390 } 391 392 @Override onMessageReceived(int peerId, byte[] message, int messageLength)393 public void onMessageReceived(int peerId, byte[] message, int messageLength) { 394 Bundle mResults = new Bundle(); 395 mResults.putInt("listenerId", mListenerId); 396 mResults.putInt("peerId", peerId); 397 mResults.putInt("messageLength", messageLength); 398 mResults.putByteArray("message", message); // TODO: base64 399 mResults.putString("messageAsString", new String(message, 0, messageLength)); 400 mEventFacade.postEvent("WifiNanSessionOnMessageReceived", mResults); 401 } 402 } 403 } 404