/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.bluetooth.le; import static android.Manifest.permission.BLUETOOTH_CONNECT; import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; import static android.bluetooth.BluetoothUtils.executeFromBinder; import static java.util.Objects.requireNonNull; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothStatusCodes; import android.bluetooth.IDistanceMeasurement; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.content.AttributionSource; import android.os.ParcelUuid; import android.os.RemoteException; import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.concurrent.Executor; /** * This class provides a way to control an active distance measurement session. * *

It also defines the required {@link DistanceMeasurementSession.Callback} that must be * implemented in order to be notified of distance measurement results and status events related to * the {@link DistanceMeasurementSession}. * *

To get an instance of {@link DistanceMeasurementSession}, first use {@link * DistanceMeasurementManager#startMeasurementSession(DistanceMeasurementParams, Executor, * DistanceMeasurementSession.Callback)} to request to start a session. Once the session is started, * a {@link DistanceMeasurementSession} object is provided through {@link * DistanceMeasurementSession.Callback#onStarted(DistanceMeasurementSession)}. If starting a session * fails, the failure is reported through {@link * DistanceMeasurementSession.Callback#onStartFail(int)} with the failure reason. * * @hide */ @SystemApi public final class DistanceMeasurementSession { private static final String TAG = DistanceMeasurementSession.class.getSimpleName(); private final IDistanceMeasurement mDistanceMeasurement; private final ParcelUuid mUuid; private final DistanceMeasurementParams mDistanceMeasurementParams; private final Executor mExecutor; private final Callback mCallback; private final AttributionSource mAttributionSource; /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef( value = { BluetoothStatusCodes.SUCCESS, BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, BluetoothStatusCodes.ERROR_DISTANCE_MEASUREMENT_INTERNAL, }) public @interface StopSessionReturnValues {} /** @hide */ public DistanceMeasurementSession( IDistanceMeasurement distanceMeasurement, ParcelUuid uuid, DistanceMeasurementParams params, Executor executor, AttributionSource attributionSource, Callback callback) { mDistanceMeasurement = requireNonNull(distanceMeasurement); mDistanceMeasurementParams = requireNonNull(params); mExecutor = requireNonNull(executor); mCallback = requireNonNull(callback); mUuid = uuid; mAttributionSource = attributionSource; } /** * Stops actively ranging, {@link Callback#onStopped} will be invoked if this succeeds. * * @return whether successfully stop or not * @hide */ @SystemApi @RequiresBluetoothConnectPermission @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) public @StopSessionReturnValues int stopSession() { try { return mDistanceMeasurement.stopDistanceMeasurement( mUuid, mDistanceMeasurementParams.getDevice(), mDistanceMeasurementParams.getMethodId(), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; } } /** @hide */ void onStarted() { executeFromBinder(mExecutor, () -> mCallback.onStarted(this)); } /** @hide */ void onStartFail(int reason) { executeFromBinder(mExecutor, () -> mCallback.onStartFail(reason)); } /** @hide */ void onStopped(int reason) { executeFromBinder(mExecutor, () -> mCallback.onStopped(this, reason)); } /** @hide */ void onResult(@NonNull BluetoothDevice device, @NonNull DistanceMeasurementResult result) { executeFromBinder(mExecutor, () -> mCallback.onResult(device, result)); } /** * Interface for receiving {@link DistanceMeasurementSession} events. * * @hide */ @SystemApi public interface Callback { /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef( value = { BluetoothStatusCodes.ERROR_UNKNOWN, BluetoothStatusCodes.FEATURE_NOT_SUPPORTED, BluetoothStatusCodes.ERROR_REMOTE_OPERATION_NOT_SUPPORTED, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST, BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST, BluetoothStatusCodes.REASON_REMOTE_REQUEST, BluetoothStatusCodes.ERROR_TIMEOUT, BluetoothStatusCodes.ERROR_NO_LE_CONNECTION, BluetoothStatusCodes.ERROR_BAD_PARAMETERS, BluetoothStatusCodes.ERROR_DISTANCE_MEASUREMENT_INTERNAL, }) @interface Reason {} /** * Invoked when {@link DistanceMeasurementManager#startMeasurementSession( * DistanceMeasurementParams, Executor, DistanceMeasurementSession.Callback)} is successful. * * @param session the started {@link DistanceMeasurementSession} * @hide */ @SystemApi void onStarted(@NonNull DistanceMeasurementSession session); /** * Invoked if {@link DistanceMeasurementManager#startMeasurementSession( * DistanceMeasurementParams, Executor, DistanceMeasurementSession.Callback)} fails. * * @param reason the failure reason * @hide */ @SystemApi void onStartFail(@Reason int reason); /** * Invoked when a distance measurement session stopped. * * @param reason reason for the session stop * @hide */ @SystemApi void onStopped(@NonNull DistanceMeasurementSession session, @Reason int reason); /** * Invoked when get distance measurement result. * * @param device remote device * @param result {@link DistanceMeasurementResult} for this device * @hide */ @SystemApi void onResult(@NonNull BluetoothDevice device, @NonNull DistanceMeasurementResult result); } }