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 android.net.wifi.aware; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.SdkConstant; 23 import android.annotation.SystemService; 24 import android.annotation.SdkConstant.SdkConstantType; 25 import android.content.Context; 26 import android.net.ConnectivityManager; 27 import android.net.NetworkRequest; 28 import android.net.NetworkSpecifier; 29 import android.net.wifi.RttManager; 30 import android.os.Binder; 31 import android.os.Bundle; 32 import android.os.Handler; 33 import android.os.Looper; 34 import android.os.Message; 35 import android.os.RemoteException; 36 import android.util.Log; 37 import android.util.SparseArray; 38 39 import com.android.internal.annotations.GuardedBy; 40 41 import libcore.util.HexEncoding; 42 43 import java.lang.annotation.Retention; 44 import java.lang.annotation.RetentionPolicy; 45 import java.lang.ref.WeakReference; 46 import java.nio.BufferOverflowException; 47 import java.util.Arrays; 48 import java.util.List; 49 50 /** 51 * This class provides the primary API for managing Wi-Fi Aware operations: 52 * discovery and peer-to-peer data connections. 53 * <p> 54 * The class provides access to: 55 * <ul> 56 * <li>Initialize a Aware cluster (peer-to-peer synchronization). Refer to 57 * {@link #attach(AttachCallback, Handler)}. 58 * <li>Create discovery sessions (publish or subscribe sessions). Refer to 59 * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback, Handler)} and 60 * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback, Handler)}. 61 * <li>Create a Aware network specifier to be used with 62 * {@link ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)} 63 * to set-up a Aware connection with a peer. Refer to 64 * {@link DiscoverySession#createNetworkSpecifierOpen(PeerHandle)}, 65 * {@link DiscoverySession#createNetworkSpecifierPassphrase(PeerHandle, String)}, 66 * {@link WifiAwareSession#createNetworkSpecifierOpen(int, byte[])}, and 67 * {@link WifiAwareSession#createNetworkSpecifierPassphrase(int, byte[], String)}. 68 * </ul> 69 * <p> 70 * Aware may not be usable when Wi-Fi is disabled (and other conditions). To validate that 71 * the functionality is available use the {@link #isAvailable()} function. To track 72 * changes in Aware usability register for the {@link #ACTION_WIFI_AWARE_STATE_CHANGED} 73 * broadcast. Note that this broadcast is not sticky - you should register for it and then 74 * check the above API to avoid a race condition. 75 * <p> 76 * An application must use {@link #attach(AttachCallback, Handler)} to initialize a 77 * Aware cluster - before making any other Aware operation. Aware cluster membership is a 78 * device-wide operation - the API guarantees that the device is in a cluster or joins a 79 * Aware cluster (or starts one if none can be found). Information about attach success (or 80 * failure) are returned in callbacks of {@link AttachCallback}. Proceed with Aware 81 * discovery or connection setup only after receiving confirmation that Aware attach 82 * succeeded - {@link AttachCallback#onAttached(WifiAwareSession)}. When an 83 * application is finished using Aware it <b>must</b> use the 84 * {@link WifiAwareSession#close()} API to indicate to the Aware service that the device 85 * may detach from the Aware cluster. The device will actually disable Aware once the last 86 * application detaches. 87 * <p> 88 * Once a Aware attach is confirmed use the 89 * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback, Handler)} 90 * or 91 * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback, 92 * Handler)} to create publish or subscribe Aware discovery sessions. Events are called on the 93 * provided callback object {@link DiscoverySessionCallback}. Specifically, the 94 * {@link DiscoverySessionCallback#onPublishStarted(PublishDiscoverySession)} 95 * and 96 * {@link DiscoverySessionCallback#onSubscribeStarted( 97 *SubscribeDiscoverySession)} 98 * return {@link PublishDiscoverySession} and 99 * {@link SubscribeDiscoverySession} 100 * objects respectively on which additional session operations can be performed, e.g. updating 101 * the session {@link PublishDiscoverySession#updatePublish(PublishConfig)} and 102 * {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}. Sessions can 103 * also be used to send messages using the 104 * {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])} APIs. When an 105 * application is finished with a discovery session it <b>must</b> terminate it using the 106 * {@link DiscoverySession#close()} API. 107 * <p> 108 * Creating connections between Aware devices is managed by the standard 109 * {@link ConnectivityManager#requestNetwork(NetworkRequest, 110 * ConnectivityManager.NetworkCallback)}. 111 * The {@link NetworkRequest} object should be constructed with: 112 * <ul> 113 * <li>{@link NetworkRequest.Builder#addTransportType(int)} of 114 * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}. 115 * <li>{@link NetworkRequest.Builder#setNetworkSpecifier(String)} using 116 * {@link WifiAwareSession#createNetworkSpecifierOpen(int, byte[])}, 117 * {@link WifiAwareSession#createNetworkSpecifierPassphrase(int, byte[], String)}, 118 * {@link DiscoverySession#createNetworkSpecifierOpen(PeerHandle)}, or 119 * {@link DiscoverySession#createNetworkSpecifierPassphrase(PeerHandle, String)}. 120 * </ul> 121 */ 122 @SystemService(Context.WIFI_AWARE_SERVICE) 123 public class WifiAwareManager { 124 private static final String TAG = "WifiAwareManager"; 125 private static final boolean DBG = false; 126 private static final boolean VDBG = false; // STOPSHIP if true 127 128 /** 129 * Broadcast intent action to indicate that the state of Wi-Fi Aware availability has changed. 130 * Use the {@link #isAvailable()} to query the current status. 131 * This broadcast is <b>not</b> sticky, use the {@link #isAvailable()} API after registering 132 * the broadcast to check the current state of Wi-Fi Aware. 133 * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered 134 * components will be launched. 135 */ 136 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 137 public static final String ACTION_WIFI_AWARE_STATE_CHANGED = 138 "android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED"; 139 140 /** @hide */ 141 @IntDef({ 142 WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}) 143 @Retention(RetentionPolicy.SOURCE) 144 public @interface DataPathRole { 145 } 146 147 /** 148 * Connection creation role is that of INITIATOR. Used to create a network specifier string 149 * when requesting a Aware network. 150 * 151 * @see DiscoverySession#createNetworkSpecifierOpen(PeerHandle) 152 * @see DiscoverySession#createNetworkSpecifierPassphrase(PeerHandle, String) 153 * @see WifiAwareSession#createNetworkSpecifierOpen(int, byte[]) 154 * @see WifiAwareSession#createNetworkSpecifierPassphrase(int, byte[], String) 155 */ 156 public static final int WIFI_AWARE_DATA_PATH_ROLE_INITIATOR = 0; 157 158 /** 159 * Connection creation role is that of RESPONDER. Used to create a network specifier string 160 * when requesting a Aware network. 161 * 162 * @see DiscoverySession#createNetworkSpecifierOpen(PeerHandle) 163 * @see DiscoverySession#createNetworkSpecifierPassphrase(PeerHandle, String) 164 * @see WifiAwareSession#createNetworkSpecifierOpen(int, byte[]) 165 * @see WifiAwareSession#createNetworkSpecifierPassphrase(int, byte[], String) 166 */ 167 public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1; 168 169 private final Context mContext; 170 private final IWifiAwareManager mService; 171 172 private final Object mLock = new Object(); // lock access to the following vars 173 174 @GuardedBy("mLock") 175 private SparseArray<RttManager.RttListener> mRangingListeners = new SparseArray<>(); 176 177 /** @hide */ 178 public WifiAwareManager(Context context, IWifiAwareManager service) { 179 mContext = context; 180 mService = service; 181 } 182 183 /** 184 * Returns the current status of Aware API: whether or not Aware is available. To track 185 * changes in the state of Aware API register for the 186 * {@link #ACTION_WIFI_AWARE_STATE_CHANGED} broadcast. 187 * 188 * @return A boolean indicating whether the app can use the Aware API at this time (true) or 189 * not (false). 190 */ 191 public boolean isAvailable() { 192 try { 193 return mService.isUsageEnabled(); 194 } catch (RemoteException e) { 195 throw e.rethrowFromSystemServer(); 196 } 197 } 198 199 /** 200 * Returns the characteristics of the Wi-Fi Aware interface: a set of parameters which specify 201 * limitations on configurations, e.g. the maximum service name length. 202 * 203 * @return An object specifying configuration limitations of Aware. 204 */ 205 public Characteristics getCharacteristics() { 206 try { 207 return mService.getCharacteristics(); 208 } catch (RemoteException e) { 209 throw e.rethrowFromSystemServer(); 210 } 211 } 212 213 /** 214 * Attach to the Wi-Fi Aware service - enabling the application to create discovery sessions or 215 * create connections to peers. The device will attach to an existing cluster if it can find 216 * one or create a new cluster (if it is the first to enable Aware in its vicinity). Results 217 * (e.g. successful attach to a cluster) are provided to the {@code attachCallback} object. 218 * An application <b>must</b> call {@link WifiAwareSession#close()} when done with the 219 * Wi-Fi Aware object. 220 * <p> 221 * Note: a Aware cluster is a shared resource - if the device is already attached to a cluster 222 * then this function will simply indicate success immediately using the same {@code 223 * attachCallback}. 224 * 225 * @param attachCallback A callback for attach events, extended from 226 * {@link AttachCallback}. 227 * @param handler The Handler on whose thread to execute the callbacks of the {@code 228 * attachCallback} object. If a null is provided then the application's main thread will be 229 * used. 230 */ 231 public void attach(@NonNull AttachCallback attachCallback, @Nullable Handler handler) { 232 attach(handler, null, attachCallback, null); 233 } 234 235 /** 236 * Attach to the Wi-Fi Aware service - enabling the application to create discovery sessions or 237 * create connections to peers. The device will attach to an existing cluster if it can find 238 * one or create a new cluster (if it is the first to enable Aware in its vicinity). Results 239 * (e.g. successful attach to a cluster) are provided to the {@code attachCallback} object. 240 * An application <b>must</b> call {@link WifiAwareSession#close()} when done with the 241 * Wi-Fi Aware object. 242 * <p> 243 * Note: a Aware cluster is a shared resource - if the device is already attached to a cluster 244 * then this function will simply indicate success immediately using the same {@code 245 * attachCallback}. 246 * <p> 247 * This version of the API attaches a listener to receive the MAC address of the Aware interface 248 * on startup and whenever it is updated (it is randomized at regular intervals for privacy). 249 * The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} 250 * permission to execute this attach request. Otherwise, use the 251 * {@link #attach(AttachCallback, Handler)} version. Note that aside from permission 252 * requirements this listener will wake up the host at regular intervals causing higher power 253 * consumption, do not use it unless the information is necessary (e.g. for OOB discovery). 254 * 255 * @param attachCallback A callback for attach events, extended from 256 * {@link AttachCallback}. 257 * @param identityChangedListener A listener for changed identity, extended from 258 * {@link IdentityChangedListener}. 259 * @param handler The Handler on whose thread to execute the callbacks of the {@code 260 * attachCallback} and {@code identityChangedListener} objects. If a null is provided then the 261 * application's main thread will be used. 262 */ 263 public void attach(@NonNull AttachCallback attachCallback, 264 @NonNull IdentityChangedListener identityChangedListener, 265 @Nullable Handler handler) { 266 attach(handler, null, attachCallback, identityChangedListener); 267 } 268 269 /** @hide */ 270 public void attach(Handler handler, ConfigRequest configRequest, 271 AttachCallback attachCallback, 272 IdentityChangedListener identityChangedListener) { 273 if (VDBG) { 274 Log.v(TAG, "attach(): handler=" + handler + ", callback=" + attachCallback 275 + ", configRequest=" + configRequest + ", identityChangedListener=" 276 + identityChangedListener); 277 } 278 279 synchronized (mLock) { 280 Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper(); 281 282 try { 283 Binder binder = new Binder(); 284 mService.connect(binder, mContext.getOpPackageName(), 285 new WifiAwareEventCallbackProxy(this, looper, binder, attachCallback, 286 identityChangedListener), configRequest, 287 identityChangedListener != null); 288 } catch (RemoteException e) { 289 throw e.rethrowFromSystemServer(); 290 } 291 } 292 } 293 294 /** @hide */ 295 public void disconnect(int clientId, Binder binder) { 296 if (VDBG) Log.v(TAG, "disconnect()"); 297 298 try { 299 mService.disconnect(clientId, binder); 300 } catch (RemoteException e) { 301 throw e.rethrowFromSystemServer(); 302 } 303 } 304 305 /** @hide */ 306 public void publish(int clientId, Looper looper, PublishConfig publishConfig, 307 DiscoverySessionCallback callback) { 308 if (VDBG) Log.v(TAG, "publish(): clientId=" + clientId + ", config=" + publishConfig); 309 310 try { 311 mService.publish(clientId, publishConfig, 312 new WifiAwareDiscoverySessionCallbackProxy(this, looper, true, callback, 313 clientId)); 314 } catch (RemoteException e) { 315 throw e.rethrowFromSystemServer(); 316 } 317 } 318 319 /** @hide */ 320 public void updatePublish(int clientId, int sessionId, PublishConfig publishConfig) { 321 if (VDBG) { 322 Log.v(TAG, "updatePublish(): clientId=" + clientId + ",sessionId=" + sessionId 323 + ", config=" + publishConfig); 324 } 325 326 try { 327 mService.updatePublish(clientId, sessionId, publishConfig); 328 } catch (RemoteException e) { 329 throw e.rethrowFromSystemServer(); 330 } 331 } 332 333 /** @hide */ 334 public void subscribe(int clientId, Looper looper, SubscribeConfig subscribeConfig, 335 DiscoverySessionCallback callback) { 336 if (VDBG) { 337 if (VDBG) { 338 Log.v(TAG, 339 "subscribe(): clientId=" + clientId + ", config=" + subscribeConfig); 340 } 341 } 342 343 try { 344 mService.subscribe(clientId, subscribeConfig, 345 new WifiAwareDiscoverySessionCallbackProxy(this, looper, false, callback, 346 clientId)); 347 } catch (RemoteException e) { 348 throw e.rethrowFromSystemServer(); 349 } 350 } 351 352 /** @hide */ 353 public void updateSubscribe(int clientId, int sessionId, SubscribeConfig subscribeConfig) { 354 if (VDBG) { 355 Log.v(TAG, "updateSubscribe(): clientId=" + clientId + ",sessionId=" + sessionId 356 + ", config=" + subscribeConfig); 357 } 358 359 try { 360 mService.updateSubscribe(clientId, sessionId, subscribeConfig); 361 } catch (RemoteException e) { 362 throw e.rethrowFromSystemServer(); 363 } 364 } 365 366 /** @hide */ 367 public void terminateSession(int clientId, int sessionId) { 368 if (VDBG) { 369 Log.d(TAG, 370 "terminateSession(): clientId=" + clientId + ", sessionId=" + sessionId); 371 } 372 373 try { 374 mService.terminateSession(clientId, sessionId); 375 } catch (RemoteException e) { 376 throw e.rethrowFromSystemServer(); 377 } 378 } 379 380 /** @hide */ 381 public void sendMessage(int clientId, int sessionId, PeerHandle peerHandle, byte[] message, 382 int messageId, int retryCount) { 383 if (peerHandle == null) { 384 throw new IllegalArgumentException( 385 "sendMessage: invalid peerHandle - must be non-null"); 386 } 387 388 if (VDBG) { 389 Log.v(TAG, "sendMessage(): clientId=" + clientId + ", sessionId=" + sessionId 390 + ", peerHandle=" + peerHandle.peerId + ", messageId=" 391 + messageId + ", retryCount=" + retryCount); 392 } 393 394 try { 395 mService.sendMessage(clientId, sessionId, peerHandle.peerId, message, messageId, 396 retryCount); 397 } catch (RemoteException e) { 398 throw e.rethrowFromSystemServer(); 399 } 400 } 401 402 /** @hide */ 403 public void startRanging(int clientId, int sessionId, RttManager.RttParams[] params, 404 RttManager.RttListener listener) { 405 if (VDBG) { 406 Log.v(TAG, "startRanging: clientId=" + clientId + ", sessionId=" + sessionId + ", " 407 + "params=" + Arrays.toString(params) + ", listener=" + listener); 408 } 409 410 int rangingKey = 0; 411 try { 412 rangingKey = mService.startRanging(clientId, sessionId, 413 new RttManager.ParcelableRttParams(params)); 414 } catch (RemoteException e) { 415 throw e.rethrowFromSystemServer(); 416 } 417 418 synchronized (mLock) { 419 mRangingListeners.put(rangingKey, listener); 420 } 421 } 422 423 /** @hide */ 424 public NetworkSpecifier createNetworkSpecifier(int clientId, int role, int sessionId, 425 PeerHandle peerHandle, @Nullable byte[] pmk, @Nullable String passphrase) { 426 if (VDBG) { 427 Log.v(TAG, "createNetworkSpecifier: role=" + role + ", sessionId=" + sessionId 428 + ", peerHandle=" + ((peerHandle == null) ? peerHandle : peerHandle.peerId) 429 + ", pmk=" + ((pmk == null) ? "null" : "non-null") 430 + ", passphrase=" + ((passphrase == null) ? "null" : "non-null")); 431 } 432 433 if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR 434 && role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) { 435 throw new IllegalArgumentException( 436 "createNetworkSpecifier: Invalid 'role' argument when creating a network " 437 + "specifier"); 438 } 439 if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR) { 440 if (peerHandle == null) { 441 throw new IllegalArgumentException( 442 "createNetworkSpecifier: Invalid peer handle (value of null) - not " 443 + "permitted on INITIATOR"); 444 } 445 } 446 447 return new WifiAwareNetworkSpecifier( 448 (peerHandle == null) ? WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB_ANY_PEER 449 : WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB, 450 role, 451 clientId, 452 sessionId, 453 peerHandle != null ? peerHandle.peerId : 0, // 0 is an invalid peer ID 454 null, // peerMac (not used in this method) 455 pmk, 456 passphrase); 457 } 458 459 /** @hide */ 460 public NetworkSpecifier createNetworkSpecifier(int clientId, @DataPathRole int role, 461 @Nullable byte[] peer, @Nullable byte[] pmk, @Nullable String passphrase) { 462 if (VDBG) { 463 Log.v(TAG, "createNetworkSpecifier: role=" + role 464 + ", pmk=" + ((pmk == null) ? "null" : "non-null") 465 + ", passphrase=" + ((passphrase == null) ? "null" : "non-null")); 466 } 467 468 if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR 469 && role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) { 470 throw new IllegalArgumentException( 471 "createNetworkSpecifier: Invalid 'role' argument when creating a network " 472 + "specifier"); 473 } 474 if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR) { 475 if (peer == null) { 476 throw new IllegalArgumentException("createNetworkSpecifier: Invalid peer MAC " 477 + "address - null not permitted on INITIATOR"); 478 } 479 } 480 if (peer != null && peer.length != 6) { 481 throw new IllegalArgumentException("createNetworkSpecifier: Invalid peer MAC address"); 482 } 483 484 return new WifiAwareNetworkSpecifier( 485 (peer == null) ? WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER 486 : WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_OOB, 487 role, 488 clientId, 489 0, // 0 is an invalid session ID 490 0, // 0 is an invalid peer ID 491 peer, 492 pmk, 493 passphrase); 494 } 495 496 private static class WifiAwareEventCallbackProxy extends IWifiAwareEventCallback.Stub { 497 private static final int CALLBACK_CONNECT_SUCCESS = 0; 498 private static final int CALLBACK_CONNECT_FAIL = 1; 499 private static final int CALLBACK_IDENTITY_CHANGED = 2; 500 private static final int CALLBACK_RANGING_SUCCESS = 3; 501 private static final int CALLBACK_RANGING_FAILURE = 4; 502 private static final int CALLBACK_RANGING_ABORTED = 5; 503 504 private final Handler mHandler; 505 private final WeakReference<WifiAwareManager> mAwareManager; 506 private final Binder mBinder; 507 private final Looper mLooper; 508 509 RttManager.RttListener getAndRemoveRangingListener(int rangingId) { 510 WifiAwareManager mgr = mAwareManager.get(); 511 if (mgr == null) { 512 Log.w(TAG, "getAndRemoveRangingListener: called post GC"); 513 return null; 514 } 515 516 synchronized (mgr.mLock) { 517 RttManager.RttListener listener = mgr.mRangingListeners.get(rangingId); 518 mgr.mRangingListeners.delete(rangingId); 519 return listener; 520 } 521 } 522 523 /** 524 * Constructs a {@link AttachCallback} using the specified looper. 525 * All callbacks will delivered on the thread of the specified looper. 526 * 527 * @param looper The looper on which to execute the callbacks. 528 */ 529 WifiAwareEventCallbackProxy(WifiAwareManager mgr, Looper looper, Binder binder, 530 final AttachCallback attachCallback, 531 final IdentityChangedListener identityChangedListener) { 532 mAwareManager = new WeakReference<>(mgr); 533 mLooper = looper; 534 mBinder = binder; 535 536 if (VDBG) Log.v(TAG, "WifiAwareEventCallbackProxy ctor: looper=" + looper); 537 mHandler = new Handler(looper) { 538 @Override 539 public void handleMessage(Message msg) { 540 if (DBG) { 541 Log.d(TAG, "WifiAwareEventCallbackProxy: What=" + msg.what + ", msg=" 542 + msg); 543 } 544 545 WifiAwareManager mgr = mAwareManager.get(); 546 if (mgr == null) { 547 Log.w(TAG, "WifiAwareEventCallbackProxy: handleMessage post GC"); 548 return; 549 } 550 551 switch (msg.what) { 552 case CALLBACK_CONNECT_SUCCESS: 553 attachCallback.onAttached( 554 new WifiAwareSession(mgr, mBinder, msg.arg1)); 555 break; 556 case CALLBACK_CONNECT_FAIL: 557 mAwareManager.clear(); 558 attachCallback.onAttachFailed(); 559 break; 560 case CALLBACK_IDENTITY_CHANGED: 561 if (identityChangedListener == null) { 562 Log.e(TAG, "CALLBACK_IDENTITY_CHANGED: null listener."); 563 } else { 564 identityChangedListener.onIdentityChanged((byte[]) msg.obj); 565 } 566 break; 567 case CALLBACK_RANGING_SUCCESS: { 568 RttManager.RttListener listener = getAndRemoveRangingListener(msg.arg1); 569 if (listener == null) { 570 Log.e(TAG, "CALLBACK_RANGING_SUCCESS rangingId=" + msg.arg1 571 + ": no listener registered (anymore)"); 572 } else { 573 listener.onSuccess( 574 ((RttManager.ParcelableRttResults) msg.obj).mResults); 575 } 576 break; 577 } 578 case CALLBACK_RANGING_FAILURE: { 579 RttManager.RttListener listener = getAndRemoveRangingListener(msg.arg1); 580 if (listener == null) { 581 Log.e(TAG, "CALLBACK_RANGING_SUCCESS rangingId=" + msg.arg1 582 + ": no listener registered (anymore)"); 583 } else { 584 listener.onFailure(msg.arg2, (String) msg.obj); 585 } 586 break; 587 } 588 case CALLBACK_RANGING_ABORTED: { 589 RttManager.RttListener listener = getAndRemoveRangingListener(msg.arg1); 590 if (listener == null) { 591 Log.e(TAG, "CALLBACK_RANGING_SUCCESS rangingId=" + msg.arg1 592 + ": no listener registered (anymore)"); 593 } else { 594 listener.onAborted(); 595 } 596 break; 597 } 598 } 599 } 600 }; 601 } 602 603 @Override 604 public void onConnectSuccess(int clientId) { 605 if (VDBG) Log.v(TAG, "onConnectSuccess"); 606 607 Message msg = mHandler.obtainMessage(CALLBACK_CONNECT_SUCCESS); 608 msg.arg1 = clientId; 609 mHandler.sendMessage(msg); 610 } 611 612 @Override 613 public void onConnectFail(int reason) { 614 if (VDBG) Log.v(TAG, "onConnectFail: reason=" + reason); 615 616 Message msg = mHandler.obtainMessage(CALLBACK_CONNECT_FAIL); 617 msg.arg1 = reason; 618 mHandler.sendMessage(msg); 619 } 620 621 @Override 622 public void onIdentityChanged(byte[] mac) { 623 if (VDBG) Log.v(TAG, "onIdentityChanged: mac=" + new String(HexEncoding.encode(mac))); 624 625 Message msg = mHandler.obtainMessage(CALLBACK_IDENTITY_CHANGED); 626 msg.obj = mac; 627 mHandler.sendMessage(msg); 628 } 629 630 @Override 631 public void onRangingSuccess(int rangingId, RttManager.ParcelableRttResults results) { 632 if (VDBG) { 633 Log.v(TAG, "onRangingSuccess: rangingId=" + rangingId + ", results=" + results); 634 } 635 636 Message msg = mHandler.obtainMessage(CALLBACK_RANGING_SUCCESS); 637 msg.arg1 = rangingId; 638 msg.obj = results; 639 mHandler.sendMessage(msg); 640 } 641 642 @Override 643 public void onRangingFailure(int rangingId, int reason, String description) { 644 if (VDBG) { 645 Log.v(TAG, "onRangingSuccess: rangingId=" + rangingId + ", reason=" + reason 646 + ", description=" + description); 647 } 648 649 Message msg = mHandler.obtainMessage(CALLBACK_RANGING_FAILURE); 650 msg.arg1 = rangingId; 651 msg.arg2 = reason; 652 msg.obj = description; 653 mHandler.sendMessage(msg); 654 655 } 656 657 @Override 658 public void onRangingAborted(int rangingId) { 659 if (VDBG) Log.v(TAG, "onRangingAborted: rangingId=" + rangingId); 660 661 Message msg = mHandler.obtainMessage(CALLBACK_RANGING_ABORTED); 662 msg.arg1 = rangingId; 663 mHandler.sendMessage(msg); 664 665 } 666 } 667 668 private static class WifiAwareDiscoverySessionCallbackProxy extends 669 IWifiAwareDiscoverySessionCallback.Stub { 670 private static final int CALLBACK_SESSION_STARTED = 0; 671 private static final int CALLBACK_SESSION_CONFIG_SUCCESS = 1; 672 private static final int CALLBACK_SESSION_CONFIG_FAIL = 2; 673 private static final int CALLBACK_SESSION_TERMINATED = 3; 674 private static final int CALLBACK_MATCH = 4; 675 private static final int CALLBACK_MESSAGE_SEND_SUCCESS = 5; 676 private static final int CALLBACK_MESSAGE_SEND_FAIL = 6; 677 private static final int CALLBACK_MESSAGE_RECEIVED = 7; 678 679 private static final String MESSAGE_BUNDLE_KEY_MESSAGE = "message"; 680 private static final String MESSAGE_BUNDLE_KEY_MESSAGE2 = "message2"; 681 682 private final WeakReference<WifiAwareManager> mAwareManager; 683 private final boolean mIsPublish; 684 private final DiscoverySessionCallback mOriginalCallback; 685 private final int mClientId; 686 687 private final Handler mHandler; 688 private DiscoverySession mSession; 689 690 WifiAwareDiscoverySessionCallbackProxy(WifiAwareManager mgr, Looper looper, 691 boolean isPublish, DiscoverySessionCallback originalCallback, 692 int clientId) { 693 mAwareManager = new WeakReference<>(mgr); 694 mIsPublish = isPublish; 695 mOriginalCallback = originalCallback; 696 mClientId = clientId; 697 698 if (VDBG) { 699 Log.v(TAG, "WifiAwareDiscoverySessionCallbackProxy ctor: isPublish=" + isPublish); 700 } 701 702 mHandler = new Handler(looper) { 703 @Override 704 public void handleMessage(Message msg) { 705 if (DBG) Log.d(TAG, "What=" + msg.what + ", msg=" + msg); 706 707 if (mAwareManager.get() == null) { 708 Log.w(TAG, "WifiAwareDiscoverySessionCallbackProxy: handleMessage post GC"); 709 return; 710 } 711 712 switch (msg.what) { 713 case CALLBACK_SESSION_STARTED: 714 onProxySessionStarted(msg.arg1); 715 break; 716 case CALLBACK_SESSION_CONFIG_SUCCESS: 717 mOriginalCallback.onSessionConfigUpdated(); 718 break; 719 case CALLBACK_SESSION_CONFIG_FAIL: 720 mOriginalCallback.onSessionConfigFailed(); 721 if (mSession == null) { 722 /* 723 * creation failed (as opposed to update 724 * failing) 725 */ 726 mAwareManager.clear(); 727 } 728 break; 729 case CALLBACK_SESSION_TERMINATED: 730 onProxySessionTerminated(msg.arg1); 731 break; 732 case CALLBACK_MATCH: { 733 List<byte[]> matchFilter = null; 734 byte[] arg = msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2); 735 try { 736 matchFilter = new TlvBufferUtils.TlvIterable(0, 1, arg).toList(); 737 } catch (BufferOverflowException e) { 738 matchFilter = null; 739 Log.e(TAG, "onServiceDiscovered: invalid match filter byte array '" 740 + new String(HexEncoding.encode(arg)) 741 + "' - cannot be parsed: e=" + e); 742 } 743 mOriginalCallback.onServiceDiscovered(new PeerHandle(msg.arg1), 744 msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE), 745 matchFilter); 746 break; 747 } 748 case CALLBACK_MESSAGE_SEND_SUCCESS: 749 mOriginalCallback.onMessageSendSucceeded(msg.arg1); 750 break; 751 case CALLBACK_MESSAGE_SEND_FAIL: 752 mOriginalCallback.onMessageSendFailed(msg.arg1); 753 break; 754 case CALLBACK_MESSAGE_RECEIVED: 755 mOriginalCallback.onMessageReceived(new PeerHandle(msg.arg1), 756 (byte[]) msg.obj); 757 break; 758 } 759 } 760 }; 761 } 762 763 @Override 764 public void onSessionStarted(int sessionId) { 765 if (VDBG) Log.v(TAG, "onSessionStarted: sessionId=" + sessionId); 766 767 Message msg = mHandler.obtainMessage(CALLBACK_SESSION_STARTED); 768 msg.arg1 = sessionId; 769 mHandler.sendMessage(msg); 770 } 771 772 @Override 773 public void onSessionConfigSuccess() { 774 if (VDBG) Log.v(TAG, "onSessionConfigSuccess"); 775 776 Message msg = mHandler.obtainMessage(CALLBACK_SESSION_CONFIG_SUCCESS); 777 mHandler.sendMessage(msg); 778 } 779 780 @Override 781 public void onSessionConfigFail(int reason) { 782 if (VDBG) Log.v(TAG, "onSessionConfigFail: reason=" + reason); 783 784 Message msg = mHandler.obtainMessage(CALLBACK_SESSION_CONFIG_FAIL); 785 msg.arg1 = reason; 786 mHandler.sendMessage(msg); 787 } 788 789 @Override 790 public void onSessionTerminated(int reason) { 791 if (VDBG) Log.v(TAG, "onSessionTerminated: reason=" + reason); 792 793 Message msg = mHandler.obtainMessage(CALLBACK_SESSION_TERMINATED); 794 msg.arg1 = reason; 795 mHandler.sendMessage(msg); 796 } 797 798 @Override 799 public void onMatch(int peerId, byte[] serviceSpecificInfo, byte[] matchFilter) { 800 if (VDBG) Log.v(TAG, "onMatch: peerId=" + peerId); 801 802 Bundle data = new Bundle(); 803 data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE, serviceSpecificInfo); 804 data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2, matchFilter); 805 806 Message msg = mHandler.obtainMessage(CALLBACK_MATCH); 807 msg.arg1 = peerId; 808 msg.setData(data); 809 mHandler.sendMessage(msg); 810 } 811 812 @Override 813 public void onMessageSendSuccess(int messageId) { 814 if (VDBG) Log.v(TAG, "onMessageSendSuccess"); 815 816 Message msg = mHandler.obtainMessage(CALLBACK_MESSAGE_SEND_SUCCESS); 817 msg.arg1 = messageId; 818 mHandler.sendMessage(msg); 819 } 820 821 @Override 822 public void onMessageSendFail(int messageId, int reason) { 823 if (VDBG) Log.v(TAG, "onMessageSendFail: reason=" + reason); 824 825 Message msg = mHandler.obtainMessage(CALLBACK_MESSAGE_SEND_FAIL); 826 msg.arg1 = messageId; 827 msg.arg2 = reason; 828 mHandler.sendMessage(msg); 829 } 830 831 @Override 832 public void onMessageReceived(int peerId, byte[] message) { 833 if (VDBG) { 834 Log.v(TAG, "onMessageReceived: peerId=" + peerId); 835 } 836 837 Message msg = mHandler.obtainMessage(CALLBACK_MESSAGE_RECEIVED); 838 msg.arg1 = peerId; 839 msg.obj = message; 840 mHandler.sendMessage(msg); 841 } 842 843 /* 844 * Proxied methods 845 */ 846 public void onProxySessionStarted(int sessionId) { 847 if (VDBG) Log.v(TAG, "Proxy: onSessionStarted: sessionId=" + sessionId); 848 if (mSession != null) { 849 Log.e(TAG, 850 "onSessionStarted: sessionId=" + sessionId + ": session already created!?"); 851 throw new IllegalStateException( 852 "onSessionStarted: sessionId=" + sessionId + ": session already created!?"); 853 } 854 855 WifiAwareManager mgr = mAwareManager.get(); 856 if (mgr == null) { 857 Log.w(TAG, "onProxySessionStarted: mgr GC'd"); 858 return; 859 } 860 861 if (mIsPublish) { 862 PublishDiscoverySession session = new PublishDiscoverySession(mgr, 863 mClientId, sessionId); 864 mSession = session; 865 mOriginalCallback.onPublishStarted(session); 866 } else { 867 SubscribeDiscoverySession 868 session = new SubscribeDiscoverySession(mgr, mClientId, sessionId); 869 mSession = session; 870 mOriginalCallback.onSubscribeStarted(session); 871 } 872 } 873 874 public void onProxySessionTerminated(int reason) { 875 if (VDBG) Log.v(TAG, "Proxy: onSessionTerminated: reason=" + reason); 876 if (mSession != null) { 877 mSession.setTerminated(); 878 mSession = null; 879 } else { 880 Log.w(TAG, "Proxy: onSessionTerminated called but mSession is null!?"); 881 } 882 mAwareManager.clear(); 883 mOriginalCallback.onSessionTerminated(); 884 } 885 } 886 } 887