1 /* 2 * Copyright (C) 2022 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.bluetooth.le; 18 19 import static android.Manifest.permission.BLUETOOTH_CONNECT; 20 import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; 21 import static android.bluetooth.BluetoothUtils.executeFromBinder; 22 23 import static java.util.Objects.requireNonNull; 24 25 import android.annotation.IntDef; 26 import android.annotation.NonNull; 27 import android.annotation.RequiresPermission; 28 import android.annotation.SystemApi; 29 import android.bluetooth.BluetoothDevice; 30 import android.bluetooth.BluetoothStatusCodes; 31 import android.bluetooth.IDistanceMeasurement; 32 import android.bluetooth.annotations.RequiresBluetoothConnectPermission; 33 import android.content.AttributionSource; 34 import android.os.ParcelUuid; 35 import android.os.RemoteException; 36 import android.util.Log; 37 38 import java.lang.annotation.Retention; 39 import java.lang.annotation.RetentionPolicy; 40 import java.util.concurrent.Executor; 41 42 /** 43 * This class provides a way to control an active distance measurement session. 44 * 45 * <p>It also defines the required {@link DistanceMeasurementSession.Callback} that must be 46 * implemented in order to be notified of distance measurement results and status events related to 47 * the {@link DistanceMeasurementSession}. 48 * 49 * <p>To get an instance of {@link DistanceMeasurementSession}, first use {@link 50 * DistanceMeasurementManager#startMeasurementSession(DistanceMeasurementParams, Executor, 51 * DistanceMeasurementSession.Callback)} to request to start a session. Once the session is started, 52 * a {@link DistanceMeasurementSession} object is provided through {@link 53 * DistanceMeasurementSession.Callback#onStarted(DistanceMeasurementSession)}. If starting a session 54 * fails, the failure is reported through {@link 55 * DistanceMeasurementSession.Callback#onStartFail(int)} with the failure reason. 56 * 57 * @hide 58 */ 59 @SystemApi 60 public final class DistanceMeasurementSession { 61 private static final String TAG = DistanceMeasurementSession.class.getSimpleName(); 62 63 private final IDistanceMeasurement mDistanceMeasurement; 64 private final ParcelUuid mUuid; 65 private final DistanceMeasurementParams mDistanceMeasurementParams; 66 private final Executor mExecutor; 67 private final Callback mCallback; 68 private final AttributionSource mAttributionSource; 69 70 /** @hide */ 71 @Retention(RetentionPolicy.SOURCE) 72 @IntDef( 73 value = { 74 BluetoothStatusCodes.SUCCESS, 75 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, 76 BluetoothStatusCodes.ERROR_DISTANCE_MEASUREMENT_INTERNAL, 77 }) 78 public @interface StopSessionReturnValues {} 79 80 /** @hide */ DistanceMeasurementSession( IDistanceMeasurement distanceMeasurement, ParcelUuid uuid, DistanceMeasurementParams params, Executor executor, AttributionSource attributionSource, Callback callback)81 public DistanceMeasurementSession( 82 IDistanceMeasurement distanceMeasurement, 83 ParcelUuid uuid, 84 DistanceMeasurementParams params, 85 Executor executor, 86 AttributionSource attributionSource, 87 Callback callback) { 88 mDistanceMeasurement = requireNonNull(distanceMeasurement); 89 mDistanceMeasurementParams = requireNonNull(params); 90 mExecutor = requireNonNull(executor); 91 mCallback = requireNonNull(callback); 92 mUuid = uuid; 93 mAttributionSource = attributionSource; 94 } 95 96 /** 97 * Stops actively ranging, {@link Callback#onStopped} will be invoked if this succeeds. 98 * 99 * @return whether successfully stop or not 100 * @hide 101 */ 102 @SystemApi 103 @RequiresBluetoothConnectPermission 104 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) stopSession()105 public @StopSessionReturnValues int stopSession() { 106 try { 107 return mDistanceMeasurement.stopDistanceMeasurement( 108 mUuid, 109 mDistanceMeasurementParams.getDevice(), 110 mDistanceMeasurementParams.getMethodId(), 111 mAttributionSource); 112 } catch (RemoteException e) { 113 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 114 return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; 115 } 116 } 117 118 /** @hide */ onStarted()119 void onStarted() { 120 executeFromBinder(mExecutor, () -> mCallback.onStarted(this)); 121 } 122 123 /** @hide */ onStartFail(int reason)124 void onStartFail(int reason) { 125 executeFromBinder(mExecutor, () -> mCallback.onStartFail(reason)); 126 } 127 128 /** @hide */ onStopped(int reason)129 void onStopped(int reason) { 130 executeFromBinder(mExecutor, () -> mCallback.onStopped(this, reason)); 131 } 132 133 /** @hide */ onResult(@onNull BluetoothDevice device, @NonNull DistanceMeasurementResult result)134 void onResult(@NonNull BluetoothDevice device, @NonNull DistanceMeasurementResult result) { 135 executeFromBinder(mExecutor, () -> mCallback.onResult(device, result)); 136 } 137 138 /** 139 * Interface for receiving {@link DistanceMeasurementSession} events. 140 * 141 * @hide 142 */ 143 @SystemApi 144 public interface Callback { 145 /** @hide */ 146 @Retention(RetentionPolicy.SOURCE) 147 @IntDef( 148 value = { 149 BluetoothStatusCodes.ERROR_UNKNOWN, 150 BluetoothStatusCodes.FEATURE_NOT_SUPPORTED, 151 BluetoothStatusCodes.ERROR_REMOTE_OPERATION_NOT_SUPPORTED, 152 BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST, 153 BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST, 154 BluetoothStatusCodes.REASON_REMOTE_REQUEST, 155 BluetoothStatusCodes.ERROR_TIMEOUT, 156 BluetoothStatusCodes.ERROR_NO_LE_CONNECTION, 157 BluetoothStatusCodes.ERROR_BAD_PARAMETERS, 158 BluetoothStatusCodes.ERROR_DISTANCE_MEASUREMENT_INTERNAL, 159 }) 160 @interface Reason {} 161 162 /** 163 * Invoked when {@link DistanceMeasurementManager#startMeasurementSession( 164 * DistanceMeasurementParams, Executor, DistanceMeasurementSession.Callback)} is successful. 165 * 166 * @param session the started {@link DistanceMeasurementSession} 167 * @hide 168 */ 169 @SystemApi onStarted(@onNull DistanceMeasurementSession session)170 void onStarted(@NonNull DistanceMeasurementSession session); 171 172 /** 173 * Invoked if {@link DistanceMeasurementManager#startMeasurementSession( 174 * DistanceMeasurementParams, Executor, DistanceMeasurementSession.Callback)} fails. 175 * 176 * @param reason the failure reason 177 * @hide 178 */ 179 @SystemApi onStartFail(@eason int reason)180 void onStartFail(@Reason int reason); 181 182 /** 183 * Invoked when a distance measurement session stopped. 184 * 185 * @param reason reason for the session stop 186 * @hide 187 */ 188 @SystemApi onStopped(@onNull DistanceMeasurementSession session, @Reason int reason)189 void onStopped(@NonNull DistanceMeasurementSession session, @Reason int reason); 190 191 /** 192 * Invoked when get distance measurement result. 193 * 194 * @param device remote device 195 * @param result {@link DistanceMeasurementResult} for this device 196 * @hide 197 */ 198 @SystemApi onResult(@onNull BluetoothDevice device, @NonNull DistanceMeasurementResult result)199 void onResult(@NonNull BluetoothDevice device, @NonNull DistanceMeasurementResult result); 200 } 201 } 202