蓝牙低功耗公告功能

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

蓝牙 5 公告功能扩展

Android 8.0 支持蓝牙 5,该版本针对 BLE 对广播功能进行了改进,并提供了灵活的数据公告功能。蓝牙 5 支持 BLE 物理层 (PHY),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_2M)
           .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 的测试。您可以在以下位置找到针对蓝牙 5 的 ACTS 测试: tools/test/connectivity/acts/tests/google/ble/bt5