• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static android.Manifest.permission.ACCESS_FINE_LOCATION;
20 import static android.Manifest.permission.ACCESS_WIFI_STATE;
21 import static android.Manifest.permission.CHANGE_WIFI_STATE;
22 import static android.Manifest.permission.NEARBY_WIFI_DEVICES;
23 import static android.Manifest.permission.OVERRIDE_WIFI_CONFIG;
24 
25 import android.annotation.CallbackExecutor;
26 import android.annotation.IntDef;
27 import android.annotation.NonNull;
28 import android.annotation.Nullable;
29 import android.annotation.RequiresPermission;
30 import android.annotation.SdkConstant;
31 import android.annotation.SdkConstant.SdkConstantType;
32 import android.annotation.SystemApi;
33 import android.annotation.SystemService;
34 import android.content.Context;
35 import android.net.ConnectivityManager;
36 import android.net.MacAddress;
37 import android.net.NetworkRequest;
38 import android.net.NetworkSpecifier;
39 import android.net.wifi.IBooleanListener;
40 import android.net.wifi.IIntegerListener;
41 import android.net.wifi.IListListener;
42 import android.net.wifi.WifiManager;
43 import android.net.wifi.util.HexEncoding;
44 import android.os.Binder;
45 import android.os.Build;
46 import android.os.Bundle;
47 import android.os.Handler;
48 import android.os.Looper;
49 import android.os.RemoteException;
50 import android.util.Log;
51 
52 import androidx.annotation.RequiresApi;
53 
54 import com.android.modules.utils.HandlerExecutor;
55 import com.android.modules.utils.build.SdkLevel;
56 
57 import java.lang.annotation.Retention;
58 import java.lang.annotation.RetentionPolicy;
59 import java.lang.ref.WeakReference;
60 import java.nio.BufferOverflowException;
61 import java.util.Collections;
62 import java.util.List;
63 import java.util.Objects;
64 import java.util.concurrent.Executor;
65 import java.util.function.Consumer;
66 
67 /**
68  * This class provides the primary API for managing Wi-Fi Aware operations:
69  * discovery and peer-to-peer data connections.
70  * <p>
71  * The class provides access to:
72  * <ul>
73  * <li>Initialize a Aware cluster (peer-to-peer synchronization). Refer to
74  * {@link #attach(AttachCallback, Handler)}.
75  * <li>Create discovery sessions (publish or subscribe sessions). Refer to
76  * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback, Handler)} and
77  * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback, Handler)}.
78  * <li>Create a Aware network specifier to be used with
79  * {@link ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)}
80  * to set-up a Aware connection with a peer. Refer to {@link WifiAwareNetworkSpecifier.Builder}.
81  * </ul>
82  * <p>
83  *     Aware may not be usable when Wi-Fi is disabled (and other conditions). To validate that
84  *     the functionality is available use the {@link #isAvailable()} function. To track
85  *     changes in Aware usability register for the {@link #ACTION_WIFI_AWARE_STATE_CHANGED}
86  *     broadcast. Note that this broadcast is not sticky - you should register for it and then
87  *     check the above API to avoid a race condition.
88  * <p>
89  *     An application must use {@link #attach(AttachCallback, Handler)} to initialize a
90  *     Aware cluster - before making any other Aware operation. Aware cluster membership is a
91  *     device-wide operation - the API guarantees that the device is in a cluster or joins a
92  *     Aware cluster (or starts one if none can be found). Information about attach success (or
93  *     failure) are returned in callbacks of {@link AttachCallback}. Proceed with Aware
94  *     discovery or connection setup only after receiving confirmation that Aware attach
95  *     succeeded - {@link AttachCallback#onAttached(WifiAwareSession)}. When an
96  *     application is finished using Aware it <b>must</b> use the
97  *     {@link WifiAwareSession#close()} API to indicate to the Aware service that the device
98  *     may detach from the Aware cluster. The device will actually disable Aware once the last
99  *     application detaches.
100  * <p>
101  *     Once a Aware attach is confirmed use the
102  *     {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback, Handler)}
103  *     or
104  *     {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback,
105  *     Handler)} to create publish or subscribe Aware discovery sessions. Events are called on the
106  *     provided callback object {@link DiscoverySessionCallback}. Specifically, the
107  *     {@link DiscoverySessionCallback#onPublishStarted(PublishDiscoverySession)}
108  *     and
109  *     {@link DiscoverySessionCallback#onSubscribeStarted(
110  *SubscribeDiscoverySession)}
111  *     return {@link PublishDiscoverySession} and
112  *     {@link SubscribeDiscoverySession}
113  *     objects respectively on which additional session operations can be performed, e.g. updating
114  *     the session {@link PublishDiscoverySession#updatePublish(PublishConfig)} and
115  *     {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}. Sessions can
116  *     also be used to send messages using the
117  *     {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])} APIs. When an
118  *     application is finished with a discovery session it <b>must</b> terminate it using the
119  *     {@link DiscoverySession#close()} API.
120  * <p>
121  *    Creating connections between Aware devices is managed by the standard
122  *    {@link ConnectivityManager#requestNetwork(NetworkRequest,
123  *    ConnectivityManager.NetworkCallback)}.
124  *    The {@link NetworkRequest} object should be constructed with:
125  *    <ul>
126  *        <li>{@link NetworkRequest.Builder#addTransportType(int)} of
127  *        {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
128  *        <li>{@link NetworkRequest.Builder#setNetworkSpecifier(String)} using
129  *        {@link WifiAwareNetworkSpecifier.Builder}.
130  *    </ul>
131  */
132 @SystemService(Context.WIFI_AWARE_SERVICE)
133 public class WifiAwareManager {
134     private static final String TAG = "WifiAwareManager";
135     private static final boolean DBG = false;
136     private static final boolean VDBG = false; // STOPSHIP if true
137 
138     /**
139      * Broadcast intent action to indicate that the state of Wi-Fi Aware availability has changed
140      * and all active Aware sessions are no longer usable. Use the {@link #isAvailable()} to query
141      * the current status.
142      * This broadcast is <b>not</b> sticky, use the {@link #isAvailable()} API after registering
143      * the broadcast to check the current state of Wi-Fi Aware.
144      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
145      * components will be launched.
146      */
147     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
148     public static final String ACTION_WIFI_AWARE_STATE_CHANGED =
149             "android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED";
150     /**
151      * Intent broadcast sent whenever Wi-Fi Aware resource availability has changed. The resources
152      * are attached with the {@link #EXTRA_AWARE_RESOURCES} extra. The resources can also be
153      * obtained using the {@link #getAvailableAwareResources()} method. To receive this broadcast,
154      * apps must hold {@link android.Manifest.permission#ACCESS_WIFI_STATE}.
155      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
156      * components will be launched.
157      */
158     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
159     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
160     @RequiresPermission(ACCESS_WIFI_STATE)
161     public static final String ACTION_WIFI_AWARE_RESOURCE_CHANGED =
162             "android.net.wifi.aware.action.WIFI_AWARE_RESOURCE_CHANGED";
163 
164     /**
165      * Sent as a part of {@link #ACTION_WIFI_AWARE_RESOURCE_CHANGED} that contains an instance of
166      * {@link AwareResources} representing the current Wi-Fi Aware resources.
167      */
168     public static final String EXTRA_AWARE_RESOURCES =
169             "android.net.wifi.aware.extra.AWARE_RESOURCES";
170 
171     /** @hide */
172     @IntDef({
173             WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, WIFI_AWARE_DATA_PATH_ROLE_RESPONDER})
174     @Retention(RetentionPolicy.SOURCE)
175     public @interface DataPathRole {
176     }
177 
178     /**
179      * Connection creation role is that of INITIATOR. Used to create a network specifier string
180      * when requesting a Aware network.
181      *
182      * @see WifiAwareSession#createNetworkSpecifierOpen(int, byte[])
183      * @see WifiAwareSession#createNetworkSpecifierPassphrase(int, byte[], String)
184      */
185     public static final int WIFI_AWARE_DATA_PATH_ROLE_INITIATOR = 0;
186 
187     /**
188      * Connection creation role is that of RESPONDER. Used to create a network specifier string
189      * when requesting a Aware network.
190      *
191      * @see WifiAwareSession#createNetworkSpecifierOpen(int, byte[])
192      * @see WifiAwareSession#createNetworkSpecifierPassphrase(int, byte[], String)
193      */
194     public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1;
195 
196     /** @hide */
197     @IntDef({
198             WIFI_AWARE_DISCOVERY_LOST_REASON_UNKNOWN,
199             WIFI_AWARE_DISCOVERY_LOST_REASON_PEER_NOT_VISIBLE})
200     @Retention(RetentionPolicy.SOURCE)
201     public @interface DiscoveryLostReasonCode {
202     }
203 
204     /**
205      * Reason code provided in {@link DiscoverySessionCallback#onServiceLost(PeerHandle, int)}
206      * indicating that the service was lost for unknown reason.
207      */
208     public static final int WIFI_AWARE_DISCOVERY_LOST_REASON_UNKNOWN = 0;
209 
210     /**
211      * Reason code provided in {@link DiscoverySessionCallback#onServiceLost(PeerHandle, int)}
212      * indicating that the service advertised by the peer is no longer visible. This may be because
213      * the peer is out of range or because the peer stopped advertising this service.
214      */
215     public static final int WIFI_AWARE_DISCOVERY_LOST_REASON_PEER_NOT_VISIBLE = 1;
216 
217     /** @hide */
218     @IntDef({
219             WIFI_AWARE_SUSPEND_REDUNDANT_REQUEST,
220             WIFI_AWARE_SUSPEND_INVALID_SESSION,
221             WIFI_AWARE_SUSPEND_CANNOT_SUSPEND,
222             WIFI_AWARE_SUSPEND_INTERNAL_ERROR})
223     @Retention(RetentionPolicy.SOURCE)
224     public @interface SessionSuspensionFailedReasonCode {}
225 
226     /**
227      * Reason code provided in {@link DiscoverySessionCallback#onSessionSuspendFailed(int)} when the
228      * session is already suspended.
229      * @hide
230      */
231     @SystemApi
232     public static final int WIFI_AWARE_SUSPEND_REDUNDANT_REQUEST = 0;
233 
234     /**
235      * Reason code provided in {@link DiscoverySessionCallback#onSessionSuspendFailed(int)} when the
236      * specified session does not support suspension.
237       @hide
238      */
239     @SystemApi
240     public static final int WIFI_AWARE_SUSPEND_INVALID_SESSION = 1;
241 
242     /**
243      * Reason code provided in {@link DiscoverySessionCallback#onSessionSuspendFailed(int)} when the
244      * session could not be suspended due to more than one app using it.
245       @hide
246      */
247     @SystemApi
248     public static final int WIFI_AWARE_SUSPEND_CANNOT_SUSPEND = 2;
249 
250     /**
251      * Reason code provided in {@link DiscoverySessionCallback#onSessionSuspendFailed(int)} when an
252      * error is encountered with the request.
253       @hide
254      */
255     @SystemApi
256     public static final int WIFI_AWARE_SUSPEND_INTERNAL_ERROR = 3;
257 
258     /** @hide */
259     @IntDef({
260             WIFI_AWARE_RESUME_REDUNDANT_REQUEST,
261             WIFI_AWARE_RESUME_INVALID_SESSION,
262             WIFI_AWARE_RESUME_INTERNAL_ERROR})
263     @Retention(RetentionPolicy.SOURCE)
264     public @interface SessionResumptionFailedReasonCode {}
265 
266     /**
267      * Reason code provided in {@link DiscoverySessionCallback#onSessionResumeFailed(int)} when the
268      * session is not suspended.
269      * @hide
270      */
271     @SystemApi
272     public static final int WIFI_AWARE_RESUME_REDUNDANT_REQUEST = 0;
273 
274     /**
275      * Reason code provided in {@link DiscoverySessionCallback#onSessionResumeFailed(int)} when the
276      * specified session does not support suspension.
277       @hide
278      */
279     @SystemApi
280     public static final int WIFI_AWARE_RESUME_INVALID_SESSION = 1;
281 
282     /**
283      * Reason code provided in {@link DiscoverySessionCallback#onSessionResumeFailed(int)} when an
284      * error is encountered with the request.
285       @hide
286      */
287     @SystemApi
288     public static final int WIFI_AWARE_RESUME_INTERNAL_ERROR = 2;
289 
290     private final Context mContext;
291     private final IWifiAwareManager mService;
292 
293     private final Object mLock = new Object(); // lock access to the following vars
294 
295     /** @hide */
WifiAwareManager(@onNull Context context, @NonNull IWifiAwareManager service)296     public WifiAwareManager(@NonNull Context context, @NonNull IWifiAwareManager service) {
297         mContext = context;
298         mService = service;
299     }
300 
301     /**
302      * Returns the current status of Aware API: whether or not Aware is available. To track
303      * changes in the state of Aware API register for the
304      * {@link #ACTION_WIFI_AWARE_STATE_CHANGED} broadcast.
305      *
306      * @return A boolean indicating whether the app can use the Aware API at this time (true) or
307      * not (false).
308      */
309     @RequiresPermission(ACCESS_WIFI_STATE)
isAvailable()310     public boolean isAvailable() {
311         try {
312             return mService.isUsageEnabled();
313         } catch (RemoteException e) {
314             throw e.rethrowFromSystemServer();
315         }
316     }
317 
318     /**
319      * Return the current status of the Aware service: whether or not the device is already attached
320      * to an Aware cluster. To attach to an Aware cluster, please use
321      * {@link #attach(AttachCallback, Handler)} or
322      * {@link #attach(AttachCallback, IdentityChangedListener, Handler)}.
323      * @return A boolean indicating whether the device is attached to a cluster at this time (true)
324      *         or not (false).
325      */
326     @RequiresPermission(ACCESS_WIFI_STATE)
isDeviceAttached()327     public boolean isDeviceAttached() {
328         try {
329             return mService.isDeviceAttached();
330         } catch (RemoteException e) {
331             throw e.rethrowFromSystemServer();
332         }
333     }
334 
335     /**
336      * Return the device support for setting a channel requirement in a data-path request. If true
337      * the channel set by
338      * {@link WifiAwareNetworkSpecifier.Builder#setChannelFrequencyMhz(int, boolean)} will be
339      * honored, otherwise it will be ignored.
340      * @return True is the device support set channel on data-path request, false otherwise.
341      */
342     @RequiresPermission(ACCESS_WIFI_STATE)
isSetChannelOnDataPathSupported()343     public boolean isSetChannelOnDataPathSupported() {
344         try {
345             return mService.isSetChannelOnDataPathSupported();
346         } catch (RemoteException e) {
347             throw e.rethrowFromSystemServer();
348         }
349     }
350 
351     /**
352      * Enable the Wifi Aware Instant communication mode. If the device doesn't support this feature
353      * calling this API will result no action.
354      * <p>
355      * Note: before {@link android.os.Build.VERSION_CODES#TIRAMISU}, only system app can use this
356      * API. Start with {@link android.os.Build.VERSION_CODES#TIRAMISU} apps hold
357      * {@link android.Manifest.permission#OVERRIDE_WIFI_CONFIG} are allowed to use it.
358      *
359      * @see Characteristics#isInstantCommunicationModeSupported()
360      * @param enable true for enable, false otherwise.
361      * @hide
362      */
363     @SystemApi
364     @RequiresApi(Build.VERSION_CODES.S)
365     @RequiresPermission(allOf = {CHANGE_WIFI_STATE, OVERRIDE_WIFI_CONFIG})
enableInstantCommunicationMode(boolean enable)366     public void enableInstantCommunicationMode(boolean enable) {
367         if (!SdkLevel.isAtLeastS()) {
368             throw new UnsupportedOperationException();
369         }
370         try {
371             mService.enableInstantCommunicationMode(mContext.getOpPackageName(), enable);
372         } catch (RemoteException e) {
373             throw e.rethrowFromSystemServer();
374         }
375     }
376 
377     /**
378      * Return the current status of the Wifi Aware instant communication mode.
379      * If the device doesn't support this feature, return will always be false.
380      * @see Characteristics#isInstantCommunicationModeSupported()
381      * @return true if it is enabled, false otherwise.
382      */
383     @RequiresApi(Build.VERSION_CODES.S)
384     @RequiresPermission(ACCESS_WIFI_STATE)
isInstantCommunicationModeEnabled()385     public boolean isInstantCommunicationModeEnabled() {
386         if (!SdkLevel.isAtLeastS()) {
387             throw new UnsupportedOperationException();
388         }
389         try {
390             return mService.isInstantCommunicationModeEnabled();
391         } catch (RemoteException e) {
392             throw e.rethrowFromSystemServer();
393         }
394     }
395 
396     /**
397      * Returns the characteristics of the Wi-Fi Aware interface: a set of parameters which specify
398      * limitations on configurations, e.g. the maximum service name length.
399      * <p>
400      * May return {@code null} if the Wi-Fi Aware service is not initialized. Use
401      * {@link #attach(AttachCallback, Handler)} or
402      * {@link #attach(AttachCallback, IdentityChangedListener, Handler)} to initialize the Wi-Fi
403      * Aware service.
404      *
405      * @return An object specifying configuration limitations of Aware.
406      */
407     @RequiresPermission(ACCESS_WIFI_STATE)
getCharacteristics()408     public @Nullable Characteristics getCharacteristics() {
409         try {
410             return mService.getCharacteristics();
411         } catch (RemoteException e) {
412             throw e.rethrowFromSystemServer();
413         }
414     }
415 
416     /**
417      * Return the available resources of the Wi-Fi aware service: a set of parameters which specify
418      * limitations on service usage, e.g the number of data-paths which could be created.
419      * <p>
420      * May return {@code null} if the Wi-Fi Aware service is not initialized. Use
421      * {@link #attach(AttachCallback, Handler)} or
422      * {@link #attach(AttachCallback, IdentityChangedListener, Handler)} to initialize the Wi-Fi
423      * Aware service.
424      *
425      * @return An object specifying the currently available resource of the Wi-Fi Aware service.
426      */
427     @RequiresPermission(ACCESS_WIFI_STATE)
getAvailableAwareResources()428     public @Nullable AwareResources getAvailableAwareResources() {
429         try {
430             return mService.getAvailableAwareResources();
431         } catch (RemoteException e) {
432             throw e.rethrowFromSystemServer();
433         }
434     }
435 
436     /**
437      * Attach to the Wi-Fi Aware service - enabling the application to create discovery sessions or
438      * create connections to peers. The device will attach to an existing cluster if it can find
439      * one or create a new cluster (if it is the first to enable Aware in its vicinity). Results
440      * (e.g. successful attach to a cluster) are provided to the {@code attachCallback} object.
441      * An application <b>must</b> call {@link WifiAwareSession#close()} when done with the
442      * Wi-Fi Aware object.
443      * <p>
444      * Note: a Aware cluster is a shared resource - if the device is already attached to a cluster
445      * then this function will simply indicate success immediately using the same {@code
446      * attachCallback}.
447      *
448      * @param attachCallback A callback for attach events, extended from
449      * {@link AttachCallback}.
450      * @param handler The Handler on whose thread to execute the callbacks of the {@code
451      * attachCallback} object. If a null is provided then the application's main thread will be
452      *                used.
453      */
454     @RequiresPermission(allOf = {
455             ACCESS_WIFI_STATE,
456             CHANGE_WIFI_STATE
457     })
attach(@onNull AttachCallback attachCallback, @Nullable Handler handler)458     public void attach(@NonNull AttachCallback attachCallback, @Nullable Handler handler) {
459         attach(handler, null, attachCallback, null, false, null);
460     }
461 
462     /**
463      * Attach to the Wi-Fi Aware service - enabling the application to create discovery sessions or
464      * create connections to peers. The device will attach to an existing cluster if it can find
465      * one or create a new cluster (if it is the first to enable Aware in its vicinity). Results
466      * (e.g. successful attach to a cluster) are provided to the {@code attachCallback} object.
467      * An application <b>must</b> call {@link WifiAwareSession#close()} when done with the
468      * Wi-Fi Aware object.
469      * <p>
470      * Note: a Aware cluster is a shared resource - if the device is already attached to a cluster
471      * then this function will simply indicate success immediately using the same {@code
472      * attachCallback}.
473      * <p>
474      * This version of the API attaches a listener to receive the MAC address of the Aware interface
475      * on startup and whenever it is updated (it is randomized at regular intervals for privacy).
476      *
477      * If targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later, the application must
478      * have {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
479      * android:usesPermissionFlags="neverForLocation". If the application does not declare
480      * android:usesPermissionFlags="neverForLocation", then it must also have
481      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
482      *
483      * If targeting an earlier release than {@link android.os.Build.VERSION_CODES#TIRAMISU}, the
484      * application must have {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
485      *
486      * Apps without {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} or
487      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} can use the
488      * {@link #attach(AttachCallback, Handler)} version.
489      * Note that aside from permission requirements the {@link IdentityChangedListener} will wake up
490      * the host at regular intervals causing higher power consumption, do not use it unless the
491      * information is necessary (e.g. for out-of-band discovery).
492      *
493      * @param attachCallback A callback for attach events, extended from
494      * {@link AttachCallback}.
495      * @param identityChangedListener A callback for changed identity or cluster ID, extended from
496      * {@link IdentityChangedListener}.
497      * @param handler The Handler on whose thread to execute the callbacks of the {@code
498      * attachCallback} and {@code identityChangedListener} objects. If a null is provided then the
499      *                application's main thread will be used.
500      */
501     @RequiresPermission(allOf = {
502             ACCESS_WIFI_STATE,
503             CHANGE_WIFI_STATE,
504             ACCESS_FINE_LOCATION,
505             NEARBY_WIFI_DEVICES}, conditional = true)
attach(@onNull AttachCallback attachCallback, @NonNull IdentityChangedListener identityChangedListener, @Nullable Handler handler)506     public void attach(@NonNull AttachCallback attachCallback,
507             @NonNull IdentityChangedListener identityChangedListener,
508             @Nullable Handler handler) {
509         attach(handler, null, attachCallback, identityChangedListener, false, null);
510     }
511 
512     /** @hide */
attach(Handler handler, ConfigRequest configRequest, AttachCallback attachCallback, IdentityChangedListener identityChangedListener, boolean forOffloading, Executor executor)513     public void attach(Handler handler, ConfigRequest configRequest,
514             AttachCallback attachCallback,
515             IdentityChangedListener identityChangedListener, boolean forOffloading,
516             Executor executor) {
517         if (VDBG) {
518             Log.v(TAG, "attach(): handler=" + handler + ", callback=" + attachCallback
519                     + ", configRequest=" + configRequest + ", identityChangedListener="
520                     + identityChangedListener + ", forOffloading" + forOffloading);
521         }
522 
523         if (attachCallback == null) {
524             throw new IllegalArgumentException("Null callback provided");
525         }
526 
527         synchronized (mLock) {
528             Executor localExecutor = executor;
529             if (localExecutor == null) {
530                 localExecutor = new HandlerExecutor((handler == null)
531                         ? new Handler(Looper.getMainLooper()) : handler);
532             }
533 
534             try {
535                 Binder binder = new Binder();
536                 Bundle extras = new Bundle();
537                 if (SdkLevel.isAtLeastS()) {
538                     extras.putParcelable(WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
539                             mContext.getAttributionSource());
540                 }
541                 mService.connect(binder, mContext.getOpPackageName(), mContext.getAttributionTag(),
542                         new WifiAwareEventCallbackProxy(this, localExecutor, binder,
543                                 attachCallback, identityChangedListener), configRequest,
544                         identityChangedListener != null, extras, forOffloading);
545             } catch (RemoteException e) {
546                 throw e.rethrowFromSystemServer();
547             }
548         }
549     }
550 
551     /** @hide */
disconnect(int clientId, Binder binder)552     public void disconnect(int clientId, Binder binder) {
553         if (VDBG) Log.v(TAG, "disconnect()");
554 
555         try {
556             mService.disconnect(clientId, binder);
557         } catch (RemoteException e) {
558             throw e.rethrowFromSystemServer();
559         }
560     }
561 
562     /** @hide */
setMasterPreference(int clientId, Binder binder, int mp)563     public void setMasterPreference(int clientId, Binder binder, int mp) {
564         if (VDBG) Log.v(TAG, "setMasterPreference()");
565 
566         try {
567             mService.setMasterPreference(clientId, binder, mp);
568         } catch (RemoteException e) {
569             throw e.rethrowFromSystemServer();
570         }
571     }
572 
573     /**
574      * @hide
575      */
getMasterPreference(int clientId, Binder binder, @NonNull Executor executor, @NonNull Consumer<Integer> resultsCallback)576     public void getMasterPreference(int clientId, Binder binder, @NonNull Executor executor,
577             @NonNull Consumer<Integer> resultsCallback) {
578         Objects.requireNonNull(executor, "executor cannot be null");
579         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
580         try {
581             mService.getMasterPreference(clientId, binder,
582                     new IIntegerListener.Stub() {
583                         public void onResult(int value) {
584                             Binder.clearCallingIdentity();
585                             executor.execute(() -> resultsCallback.accept(value));
586                         }
587                     });
588         } catch (RemoteException e) {
589             throw e.rethrowFromSystemServer();
590         }
591     }
592 
593     /** @hide */
publish(int clientId, Looper looper, PublishConfig publishConfig, DiscoverySessionCallback callback)594     public void publish(int clientId, Looper looper, PublishConfig publishConfig,
595             DiscoverySessionCallback callback) {
596         if (VDBG) Log.v(TAG, "publish(): clientId=" + clientId + ", config=" + publishConfig);
597 
598         if (callback == null) {
599             throw new IllegalArgumentException("Null callback provided");
600         }
601 
602         try {
603             Bundle extras = new Bundle();
604             if (SdkLevel.isAtLeastS()) {
605                 extras.putParcelable(WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
606                         mContext.getAttributionSource());
607             }
608             mService.publish(mContext.getOpPackageName(), mContext.getAttributionTag(), clientId,
609                     publishConfig,
610                     new WifiAwareDiscoverySessionCallbackProxy(this, looper, true, callback,
611                             clientId), extras);
612         } catch (RemoteException e) {
613             throw e.rethrowFromSystemServer();
614         }
615     }
616 
617     /** @hide */
updatePublish(int clientId, int sessionId, PublishConfig publishConfig)618     public void updatePublish(int clientId, int sessionId, PublishConfig publishConfig) {
619         if (VDBG) {
620             Log.v(TAG, "updatePublish(): clientId=" + clientId + ",sessionId=" + sessionId
621                     + ", config=" + publishConfig);
622         }
623 
624         try {
625             mService.updatePublish(clientId, sessionId, publishConfig);
626         } catch (RemoteException e) {
627             throw e.rethrowFromSystemServer();
628         }
629     }
630 
631     /** @hide */
subscribe(int clientId, Looper looper, SubscribeConfig subscribeConfig, DiscoverySessionCallback callback)632     public void subscribe(int clientId, Looper looper, SubscribeConfig subscribeConfig,
633             DiscoverySessionCallback callback) {
634         if (VDBG) {
635             if (VDBG) {
636                 Log.v(TAG,
637                         "subscribe(): clientId=" + clientId + ", config=" + subscribeConfig);
638             }
639         }
640 
641         if (callback == null) {
642             throw new IllegalArgumentException("Null callback provided");
643         }
644 
645         try {
646             Bundle extras = new Bundle();
647             if (SdkLevel.isAtLeastS()) {
648                 extras.putParcelable(WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
649                         mContext.getAttributionSource());
650             }
651             mService.subscribe(mContext.getOpPackageName(), mContext.getAttributionTag(), clientId,
652                     subscribeConfig,
653                     new WifiAwareDiscoverySessionCallbackProxy(this, looper, false, callback,
654                             clientId), extras);
655         } catch (RemoteException e) {
656             throw e.rethrowFromSystemServer();
657         }
658     }
659 
660     /** @hide */
updateSubscribe(int clientId, int sessionId, SubscribeConfig subscribeConfig)661     public void updateSubscribe(int clientId, int sessionId, SubscribeConfig subscribeConfig) {
662         if (VDBG) {
663             Log.v(TAG, "updateSubscribe(): clientId=" + clientId + ",sessionId=" + sessionId
664                     + ", config=" + subscribeConfig);
665         }
666 
667         try {
668             mService.updateSubscribe(clientId, sessionId, subscribeConfig);
669         } catch (RemoteException e) {
670             throw e.rethrowFromSystemServer();
671         }
672     }
673 
674     /** @hide */
terminateSession(int clientId, int sessionId)675     public void terminateSession(int clientId, int sessionId) {
676         if (VDBG) {
677             Log.d(TAG,
678                     "terminateSession(): clientId=" + clientId + ", sessionId=" + sessionId);
679         }
680 
681         try {
682             mService.terminateSession(clientId, sessionId);
683         } catch (RemoteException e) {
684             throw e.rethrowFromSystemServer();
685         }
686     }
687 
688     /** @hide */
sendMessage(int clientId, int sessionId, PeerHandle peerHandle, byte[] message, int messageId, int retryCount)689     public void sendMessage(int clientId, int sessionId, PeerHandle peerHandle, byte[] message,
690             int messageId, int retryCount) {
691         if (peerHandle == null) {
692             throw new IllegalArgumentException(
693                     "sendMessage: invalid peerHandle - must be non-null");
694         }
695 
696         if (VDBG) {
697             Log.v(TAG, "sendMessage(): clientId=" + clientId + ", sessionId=" + sessionId
698                     + ", peerHandle=" + peerHandle.peerId + ", messageId="
699                     + messageId + ", retryCount=" + retryCount);
700         }
701 
702         try {
703             mService.sendMessage(clientId, sessionId, peerHandle.peerId, message, messageId,
704                     retryCount);
705         } catch (RemoteException e) {
706             throw e.rethrowFromSystemServer();
707         }
708     }
709 
710     /**
711      * @hide
712      */
initiateNanPairingSetupRequest(int clientId, int sessionId, PeerHandle peerHandle, String password, String pairingDeviceAlias, int cipherSuite)713     public void initiateNanPairingSetupRequest(int clientId, int sessionId, PeerHandle peerHandle,
714             String password, String pairingDeviceAlias, int cipherSuite) {
715         if (peerHandle == null) {
716             throw new IllegalArgumentException(
717                     "initiateNanPairingRequest: invalid peerHandle - must be non-null");
718         }
719         if (VDBG) {
720             Log.v(TAG, "initiateNanPairingRequest(): clientId=" + clientId
721                     + ", sessionId=" + sessionId + ", peerHandle=" + peerHandle.peerId);
722         }
723         try {
724             mService.initiateNanPairingSetupRequest(clientId, sessionId, peerHandle.peerId,
725                     password, pairingDeviceAlias, cipherSuite);
726         } catch (RemoteException e) {
727             throw e.rethrowFromSystemServer();
728         }
729     }
730 
731     /**
732      * @hide
733      */
responseNanPairingSetupRequest(int clientId, int sessionId, PeerHandle peerHandle, int requestId, String password, String pairingDeviceAlias, boolean accept, int cipherSuite)734     public void responseNanPairingSetupRequest(int clientId, int sessionId, PeerHandle peerHandle,
735             int requestId, String password, String pairingDeviceAlias, boolean accept,
736             int cipherSuite) {
737         if (peerHandle == null) {
738             throw new IllegalArgumentException(
739                     "initiateNanPairingRequest: invalid peerHandle - must be non-null");
740         }
741         if (VDBG) {
742             Log.v(TAG, "initiateNanPairingRequest(): clientId=" + clientId
743                     + ", sessionId=" + sessionId + ", peerHandle=" + peerHandle.peerId);
744         }
745         try {
746             mService.responseNanPairingSetupRequest(clientId, sessionId, peerHandle.peerId,
747                     requestId, password, pairingDeviceAlias, accept, cipherSuite);
748         } catch (RemoteException e) {
749             throw e.rethrowFromSystemServer();
750         }
751     }
752 
753     /**
754      * @hide
755      */
initiateBootStrappingSetupRequest(int clientId, int sessionId, PeerHandle peerHandle, int method)756     public void initiateBootStrappingSetupRequest(int clientId, int sessionId,
757             PeerHandle peerHandle, int method) {
758         if (peerHandle == null) {
759             throw new IllegalArgumentException(
760                     "initiateBootStrappingSetupRequest: invalid peerHandle - must be non-null");
761         }
762         if (VDBG) {
763             Log.v(TAG, "initiateBootStrappingSetupRequest(): clientId=" + clientId
764                     + ", sessionId=" + sessionId + ", peerHandle=" + peerHandle.peerId);
765         }
766         try {
767             mService.initiateBootStrappingSetupRequest(clientId, sessionId, peerHandle.peerId,
768                     method);
769         } catch (RemoteException e) {
770             throw e.rethrowFromSystemServer();
771         }
772     }
773 
774     /** @hide */
775     @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
requestMacAddresses(int uid, int[] peerIds, IWifiAwareMacAddressProvider callback)776     public void requestMacAddresses(int uid, int[] peerIds,
777             IWifiAwareMacAddressProvider callback) {
778         try {
779             mService.requestMacAddresses(uid, peerIds, callback);
780         } catch (RemoteException e) {
781             throw e.rethrowFromSystemServer();
782         }
783     }
784 
785     /** @hide */
createNetworkSpecifier(int clientId, int role, int sessionId, @NonNull PeerHandle peerHandle, @Nullable byte[] pmk, @Nullable String passphrase)786     public NetworkSpecifier createNetworkSpecifier(int clientId, int role, int sessionId,
787             @NonNull PeerHandle peerHandle, @Nullable byte[] pmk, @Nullable String passphrase) {
788         if (VDBG) {
789             Log.v(TAG, "createNetworkSpecifier: role=" + role + ", sessionId=" + sessionId
790                     + ", peerHandle=" + ((peerHandle == null) ? peerHandle : peerHandle.peerId)
791                     + ", pmk=" + ((pmk == null) ? "null" : "non-null")
792                     + ", passphrase=" + ((passphrase == null) ? "null" : "non-null"));
793         }
794 
795         if (!WifiAwareUtils.isLegacyVersion(mContext, Build.VERSION_CODES.Q)) {
796             throw new UnsupportedOperationException(
797                     "API deprecated - use WifiAwareNetworkSpecifier.Builder");
798         }
799 
800         if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
801                 && role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) {
802             throw new IllegalArgumentException(
803                     "createNetworkSpecifier: Invalid 'role' argument when creating a network "
804                             + "specifier");
805         }
806         if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR || !WifiAwareUtils.isLegacyVersion(mContext,
807                 Build.VERSION_CODES.P)) {
808             if (peerHandle == null) {
809                 throw new IllegalArgumentException(
810                         "createNetworkSpecifier: Invalid peer handle - cannot be null");
811             }
812         }
813 
814         return new WifiAwareNetworkSpecifier(
815                 (peerHandle == null) ? WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB_ANY_PEER
816                         : WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB,
817                 role,
818                 clientId,
819                 sessionId,
820                 peerHandle != null ? peerHandle.peerId : 0, // 0 is an invalid peer ID
821                 null, // peerMac (not used in this method)
822                 pmk,
823                 passphrase,
824                 0, // no port info for deprecated IB APIs
825                 -1); // no transport info for deprecated IB APIs
826     }
827 
828     /** @hide */
createNetworkSpecifier(int clientId, @DataPathRole int role, @NonNull byte[] peer, @Nullable byte[] pmk, @Nullable String passphrase)829     public NetworkSpecifier createNetworkSpecifier(int clientId, @DataPathRole int role,
830             @NonNull byte[] peer, @Nullable byte[] pmk, @Nullable String passphrase) {
831         if (VDBG) {
832             Log.v(TAG, "createNetworkSpecifier: role=" + role
833                     + ", pmk=" + ((pmk == null) ? "null" : "non-null")
834                     + ", passphrase=" + ((passphrase == null) ? "null" : "non-null"));
835         }
836 
837         if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
838                 && role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) {
839             throw new IllegalArgumentException(
840                     "createNetworkSpecifier: Invalid 'role' argument when creating a network "
841                             + "specifier");
842         }
843         if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR || !WifiAwareUtils.isLegacyVersion(mContext,
844                 Build.VERSION_CODES.P)) {
845             if (peer == null) {
846                 throw new IllegalArgumentException(
847                         "createNetworkSpecifier: Invalid peer MAC - cannot be null");
848             }
849         }
850         if (peer != null && peer.length != 6) {
851             throw new IllegalArgumentException("createNetworkSpecifier: Invalid peer MAC address");
852         }
853 
854         return new WifiAwareNetworkSpecifier(
855                 (peer == null) ? WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER
856                         : WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_OOB,
857                 role,
858                 clientId,
859                 0, // 0 is an invalid session ID
860                 0, // 0 is an invalid peer ID
861                 peer,
862                 pmk,
863                 passphrase,
864                 0, // no port info for OOB APIs
865                 -1); // no transport protocol info for OOB APIs
866     }
867 
868     private static class WifiAwareEventCallbackProxy extends IWifiAwareEventCallback.Stub {
869         private final WeakReference<WifiAwareManager> mAwareManager;
870         private final Binder mBinder;
871         private final Executor mExecutor;
872 
873         private final AttachCallback mAttachCallback;
874 
875         private final IdentityChangedListener mIdentityChangedListener;
876 
877         /**
878          * Constructs a {@link AttachCallback} using the specified looper.
879          * All callbacks will delivered on the thread of the specified looper.
880          *
881          * @param executor The executor to execute the callbacks.
882          */
WifiAwareEventCallbackProxy(WifiAwareManager mgr, Executor executor, Binder binder, final AttachCallback attachCallback, final IdentityChangedListener identityChangedListener)883         WifiAwareEventCallbackProxy(WifiAwareManager mgr, Executor executor, Binder binder,
884                 final AttachCallback attachCallback,
885                 final IdentityChangedListener identityChangedListener) {
886             mAwareManager = new WeakReference<>(mgr);
887             mExecutor = executor;
888             mBinder = binder;
889             mAttachCallback = attachCallback;
890             mIdentityChangedListener = identityChangedListener;
891         }
892 
893         @Override
onConnectSuccess(int clientId)894         public void onConnectSuccess(int clientId) {
895             if (VDBG) Log.v(TAG, "onConnectSuccess");
896             Binder.clearCallingIdentity();
897             mExecutor.execute(() -> {
898                 WifiAwareManager mgr = mAwareManager.get();
899                 if (mgr == null) {
900                     Log.w(TAG, "WifiAwareEventCallbackProxy: handleMessage post GC");
901                     return;
902                 }
903                 mAttachCallback.onAttached(new WifiAwareSession(mgr, mBinder, clientId));
904             });
905         }
906 
907         @Override
onConnectFail(int reason)908         public void onConnectFail(int reason) {
909             if (VDBG) Log.v(TAG, "onConnectFail: reason=" + reason);
910             Binder.clearCallingIdentity();
911             mExecutor.execute(() -> {
912                 WifiAwareManager mgr = mAwareManager.get();
913                 if (mgr == null) {
914                     Log.w(TAG, "WifiAwareEventCallbackProxy: handleMessage post GC");
915                     return;
916                 }
917                 mAwareManager.clear();
918                 mAttachCallback.onAttachFailed();
919             });
920         }
921 
922         @Override
onIdentityChanged(byte[] mac)923         public void onIdentityChanged(byte[] mac) {
924             if (VDBG) Log.v(TAG, "onIdentityChanged: mac=" + new String(HexEncoding.encode(mac)));
925             Binder.clearCallingIdentity();
926             mExecutor.execute(() -> {
927                 WifiAwareManager mgr = mAwareManager.get();
928                 if (mgr == null) {
929                     Log.w(TAG, "WifiAwareEventCallbackProxy: handleMessage post GC");
930                     return;
931                 }
932                 if (mIdentityChangedListener == null) {
933                     Log.e(TAG, "CALLBACK_IDENTITY_CHANGED: null listener.");
934                 } else {
935                     mIdentityChangedListener.onIdentityChanged(mac);
936                 }
937             });
938         }
939 
940         @Override
onAttachTerminate()941         public void onAttachTerminate() {
942             if (VDBG) Log.v(TAG, "onAwareSessionTerminated");
943             Binder.clearCallingIdentity();
944             mExecutor.execute(() -> {
945                 WifiAwareManager mgr = mAwareManager.get();
946                 if (mgr == null) {
947                     Log.w(TAG, "WifiAwareEventCallbackProxy: handleMessage post GC");
948                     return;
949                 }
950                 mAwareManager.clear();
951                 mAttachCallback.onAwareSessionTerminated();
952             });
953         }
954 
955         @Override
onClusterIdChanged( @dentityChangedListener.ClusterChangeEvent int clusterEventType, byte[] clusterId)956         public void onClusterIdChanged(
957                 @IdentityChangedListener.ClusterChangeEvent int clusterEventType,
958                 byte[] clusterId) {
959             Binder.clearCallingIdentity();
960             mExecutor.execute(() -> {
961                 WifiAwareManager mgr = mAwareManager.get();
962                 if (mgr == null) {
963                     Log.w(TAG, "WifiAwareEventCallbackProxy: handleMessage post GC");
964                     return;
965                 }
966                 if (mIdentityChangedListener == null) {
967                     Log.e(TAG, "CALLBACK_CLUSTER_ID_CHANGED: null listener.");
968                 } else {
969                     try {
970                         mIdentityChangedListener.onClusterIdChanged(
971                                 clusterEventType, MacAddress.fromBytes(clusterId));
972                     } catch (IllegalArgumentException iae) {
973                         Log.e(TAG, " Invalid MAC address, " + iae);
974                     }
975                 }
976             });
977         }
978     }
979 
980     private static class WifiAwareDiscoverySessionCallbackProxy extends
981             IWifiAwareDiscoverySessionCallback.Stub {
982         private final WeakReference<WifiAwareManager> mAwareManager;
983         private final boolean mIsPublish;
984         private final DiscoverySessionCallback mOriginalCallback;
985         private final int mClientId;
986 
987         private final Handler mHandler;
988         private DiscoverySession mSession;
989 
WifiAwareDiscoverySessionCallbackProxy(WifiAwareManager mgr, Looper looper, boolean isPublish, DiscoverySessionCallback originalCallback, int clientId)990         WifiAwareDiscoverySessionCallbackProxy(WifiAwareManager mgr, Looper looper,
991                 boolean isPublish, DiscoverySessionCallback originalCallback,
992                 int clientId) {
993             mAwareManager = new WeakReference<>(mgr);
994             mIsPublish = isPublish;
995             mOriginalCallback = originalCallback;
996             mClientId = clientId;
997 
998             if (VDBG) {
999                 Log.v(TAG, "WifiAwareDiscoverySessionCallbackProxy ctor: isPublish=" + isPublish);
1000             }
1001 
1002             mHandler = new Handler(looper);
1003         }
1004 
1005         @Override
onSessionStarted(int sessionId)1006         public void onSessionStarted(int sessionId) {
1007             if (VDBG) Log.v(TAG, "onSessionStarted: sessionId=" + sessionId);
1008             mHandler.post(() -> onProxySessionStarted(sessionId));
1009         }
1010 
1011         @Override
onSessionConfigSuccess()1012         public void onSessionConfigSuccess() {
1013             if (VDBG) Log.v(TAG, "onSessionConfigSuccess");
1014             mHandler.post(mOriginalCallback::onSessionConfigUpdated);
1015         }
1016 
1017         @Override
onSessionConfigFail(int reason)1018         public void onSessionConfigFail(int reason) {
1019             if (VDBG) Log.v(TAG, "onSessionConfigFail: reason=" + reason);
1020             mHandler.post(() -> {
1021                 mOriginalCallback.onSessionConfigFailed();
1022                 if (mSession == null) {
1023                     /* creation failed (as opposed to update failing) */
1024                     mAwareManager.clear();
1025                 }
1026             });
1027         }
1028 
1029         @Override
onSessionTerminated(int reason)1030         public void onSessionTerminated(int reason) {
1031             if (VDBG) Log.v(TAG, "onSessionTerminated: reason=" + reason);
1032             mHandler.post(() -> onProxySessionTerminated(reason));
1033         }
1034 
1035         @Override
onSessionSuspendSucceeded()1036         public void onSessionSuspendSucceeded() {
1037             if (VDBG) Log.v(TAG, "onSessionSuspendSucceeded");
1038             mHandler.post(mOriginalCallback::onSessionSuspendSucceeded);
1039         }
1040 
1041         @Override
onSessionSuspendFail(int reason)1042         public void onSessionSuspendFail(int reason) {
1043             if (VDBG) Log.v(TAG, "onSessionSuspendFail: reason=" + reason);
1044             mHandler.post(() -> mOriginalCallback.onSessionSuspendFailed(reason));
1045         }
1046 
1047         @Override
onSessionResumeSucceeded()1048         public void onSessionResumeSucceeded() {
1049             if (VDBG) Log.v(TAG, "onSessionResumeSucceeded");
1050             mHandler.post(mOriginalCallback::onSessionResumeSucceeded);
1051         }
1052 
1053         @Override
onSessionResumeFail(int reason)1054         public void onSessionResumeFail(int reason) {
1055             if (VDBG) Log.v(TAG, "onSessionResumeFail: reason=" + reason);
1056             mHandler.post(() -> mOriginalCallback.onSessionResumeFailed(reason));
1057         }
1058 
1059         @Override
onMatch(int peerId, byte[] serviceSpecificInfo, byte[] matchFilter, int peerCipherSuite, byte[] scid, String pairingAlias, AwarePairingConfig pairingConfig)1060         public void onMatch(int peerId, byte[] serviceSpecificInfo, byte[] matchFilter,
1061                 int peerCipherSuite, byte[] scid, String pairingAlias,
1062                 AwarePairingConfig pairingConfig) {
1063             if (VDBG) Log.v(TAG, "onMatch: peerId=" + peerId);
1064 
1065             mHandler.post(() -> {
1066                 List<byte[]> matchFilterList = getMatchFilterList(matchFilter);
1067                 mOriginalCallback.onServiceDiscovered(new PeerHandle(peerId), serviceSpecificInfo,
1068                         matchFilterList);
1069                 mOriginalCallback.onServiceDiscovered(
1070                         new ServiceDiscoveryInfo(new PeerHandle(peerId), peerCipherSuite,
1071                                 serviceSpecificInfo, matchFilterList, scid, pairingAlias,
1072                                 pairingConfig));
1073             });
1074         }
1075 
getMatchFilterList(byte[] matchFilter)1076         private List<byte[]> getMatchFilterList(byte[] matchFilter) {
1077             List<byte[]> matchFilterList = null;
1078             try {
1079                 matchFilterList = new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList();
1080             } catch (BufferOverflowException e) {
1081                 matchFilterList = Collections.emptyList();
1082                 Log.e(TAG, "onServiceDiscovered: invalid match filter byte array '"
1083                         + new String(HexEncoding.encode(matchFilter))
1084                         + "' - cannot be parsed: e=" + e);
1085             }
1086             return matchFilterList;
1087         }
1088 
1089         @Override
onMatchWithDistance(int peerId, byte[] serviceSpecificInfo, byte[] matchFilter, int distanceMm, int peerCipherSuite, byte[] scid, String pairingAlias, AwarePairingConfig pairingConfig)1090         public void onMatchWithDistance(int peerId, byte[] serviceSpecificInfo, byte[] matchFilter,
1091                 int distanceMm, int peerCipherSuite, byte[] scid, String pairingAlias,
1092                 AwarePairingConfig pairingConfig) {
1093             if (VDBG) {
1094                 Log.v(TAG, "onMatchWithDistance: peerId=" + peerId + ", distanceMm=" + distanceMm);
1095             }
1096             mHandler.post(() -> {
1097                 List<byte[]> matchFilterList = getMatchFilterList(matchFilter);
1098                 mOriginalCallback.onServiceDiscoveredWithinRange(
1099                         new PeerHandle(peerId),
1100                         serviceSpecificInfo,
1101                         matchFilterList, distanceMm);
1102                 mOriginalCallback.onServiceDiscoveredWithinRange(
1103                         new ServiceDiscoveryInfo(
1104                                 new PeerHandle(peerId),
1105                                 peerCipherSuite,
1106                                 serviceSpecificInfo,
1107                                 matchFilterList,
1108                                 scid,
1109                                 pairingAlias,
1110                                 pairingConfig),
1111                         distanceMm);
1112             });
1113         }
1114         @Override
onMatchExpired(int peerId)1115         public void onMatchExpired(int peerId) {
1116             if (VDBG) {
1117                 Log.v(TAG, "onMatchExpired: peerId=" + peerId);
1118             }
1119             mHandler.post(() ->
1120                     mOriginalCallback.onServiceLost(new PeerHandle(peerId),
1121                             WIFI_AWARE_DISCOVERY_LOST_REASON_PEER_NOT_VISIBLE));
1122         }
1123 
1124         @Override
onMessageSendSuccess(int messageId)1125         public void onMessageSendSuccess(int messageId) {
1126             if (VDBG) Log.v(TAG, "onMessageSendSuccess");
1127             mHandler.post(() -> mOriginalCallback.onMessageSendSucceeded(messageId));
1128         }
1129 
1130         @Override
onMessageSendFail(int messageId, int reason)1131         public void onMessageSendFail(int messageId, int reason) {
1132             if (VDBG) Log.v(TAG, "onMessageSendFail: reason=" + reason);
1133             mHandler.post(() -> mOriginalCallback.onMessageSendFailed(messageId));
1134         }
1135 
1136         @Override
onMessageReceived(int peerId, byte[] message)1137         public void onMessageReceived(int peerId, byte[] message) {
1138             if (VDBG) {
1139                 Log.v(TAG, "onMessageReceived: peerId=" + peerId);
1140             }
1141             mHandler.post(() -> mOriginalCallback.onMessageReceived(new PeerHandle(peerId),
1142                     message));
1143         }
1144 
1145         @Override
onPairingSetupRequestReceived(int peerId, int requestId)1146         public void onPairingSetupRequestReceived(int peerId, int requestId) {
1147             mHandler.post(() ->
1148                     mOriginalCallback.onPairingSetupRequestReceived(new PeerHandle(peerId),
1149                             requestId));
1150         }
1151         @Override
onPairingSetupConfirmed(int peerId, boolean accept, String alias)1152         public void onPairingSetupConfirmed(int peerId, boolean accept, String alias) {
1153             if (accept) {
1154                 mHandler.post(() -> mOriginalCallback
1155                         .onPairingSetupSucceeded(new PeerHandle(peerId), alias));
1156             } else {
1157                 mHandler.post(() -> mOriginalCallback
1158                         .onPairingSetupFailed(new PeerHandle(peerId)));
1159             }
1160         }
1161         @Override
onPairingVerificationConfirmed(int peerId, boolean accept, String alias)1162         public void onPairingVerificationConfirmed(int peerId, boolean accept, String alias) {
1163             if (accept) {
1164                 mHandler.post(() -> mOriginalCallback.onPairingVerificationSucceed(
1165                         new PeerHandle(peerId), alias));
1166             } else {
1167                 mHandler.post(() -> mOriginalCallback
1168                         .onPairingVerificationFailed(new PeerHandle(peerId)));
1169             }
1170         }
1171         @Override
onBootstrappingVerificationConfirmed(int peerId, boolean accept, int method)1172         public void onBootstrappingVerificationConfirmed(int peerId, boolean accept, int method) {
1173             if (accept) {
1174                 mHandler.post(() -> mOriginalCallback.onBootstrappingSucceeded(
1175                         new PeerHandle(peerId), method));
1176             } else {
1177                 mHandler.post(() -> mOriginalCallback.onBootstrappingFailed(
1178                         new PeerHandle(peerId)));
1179             }
1180         }
1181 
1182         /*
1183          * Proxies methods
1184          */
onProxySessionStarted(int sessionId)1185         public void onProxySessionStarted(int sessionId) {
1186             if (VDBG) Log.v(TAG, "Proxy: onSessionStarted: sessionId=" + sessionId);
1187             if (mSession != null) {
1188                 Log.e(TAG,
1189                         "onSessionStarted: sessionId=" + sessionId + ": session already created!?");
1190                 throw new IllegalStateException(
1191                         "onSessionStarted: sessionId=" + sessionId + ": session already created!?");
1192             }
1193 
1194             WifiAwareManager mgr = mAwareManager.get();
1195             if (mgr == null) {
1196                 Log.w(TAG, "onProxySessionStarted: mgr GC'd");
1197                 return;
1198             }
1199 
1200             if (mIsPublish) {
1201                 PublishDiscoverySession session = new PublishDiscoverySession(mgr,
1202                         mClientId, sessionId);
1203                 mSession = session;
1204                 mOriginalCallback.onPublishStarted(session);
1205             } else {
1206                 SubscribeDiscoverySession
1207                         session = new SubscribeDiscoverySession(mgr, mClientId, sessionId);
1208                 mSession = session;
1209                 mOriginalCallback.onSubscribeStarted(session);
1210             }
1211         }
1212 
onProxySessionTerminated(int reason)1213         public void onProxySessionTerminated(int reason) {
1214             if (VDBG) Log.v(TAG, "Proxy: onSessionTerminated: reason=" + reason);
1215             if (mSession != null) {
1216                 mSession.setTerminated();
1217                 mSession = null;
1218             } else {
1219                 Log.w(TAG, "Proxy: onSessionTerminated called but mSession is null!?");
1220             }
1221             mAwareManager.clear();
1222             mOriginalCallback.onSessionTerminated();
1223         }
1224     }
1225 
1226     /**
1227      * Set Wi-Fi Aware protocol parameters.
1228      * @hide
1229      * @param params An object contain specified parameters. Use {@code null} to remove previously
1230      *               set configuration and restore default behavior.
1231      */
1232     @SystemApi
1233     @RequiresPermission(allOf = {OVERRIDE_WIFI_CONFIG,
1234             CHANGE_WIFI_STATE})
setAwareParams(@ullable AwareParams params)1235     public void setAwareParams(@Nullable AwareParams params) {
1236         try {
1237             mService.setAwareParams(params);
1238         } catch (RemoteException e) {
1239             throw e.rethrowFromSystemServer();
1240         }
1241     }
1242 
1243     /**
1244      *  Set all Wi-Fi Aware sessions created by the calling app to be opportunistic. Opportunistic
1245      *  Wi-Fi Aware sessions are considered low priority and may be torn down (the sessions or the
1246      *  Aware interface) if there are resource conflicts.
1247      *
1248      * @param enabled True to configure all Wi-Fi Aware sessions by the calling app as
1249      *                Opportunistic. False by default.
1250      */
1251     @RequiresPermission(CHANGE_WIFI_STATE)
setOpportunisticModeEnabled(boolean enabled)1252     public void setOpportunisticModeEnabled(boolean enabled) {
1253         try {
1254             mService.setOpportunisticModeEnabled(mContext.getOpPackageName(), enabled);
1255         } catch (RemoteException e) {
1256             throw e.rethrowFromSystemServer();
1257         }
1258     }
1259 
1260     /**
1261      * Indicate whether all Wi-Fi Aware sessions created by the calling app are opportunistic as
1262      * defined and configured by {@link #setOpportunisticModeEnabled(boolean)}
1263      *
1264      * @param executor The executor on which callback will be invoked.
1265      * @param resultsCallback An asynchronous callback that will return boolean
1266      */
1267     @RequiresPermission(ACCESS_WIFI_STATE)
isOpportunisticModeEnabled(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Boolean> resultsCallback)1268     public void isOpportunisticModeEnabled(@NonNull @CallbackExecutor Executor executor,
1269             @NonNull Consumer<Boolean> resultsCallback) {
1270         Objects.requireNonNull(executor, "executor cannot be null");
1271         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
1272 
1273         try {
1274             mService.isOpportunisticModeEnabled(mContext.getOpPackageName(),
1275                     new IBooleanListener.Stub() {
1276                         @Override
1277                         public void onResult(boolean value) {
1278                             Binder.clearCallingIdentity();
1279                             executor.execute(() -> {
1280                                 resultsCallback.accept(value);
1281                             });
1282                         }
1283                     });
1284         } catch (RemoteException e) {
1285             throw e.rethrowFromSystemServer();
1286         }
1287     }
1288 
1289     /**
1290      * Reset all paired devices setup by the caller by
1291      * {@link DiscoverySession#initiatePairingRequest(PeerHandle, String, int, String)} and
1292      * {@link DiscoverySession#acceptPairingRequest(int, PeerHandle, String, int, String)}
1293      */
1294     @RequiresPermission(CHANGE_WIFI_STATE)
resetPairedDevices()1295     public void resetPairedDevices() {
1296         try {
1297             mService.resetPairedDevices(mContext.getOpPackageName());
1298         } catch (RemoteException e) {
1299             throw e.rethrowFromSystemServer();
1300         }
1301     }
1302 
1303     /**
1304      * Remove the target paired device setup by the caller by
1305      * {@link DiscoverySession#initiatePairingRequest(PeerHandle, String, int, String)} and
1306      * {@link DiscoverySession#acceptPairingRequest(int, PeerHandle, String, int, String)}
1307      * @param alias The alias set by the caller
1308      */
1309     @RequiresPermission(CHANGE_WIFI_STATE)
removePairedDevice(@onNull String alias)1310     public void removePairedDevice(@NonNull String alias) {
1311         try {
1312             mService.removePairedDevice(mContext.getOpPackageName(), alias);
1313         } catch (RemoteException e) {
1314             throw e.rethrowFromSystemServer();
1315         }
1316     }
1317 
1318     /**
1319      * Get all the paired devices configured by the calling app.
1320      * @param executor The executor on which callback will be invoked.
1321      * @param resultsCallback An asynchronous callback that will return a list of paired devices'
1322      *                        alias
1323      */
1324     @RequiresPermission(ACCESS_WIFI_STATE)
getPairedDevices(@onNull Executor executor, @NonNull Consumer<List<String>> resultsCallback)1325     public void getPairedDevices(@NonNull Executor executor,
1326             @NonNull Consumer<List<String>> resultsCallback) {
1327         Objects.requireNonNull(executor, "executor cannot be null");
1328         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
1329         try {
1330             mService.getPairedDevices(
1331                     mContext.getOpPackageName(),
1332                     new IListListener.Stub() {
1333                         public void onResult(List value) {
1334                             Binder.clearCallingIdentity();
1335                             executor.execute(() -> resultsCallback.accept(value));
1336                         }
1337                     });
1338         } catch (RemoteException e) {
1339             throw e.rethrowFromSystemServer();
1340         }
1341     }
1342 
1343     /**
1344      * @hide
1345      */
suspend(int clientId, int sessionId)1346     public void suspend(int clientId, int sessionId) {
1347         try {
1348             mService.suspend(clientId, sessionId);
1349         } catch (RemoteException e) {
1350             throw e.rethrowFromSystemServer();
1351         }
1352     }
1353 
1354     /**
1355      * @hide
1356      */
resume(int clientId, int sessionId)1357     public void resume(int clientId, int sessionId) {
1358         try {
1359             mService.resume(clientId, sessionId);
1360         } catch (RemoteException e) {
1361             throw e.rethrowFromSystemServer();
1362         }
1363     }
1364     /**
1365      * Attach to the Wi-Fi Aware service as an offload session. All discovery sessions and
1366      * connections will be handled via out-of-band connections.
1367      * The Aware session created by this attach method will have the lowest priority when resource
1368      * conflicts arise (e.g. Aware has to be torn down to create other WiFi interfaces).
1369      *
1370      * @param executor       The executor to execute the listener of the {@code attachCallback}
1371      *                       object.
1372      * @param attachCallback A callback for attach events, extended from
1373      *                       {@link AttachCallback}.
1374      * @hide
1375      * @see #attach(AttachCallback, Handler)
1376      */
1377     @SystemApi
1378     @RequiresPermission(allOf = {ACCESS_WIFI_STATE, CHANGE_WIFI_STATE, OVERRIDE_WIFI_CONFIG})
attachOffload(@onNull @allbackExecutor Executor executor, @NonNull AttachCallback attachCallback)1379     public void attachOffload(@NonNull @CallbackExecutor Executor executor,
1380             @NonNull AttachCallback attachCallback) {
1381         if (executor == null) {
1382             throw new IllegalArgumentException("Null executor provided");
1383         }
1384         attach(null, null, attachCallback, null, true, executor);
1385     }
1386 
1387 }
1388