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

Commit 2703518e authored by Charlie Boutier's avatar Charlie Boutier
Browse files

Pandora Add waitLeConnection Modify waitConnection

* Add waitLeConnection
* Listen for the acl intent in waitConnection instead of the bond intent
* Add general pairingReceiver in Security.kt to handle pairing events
* Add intentQueue which is filled in the same time as the intentFlow.
  This will prevent early intent to be missed when entering some method
  such as waitConnection.

Test: avatar_runner example.py config.yml
Bug: 260774624
Bug: 259102046
Change-Id: I09a2dbf4868b04e73e69234d4134b320fdd1eea3
parent ff5778fd
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -62,7 +62,7 @@ class AVRCPProxy(ProfileProxy):

        """
        # Simulate CSR timeout: b/259102046
        time.sleep(2)
        time.sleep(4)
        self.connection = self.host.WaitConnection(address=pts_addr).connection
        if ("TG" in test and "TG/VLH" not in test) or "CT/VLH" in test:
            try:
+0 −11
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.pandora

import android.bluetooth.BluetoothA2dp
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothManager
import android.bluetooth.BluetoothProfile
import android.content.Context
@@ -78,11 +77,6 @@ class A2dp(val context: Context) : A2DPImplBase() {
      val device = request.connection.toBluetoothDevice(bluetoothAdapter)
      Log.i(TAG, "openSource: device=$device")

      if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
        Log.e(TAG, "Device is not bonded, cannot openSource")
        throw Status.UNKNOWN.asException()
      }

      if (bluetoothA2dp.getConnectionState(device) != BluetoothA2dp.STATE_CONNECTED) {
        bluetoothA2dp.connect(device)
        val state =
@@ -117,11 +111,6 @@ class A2dp(val context: Context) : A2DPImplBase() {
      val device = request.connection.toBluetoothDevice(bluetoothAdapter)
      Log.i(TAG, "waitSource: device=$device")

      if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
        Log.e(TAG, "Device is not bonded, cannot openSource")
        throw Status.UNKNOWN.asException()
      }

      if (bluetoothA2dp.getConnectionState(device) != BluetoothA2dp.STATE_CONNECTED) {
        val state =
          flow
+3 −13
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.pandora

import android.bluetooth.BluetoothA2dpSink
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothManager
import android.bluetooth.BluetoothProfile
import android.content.Context
@@ -73,11 +72,6 @@ class A2dpSink(val context: Context) : A2DPImplBase() {
      val device = request.connection.toBluetoothDevice(bluetoothAdapter)
      Log.i(TAG, "waitSink: device=$device")

      if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
        Log.e(TAG, "Device is not bonded, cannot wait for stream")
        throw Status.UNKNOWN.asException()
      }

      if (bluetoothA2dpSink.getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) {
        val state =
          flow
@@ -102,13 +96,7 @@ class A2dpSink(val context: Context) : A2DPImplBase() {

  override fun close(request: CloseRequest, responseObserver: StreamObserver<CloseResponse>) {
    grpcUnary<CloseResponse>(scope, responseObserver) {
      val device =
        if (request.hasSink()) {
          request.sink.connection.toBluetoothDevice(bluetoothAdapter)
        } else {
          Log.e(TAG, "Sink device required")
          throw Status.UNKNOWN.asException()
        }
      val device = request.sink.connection.toBluetoothDevice(bluetoothAdapter)
      Log.i(TAG, "close: device=$device")
      if (bluetoothA2dpSink.getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) {
        Log.e(TAG, "Device is not connected, cannot close")
@@ -120,8 +108,10 @@ class A2dpSink(val context: Context) : A2DPImplBase() {
          .filter { it.getAction() == BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED }
          .filter { it.getBluetoothDeviceExtra() == device }
          .map { it.getIntExtra(BluetoothProfile.EXTRA_STATE, BluetoothAdapter.ERROR) }

      bluetoothA2dpSink.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN)
      a2dpConnectionStateChangedFlow.filter { it == BluetoothProfile.STATE_DISCONNECTED }.first()

      CloseResponse.getDefaultInstance()
    }
  }
+4 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.take
import pandora.GATTGrpc.GATTImplBase
import pandora.GattProto.*

@@ -150,9 +151,12 @@ class Gatt(private val context: Context) : GATTImplBase() {
      Log.i(TAG, "discoverServicesSdp")
      val bluetoothDevice = request.address.toBluetoothDevice(mBluetoothAdapter)
      check(bluetoothDevice.fetchUuidsWithSdp())
      // Several ACTION_UUID could be sent and some of them are empty (null)
      flow
        .filter { it.getAction() == BluetoothDevice.ACTION_UUID }
        .filter { it.getBluetoothDeviceExtra() == bluetoothDevice }
        .take(2)
        .filter { bluetoothDevice.getUuids() != null }
        .first()
      val uuidsList = arrayListOf<String>()
      for (parcelUuid in bluetoothDevice.getUuids()) {
+63 −19
Original line number Diff line number Diff line
@@ -213,6 +213,22 @@ class Host(
      .first()
  }

  suspend fun waitAclIntent(bluetoothDevice: BluetoothDevice?): Intent {
    for (intent in intentQueue) {
      if (
        intent.getAction() == BluetoothDevice.ACTION_ACL_CONNECTED &&
          (bluetoothDevice == null || intent.getBluetoothDeviceExtra() == bluetoothDevice)
      ) {
        intentQueue.remove(intent)
        return intent
      }
    }
    return flow
      .filter { it.action == BluetoothDevice.ACTION_ACL_CONNECTED }
      .filter { bluetoothDevice == null || it.getBluetoothDeviceExtra() == bluetoothDevice }
      .first()
  }

  private suspend fun acceptPairingAndAwaitBonded(bluetoothDevice: BluetoothDevice) {
    val acceptPairingJob = scope.launch { waitPairingRequestIntent(bluetoothDevice) }
    waitBondIntent(bluetoothDevice)
@@ -226,7 +242,12 @@ class Host(
    responseObserver: StreamObserver<WaitConnectionResponse>
  ) {
    grpcUnary(scope, responseObserver) {
      val bluetoothDevice = request.address.toBluetoothDevice(bluetoothAdapter)
      val bluetoothDevice =
        if (!request.address.isEmpty()) {
          request.address.toBluetoothDevice(bluetoothAdapter)
        } else {
          null
        }

      Log.i(TAG, "waitConnection: device=$bluetoothDevice")

@@ -235,14 +256,42 @@ class Host(
        throw Status.UNKNOWN.asException()
      }

      if (security.manuallyConfirm) {
        waitBondIntent(bluetoothDevice)
      val intent = waitAclIntent(bluetoothDevice)

      WaitConnectionResponse.newBuilder()
        .setConnection(intent.getBluetoothDeviceExtra().toConnection(TRANSPORT_BREDR))
        .build()
    }
  }

  override fun waitLEConnection(
    request: WaitLEConnectionRequest,
    responseObserver: StreamObserver<WaitLEConnectionResponse>
  ) {
    grpcUnary(scope, responseObserver) {
      if (request.getAddressCase() != WaitLEConnectionRequest.AddressCase.PUBLIC) {
        Log.e(TAG, "waitLEConnection: public address not provided")
        throw Status.UNKNOWN.asException()
      }

      val bluetoothDevice =
        if (!request.public.isEmpty()) {
          request.public.toBluetoothDevice(bluetoothAdapter)
        } else {
        acceptPairingAndAwaitBonded(bluetoothDevice)
          null
        }

      WaitConnectionResponse.newBuilder()
        .setConnection(bluetoothDevice.toConnection(TRANSPORT_BREDR))
      Log.i(TAG, "waitLEConnection: device=$bluetoothDevice")

      if (!bluetoothAdapter.isEnabled) {
        Log.e(TAG, "Bluetooth is not enabled, cannot waitConnection")
        throw Status.UNKNOWN.asException()
      }

      val intent = waitAclIntent(bluetoothDevice)

      WaitLEConnectionResponse.newBuilder()
        .setConnection(intent.getBluetoothDeviceExtra().toConnection(TRANSPORT_LE))
        .build()
    }
  }
@@ -304,16 +353,11 @@ class Host(
      when (request.connection.transport) {
        TRANSPORT_BREDR -> {
          Log.i(TAG, "disconnect BR_EDR")
          val connectionStateChangedFlow =
          bluetoothDevice.disconnect()
          flow
              .filter { it.getAction() == BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED }
            .filter { it.action == BluetoothDevice.ACTION_ACL_DISCONNECTED }
            .filter { it.getBluetoothDeviceExtra() == bluetoothDevice }
              .map {
                it.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, BluetoothAdapter.ERROR)
              }

          bluetoothDevice.disconnect()
          connectionStateChangedFlow.filter { it == BluetoothAdapter.STATE_DISCONNECTED }.first()
            .first()
        }
        TRANSPORT_LE -> {
          Log.i(TAG, "disconnect LE")
Loading