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 */
WifiAwareManager(Context context, IWifiAwareManager service)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      */
isAvailable()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      */
getCharacteristics()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      */
attach(@onNull AttachCallback attachCallback, @Nullable Handler handler)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      */
attach(@onNull AttachCallback attachCallback, @NonNull IdentityChangedListener identityChangedListener, @Nullable Handler handler)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 */
attach(Handler handler, ConfigRequest configRequest, AttachCallback attachCallback, IdentityChangedListener identityChangedListener)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 */
disconnect(int clientId, Binder binder)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 */
publish(int clientId, Looper looper, PublishConfig publishConfig, DiscoverySessionCallback callback)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 */
updatePublish(int clientId, int sessionId, PublishConfig publishConfig)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 */
subscribe(int clientId, Looper looper, SubscribeConfig subscribeConfig, DiscoverySessionCallback callback)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 */
updateSubscribe(int clientId, int sessionId, SubscribeConfig subscribeConfig)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 */
terminateSession(int clientId, int sessionId)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 */
sendMessage(int clientId, int sessionId, PeerHandle peerHandle, byte[] message, int messageId, int retryCount)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 */
startRanging(int clientId, int sessionId, RttManager.RttParams[] params, RttManager.RttListener listener)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 */
createNetworkSpecifier(int clientId, int role, int sessionId, PeerHandle peerHandle, @Nullable byte[] pmk, @Nullable String passphrase)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 */
createNetworkSpecifier(int clientId, @DataPathRole int role, @Nullable byte[] peer, @Nullable byte[] pmk, @Nullable String passphrase)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 
getAndRemoveRangingListener(int rangingId)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          */
WifiAwareEventCallbackProxy(WifiAwareManager mgr, Looper looper, Binder binder, final AttachCallback attachCallback, final IdentityChangedListener identityChangedListener)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
onConnectSuccess(int clientId)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
onConnectFail(int reason)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
onIdentityChanged(byte[] mac)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
onRangingSuccess(int rangingId, RttManager.ParcelableRttResults results)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
onRangingFailure(int rangingId, int reason, String description)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
onRangingAborted(int rangingId)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 
WifiAwareDiscoverySessionCallbackProxy(WifiAwareManager mgr, Looper looper, boolean isPublish, DiscoverySessionCallback originalCallback, int clientId)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
onSessionStarted(int sessionId)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
onSessionConfigSuccess()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
onSessionConfigFail(int reason)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
onSessionTerminated(int reason)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
onMatch(int peerId, byte[] serviceSpecificInfo, byte[] matchFilter)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
onMessageSendSuccess(int messageId)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
onMessageSendFail(int messageId, int reason)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
onMessageReceived(int peerId, byte[] message)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          */
onProxySessionStarted(int sessionId)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 
onProxySessionTerminated(int reason)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