蓝牙低功耗通告功能

蓝牙低功耗 (BLE) 大部分时间处于睡眠模式,以节省电量。它只会在进行通告和短促连接时唤醒,因此这些通告会影响电量消耗和数据传输带宽。

蓝牙 5 通告功能扩展

Android 8.0 支持蓝牙 5,该版本针对 BLE 实现了广播功能的改进,并提供灵活的数据通告功能。蓝牙 5 支持 BLE 物理层 (PHY),BLE PHY 不仅保留了蓝牙 4.2 的低能耗,还允许用户选择更大的带宽或范围。如需更多信息,请参阅蓝牙 5 核心规范

实现

蓝牙 5 的新功能可自动适用于运行 Android 8.0 且具有兼容蓝牙控制器的设备。您可以使用这些 BluetoothAdapter 方法检查设备是否支持蓝牙 5 的功能:

  • isLe2MPhySupported()
  • isLeCodedPhySupported()
  • isLeExtendedAdvertisingSupported()
  • isLePeriodicAdvertisingSupported()

如需停用通告功能,请联系蓝牙芯片供应商来停用芯片组支持。

蓝牙 PHY 是互斥的,并且每个 PHY 的行为均由蓝牙 SIG 预先定义。默认情况下,Android 8.0 使用蓝牙 4.2 的蓝牙 LE 1M PHY。 android.bluetooth.le 软件包通过以下 API 提供蓝牙 5 的通告功能:

  • AdvertisingSet
  • AdvertisingSetCallback
  • AdvertisingSetParameters
  • PeriodicAdvertisingParameters

通过使用 android.bluetooth.le.BluetoothLeAdvertiser 中的 startAdvertisingSet() 方法,可以创建 AdvertisingSet 来修改蓝牙通告设置。即使停用对蓝牙 5 或其通告功能的支持,API 功能也可以应用于 LE 1M PHY。

示例

该示例应用使用蓝牙 LE 1M PHY 进行通告:

  // Start legacy advertising. Works for devices with 5.x controllers,
  and devices that support multi-advertising.

  void example1() {
   BluetoothLeAdvertiser advertiser =
      BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();

   AdvertisingSetParameters parameters = (new AdvertisingSetParameters.Builder())
           .setLegacyMode(true) // True by default, but set here as a reminder.
           .setConnectable(true)
           .setInterval(AdvertisingSetParameters.INTERVAL_HIGH)
           .setTxPowerLevel(AdvertisingSetParameters.TX_POWER_MEDIUM)
           .build();

   AdvertiseData data = (new AdvertiseData.Builder()).setIncludeDeviceName(true).build();

   AdvertisingSetCallback callback = new AdvertisingSetCallback() {
       @Override
       public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower, int status) {
           Log.i(LOG_TAG, "onAdvertisingSetStarted(): txPower:" + txPower + " , status: "
             + status);
           currentAdvertisingSet = advertisingSet;
       }

       @Override
       public void onAdvertisingDataSet(AdvertisingSet advertisingSet, int status) {
           Log.i(LOG_TAG, "onAdvertisingDataSet() :status:" + status);
       }

       @Override
       public void onScanResponseDataSet(AdvertisingSet advertisingSet, int status) {
           Log.i(LOG_TAG, "onScanResponseDataSet(): status:" + status);
       }

       @Override
       public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) {
           Log.i(LOG_TAG, "onAdvertisingSetStopped():");
       }
   };

   advertiser.startAdvertisingSet(parameters, data, null, null, null, callback);

   // After onAdvertisingSetStarted callback is called, you can modify the
   // advertising data and scan response data:
   currentAdvertisingSet.setAdvertisingData(new AdvertiseData.Builder().
     setIncludeDeviceName(true).setIncludeTxPowerLevel(true).build());
   // Wait for onAdvertisingDataSet callback...
   currentAdvertisingSet.setScanResponseData(new
     AdvertiseData.Builder().addServiceUuid(new ParcelUuid(UUID.randomUUID())).build());
   // Wait for onScanResponseDataSet callback...

   // When done with the advertising:
   advertiser.stopAdvertisingSet(callback);
}

该示例应用使用 BLE 2M PHY 进行通告。该应用会首先检查设备是否支持要使用的功能。如果设备支持广播功能,该应用会将 BLE 2M PHY 配置为主 PHY。当 2M PHY 处于活跃状态时,通告功能不支持蓝牙 4.x 控制器,因此 setLegacyMode 会被设置为 false。该示例可在进行广播时修改参数,也可暂停广播。

void example2() {
   BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
   BluetoothLeAdvertiser advertiser =
     BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();

   // Check if all features are supported
   if (!adapter.isLe2MPhySupported()) {
       Log.e(LOG_TAG, "2M PHY not supported!");
       return;
   }
   if (!adapter.isLeExtendedAdvertisingSupported()) {
       Log.e(LOG_TAG, "LE Extended Advertising not supported!");
       return;
   }

   int maxDataLength = adapter.getLeMaximumAdvertisingDataLength();

   AdvertisingSetParameters.Builder parameters = (new AdvertisingSetParameters.Builder())
           .setLegacyMode(false)
           .setInterval(AdvertisingSetParameters.INTERVAL_HIGH)
           .setTxPowerLevel(AdvertisingSetParameters.TX_POWER_MEDIUM)
           .setPrimaryPhy(BluetoothDevice.PHY_LE_1M)
           .setSecondaryPhy(BluetoothDevice.PHY_LE_2M);

   AdvertiseData data = (new AdvertiseData.Builder()).addServiceData(new
     ParcelUuid(UUID.randomUUID()),
           "You should be able to fit large amounts of data up to maxDataLength. This goes
           up to 1650 bytes. For legacy advertising this would not
           work".getBytes()).build();

   AdvertisingSetCallback callback = new AdvertisingSetCallback() {
       @Override
       public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower, int status) {
           Log.i(LOG_TAG, "onAdvertisingSetStarted(): txPower:" + txPower + " , status: "
            + status);
           currentAdvertisingSet = advertisingSet;
       }

       @Override
       public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) {
           Log.i(LOG_TAG, "onAdvertisingSetStopped():");
       }
   };

   advertiser.startAdvertisingSet(parameters.build(), data, null, null, null, callback);

   // After the set starts, you can modify the data and parameters of currentAdvertisingSet.
   currentAdvertisingSet.setAdvertisingData((new
     AdvertiseData.Builder()).addServiceData(new ParcelUuid(UUID.randomUUID()),
           "Without disabling the advertiser first, you can set the data, if new data is
            less than 251 bytes long.".getBytes()).build());

   // Wait for onAdvertisingDataSet callback...

   // Can also stop and restart the advertising
   currentAdvertisingSet.enableAdvertising(false, 0, 0);
   // Wait for onAdvertisingEnabled callback...
   currentAdvertisingSet.enableAdvertising(true, 0, 0);
   // Wait for onAdvertisingEnabled callback...

   // Or modify the parameters - i.e. lower the tx power
   currentAdvertisingSet.enableAdvertising(false, 0, 0);
   // Wait for onAdvertisingEnabled callback...
   currentAdvertisingSet.setAdvertisingParameters(parameters.setTxPowerLevel
     (AdvertisingSetParameters.TX_POWER_LOW).build());
   // Wait for onAdvertisingParametersUpdated callback...
   currentAdvertisingSet.enableAdvertising(true, 0, 0);
   // Wait for onAdvertisingEnabled callback...

   // When done with the advertising:
   advertiser.stopAdvertisingSet(callback);
}

验证

运行适用的蓝牙产品测试,以验证设备是否与蓝牙 5 兼容。

AOSP 包含 Android 通讯测试套件 (ACTS),其中包括针对蓝牙 5 的测试。可以在 tools/test/connectivity/acts/tests/google/ble/bt5 中找到针对蓝牙 5 的 ACTS 测试。