Home | History | Annotate | Download | only in aware
      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