Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2fd67fec authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Add framework APIs for Bluetooth Distance Measurement"

parents dfd112ed 6d2a089f
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -3719,6 +3719,30 @@ public class AdapterService extends Service {
            return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED;
        }

        @Override
        public void isDistanceMeasurementSupported(AttributionSource source,
                SynchronousResultReceiver receiver) {
            try {
                receiver.send(isDistanceMeasurementSupported(source));
            } catch (RuntimeException e) {
                receiver.propagateException(e);
            }
        }
        public int isDistanceMeasurementSupported(AttributionSource source) {
            AdapterService service = getService();
            if (service == null) {
                return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
            } else if (!callerIsSystemOrActiveOrManagedUser(service, TAG,
                    "isDistanceMeasurementSupported")) {
                return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED;
            } else if (!Utils.checkConnectPermissionForDataDelivery(
                    service, source, TAG)) {
                return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION;
            }
            enforceBluetoothPrivilegedPermission(service);
            return BluetoothStatusCodes.FEATURE_SUPPORTED;
        }

        @Override
        public void getLeMaximumAdvertisingDataLength(SynchronousResultReceiver receiver) {
            try {
+105 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.bluetooth.gatt;

import static com.android.bluetooth.Utils.callerIsSystemOrActiveOrManagedUser;
import static com.android.bluetooth.Utils.checkCallerTargetSdk;
import static com.android.bluetooth.Utils.enforceBluetoothPrivilegedPermission;

@@ -41,7 +42,10 @@ import android.bluetooth.IBluetoothGattServerCallback;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertisingSetParameters;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.DistanceMeasurementMethod;
import android.bluetooth.le.DistanceMeasurementParams;
import android.bluetooth.le.IAdvertisingSetCallback;
import android.bluetooth.le.IDistanceMeasurementCallback;
import android.bluetooth.le.IPeriodicAdvertisingCallback;
import android.bluetooth.le.IScannerCallback;
import android.bluetooth.le.PeriodicAdvertisingParameters;
@@ -1768,9 +1772,83 @@ public class GattService extends ProfileService {
            }
            return service.numHwTrackFiltersAvailable(attributionSource);
        }

        @Override
        public void getSupportedDistanceMeasurementMethods(AttributionSource attributionSource,
                SynchronousResultReceiver receiver) {
            try {
                receiver.send(getSupportedDistanceMeasurementMethods(attributionSource));
            } catch (RuntimeException e) {
                receiver.propagateException(e);
            }
        }

    ;
        private List<DistanceMeasurementMethod> getSupportedDistanceMeasurementMethods(
                AttributionSource attributionSource) {
            GattService service = getService();
            if (service == null || !callerIsSystemOrActiveOrManagedUser(service, TAG,
                    "GattService getSupportedDistanceMeasurementMethods")
                    || !Utils.checkConnectPermissionForDataDelivery(
                    service, attributionSource, "GattService startDistanceMeasurement")) {
                return new ArrayList<>();
            }
            enforceBluetoothPrivilegedPermission(service);
            return Arrays.asList(service.getSupportedDistanceMeasurementMethods());
        }

        @Override
        public void startDistanceMeasurement(ParcelUuid uuid,
                DistanceMeasurementParams distanceMeasurementParams,
                IDistanceMeasurementCallback callback, AttributionSource attributionSource,
                SynchronousResultReceiver receiver) {
            try {
                startDistanceMeasurement(uuid, distanceMeasurementParams, callback,
                        attributionSource);
                receiver.send(null);
            } catch (RuntimeException e) {
                receiver.propagateException(e);
            }
        }

        private void startDistanceMeasurement(ParcelUuid uuid,
                DistanceMeasurementParams distanceMeasurementParams,
                IDistanceMeasurementCallback callback, AttributionSource attributionSource) {
            GattService service = getService();
            if (service == null || !callerIsSystemOrActiveOrManagedUser(service, TAG,
                    "startDistanceMeasurement") || !Utils.checkConnectPermissionForDataDelivery(
                    service, attributionSource, "GattService startDistanceMeasurement")) {
                return;
            }
            enforceBluetoothPrivilegedPermission(service);
            service.startDistanceMeasurement(uuid, distanceMeasurementParams, callback);
        }

        @Override
        public void stopDistanceMeasurement(ParcelUuid uuid, BluetoothDevice device, int method,
                AttributionSource attributionSource, SynchronousResultReceiver receiver) {
            try {
                receiver.send(stopDistanceMeasurement(uuid, device, method, attributionSource));
            } catch (RuntimeException e) {
                receiver.propagateException(e);
            }
        }

        private int stopDistanceMeasurement(ParcelUuid uuid, BluetoothDevice device, int method,
                AttributionSource attributionSource) {
            GattService service = getService();
            if (service == null) {
                return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
            } else if (!callerIsSystemOrActiveOrManagedUser(service, TAG,
                    "stopDistanceMeasurement")) {
                return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED;
            } else if (!Utils.checkConnectPermissionForDataDelivery(
                    service, attributionSource, "GattService stopDistanceMeasurement")) {
                return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION;
            }
            enforceBluetoothPrivilegedPermission(service);
            return service.stopDistanceMeasurement(uuid, device, method);
        }
    };

    /**************************************************************************
     * Callback functions - CLIENT
@@ -3488,6 +3566,31 @@ public class GattService extends ProfileService {
        mAdvertiseManager.setPeriodicAdvertisingEnable(advertiserId, enable);
    }

    /**************************************************************************
     * Distance Measurement
     *************************************************************************/

    DistanceMeasurementMethod[] getSupportedDistanceMeasurementMethods() {
        // TODO(b/256055210): Implement DistanceMeasurementManager in Bluetooth APP
        // return mDistanceMeasurementManager.getSupportedMethods();
        return new DistanceMeasurementMethod[0];
    }


    void startDistanceMeasurement(ParcelUuid uuid,
            DistanceMeasurementParams distanceMeasurementParams,
            IDistanceMeasurementCallback callback) {
        // TODO(b/256055210): Implement DistanceMeasurementManager in Bluetooth APP
        // mDistanceMeasurementManager.startDistanceMeasurement(uuid, distanceMeasurementParams,
        // callback);
    }

    int stopDistanceMeasurement(ParcelUuid uuid, BluetoothDevice device, int method) {
        // TODO(b/256055210): Implement DistanceMeasurementManager in Bluetooth APP
        // mDistanceMeasurementManager.stopDistanceMeasurement(uuid, device, method, false);
        return BluetoothStatusCodes.SUCCESS;
    }

    /**************************************************************************
     * GATT Service functions - CLIENT
     *************************************************************************/
+76 −0
Original line number Diff line number Diff line
@@ -61,11 +61,13 @@ package android.bluetooth {
    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getBluetoothHciSnoopLoggingMode();
    method public int getConnectionState();
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public long getDiscoveryEndMillis();
    method @Nullable @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public android.bluetooth.le.DistanceMeasurementManager getDistanceMeasurementManager();
    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getMostRecentlyConnectedDevices();
    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public android.os.Bundle getPreferredAudioProfiles(@NonNull android.bluetooth.BluetoothDevice);
    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<java.lang.Integer> getSupportedProfiles();
    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.os.ParcelUuid> getUuidsList();
    method public boolean isBleScanAlwaysAvailable();
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int isDistanceMeasurementSupported();
    method public boolean isLeEnabled();
    method @NonNull public static String nameForState(int);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int notifyPreferredAudioProfileChangeApplied(@NonNull android.bluetooth.BluetoothDevice);
@@ -754,6 +756,7 @@ package android.bluetooth {

  public final class BluetoothStatusCodes {
    field public static final int ALLOWED = 400; // 0x190
    field public static final int DISTANCE_MEASUREMENT_ERROR_INTERNAL = 1301; // 0x515
    field public static final int ERROR_ALREADY_IN_TARGET_STATE = 26; // 0x1a
    field public static final int ERROR_ANOTHER_ACTIVE_OOB_REQUEST = 1000; // 0x3e8
    field public static final int ERROR_ANOTHER_ACTIVE_REQUEST = 29; // 0x1d
@@ -779,6 +782,7 @@ package android.bluetooth {
    field public static final int ERROR_LOCAL_NOT_ENOUGH_RESOURCES = 22; // 0x16
    field public static final int ERROR_NOT_ACTIVE_DEVICE = 12; // 0xc
    field public static final int ERROR_NO_ACTIVE_DEVICES = 13; // 0xd
    field public static final int ERROR_NO_LE_CONNECTION = 1300; // 0x514
    field public static final int ERROR_PROFILE_NOT_CONNECTED = 14; // 0xe
    field public static final int ERROR_REMOTE_LINK_ERROR = 25; // 0x19
    field public static final int ERROR_REMOTE_NOT_ENOUGH_RESOURCES = 23; // 0x17
@@ -964,6 +968,78 @@ package android.bluetooth.le {
    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void startTruncatedScan(java.util.List<android.bluetooth.le.TruncatedFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
  }

  public final class DistanceMeasurementManager {
    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.le.DistanceMeasurementMethod> getSupportedMethods();
    method @Nullable @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public android.os.CancellationSignal startMeasurementSession(@NonNull android.bluetooth.le.DistanceMeasurementParams, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.le.DistanceMeasurementSession.Callback);
  }

  public final class DistanceMeasurementMethod implements android.os.Parcelable {
    method public double getId();
    method public boolean isAltitudeAngleSupported();
    method public boolean isAzimuthAngleSupported();
    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.DistanceMeasurementMethod> CREATOR;
    field public static final int DISTANCE_MEASUREMENT_METHOD_AUTO = 0; // 0x0
    field public static final int DISTANCE_MEASUREMENT_METHOD_RSSI = 1; // 0x1
  }

  public static final class DistanceMeasurementMethod.Builder {
    ctor public DistanceMeasurementMethod.Builder(int);
    method @NonNull public android.bluetooth.le.DistanceMeasurementMethod build();
    method @NonNull public android.bluetooth.le.DistanceMeasurementMethod.Builder setAltitudeAngleSupported(boolean);
    method @NonNull public android.bluetooth.le.DistanceMeasurementMethod.Builder setAzimuthAngleSupported(boolean);
  }

  public final class DistanceMeasurementParams implements android.os.Parcelable {
    method public static int getDefaultDuration();
    method @NonNull public android.bluetooth.BluetoothDevice getDevice();
    method public int getDuration();
    method public int getFrequency();
    method public static int getMaxDuration();
    method public int getMethod();
    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.DistanceMeasurementParams> CREATOR;
    field public static final int REPORT_FREQUENCY_HIGH = 2; // 0x2
    field public static final int REPORT_FREQUENCY_LOW = 0; // 0x0
    field public static final int REPORT_FREQUENCY_MEDIUM = 1; // 0x1
  }

  public static final class DistanceMeasurementParams.Builder {
    ctor public DistanceMeasurementParams.Builder(@NonNull android.bluetooth.BluetoothDevice);
    method @NonNull public android.bluetooth.le.DistanceMeasurementParams build();
    method @NonNull public android.bluetooth.le.DistanceMeasurementParams.Builder setDuration(@IntRange(from=0, to=3600) int);
    method @NonNull public android.bluetooth.le.DistanceMeasurementParams.Builder setFrequency(int);
    method @NonNull public android.bluetooth.le.DistanceMeasurementParams.Builder setMethod(int);
  }

  public final class DistanceMeasurementResult implements android.os.Parcelable {
    method @FloatRange(from=-90.0, to=90.0) public double getAltitudeAngle();
    method @FloatRange(from=0.0, to=360.0) public double getAzimuthAngle();
    method public double getErrorAltitudeAngle();
    method public double getErrorAzimuthAngle();
    method @FloatRange(from=0.0) public double getErrorMeters();
    method public double getMeters();
    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.DistanceMeasurementResult> CREATOR;
  }

  public static final class DistanceMeasurementResult.Builder {
    ctor public DistanceMeasurementResult.Builder(@FloatRange(from=0.0) double, @FloatRange(from=0.0) double);
    method @NonNull public android.bluetooth.le.DistanceMeasurementResult build();
    method @NonNull public android.bluetooth.le.DistanceMeasurementResult.Builder setAltitudeAngle(@FloatRange(from=-90.0, to=90.0) double);
    method @NonNull public android.bluetooth.le.DistanceMeasurementResult.Builder setAzimuthAngle(@FloatRange(from=0.0, to=360.0) double);
    method @NonNull public android.bluetooth.le.DistanceMeasurementResult.Builder setErrorAltitudeAngle(@FloatRange(from=0.0, to=180.0) double);
    method @NonNull public android.bluetooth.le.DistanceMeasurementResult.Builder setErrorAzimuthAngle(@FloatRange(from=0.0, to=360.0) double);
  }

  public final class DistanceMeasurementSession {
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int stopSession();
  }

  public static interface DistanceMeasurementSession.Callback {
    method public void onResult(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.le.DistanceMeasurementResult);
    method public void onStartFail(@NonNull int);
    method public void onStarted(@NonNull android.bluetooth.le.DistanceMeasurementSession);
    method public void onStopped(@NonNull android.bluetooth.le.DistanceMeasurementSession, @NonNull int);
  }

  @Deprecated public final class ResultStorageDescriptor implements android.os.Parcelable {
    ctor @Deprecated public ResultStorageDescriptor(int, int, int);
    method @Deprecated public int describeContents();
+74 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.DistanceMeasurementManager;
import android.bluetooth.le.PeriodicAdvertisingManager;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
@@ -853,6 +854,7 @@ public final class BluetoothAdapter {
    private BluetoothLeScanner mBluetoothLeScanner;
    private BluetoothLeAdvertiser mBluetoothLeAdvertiser;
    private PeriodicAdvertisingManager mPeriodicAdvertisingManager;
    private DistanceMeasurementManager mDistanceMeasurementManager;

    private final IBluetoothManager mManagerService;
    private final AttributionSource mAttributionSource;
@@ -1198,6 +1200,40 @@ public final class BluetoothAdapter {
        }
    }

     /**
     * Get a {@link DistanceMeasurementManager} object for distance measurement operations.
     * <p>
     * Use {@link #isDistanceMeasurementSupported()} to check whether distance
     * measurement is supported on this device before calling this method.
     *
     * @return a new instance of {@link DistanceMeasurementManager}, or {@code null} if Bluetooth is
     * turned off
     * @throws UnsupportedOperationException if distance measurement is not supported on this device
     *
     * @hide
     */
    @SystemApi
    @RequiresPermission(allOf = {
            android.Manifest.permission.BLUETOOTH_CONNECT,
            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
    })
    public @Nullable DistanceMeasurementManager getDistanceMeasurementManager() {
        if (!getLeAccess()) {
            return null;
        }

        if (isDistanceMeasurementSupported() != BluetoothStatusCodes.FEATURE_SUPPORTED) {
            throw new UnsupportedOperationException("Distance measurement is unsupported");
        }

        synchronized (mLock) {
            if (mDistanceMeasurementManager == null) {
                mDistanceMeasurementManager = new DistanceMeasurementManager(this);
            }
            return mDistanceMeasurementManager;
        }
    }

    /**
     * Return true if Bluetooth is currently enabled and ready for use.
     * <p>Equivalent to:
@@ -2789,6 +2825,44 @@ public final class BluetoothAdapter {
        return BluetoothStatusCodes.ERROR_UNKNOWN;
    }

    /**
     * Returns whether the distance measurement feature is supported.
     *
     * @return whether the Bluetooth distance measurement is supported
     * @throws IllegalStateException if the bluetooth service is null
     *
     * @hide
     */
    @SystemApi
    @RequiresPermission(allOf = {
            android.Manifest.permission.BLUETOOTH_CONNECT,
            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
    })
    public @LeFeatureReturnValues int isDistanceMeasurementSupported() {
        if (!getLeAccess()) {
            return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
        }
        mServiceLock.readLock().lock();
        try {
            if (mService != null) {
                final SynchronousResultReceiver<Integer> recv = SynchronousResultReceiver.get();
                mService.isDistanceMeasurementSupported(mAttributionSource, recv);
                return recv.awaitResultNoInterrupt(getSyncTimeout())
                    .getValue(BluetoothStatusCodes.ERROR_UNKNOWN);
            } else {
                throw new IllegalStateException(
                        "LE state is on, but there is no bluetooth service.");
            }
        } catch (TimeoutException e) {
            Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
        } finally {
            mServiceLock.readLock().unlock();
        }
        return BluetoothStatusCodes.ERROR_UNKNOWN;
    }

    /**
     * Return the maximum LE advertising data length in bytes,
     * if LE Extended Advertising feature is supported, 0 otherwise.
+19 −0
Original line number Diff line number Diff line
@@ -505,6 +505,25 @@ public final class BluetoothStatusCodes {
    @SystemApi
    public static final int ERROR_HAP_INVALID_PRESET_INDEX = 1211;

    /**
     * Indicates that LE connection is required but not exist or disconnected.
     * <p>
     * Example solution: create LE connection then retry again.
     *
     * @hide
     */
    @SystemApi
    public static final int ERROR_NO_LE_CONNECTION = 1300;

    /**
     * Indicates internal error of distance measurement, such as read RSSI data fail.
     *
     * @hide
     */
    @SystemApi
    public static final int DISTANCE_MEASUREMENT_ERROR_INTERNAL = 1301;


    /**
     * Indicates that the RFCOMM listener could not be started due to the requested UUID already
     * being in use.
Loading