1 /* 2 * Copyright (C) 2017 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.BroadcastReceiver; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.IntentFilter; 24 import android.net.NetworkSpecifier; 25 import android.net.wifi.RttManager; 26 import android.net.wifi.RttManager.RttResult; 27 import android.net.wifi.aware.AttachCallback; 28 import android.net.wifi.aware.ConfigRequest; 29 import android.net.wifi.aware.DiscoverySession; 30 import android.net.wifi.aware.DiscoverySessionCallback; 31 import android.net.wifi.aware.IdentityChangedListener; 32 import android.net.wifi.aware.PeerHandle; 33 import android.net.wifi.aware.PublishConfig; 34 import android.net.wifi.aware.PublishDiscoverySession; 35 import android.net.wifi.aware.SubscribeConfig; 36 import android.net.wifi.aware.SubscribeDiscoverySession; 37 import android.net.wifi.aware.TlvBufferUtils; 38 import android.net.wifi.aware.WifiAwareManager; 39 import android.net.wifi.aware.WifiAwareNetworkSpecifier; 40 import android.net.wifi.aware.WifiAwareSession; 41 import android.os.Bundle; 42 import android.os.Parcelable; 43 import android.os.RemoteException; 44 import android.util.Base64; 45 import android.util.SparseArray; 46 47 import com.android.internal.annotations.GuardedBy; 48 49 import libcore.util.HexEncoding; 50 51 import com.googlecode.android_scripting.facade.EventFacade; 52 import com.googlecode.android_scripting.facade.FacadeManager; 53 import com.googlecode.android_scripting.jsonrpc.RpcReceiver; 54 import com.googlecode.android_scripting.rpc.Rpc; 55 import com.googlecode.android_scripting.rpc.RpcOptional; 56 import com.googlecode.android_scripting.rpc.RpcParameter; 57 58 import org.json.JSONArray; 59 import org.json.JSONException; 60 import org.json.JSONObject; 61 62 import java.util.List; 63 64 /** 65 * WifiAwareManager functions. 66 */ 67 public class WifiAwareManagerFacade extends RpcReceiver { 68 private final Service mService; 69 private final EventFacade mEventFacade; 70 private final WifiAwareStateChangedReceiver mStateChangedReceiver; 71 72 private final Object mLock = new Object(); // lock access to the following vars 73 74 @GuardedBy("mLock") 75 private WifiAwareManager mMgr; 76 77 @GuardedBy("mLock") 78 private int mNextDiscoverySessionId = 1; 79 @GuardedBy("mLock") 80 private SparseArray<DiscoverySession> mDiscoverySessions = new SparseArray<>(); getNextDiscoverySessionId()81 private int getNextDiscoverySessionId() { 82 synchronized (mLock) { 83 return mNextDiscoverySessionId++; 84 } 85 } 86 87 @GuardedBy("mLock") 88 private int mNextSessionId = 1; 89 @GuardedBy("mLock") 90 private SparseArray<WifiAwareSession> mSessions = new SparseArray<>(); getNextSessionId()91 private int getNextSessionId() { 92 synchronized (mLock) { 93 return mNextSessionId++; 94 } 95 } 96 97 @GuardedBy("mLock") 98 private SparseArray<Long> mMessageStartTime = new SparseArray<>(); 99 100 private static final String NS_KEY_TYPE = "type"; 101 private static final String NS_KEY_ROLE = "role"; 102 private static final String NS_KEY_CLIENT_ID = "client_id"; 103 private static final String NS_KEY_SESSION_ID = "session_id"; 104 private static final String NS_KEY_PEER_ID = "peer_id"; 105 private static final String NS_KEY_PEER_MAC = "peer_mac"; 106 private static final String NS_KEY_PMK = "pmk"; 107 private static final String NS_KEY_PASSPHRASE = "passphrase"; 108 getJsonString(WifiAwareNetworkSpecifier ns)109 private static String getJsonString(WifiAwareNetworkSpecifier ns) throws JSONException { 110 JSONObject j = new JSONObject(); 111 112 j.put(NS_KEY_TYPE, ns.type); 113 j.put(NS_KEY_ROLE, ns.role); 114 j.put(NS_KEY_CLIENT_ID, ns.clientId); 115 j.put(NS_KEY_SESSION_ID, ns.sessionId); 116 j.put(NS_KEY_PEER_ID, ns.peerId); 117 if (ns.peerMac != null) { 118 j.put(NS_KEY_PEER_MAC, Base64.encodeToString(ns.peerMac, Base64.DEFAULT)); 119 } 120 if (ns.pmk != null) { 121 j.put(NS_KEY_PMK, Base64.encodeToString(ns.pmk, Base64.DEFAULT)); 122 } 123 if (ns.passphrase != null) { 124 j.put(NS_KEY_PASSPHRASE, ns.passphrase); 125 } 126 127 return j.toString(); 128 } 129 getNetworkSpecifier(JSONObject j)130 public static NetworkSpecifier getNetworkSpecifier(JSONObject j) throws JSONException { 131 if (j == null) { 132 return null; 133 } 134 135 int type = 0, role = 0, clientId = 0, sessionId = 0, peerId = 0; 136 byte[] peerMac = null; 137 byte[] pmk = null; 138 String passphrase = null; 139 140 if (j.has(NS_KEY_TYPE)) { 141 type = j.getInt((NS_KEY_TYPE)); 142 } 143 if (j.has(NS_KEY_ROLE)) { 144 role = j.getInt((NS_KEY_ROLE)); 145 } 146 if (j.has(NS_KEY_CLIENT_ID)) { 147 clientId = j.getInt((NS_KEY_CLIENT_ID)); 148 } 149 if (j.has(NS_KEY_SESSION_ID)) { 150 sessionId = j.getInt((NS_KEY_SESSION_ID)); 151 } 152 if (j.has(NS_KEY_PEER_ID)) { 153 peerId = j.getInt((NS_KEY_PEER_ID)); 154 } 155 if (j.has(NS_KEY_PEER_MAC)) { 156 peerMac = Base64.decode(j.getString(NS_KEY_PEER_MAC), Base64.DEFAULT); 157 } 158 if (j.has(NS_KEY_PMK)) { 159 pmk = Base64.decode(j.getString(NS_KEY_PMK), Base64.DEFAULT); 160 } 161 if (j.has(NS_KEY_PASSPHRASE)) { 162 passphrase = j.getString((NS_KEY_PASSPHRASE)); 163 } 164 165 return new WifiAwareNetworkSpecifier(type, role, clientId, sessionId, peerId, peerMac, pmk, 166 passphrase); 167 } 168 getFilterData(JSONObject j)169 private static TlvBufferUtils.TlvConstructor getFilterData(JSONObject j) throws JSONException { 170 if (j == null) { 171 return null; 172 } 173 174 TlvBufferUtils.TlvConstructor constructor = new TlvBufferUtils.TlvConstructor(0, 1); 175 constructor.allocate(255); 176 177 if (j.has("int0")) { 178 constructor.putShort(0, (short) j.getInt("int0")); 179 } 180 181 if (j.has("int1")) { 182 constructor.putShort(0, (short) j.getInt("int1")); 183 } 184 185 if (j.has("data0")) { 186 constructor.putString(0, j.getString("data0")); 187 } 188 189 if (j.has("data1")) { 190 constructor.putString(0, j.getString("data1")); 191 } 192 193 return constructor; 194 } 195 getConfigRequest(JSONObject j)196 private static ConfigRequest getConfigRequest(JSONObject j) throws JSONException { 197 if (j == null) { 198 return null; 199 } 200 201 ConfigRequest.Builder builder = new ConfigRequest.Builder(); 202 203 if (j.has("Support5gBand")) { 204 builder.setSupport5gBand(j.getBoolean("Support5gBand")); 205 } 206 if (j.has("MasterPreference")) { 207 builder.setMasterPreference(j.getInt("MasterPreference")); 208 } 209 if (j.has("ClusterLow")) { 210 builder.setClusterLow(j.getInt("ClusterLow")); 211 } 212 if (j.has("ClusterHigh")) { 213 builder.setClusterHigh(j.getInt("ClusterHigh")); 214 } 215 if (j.has("DiscoveryWindowInterval")) { 216 JSONArray interval = j.getJSONArray("DiscoveryWindowInterval"); 217 if (interval.length() != 2) { 218 throw new JSONException( 219 "Expect 'DiscoveryWindowInterval' to be an array with 2 elements!"); 220 } 221 int intervalValue = interval.getInt(ConfigRequest.NAN_BAND_24GHZ); 222 if (intervalValue != ConfigRequest.DW_INTERVAL_NOT_INIT) { 223 builder.setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_24GHZ, intervalValue); 224 } 225 intervalValue = interval.getInt(ConfigRequest.NAN_BAND_5GHZ); 226 if (intervalValue != ConfigRequest.DW_INTERVAL_NOT_INIT) { 227 builder.setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ, intervalValue); 228 } 229 } 230 231 return builder.build(); 232 } 233 getPublishConfig(JSONObject j)234 private static PublishConfig getPublishConfig(JSONObject j) throws JSONException { 235 if (j == null) { 236 return null; 237 } 238 239 PublishConfig.Builder builder = new PublishConfig.Builder(); 240 241 if (j.has("ServiceName")) { 242 builder.setServiceName(j.getString("ServiceName")); 243 } 244 245 if (j.has("ServiceSpecificInfo")) { 246 String ssi = j.getString("ServiceSpecificInfo"); 247 byte[] bytes = ssi.getBytes(); 248 builder.setServiceSpecificInfo(bytes); 249 } 250 251 if (j.has("MatchFilter")) { 252 TlvBufferUtils.TlvConstructor constructor = getFilterData( 253 j.getJSONObject("MatchFilter")); 254 builder.setMatchFilter( 255 new TlvBufferUtils.TlvIterable(0, 1, constructor.getArray()).toList()); 256 } 257 258 if (j.has("PublishType")) { 259 builder.setPublishType(j.getInt("PublishType")); 260 } 261 if (j.has("TtlSec")) { 262 builder.setTtlSec(j.getInt("TtlSec")); 263 } 264 if (j.has("EnableTerminateNotification")) { 265 builder.setTerminateNotificationEnabled(j.getBoolean("TerminateNotificationEnabled")); 266 } 267 268 return builder.build(); 269 } 270 getSubscribeConfig(JSONObject j)271 private static SubscribeConfig getSubscribeConfig(JSONObject j) throws JSONException { 272 if (j == null) { 273 return null; 274 } 275 276 SubscribeConfig.Builder builder = new SubscribeConfig.Builder(); 277 278 if (j.has("ServiceName")) { 279 builder.setServiceName(j.getString("ServiceName")); 280 } 281 282 if (j.has("ServiceSpecificInfo")) { 283 String ssi = j.getString("ServiceSpecificInfo"); 284 builder.setServiceSpecificInfo(ssi.getBytes()); 285 } 286 287 if (j.has("MatchFilter")) { 288 TlvBufferUtils.TlvConstructor constructor = getFilterData( 289 j.getJSONObject("MatchFilter")); 290 builder.setMatchFilter( 291 new TlvBufferUtils.TlvIterable(0, 1, constructor.getArray()).toList()); 292 } 293 294 if (j.has("SubscribeType")) { 295 builder.setSubscribeType(j.getInt("SubscribeType")); 296 } 297 if (j.has("TtlSec")) { 298 builder.setTtlSec(j.getInt("TtlSec")); 299 } 300 if (j.has("EnableTerminateNotification")) { 301 builder.setTerminateNotificationEnabled(j.getBoolean("TerminateNotificationEnabled")); 302 } 303 304 return builder.build(); 305 } 306 WifiAwareManagerFacade(FacadeManager manager)307 public WifiAwareManagerFacade(FacadeManager manager) { 308 super(manager); 309 mService = manager.getService(); 310 311 mMgr = (WifiAwareManager) mService.getSystemService(Context.WIFI_AWARE_SERVICE); 312 313 mEventFacade = manager.getReceiver(EventFacade.class); 314 315 mStateChangedReceiver = new WifiAwareStateChangedReceiver(); 316 IntentFilter filter = new IntentFilter(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED); 317 mService.registerReceiver(mStateChangedReceiver, filter); 318 } 319 320 @Override shutdown()321 public void shutdown() { 322 wifiAwareDestroyAll(); 323 mService.unregisterReceiver(mStateChangedReceiver); 324 } 325 326 @Rpc(description = "Is Aware Usage Enabled?") wifiIsAwareAvailable()327 public Boolean wifiIsAwareAvailable() throws RemoteException { 328 synchronized (mLock) { 329 return mMgr.isAvailable(); 330 } 331 } 332 333 @Rpc(description = "Destroy all Aware sessions and discovery sessions") wifiAwareDestroyAll()334 public void wifiAwareDestroyAll() { 335 synchronized (mLock) { 336 for (int i = 0; i < mSessions.size(); ++i) { 337 mSessions.valueAt(i).close(); 338 } 339 mSessions.clear(); 340 341 /* discovery sessions automatically destroyed when containing Aware sessions 342 * destroyed */ 343 mDiscoverySessions.clear(); 344 345 mMessageStartTime.clear(); 346 } 347 } 348 349 @Rpc(description = "Attach to Aware.") wifiAwareAttach( @pcParametername = "awareConfig") @pcOptional JSONObject awareConfig)350 public Integer wifiAwareAttach( 351 @RpcParameter(name = "awareConfig") @RpcOptional JSONObject awareConfig) 352 throws RemoteException, JSONException { 353 synchronized (mLock) { 354 int sessionId = getNextSessionId(); 355 mMgr.attach(null, getConfigRequest(awareConfig), 356 new AwareAttachCallbackPostsEvents(sessionId), 357 new AwareIdentityChangeListenerPostsEvents(sessionId)); 358 return sessionId; 359 } 360 } 361 362 @Rpc(description = "Destroy a Aware session.") wifiAwareDestroy( @pcParametername = "clientId", description = "The client ID returned when a connection was created") Integer clientId)363 public void wifiAwareDestroy( 364 @RpcParameter(name = "clientId", description = "The client ID returned when a connection was created") Integer clientId) 365 throws RemoteException, JSONException { 366 WifiAwareSession session; 367 synchronized (mLock) { 368 session = mSessions.get(clientId); 369 } 370 if (session == null) { 371 throw new IllegalStateException( 372 "Calling WifiAwareDisconnect before session (client ID " + clientId 373 + ") is ready/or already disconnected"); 374 } 375 session.close(); 376 } 377 378 @Rpc(description = "Publish.") wifiAwarePublish( @pcParametername = "clientId", description = "The client ID returned when a connection was created") Integer clientId, @RpcParameter(name = "publishConfig") JSONObject publishConfig)379 public Integer wifiAwarePublish( 380 @RpcParameter(name = "clientId", description = "The client ID returned when a connection was created") Integer clientId, 381 @RpcParameter(name = "publishConfig") JSONObject publishConfig) 382 throws RemoteException, JSONException { 383 synchronized (mLock) { 384 WifiAwareSession session = mSessions.get(clientId); 385 if (session == null) { 386 throw new IllegalStateException( 387 "Calling WifiAwarePublish before session (client ID " + clientId 388 + ") is ready/or already disconnected"); 389 } 390 391 int discoverySessionId = getNextDiscoverySessionId(); 392 session.publish(getPublishConfig(publishConfig), 393 new AwareDiscoverySessionCallbackPostsEvents(discoverySessionId), null); 394 return discoverySessionId; 395 } 396 } 397 398 @Rpc(description = "Subscribe.") wifiAwareSubscribe( @pcParametername = "clientId", description = "The client ID returned when a connection was created") Integer clientId, @RpcParameter(name = "subscribeConfig") JSONObject subscribeConfig)399 public Integer wifiAwareSubscribe( 400 @RpcParameter(name = "clientId", description = "The client ID returned when a connection was created") Integer clientId, 401 @RpcParameter(name = "subscribeConfig") JSONObject subscribeConfig) 402 throws RemoteException, JSONException { 403 synchronized (mLock) { 404 WifiAwareSession session = mSessions.get(clientId); 405 if (session == null) { 406 throw new IllegalStateException( 407 "Calling WifiAwareSubscribe before session (client ID " + clientId 408 + ") is ready/or already disconnected"); 409 } 410 411 int discoverySessionId = getNextDiscoverySessionId(); 412 session.subscribe(getSubscribeConfig(subscribeConfig), 413 new AwareDiscoverySessionCallbackPostsEvents(discoverySessionId), null); 414 return discoverySessionId; 415 } 416 } 417 418 @Rpc(description = "Destroy a discovery Session.") wifiAwareDestroyDiscoverySession( @pcParametername = "sessionId", description = "The discovery session ID returned when session was created using publish or subscribe") Integer sessionId)419 public void wifiAwareDestroyDiscoverySession( 420 @RpcParameter(name = "sessionId", description = "The discovery session ID returned when session was created using publish or subscribe") Integer sessionId) 421 throws RemoteException { 422 synchronized (mLock) { 423 DiscoverySession session = mDiscoverySessions.get(sessionId); 424 if (session == null) { 425 throw new IllegalStateException( 426 "Calling WifiAwareTerminateSession before session (session ID " 427 + sessionId + ") is ready"); 428 } 429 session.close(); 430 mDiscoverySessions.remove(sessionId); 431 } 432 } 433 434 @Rpc(description = "Send peer-to-peer Aware message") wifiAwareSendMessage( @pcParametername = "sessionId", description = "The session ID returned when session" + " was created using publish or subscribe") Integer sessionId, @RpcParameter(name = "peerId", description = "The ID of the peer being communicated " + "with. Obtained from a previous message or match session.") Integer peerId, @RpcParameter(name = "messageId", description = "Arbitrary handle used for " + "identification of the message in the message status callbacks") Integer messageId, @RpcParameter(name = "message") String message, @RpcParameter(name = "retryCount", description = "Number of retries (0 for none) if " + "transmission fails due to no ACK reception") Integer retryCount)435 public void wifiAwareSendMessage( 436 @RpcParameter(name = "sessionId", description = "The session ID returned when session" 437 + " was created using publish or subscribe") Integer sessionId, 438 @RpcParameter(name = "peerId", description = "The ID of the peer being communicated " 439 + "with. Obtained from a previous message or match session.") Integer peerId, 440 @RpcParameter(name = "messageId", description = "Arbitrary handle used for " 441 + "identification of the message in the message status callbacks") 442 Integer messageId, 443 @RpcParameter(name = "message") String message, 444 @RpcParameter(name = "retryCount", description = "Number of retries (0 for none) if " 445 + "transmission fails due to no ACK reception") Integer retryCount) 446 throws RemoteException { 447 DiscoverySession session; 448 synchronized (mLock) { 449 session = mDiscoverySessions.get(sessionId); 450 } 451 if (session == null) { 452 throw new IllegalStateException( 453 "Calling WifiAwareSendMessage before session (session ID " + sessionId 454 + " is ready"); 455 } 456 byte[] bytes = null; 457 if (message != null) { 458 bytes = message.getBytes(); 459 } 460 461 synchronized (mLock) { 462 mMessageStartTime.put(messageId, System.currentTimeMillis()); 463 } 464 session.sendMessage(new PeerHandle(peerId), messageId, bytes, retryCount); 465 } 466 467 @Rpc(description = "Start peer-to-peer Aware ranging") wifiAwareStartRanging( @pcParametername = "callbackId") Integer callbackId, @RpcParameter(name = "sessionId", description = "The session ID returned when session was created using publish or subscribe") Integer sessionId, @RpcParameter(name = "rttParams", description = "RTT session parameters.") JSONArray rttParams)468 public void wifiAwareStartRanging( 469 @RpcParameter(name = "callbackId") Integer callbackId, 470 @RpcParameter(name = "sessionId", description = "The session ID returned when session was created using publish or subscribe") Integer sessionId, 471 @RpcParameter(name = "rttParams", description = "RTT session parameters.") JSONArray rttParams) throws RemoteException, JSONException { 472 DiscoverySession session; 473 synchronized (mLock) { 474 session = mDiscoverySessions.get(sessionId); 475 } 476 if (session == null) { 477 throw new IllegalStateException( 478 "Calling WifiAwareStartRanging before session (session ID " 479 + sessionId + " is ready"); 480 } 481 RttManager.RttParams[] rParams = new RttManager.RttParams[rttParams.length()]; 482 for (int i = 0; i < rttParams.length(); i++) { 483 rParams[i] = WifiRttManagerFacade.parseRttParam(rttParams.getJSONObject(i)); 484 } 485 session.startRanging(rParams, new WifiAwareRangingListener(callbackId, sessionId)); 486 } 487 488 @Rpc(description = "Create a network specifier to be used when specifying a Aware network request") wifiAwareCreateNetworkSpecifier( @pcParametername = "sessionId", description = "The session ID returned when session was created using publish or subscribe") Integer sessionId, @RpcParameter(name = "peerId", description = "The ID of the peer (obtained through OnMatch or OnMessageReceived") Integer peerId, @RpcParameter(name = "passphrase", description = "Passphrase of the data-path. Optional, can be empty/null.") @RpcOptional String passphrase)489 public String wifiAwareCreateNetworkSpecifier( 490 @RpcParameter(name = "sessionId", description = "The session ID returned when session was created using publish or subscribe") 491 Integer sessionId, 492 @RpcParameter(name = "peerId", description = "The ID of the peer (obtained through OnMatch or OnMessageReceived") 493 Integer peerId, 494 @RpcParameter(name = "passphrase", description = "Passphrase of the data-path. Optional, can be empty/null.") 495 @RpcOptional String passphrase) throws JSONException { 496 DiscoverySession session; 497 synchronized (mLock) { 498 session = mDiscoverySessions.get(sessionId); 499 } 500 if (session == null) { 501 throw new IllegalStateException( 502 "Calling WifiAwareStartRanging before session (session ID " 503 + sessionId + " is ready"); 504 } 505 NetworkSpecifier ns = null; 506 if (passphrase == null || passphrase.length() == 0) { 507 ns = session.createNetworkSpecifierOpen(new PeerHandle(peerId)); 508 } else { 509 ns = session.createNetworkSpecifierPassphrase(new PeerHandle(peerId), passphrase); 510 } 511 512 return getJsonString((WifiAwareNetworkSpecifier) ns); 513 } 514 515 private class AwareAttachCallbackPostsEvents extends AttachCallback { 516 private int mSessionId; 517 private long mCreateTimestampMs; 518 AwareAttachCallbackPostsEvents(int sessionId)519 public AwareAttachCallbackPostsEvents(int sessionId) { 520 mSessionId = sessionId; 521 mCreateTimestampMs = System.currentTimeMillis(); 522 } 523 524 @Override onAttached(WifiAwareSession session)525 public void onAttached(WifiAwareSession session) { 526 synchronized (mLock) { 527 mSessions.put(mSessionId, session); 528 } 529 530 Bundle mResults = new Bundle(); 531 mResults.putInt("sessionId", mSessionId); 532 mResults.putLong("latencyMs", System.currentTimeMillis() - mCreateTimestampMs); 533 mResults.putLong("timestampMs", System.currentTimeMillis()); 534 mEventFacade.postEvent("WifiAwareOnAttached", mResults); 535 } 536 537 @Override onAttachFailed()538 public void onAttachFailed() { 539 Bundle mResults = new Bundle(); 540 mResults.putInt("sessionId", mSessionId); 541 mResults.putLong("latencyMs", System.currentTimeMillis() - mCreateTimestampMs); 542 mEventFacade.postEvent("WifiAwareOnAttachFailed", mResults); 543 } 544 } 545 546 private class AwareIdentityChangeListenerPostsEvents extends IdentityChangedListener { 547 private int mSessionId; 548 AwareIdentityChangeListenerPostsEvents(int sessionId)549 public AwareIdentityChangeListenerPostsEvents(int sessionId) { 550 mSessionId = sessionId; 551 } 552 553 @Override onIdentityChanged(byte[] mac)554 public void onIdentityChanged(byte[] mac) { 555 Bundle mResults = new Bundle(); 556 mResults.putInt("sessionId", mSessionId); 557 mResults.putString("mac", String.valueOf(HexEncoding.encode(mac))); 558 mResults.putLong("timestampMs", System.currentTimeMillis()); 559 mEventFacade.postEvent("WifiAwareOnIdentityChanged", mResults); 560 } 561 } 562 563 private class AwareDiscoverySessionCallbackPostsEvents extends 564 DiscoverySessionCallback { 565 private int mDiscoverySessionId; 566 private long mCreateTimestampMs; 567 AwareDiscoverySessionCallbackPostsEvents(int discoverySessionId)568 public AwareDiscoverySessionCallbackPostsEvents(int discoverySessionId) { 569 mDiscoverySessionId = discoverySessionId; 570 mCreateTimestampMs = System.currentTimeMillis(); 571 } 572 573 @Override onPublishStarted(PublishDiscoverySession discoverySession)574 public void onPublishStarted(PublishDiscoverySession discoverySession) { 575 synchronized (mLock) { 576 mDiscoverySessions.put(mDiscoverySessionId, discoverySession); 577 } 578 579 Bundle mResults = new Bundle(); 580 mResults.putInt("discoverySessionId", mDiscoverySessionId); 581 mResults.putLong("latencyMs", System.currentTimeMillis() - mCreateTimestampMs); 582 mResults.putLong("timestampMs", System.currentTimeMillis()); 583 mEventFacade.postEvent("WifiAwareSessionOnPublishStarted", mResults); 584 } 585 586 @Override onSubscribeStarted(SubscribeDiscoverySession discoverySession)587 public void onSubscribeStarted(SubscribeDiscoverySession discoverySession) { 588 synchronized (mLock) { 589 mDiscoverySessions.put(mDiscoverySessionId, discoverySession); 590 } 591 592 Bundle mResults = new Bundle(); 593 mResults.putInt("discoverySessionId", mDiscoverySessionId); 594 mResults.putLong("latencyMs", System.currentTimeMillis() - mCreateTimestampMs); 595 mResults.putLong("timestampMs", System.currentTimeMillis()); 596 mEventFacade.postEvent("WifiAwareSessionOnSubscribeStarted", mResults); 597 } 598 599 @Override onSessionConfigUpdated()600 public void onSessionConfigUpdated() { 601 Bundle mResults = new Bundle(); 602 mResults.putInt("discoverySessionId", mDiscoverySessionId); 603 mEventFacade.postEvent("WifiAwareSessionOnSessionConfigUpdated", mResults); 604 } 605 606 @Override onSessionConfigFailed()607 public void onSessionConfigFailed() { 608 Bundle mResults = new Bundle(); 609 mResults.putInt("discoverySessionId", mDiscoverySessionId); 610 mEventFacade.postEvent("WifiAwareSessionOnSessionConfigFailed", mResults); 611 } 612 613 @Override onSessionTerminated()614 public void onSessionTerminated() { 615 Bundle mResults = new Bundle(); 616 mResults.putInt("discoverySessionId", mDiscoverySessionId); 617 mEventFacade.postEvent("WifiAwareSessionOnSessionTerminated", mResults); 618 } 619 620 @Override onServiceDiscovered(PeerHandle peerHandle, byte[] serviceSpecificInfo, List<byte[]> matchFilter)621 public void onServiceDiscovered(PeerHandle peerHandle, 622 byte[] serviceSpecificInfo, List<byte[]> matchFilter) { 623 Bundle mResults = new Bundle(); 624 mResults.putInt("discoverySessionId", mDiscoverySessionId); 625 mResults.putInt("peerId", peerHandle.peerId); 626 mResults.putByteArray("serviceSpecificInfo", serviceSpecificInfo); // TODO: base64 627 mResults.putByteArray("matchFilter", new TlvBufferUtils.TlvConstructor(0, 628 1).allocateAndPut(matchFilter).getArray()); // TODO: base64 629 mResults.putLong("timestampMs", System.currentTimeMillis()); 630 mEventFacade.postEvent("WifiAwareSessionOnServiceDiscovered", mResults); 631 } 632 633 @Override onMessageSendSucceeded(int messageId)634 public void onMessageSendSucceeded(int messageId) { 635 Bundle mResults = new Bundle(); 636 mResults.putInt("discoverySessionId", mDiscoverySessionId); 637 mResults.putInt("messageId", messageId); 638 synchronized (mLock) { 639 Long startTime = mMessageStartTime.get(messageId); 640 if (startTime != null) { 641 mResults.putLong("latencyMs", 642 System.currentTimeMillis() - startTime.longValue()); 643 mMessageStartTime.remove(messageId); 644 } 645 } 646 mEventFacade.postEvent("WifiAwareSessionOnMessageSent", mResults); 647 } 648 649 @Override onMessageSendFailed(int messageId)650 public void onMessageSendFailed(int messageId) { 651 Bundle mResults = new Bundle(); 652 mResults.putInt("discoverySessionId", mDiscoverySessionId); 653 mResults.putInt("messageId", messageId); 654 synchronized (mLock) { 655 Long startTime = mMessageStartTime.get(messageId); 656 if (startTime != null) { 657 mResults.putLong("latencyMs", 658 System.currentTimeMillis() - startTime.longValue()); 659 mMessageStartTime.remove(messageId); 660 } 661 } 662 mEventFacade.postEvent("WifiAwareSessionOnMessageSendFailed", mResults); 663 } 664 665 @Override onMessageReceived(PeerHandle peerHandle, byte[] message)666 public void onMessageReceived(PeerHandle peerHandle, byte[] message) { 667 Bundle mResults = new Bundle(); 668 mResults.putInt("discoverySessionId", mDiscoverySessionId); 669 mResults.putInt("peerId", peerHandle.peerId); 670 mResults.putByteArray("message", message); // TODO: base64 671 mResults.putString("messageAsString", new String(message)); 672 mEventFacade.postEvent("WifiAwareSessionOnMessageReceived", mResults); 673 } 674 } 675 676 class WifiAwareRangingListener implements RttManager.RttListener { 677 private int mCallbackId; 678 private int mSessionId; 679 WifiAwareRangingListener(int callbackId, int sessionId)680 public WifiAwareRangingListener(int callbackId, int sessionId) { 681 mCallbackId = callbackId; 682 mSessionId = sessionId; 683 } 684 685 @Override onSuccess(RttResult[] results)686 public void onSuccess(RttResult[] results) { 687 Bundle bundle = new Bundle(); 688 bundle.putInt("callbackId", mCallbackId); 689 bundle.putInt("sessionId", mSessionId); 690 691 Parcelable[] resultBundles = new Parcelable[results.length]; 692 for (int i = 0; i < results.length; i++) { 693 resultBundles[i] = WifiRttManagerFacade.RangingListener.packRttResult(results[i]); 694 } 695 bundle.putParcelableArray("Results", resultBundles); 696 697 mEventFacade.postEvent("WifiAwareRangingListenerOnSuccess", bundle); 698 } 699 700 @Override onFailure(int reason, String description)701 public void onFailure(int reason, String description) { 702 Bundle bundle = new Bundle(); 703 bundle.putInt("callbackId", mCallbackId); 704 bundle.putInt("sessionId", mSessionId); 705 bundle.putInt("reason", reason); 706 bundle.putString("description", description); 707 mEventFacade.postEvent("WifiAwareRangingListenerOnFailure", bundle); 708 } 709 710 @Override onAborted()711 public void onAborted() { 712 Bundle bundle = new Bundle(); 713 bundle.putInt("callbackId", mCallbackId); 714 bundle.putInt("sessionId", mSessionId); 715 mEventFacade.postEvent("WifiAwareRangingListenerOnAborted", bundle); 716 } 717 718 } 719 720 class WifiAwareStateChangedReceiver extends BroadcastReceiver { 721 @Override onReceive(Context c, Intent intent)722 public void onReceive(Context c, Intent intent) { 723 boolean isAvailable = mMgr.isAvailable(); 724 if (!isAvailable) { 725 wifiAwareDestroyAll(); 726 } 727 mEventFacade.postEvent(isAvailable ? "WifiAwareAvailable" : "WifiAwareNotAvailable", 728 new Bundle()); 729 } 730 } 731 } 732