WifiRttManager.java revision 4250e786ad80007024640abbc03d8d3e1186fdb6
1package android.net.wifi.rtt;
2
3import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
4import static android.Manifest.permission.ACCESS_WIFI_STATE;
5import static android.Manifest.permission.CHANGE_WIFI_STATE;
6import static android.Manifest.permission.LOCATION_HARDWARE;
7
8import android.annotation.Nullable;
9import android.annotation.RequiresPermission;
10import android.annotation.SdkConstant;
11import android.annotation.SystemApi;
12import android.annotation.SystemService;
13import android.content.Context;
14import android.os.Binder;
15import android.os.Handler;
16import android.os.Looper;
17import android.os.RemoteException;
18import android.os.WorkSource;
19import android.util.Log;
20
21import java.util.List;
22
23/**
24 * This class provides the primary API for measuring distance (range) to other devices using the
25 * IEEE 802.11mc Wi-Fi Round Trip Time (RTT) technology.
26 * <p>
27 * The devices which can be ranged include:
28 * <li>Access Points (APs)
29 * <li>Wi-Fi Aware peers
30 * <p>
31 * Ranging requests are triggered using
32 * {@link #startRanging(RangingRequest, RangingResultCallback, Handler)}. Results (in case of
33 * successful operation) are returned in the {@link RangingResultCallback#onRangingResults(List)}
34 * callback.
35 * <p>
36 *     Wi-Fi RTT may not be usable at some points, e.g. when Wi-Fi is disabled. To validate that
37 *     the functionality is available use the {@link #isAvailable()} function. To track
38 *     changes in RTT usability register for the {@link #ACTION_WIFI_RTT_STATE_CHANGED}
39 *     broadcast. Note that this broadcast is not sticky - you should register for it and then
40 *     check the above API to avoid a race condition.
41 *
42 * @hide RTT_API
43 */
44@SystemService(Context.WIFI_RTT2_SERVICE)
45public class WifiRttManager {
46    private static final String TAG = "WifiRttManager";
47    private static final boolean VDBG = true;
48
49    private final Context mContext;
50    private final IWifiRttManager mService;
51
52    /**
53     * Broadcast intent action to indicate that the state of Wi-Fi RTT availability has changed.
54     * Use the {@link #isAvailable()} to query the current status.
55     * This broadcast is <b>not</b> sticky, use the {@link #isAvailable()} API after registering
56     * the broadcast to check the current state of Wi-Fi RTT.
57     * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
58     * components will be launched.
59     */
60    @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
61    public static final String ACTION_WIFI_RTT_STATE_CHANGED =
62            "android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED";
63
64    /** @hide */
65    public WifiRttManager(Context context, IWifiRttManager service) {
66        mContext = context;
67        mService = service;
68    }
69
70    /**
71     * Returns the current status of RTT API: whether or not RTT is available. To track
72     * changes in the state of RTT API register for the
73     * {@link #ACTION_WIFI_RTT_STATE_CHANGED} broadcast.
74     *
75     * @return A boolean indicating whether the app can use the RTT API at this time (true) or
76     * not (false).
77     */
78    public boolean isAvailable() {
79        try {
80            return mService.isAvailable();
81        } catch (RemoteException e) {
82            throw e.rethrowFromSystemServer();
83        }
84    }
85
86    /**
87     * Initiate a request to range to a set of devices specified in the {@link RangingRequest}.
88     * Results will be returned in the {@link RangingResultCallback} set of callbacks.
89     *
90     * @param request  A request specifying a set of devices whose distance measurements are
91     *                 requested.
92     * @param callback A callback for the result of the ranging request.
93     * @param handler  The Handler on whose thread to execute the callbacks of the {@code
94     *                 callback} object. If a null is provided then the application's main thread
95     *                 will be used.
96     */
97    @RequiresPermission(allOf = {ACCESS_COARSE_LOCATION, CHANGE_WIFI_STATE, ACCESS_WIFI_STATE})
98    public void startRanging(RangingRequest request, RangingResultCallback callback,
99            @Nullable Handler handler) {
100        startRanging(null, request, callback, handler);
101    }
102
103    /**
104     * Initiate a request to range to a set of devices specified in the {@link RangingRequest}.
105     * Results will be returned in the {@link RangingResultCallback} set of callbacks.
106     *
107     * @param workSource A mechanism to specify an alternative work-source for the request.
108     * @param request  A request specifying a set of devices whose distance measurements are
109     *                 requested.
110     * @param callback A callback for the result of the ranging request.
111     * @param handler  The Handler on whose thread to execute the callbacks of the {@code
112     *                 callback} object. If a null is provided then the application's main thread
113     *                 will be used.
114     *
115     * @hide (@SystemApi)
116     */
117    @RequiresPermission(allOf = {LOCATION_HARDWARE, ACCESS_COARSE_LOCATION, CHANGE_WIFI_STATE,
118            ACCESS_WIFI_STATE})
119    public void startRanging(@Nullable WorkSource workSource, RangingRequest request,
120            RangingResultCallback callback, @Nullable Handler handler) {
121        if (VDBG) {
122            Log.v(TAG, "startRanging: workSource=" + workSource + ", request=" + request
123                    + ", callback=" + callback + ", handler=" + handler);
124        }
125
126        Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
127        Binder binder = new Binder();
128        try {
129            mService.startRanging(binder, mContext.getOpPackageName(), workSource, request,
130                    new RttCallbackProxy(looper, callback));
131        } catch (RemoteException e) {
132            throw e.rethrowFromSystemServer();
133        }
134    }
135
136    /**
137     * Cancel all ranging requests for the specified work sources. The requests have been requested
138     * using {@link #startRanging(WorkSource, RangingRequest, RangingResultCallback, Handler)}.
139     *
140     * @param workSource The work-sources of the requesters.
141     *
142     * @hide (@SystemApi)
143     */
144    @RequiresPermission(allOf = {LOCATION_HARDWARE})
145    public void cancelRanging(WorkSource workSource) {
146        if (VDBG) {
147            Log.v(TAG, "cancelRanging: workSource=" + workSource);
148        }
149
150        try {
151            mService.cancelRanging(workSource);
152        } catch (RemoteException e) {
153            throw e.rethrowFromSystemServer();
154        }
155    }
156
157    private static class RttCallbackProxy extends IRttCallback.Stub {
158        private final Handler mHandler;
159        private final RangingResultCallback mCallback;
160
161        RttCallbackProxy(Looper looper, RangingResultCallback callback) {
162            mHandler = new Handler(looper);
163            mCallback = callback;
164        }
165
166        @Override
167        public void onRangingFailure(int status) throws RemoteException {
168            if (VDBG) Log.v(TAG, "RttCallbackProxy: onRangingFailure: status=" + status);
169            mHandler.post(() -> {
170               mCallback.onRangingFailure(status);
171            });
172        }
173
174        @Override
175        public void onRangingResults(List<RangingResult> results) throws RemoteException {
176            if (VDBG) Log.v(TAG, "RttCallbackProxy: onRanginResults: results=" + results);
177            mHandler.post(() -> {
178               mCallback.onRangingResults(results);
179            });
180        }
181    }
182}
183