• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.rtt;
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.LOCATION_HARDWARE;
23 import static android.Manifest.permission.NEARBY_WIFI_DEVICES;
24 
25 import android.annotation.CallbackExecutor;
26 import android.annotation.NonNull;
27 import android.annotation.Nullable;
28 import android.annotation.RequiresPermission;
29 import android.annotation.SdkConstant;
30 import android.annotation.StringDef;
31 import android.annotation.SystemApi;
32 import android.annotation.SystemService;
33 import android.content.Context;
34 import android.net.wifi.ScanResult;
35 import android.net.wifi.WifiManager;
36 import android.os.Binder;
37 import android.os.Bundle;
38 import android.os.RemoteException;
39 import android.os.WorkSource;
40 import android.util.Log;
41 
42 import com.android.modules.utils.build.SdkLevel;
43 
44 import java.lang.annotation.Retention;
45 import java.lang.annotation.RetentionPolicy;
46 import java.util.List;
47 import java.util.concurrent.Executor;
48 
49 /**
50  * This class provides the primary API for measuring distance (range) to other devices using the
51  * IEEE 802.11mc Wi-Fi Round Trip Time (RTT) technology.
52  * <p>
53  * The devices which can be ranged include:
54  * <li>Access Points (APs)
55  * <li>Wi-Fi Aware peers
56  * <p>
57  * Ranging requests are triggered using
58  * {@link #startRanging(RangingRequest, Executor, RangingResultCallback)}. Results (in case of
59  * successful operation) are returned in the {@link RangingResultCallback#onRangingResults(List)}
60  * callback.
61  * <p>
62  *     Wi-Fi RTT may not be usable at some points, e.g. when Wi-Fi is disabled. To validate that
63  *     the functionality is available use the {@link #isAvailable()} function. To track
64  *     changes in RTT usability register for the {@link #ACTION_WIFI_RTT_STATE_CHANGED}
65  *     broadcast. Note that this broadcast is not sticky - you should register for it and then
66  *     check the above API to avoid a race condition.
67  */
68 @SystemService(Context.WIFI_RTT_RANGING_SERVICE)
69 public class WifiRttManager {
70     private static final String TAG = "WifiRttManager";
71     private static final boolean VDBG = false;
72 
73     private final Context mContext;
74     private final IWifiRttManager mService;
75 
76     /**
77      * Broadcast intent action to indicate that the state of Wi-Fi RTT availability has changed.
78      * Use the {@link #isAvailable()} to query the current status.
79      * This broadcast is <b>not</b> sticky, use the {@link #isAvailable()} API after registering
80      * the broadcast to check the current state of Wi-Fi RTT.
81      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
82      * components will be launched.
83      */
84     @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
85     public static final String ACTION_WIFI_RTT_STATE_CHANGED =
86             "android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED";
87 
88     /**
89      * Bundle key to access if one-sided Wi-Fi RTT is supported. When it is not supported, only
90      * two-sided RTT can be performed, which requires responder supports IEEE 802.11mc and this can
91      * be determined by the method {@link ScanResult#is80211mcResponder()}
92      */
93     public static final String CHARACTERISTICS_KEY_BOOLEAN_ONE_SIDED_RTT = "key_one_sided_rtt";
94      /**
95      * Bundle key to access if getting the Location Configuration Information(LCI) from responder is
96       * supported.
97      * @see ResponderLocation
98      */
99     public static final String CHARACTERISTICS_KEY_BOOLEAN_LCI = "key_lci";
100     /**
101      * Bundle key to access if getting the Location Civic Report(LCR) from responder is supported.
102      * @see ResponderLocation
103      */
104     public static final String CHARACTERISTICS_KEY_BOOLEAN_LCR = "key_lcr";
105 
106     /**
107      * Bundle key to access if device supports to be a responder in station mode
108      */
109     public static final String CHARACTERISTICS_KEY_BOOLEAN_STA_RESPONDER = "key_sta_responder";
110 
111     /** @hide */
112     @StringDef(prefix = { "CHARACTERISTICS_KEY_"}, value = {
113             CHARACTERISTICS_KEY_BOOLEAN_ONE_SIDED_RTT,
114             CHARACTERISTICS_KEY_BOOLEAN_LCI,
115             CHARACTERISTICS_KEY_BOOLEAN_LCR,
116             CHARACTERISTICS_KEY_BOOLEAN_STA_RESPONDER,
117     })
118     @Retention(RetentionPolicy.SOURCE)
119     public @interface RttCharacteristicsKey {}
120 
121     /** @hide */
WifiRttManager(@onNull Context context, @NonNull IWifiRttManager service)122     public WifiRttManager(@NonNull Context context, @NonNull IWifiRttManager service) {
123         mContext = context;
124         mService = service;
125     }
126 
127     /**
128      * Returns the current status of RTT API: whether or not RTT is available. To track
129      * changes in the state of RTT API register for the
130      * {@link #ACTION_WIFI_RTT_STATE_CHANGED} broadcast.
131      * <p>Note: availability of RTT does not mean that the app can use the API. The app's
132      * permissions and platform Location Mode are validated at run-time.
133      *
134      * @return A boolean indicating whether the app can use the RTT API at this time (true) or
135      * not (false).
136      */
isAvailable()137     public boolean isAvailable() {
138         try {
139             return mService.isAvailable();
140         } catch (RemoteException e) {
141             throw e.rethrowFromSystemServer();
142         }
143     }
144 
145     /**
146      * Initiate a request to range to a set of devices specified in the {@link RangingRequest}.
147      * Results will be returned in the {@link RangingResultCallback} set of callbacks.
148      * <p>
149      * Ranging request with only Wifi Aware peers can be performed with either
150      * {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
151      * android:usesPermissionFlags="neverForLocation", or
152      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}. All other types of ranging requests
153      * require {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
154      *
155      * @param request  A request specifying a set of devices whose distance measurements are
156      *                 requested.
157      * @param executor The Executor on which to run the callback.
158      * @param callback A callback for the result of the ranging request.
159      */
160     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, CHANGE_WIFI_STATE, ACCESS_WIFI_STATE,
161             NEARBY_WIFI_DEVICES})
startRanging(@onNull RangingRequest request, @NonNull @CallbackExecutor Executor executor, @NonNull RangingResultCallback callback)162     public void startRanging(@NonNull RangingRequest request,
163             @NonNull @CallbackExecutor Executor executor, @NonNull RangingResultCallback callback) {
164         startRanging(null, request, executor, callback);
165     }
166 
167     /**
168      * Initiate a request to range to a set of devices specified in the {@link RangingRequest}.
169      * Results will be returned in the {@link RangingResultCallback} set of callbacks.
170      * <p>
171      * Ranging request with only Wifi Aware peers can be performed with either
172      * {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
173      * android:usesPermissionFlags="neverForLocation", or
174      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}. All other types of ranging requests
175      * require {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
176      *
177      * @param workSource A mechanism to specify an alternative work-source for the request.
178      * @param request  A request specifying a set of devices whose distance measurements are
179      *                 requested.
180      * @param executor The Executor on which to run the callback.
181      * @param callback A callback for the result of the ranging request.
182      *
183      * @hide
184      */
185     @SystemApi
186     @RequiresPermission(allOf = {LOCATION_HARDWARE, ACCESS_FINE_LOCATION, CHANGE_WIFI_STATE,
187             ACCESS_WIFI_STATE, NEARBY_WIFI_DEVICES}, conditional = true)
startRanging(@ullable WorkSource workSource, @NonNull RangingRequest request, @NonNull @CallbackExecutor Executor executor, @NonNull RangingResultCallback callback)188     public void startRanging(@Nullable WorkSource workSource, @NonNull RangingRequest request,
189             @NonNull @CallbackExecutor Executor executor, @NonNull RangingResultCallback callback) {
190         if (VDBG) {
191             Log.v(TAG, "startRanging: workSource=" + workSource + ", request=" + request
192                     + ", callback=" + callback + ", executor=" + executor);
193         }
194 
195         if (executor == null) {
196             throw new IllegalArgumentException("Null executor provided");
197         }
198         if (callback == null) {
199             throw new IllegalArgumentException("Null callback provided");
200         }
201 
202         Binder binder = new Binder();
203         try {
204             Bundle extras = new Bundle();
205             if (SdkLevel.isAtLeastS()) {
206                 extras.putParcelable(WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
207                         mContext.getAttributionSource());
208             }
209             mService.startRanging(binder, mContext.getOpPackageName(),
210                     mContext.getAttributionTag(), workSource, request, new IRttCallback.Stub() {
211                         @Override
212                         public void onRangingFailure(int status) throws RemoteException {
213                             clearCallingIdentity();
214                             executor.execute(() -> callback.onRangingFailure(status));
215                         }
216 
217                         @Override
218                         public void onRangingResults(List<RangingResult> results)
219                                 throws RemoteException {
220                             clearCallingIdentity();
221                             executor.execute(() -> callback.onRangingResults(results));
222                         }
223                     }, extras);
224         } catch (RemoteException e) {
225             throw e.rethrowFromSystemServer();
226         }
227     }
228 
229     /**
230      * Cancel all ranging requests for the specified work sources. The requests have been requested
231      * using {@link #startRanging(WorkSource, RangingRequest, Executor, RangingResultCallback)}.
232      *
233      * @param workSource The work-sources of the requesters.
234      *
235      * @hide
236      */
237     @SystemApi
238     @RequiresPermission(allOf = {LOCATION_HARDWARE})
cancelRanging(@ullable WorkSource workSource)239     public void cancelRanging(@Nullable WorkSource workSource) {
240         if (VDBG) {
241             Log.v(TAG, "cancelRanging: workSource=" + workSource);
242         }
243 
244         try {
245             mService.cancelRanging(workSource);
246         } catch (RemoteException e) {
247             throw e.rethrowFromSystemServer();
248         }
249     }
250 
251     /**
252      * Returns a Bundle which represents the characteristics of the Wi-Fi RTT interface: a set of
253      * parameters which specify feature support. Each parameter can be accessed by the specified
254      * Bundle key, one of the {@code CHARACTERISTICS_KEY_*} value.
255      * <p>
256      * May return an empty Bundle if the Wi-Fi RTT service is not initialized.
257      *
258      * @return A Bundle specifying feature support of RTT.
259      */
260     @RequiresPermission(ACCESS_WIFI_STATE)
261     @NonNull
getRttCharacteristics()262     public Bundle getRttCharacteristics() {
263         try {
264             return mService.getRttCharacteristics();
265         } catch (RemoteException e) {
266             throw e.rethrowFromSystemServer();
267         }
268     }
269 }
270