WifiRttManager.java revision 4250e786ad80007024640abbc03d8d3e1186fdb6
117ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenpackage android.net.wifi.rtt;
217ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen
317ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport static android.Manifest.permission.ACCESS_COARSE_LOCATION;
417ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport static android.Manifest.permission.ACCESS_WIFI_STATE;
517ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport static android.Manifest.permission.CHANGE_WIFI_STATE;
64250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohenimport static android.Manifest.permission.LOCATION_HARDWARE;
717ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen
817ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport android.annotation.Nullable;
917ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport android.annotation.RequiresPermission;
1058019f524f8180423a6e46b83fa3564267612e39Etan Cohenimport android.annotation.SdkConstant;
114250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohenimport android.annotation.SystemApi;
1217ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport android.annotation.SystemService;
1317ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport android.content.Context;
1417ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport android.os.Binder;
1517ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport android.os.Handler;
1617ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport android.os.Looper;
1717ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport android.os.RemoteException;
184250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohenimport android.os.WorkSource;
1917ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport android.util.Log;
2017ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen
2117ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport java.util.List;
2217ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen
2317ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen/**
2417ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen * This class provides the primary API for measuring distance (range) to other devices using the
2517ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen * IEEE 802.11mc Wi-Fi Round Trip Time (RTT) technology.
2617ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen * <p>
2717ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen * The devices which can be ranged include:
2817ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen * <li>Access Points (APs)
2958019f524f8180423a6e46b83fa3564267612e39Etan Cohen * <li>Wi-Fi Aware peers
3017ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen * <p>
3117ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen * Ranging requests are triggered using
3217ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen * {@link #startRanging(RangingRequest, RangingResultCallback, Handler)}. Results (in case of
3317ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen * successful operation) are returned in the {@link RangingResultCallback#onRangingResults(List)}
3417ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen * callback.
3558019f524f8180423a6e46b83fa3564267612e39Etan Cohen * <p>
3658019f524f8180423a6e46b83fa3564267612e39Etan Cohen *     Wi-Fi RTT may not be usable at some points, e.g. when Wi-Fi is disabled. To validate that
3758019f524f8180423a6e46b83fa3564267612e39Etan Cohen *     the functionality is available use the {@link #isAvailable()} function. To track
3858019f524f8180423a6e46b83fa3564267612e39Etan Cohen *     changes in RTT usability register for the {@link #ACTION_WIFI_RTT_STATE_CHANGED}
3958019f524f8180423a6e46b83fa3564267612e39Etan Cohen *     broadcast. Note that this broadcast is not sticky - you should register for it and then
4058019f524f8180423a6e46b83fa3564267612e39Etan Cohen *     check the above API to avoid a race condition.
4117ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen *
4217ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen * @hide RTT_API
4317ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen */
4417ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen@SystemService(Context.WIFI_RTT2_SERVICE)
4517ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenpublic class WifiRttManager {
4617ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen    private static final String TAG = "WifiRttManager";
4717ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen    private static final boolean VDBG = true;
4817ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen
4917ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen    private final Context mContext;
5017ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen    private final IWifiRttManager mService;
5117ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen
5258019f524f8180423a6e46b83fa3564267612e39Etan Cohen    /**
5358019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * Broadcast intent action to indicate that the state of Wi-Fi RTT availability has changed.
5458019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * Use the {@link #isAvailable()} to query the current status.
5558019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * This broadcast is <b>not</b> sticky, use the {@link #isAvailable()} API after registering
5658019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * the broadcast to check the current state of Wi-Fi RTT.
5758019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
5858019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * components will be launched.
5958019f524f8180423a6e46b83fa3564267612e39Etan Cohen     */
6058019f524f8180423a6e46b83fa3564267612e39Etan Cohen    @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
6158019f524f8180423a6e46b83fa3564267612e39Etan Cohen    public static final String ACTION_WIFI_RTT_STATE_CHANGED =
6258019f524f8180423a6e46b83fa3564267612e39Etan Cohen            "android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED";
6358019f524f8180423a6e46b83fa3564267612e39Etan Cohen
6417ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen    /** @hide */
6517ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen    public WifiRttManager(Context context, IWifiRttManager service) {
6617ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        mContext = context;
6717ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        mService = service;
6817ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen    }
6917ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen
7017ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen    /**
7158019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * Returns the current status of RTT API: whether or not RTT is available. To track
7258019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * changes in the state of RTT API register for the
7358019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * {@link #ACTION_WIFI_RTT_STATE_CHANGED} broadcast.
7458019f524f8180423a6e46b83fa3564267612e39Etan Cohen     *
7558019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * @return A boolean indicating whether the app can use the RTT API at this time (true) or
7658019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * not (false).
7758019f524f8180423a6e46b83fa3564267612e39Etan Cohen     */
7858019f524f8180423a6e46b83fa3564267612e39Etan Cohen    public boolean isAvailable() {
7958019f524f8180423a6e46b83fa3564267612e39Etan Cohen        try {
8058019f524f8180423a6e46b83fa3564267612e39Etan Cohen            return mService.isAvailable();
8158019f524f8180423a6e46b83fa3564267612e39Etan Cohen        } catch (RemoteException e) {
8258019f524f8180423a6e46b83fa3564267612e39Etan Cohen            throw e.rethrowFromSystemServer();
8358019f524f8180423a6e46b83fa3564267612e39Etan Cohen        }
8458019f524f8180423a6e46b83fa3564267612e39Etan Cohen    }
8558019f524f8180423a6e46b83fa3564267612e39Etan Cohen
8658019f524f8180423a6e46b83fa3564267612e39Etan Cohen    /**
8717ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen     * Initiate a request to range to a set of devices specified in the {@link RangingRequest}.
8817ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen     * Results will be returned in the {@link RangingResultCallback} set of callbacks.
8917ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen     *
9017ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen     * @param request  A request specifying a set of devices whose distance measurements are
9117ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen     *                 requested.
9217ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen     * @param callback A callback for the result of the ranging request.
9317ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen     * @param handler  The Handler on whose thread to execute the callbacks of the {@code
9417ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen     *                 callback} object. If a null is provided then the application's main thread
9517ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen     *                 will be used.
9617ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen     */
9717ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen    @RequiresPermission(allOf = {ACCESS_COARSE_LOCATION, CHANGE_WIFI_STATE, ACCESS_WIFI_STATE})
9817ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen    public void startRanging(RangingRequest request, RangingResultCallback callback,
9917ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen            @Nullable Handler handler) {
1004250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen        startRanging(null, request, callback, handler);
1014250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen    }
1024250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen
1034250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen    /**
1044250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     * Initiate a request to range to a set of devices specified in the {@link RangingRequest}.
1054250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     * Results will be returned in the {@link RangingResultCallback} set of callbacks.
1064250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     *
1074250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     * @param workSource A mechanism to specify an alternative work-source for the request.
1084250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     * @param request  A request specifying a set of devices whose distance measurements are
1094250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     *                 requested.
1104250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     * @param callback A callback for the result of the ranging request.
1114250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     * @param handler  The Handler on whose thread to execute the callbacks of the {@code
1124250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     *                 callback} object. If a null is provided then the application's main thread
1134250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     *                 will be used.
1144250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     *
1154250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     * @hide (@SystemApi)
1164250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     */
1174250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen    @RequiresPermission(allOf = {LOCATION_HARDWARE, ACCESS_COARSE_LOCATION, CHANGE_WIFI_STATE,
1184250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen            ACCESS_WIFI_STATE})
1194250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen    public void startRanging(@Nullable WorkSource workSource, RangingRequest request,
1204250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen            RangingResultCallback callback, @Nullable Handler handler) {
12117ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        if (VDBG) {
1224250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen            Log.v(TAG, "startRanging: workSource=" + workSource + ", request=" + request
1234250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen                    + ", callback=" + callback + ", handler=" + handler);
12417ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        }
12517ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen
12617ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
12717ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        Binder binder = new Binder();
12817ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        try {
1294250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen            mService.startRanging(binder, mContext.getOpPackageName(), workSource, request,
13017ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen                    new RttCallbackProxy(looper, callback));
13117ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        } catch (RemoteException e) {
1324250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen            throw e.rethrowFromSystemServer();
1334250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen        }
1344250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen    }
1354250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen
1364250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen    /**
1374250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     * Cancel all ranging requests for the specified work sources. The requests have been requested
1384250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     * using {@link #startRanging(WorkSource, RangingRequest, RangingResultCallback, Handler)}.
1394250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     *
1404250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     * @param workSource The work-sources of the requesters.
1414250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     *
1424250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     * @hide (@SystemApi)
1434250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     */
1444250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen    @RequiresPermission(allOf = {LOCATION_HARDWARE})
1454250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen    public void cancelRanging(WorkSource workSource) {
1464250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen        if (VDBG) {
1474250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen            Log.v(TAG, "cancelRanging: workSource=" + workSource);
1484250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen        }
1494250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen
1504250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen        try {
1514250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen            mService.cancelRanging(workSource);
1524250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen        } catch (RemoteException e) {
15317ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen            throw e.rethrowFromSystemServer();
15417ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        }
15517ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen    }
15617ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen
15717ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen    private static class RttCallbackProxy extends IRttCallback.Stub {
15817ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        private final Handler mHandler;
15917ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        private final RangingResultCallback mCallback;
16017ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen
16117ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        RttCallbackProxy(Looper looper, RangingResultCallback callback) {
16217ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen            mHandler = new Handler(looper);
16317ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen            mCallback = callback;
16417ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        }
16517ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen
16617ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        @Override
167210da15b9f195c045b34ce0b125a431f394edce0Etan Cohen        public void onRangingFailure(int status) throws RemoteException {
168210da15b9f195c045b34ce0b125a431f394edce0Etan Cohen            if (VDBG) Log.v(TAG, "RttCallbackProxy: onRangingFailure: status=" + status);
16917ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen            mHandler.post(() -> {
170210da15b9f195c045b34ce0b125a431f394edce0Etan Cohen               mCallback.onRangingFailure(status);
171210da15b9f195c045b34ce0b125a431f394edce0Etan Cohen            });
172210da15b9f195c045b34ce0b125a431f394edce0Etan Cohen        }
173210da15b9f195c045b34ce0b125a431f394edce0Etan Cohen
174210da15b9f195c045b34ce0b125a431f394edce0Etan Cohen        @Override
175210da15b9f195c045b34ce0b125a431f394edce0Etan Cohen        public void onRangingResults(List<RangingResult> results) throws RemoteException {
176210da15b9f195c045b34ce0b125a431f394edce0Etan Cohen            if (VDBG) Log.v(TAG, "RttCallbackProxy: onRanginResults: results=" + results);
177210da15b9f195c045b34ce0b125a431f394edce0Etan Cohen            mHandler.post(() -> {
178210da15b9f195c045b34ce0b125a431f394edce0Etan Cohen               mCallback.onRangingResults(results);
17917ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen            });
18017ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        }
18117ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen    }
18217ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen}
183