1a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen/*
2a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen * Copyright (C) 2018 The Android Open Source Project
3a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen *
4a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen * Licensed under the Apache License, Version 2.0 (the "License");
5a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen * you may not use this file except in compliance with the License.
6a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen * You may obtain a copy of the License at
7a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen *
8a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen *      http://www.apache.org/licenses/LICENSE-2.0
9a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen *
10a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen * Unless required by applicable law or agreed to in writing, software
11a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen * distributed under the License is distributed on an "AS IS" BASIS,
12a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen * See the License for the specific language governing permissions and
14a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen * limitations under the License.
15a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen */
16a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen
1717ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenpackage android.net.wifi.rtt;
1817ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen
19eed77825b2da1b5c4bd4b4df182b89e787456a55Etan Cohenimport static android.Manifest.permission.ACCESS_FINE_LOCATION;
2017ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport static android.Manifest.permission.ACCESS_WIFI_STATE;
2117ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport static android.Manifest.permission.CHANGE_WIFI_STATE;
224250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohenimport static android.Manifest.permission.LOCATION_HARDWARE;
2317ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen
2452982a9e40650f75105adf96baf4b072af924e88Etan Cohenimport android.annotation.CallbackExecutor;
25a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohenimport android.annotation.NonNull;
2617ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport android.annotation.Nullable;
2717ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport android.annotation.RequiresPermission;
2858019f524f8180423a6e46b83fa3564267612e39Etan Cohenimport android.annotation.SdkConstant;
294250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohenimport android.annotation.SystemApi;
3017ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport android.annotation.SystemService;
3117ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport android.content.Context;
3217ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport android.os.Binder;
3317ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport android.os.RemoteException;
344250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohenimport android.os.WorkSource;
3517ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport android.util.Log;
3617ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen
3717ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenimport java.util.List;
3852982a9e40650f75105adf96baf4b072af924e88Etan Cohenimport java.util.concurrent.Executor;
3917ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen
4017ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen/**
4117ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen * This class provides the primary API for measuring distance (range) to other devices using the
4217ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen * IEEE 802.11mc Wi-Fi Round Trip Time (RTT) technology.
4317ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen * <p>
4417ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen * The devices which can be ranged include:
4517ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen * <li>Access Points (APs)
4658019f524f8180423a6e46b83fa3564267612e39Etan Cohen * <li>Wi-Fi Aware peers
4717ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen * <p>
4817ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen * Ranging requests are triggered using
4952982a9e40650f75105adf96baf4b072af924e88Etan Cohen * {@link #startRanging(RangingRequest, Executor, RangingResultCallback)}. Results (in case of
5017ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen * successful operation) are returned in the {@link RangingResultCallback#onRangingResults(List)}
5117ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen * callback.
5258019f524f8180423a6e46b83fa3564267612e39Etan Cohen * <p>
5358019f524f8180423a6e46b83fa3564267612e39Etan Cohen *     Wi-Fi RTT may not be usable at some points, e.g. when Wi-Fi is disabled. To validate that
5458019f524f8180423a6e46b83fa3564267612e39Etan Cohen *     the functionality is available use the {@link #isAvailable()} function. To track
5558019f524f8180423a6e46b83fa3564267612e39Etan Cohen *     changes in RTT usability register for the {@link #ACTION_WIFI_RTT_STATE_CHANGED}
5658019f524f8180423a6e46b83fa3564267612e39Etan Cohen *     broadcast. Note that this broadcast is not sticky - you should register for it and then
5758019f524f8180423a6e46b83fa3564267612e39Etan Cohen *     check the above API to avoid a race condition.
5817ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen */
5946efb4810011e8ce124b01e28f02d4c767658094Etan Cohen@SystemService(Context.WIFI_RTT_RANGING_SERVICE)
6017ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohenpublic class WifiRttManager {
6117ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen    private static final String TAG = "WifiRttManager";
629752663e3b0b16a07539ec78183176a3ec4e4efaEtan Cohen    private static final boolean VDBG = false;
6317ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen
6417ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen    private final Context mContext;
6517ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen    private final IWifiRttManager mService;
6617ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen
6758019f524f8180423a6e46b83fa3564267612e39Etan Cohen    /**
6858019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * Broadcast intent action to indicate that the state of Wi-Fi RTT availability has changed.
6958019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * Use the {@link #isAvailable()} to query the current status.
7058019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * This broadcast is <b>not</b> sticky, use the {@link #isAvailable()} API after registering
7158019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * the broadcast to check the current state of Wi-Fi RTT.
7258019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
7358019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * components will be launched.
7458019f524f8180423a6e46b83fa3564267612e39Etan Cohen     */
7558019f524f8180423a6e46b83fa3564267612e39Etan Cohen    @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
7658019f524f8180423a6e46b83fa3564267612e39Etan Cohen    public static final String ACTION_WIFI_RTT_STATE_CHANGED =
7758019f524f8180423a6e46b83fa3564267612e39Etan Cohen            "android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED";
7858019f524f8180423a6e46b83fa3564267612e39Etan Cohen
7917ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen    /** @hide */
8017ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen    public WifiRttManager(Context context, IWifiRttManager service) {
8117ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        mContext = context;
8217ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        mService = service;
8317ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen    }
8417ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen
8517ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen    /**
8658019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * Returns the current status of RTT API: whether or not RTT is available. To track
8758019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * changes in the state of RTT API register for the
8858019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * {@link #ACTION_WIFI_RTT_STATE_CHANGED} broadcast.
89a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen     * <p>Note: availability of RTT does not mean that the app can use the API. The app's
90a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen     * permissions and platform Location Mode are validated at run-time.
9158019f524f8180423a6e46b83fa3564267612e39Etan Cohen     *
9258019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * @return A boolean indicating whether the app can use the RTT API at this time (true) or
9358019f524f8180423a6e46b83fa3564267612e39Etan Cohen     * not (false).
9458019f524f8180423a6e46b83fa3564267612e39Etan Cohen     */
9558019f524f8180423a6e46b83fa3564267612e39Etan Cohen    public boolean isAvailable() {
9658019f524f8180423a6e46b83fa3564267612e39Etan Cohen        try {
9758019f524f8180423a6e46b83fa3564267612e39Etan Cohen            return mService.isAvailable();
9858019f524f8180423a6e46b83fa3564267612e39Etan Cohen        } catch (RemoteException e) {
9958019f524f8180423a6e46b83fa3564267612e39Etan Cohen            throw e.rethrowFromSystemServer();
10058019f524f8180423a6e46b83fa3564267612e39Etan Cohen        }
10158019f524f8180423a6e46b83fa3564267612e39Etan Cohen    }
10258019f524f8180423a6e46b83fa3564267612e39Etan Cohen
10358019f524f8180423a6e46b83fa3564267612e39Etan Cohen    /**
10417ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen     * Initiate a request to range to a set of devices specified in the {@link RangingRequest}.
10517ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen     * Results will be returned in the {@link RangingResultCallback} set of callbacks.
10617ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen     *
10717ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen     * @param request  A request specifying a set of devices whose distance measurements are
10817ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen     *                 requested.
10952982a9e40650f75105adf96baf4b072af924e88Etan Cohen     * @param executor The Executor on which to run the callback.
11017ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen     * @param callback A callback for the result of the ranging request.
11117ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen     */
112eed77825b2da1b5c4bd4b4df182b89e787456a55Etan Cohen    @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, CHANGE_WIFI_STATE, ACCESS_WIFI_STATE})
113a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen    public void startRanging(@NonNull RangingRequest request,
11452982a9e40650f75105adf96baf4b072af924e88Etan Cohen            @NonNull @CallbackExecutor Executor executor, @NonNull RangingResultCallback callback) {
11552982a9e40650f75105adf96baf4b072af924e88Etan Cohen        startRanging(null, request, executor, callback);
1164250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen    }
1174250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen
1184250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen    /**
1194250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     * Initiate a request to range to a set of devices specified in the {@link RangingRequest}.
1204250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     * Results will be returned in the {@link RangingResultCallback} set of callbacks.
1214250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     *
1224250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     * @param workSource A mechanism to specify an alternative work-source for the request.
1234250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     * @param request  A request specifying a set of devices whose distance measurements are
1244250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     *                 requested.
12552982a9e40650f75105adf96baf4b072af924e88Etan Cohen     * @param executor The Executor on which to run the callback.
1264250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     * @param callback A callback for the result of the ranging request.
1274250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     *
128a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen     * @hide
1294250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     */
130a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen    @SystemApi
131eed77825b2da1b5c4bd4b4df182b89e787456a55Etan Cohen    @RequiresPermission(allOf = {LOCATION_HARDWARE, ACCESS_FINE_LOCATION, CHANGE_WIFI_STATE,
1324250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen            ACCESS_WIFI_STATE})
133a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen    public void startRanging(@Nullable WorkSource workSource, @NonNull RangingRequest request,
13452982a9e40650f75105adf96baf4b072af924e88Etan Cohen            @NonNull @CallbackExecutor Executor executor, @NonNull RangingResultCallback callback) {
13517ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        if (VDBG) {
1364250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen            Log.v(TAG, "startRanging: workSource=" + workSource + ", request=" + request
13752982a9e40650f75105adf96baf4b072af924e88Etan Cohen                    + ", callback=" + callback + ", executor=" + executor);
13817ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        }
13917ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen
14052982a9e40650f75105adf96baf4b072af924e88Etan Cohen        if (executor == null) {
14152982a9e40650f75105adf96baf4b072af924e88Etan Cohen            throw new IllegalArgumentException("Null executor provided");
14252982a9e40650f75105adf96baf4b072af924e88Etan Cohen        }
143b7abd810ba407ac72dbb1b539925450b4ed2ad23Etan Cohen        if (callback == null) {
144b7abd810ba407ac72dbb1b539925450b4ed2ad23Etan Cohen            throw new IllegalArgumentException("Null callback provided");
145b7abd810ba407ac72dbb1b539925450b4ed2ad23Etan Cohen        }
146b7abd810ba407ac72dbb1b539925450b4ed2ad23Etan Cohen
14717ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        Binder binder = new Binder();
14817ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        try {
1494250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen            mService.startRanging(binder, mContext.getOpPackageName(), workSource, request,
15052982a9e40650f75105adf96baf4b072af924e88Etan Cohen                    new IRttCallback.Stub() {
15152982a9e40650f75105adf96baf4b072af924e88Etan Cohen                        @Override
15252982a9e40650f75105adf96baf4b072af924e88Etan Cohen                        public void onRangingFailure(int status) throws RemoteException {
15352982a9e40650f75105adf96baf4b072af924e88Etan Cohen                            clearCallingIdentity();
15452982a9e40650f75105adf96baf4b072af924e88Etan Cohen                            executor.execute(() -> callback.onRangingFailure(status));
15552982a9e40650f75105adf96baf4b072af924e88Etan Cohen                        }
15652982a9e40650f75105adf96baf4b072af924e88Etan Cohen
15752982a9e40650f75105adf96baf4b072af924e88Etan Cohen                        @Override
15852982a9e40650f75105adf96baf4b072af924e88Etan Cohen                        public void onRangingResults(List<RangingResult> results)
15952982a9e40650f75105adf96baf4b072af924e88Etan Cohen                                throws RemoteException {
16052982a9e40650f75105adf96baf4b072af924e88Etan Cohen                            clearCallingIdentity();
16152982a9e40650f75105adf96baf4b072af924e88Etan Cohen                            executor.execute(() -> callback.onRangingResults(results));
16252982a9e40650f75105adf96baf4b072af924e88Etan Cohen                        }
16352982a9e40650f75105adf96baf4b072af924e88Etan Cohen                    });
16417ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        } catch (RemoteException e) {
1654250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen            throw e.rethrowFromSystemServer();
1664250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen        }
1674250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen    }
1684250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen
1694250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen    /**
1704250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     * Cancel all ranging requests for the specified work sources. The requests have been requested
17152982a9e40650f75105adf96baf4b072af924e88Etan Cohen     * using {@link #startRanging(WorkSource, RangingRequest, Executor, RangingResultCallback)}.
1724250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     *
1734250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     * @param workSource The work-sources of the requesters.
1744250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     *
175a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen     * @hide
1764250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen     */
177a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen    @SystemApi
1784250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen    @RequiresPermission(allOf = {LOCATION_HARDWARE})
179a0688e0321a3c911080d7a5a4ae7bf196198c319Etan Cohen    public void cancelRanging(@Nullable WorkSource workSource) {
1804250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen        if (VDBG) {
1814250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen            Log.v(TAG, "cancelRanging: workSource=" + workSource);
1824250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen        }
1834250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen
1844250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen        try {
1854250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen            mService.cancelRanging(workSource);
1864250e786ad80007024640abbc03d8d3e1186fdb6Etan Cohen        } catch (RemoteException e) {
18717ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen            throw e.rethrowFromSystemServer();
18817ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen        }
18917ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen    }
19017ba47254ceabc27c3c8ebc8728fa6c0d55975bcEtan Cohen}
191