diff options
author | 2022-03-10 15:17:53 +0800 | |
---|---|---|
committer | 2022-05-26 08:49:01 +0000 | |
commit | ad7f77f4fe248699a367a804e02a9ddac0996f20 (patch) | |
tree | cd9b073e310959e39d867e7d0ddd29c1f27b6e30 | |
parent | aae5f3eecf5de58c7c6cb1c1baf031728ae5ea2b (diff) |
[LeAudio] Add LocalBluetoothLeAudioContentMetadata and LocalBluetoothLeBroadcastMetadata
Test: manual
Bug: 222676140
Change-Id: I3722ce537cc6e2b8a85d6390a432881e7fccef87
Merged-In: I3722ce537cc6e2b8a85d6390a432881e7fccef87
3 files changed, 397 insertions, 0 deletions
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothBroadcastUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothBroadcastUtils.java new file mode 100644 index 000000000000..3ce7a0e4efa5 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothBroadcastUtils.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.bluetooth; + +public final class BluetoothBroadcastUtils { + + static final String SCHEME_BT_BROADCAST_METADATA = "BT:"; + + // BluetoothLeBroadcastMetadata + static final String PREFIX_BT_ADDRESS_TYPE = "T:"; + static final String PREFIX_BT_DEVICE = "D:"; + static final String PREFIX_BT_ADVERTISING_SID = "AS:"; + static final String PREFIX_BT_BROADCAST_ID = "B:"; + static final String PREFIX_BT_SYNC_INTERVAL = "SI:"; + static final String PREFIX_BT_IS_ENCRYPTED = "E:"; + static final String PREFIX_BT_BROADCAST_CODE = "C:"; + static final String PREFIX_BT_PRESENTATION_DELAY = "D:"; + static final String PREFIX_BT_SUBGROUPS = "G:"; + static final String PREFIX_BT_ANDROID_VERSION = "V:"; + + // BluetoothLeBroadcastSubgroup + static final String PREFIX_BTSG_CODEC_ID = "CID:"; + static final String PREFIX_BTSG_CODEC_CONFIG = "CC:"; + static final String PREFIX_BTSG_AUDIO_CONTENT = "AC:"; + static final String PREFIX_BTSG_CHANNEL_PREF = "CP:"; + static final String PREFIX_BTSG_BROADCAST_CHANNEL = "BC:"; + + // BluetoothLeAudioCodecConfigMetadata + static final String PREFIX_BTCC_AUDIO_LOCATION = "AL:"; + static final String PREFIX_BTCC_RAW_METADATA = "CCRM:"; + + // BluetoothLeAudioContentMetadata + static final String PREFIX_BTAC_PROGRAM_INFO = "PI:"; + static final String PREFIX_BTAC_LANGUAGE = "L:"; + static final String PREFIX_BTAC_RAW_METADATA = "ACRM:"; + + // BluetoothLeBroadcastChannel + static final String PREFIX_BTBC_CHANNEL_INDEX = "CI:"; + static final String PREFIX_BTBC_CODEC_CONFIG = "BCCM:"; + + static final String DELIMITER_QR_CODE = ";"; +} diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeAudioContentMetadata.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeAudioContentMetadata.java new file mode 100644 index 000000000000..9df0f4df1c87 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeAudioContentMetadata.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.bluetooth; + +import android.bluetooth.BluetoothLeAudioContentMetadata; + +public class LocalBluetoothLeAudioContentMetadata { + + private static final String TAG = "LocalBluetoothLeAudioContentMetadata"; + private final BluetoothLeAudioContentMetadata mContentMetadata; + private final String mLanguage; + private final byte[] mRawMetadata; + private String mProgramInfo; + + LocalBluetoothLeAudioContentMetadata(BluetoothLeAudioContentMetadata contentMetadata) { + mContentMetadata = contentMetadata; + mProgramInfo = contentMetadata.getProgramInfo(); + mLanguage = contentMetadata.getLanguage(); + mRawMetadata = contentMetadata.getRawMetadata(); + } + + public void setProgramInfo(String programInfo) { + mProgramInfo = programInfo; + } + + public String getProgramInfo() { + return mProgramInfo; + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastMetadata.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastMetadata.java new file mode 100644 index 000000000000..cf4ba8b46c7a --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastMetadata.java @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.bluetooth; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothLeAudioCodecConfigMetadata; +import android.bluetooth.BluetoothLeAudioContentMetadata; +import android.bluetooth.BluetoothLeBroadcastChannel; +import android.bluetooth.BluetoothLeBroadcastMetadata; +import android.bluetooth.BluetoothLeBroadcastSubgroup; +import android.util.Log; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class LocalBluetoothLeBroadcastMetadata { + private static final boolean DEBUG = BluetoothUtils.D; + private static final String TAG = "LocalBluetoothLeBroadcastMetadata"; + private static final String METADATA_START = "<"; + private static final String METADATA_END = ">"; + private static final String PATTERN_REGEX = "<(.*?)>"; + + private BluetoothLeBroadcastSubgroup mSubgroup; + private List<BluetoothLeBroadcastSubgroup> mSubgroupList; + + // BluetoothLeBroadcastMetadata + // Optional: Identity address type + private int mSourceAddressType; + // Optional: Must use identity address + private BluetoothDevice mSourceDevice; + private int mSourceAdvertisingSid; + private int mBroadcastId; + private int mPaSyncInterval; + private int mPresentationDelayMicros; + private boolean mIsEncrypted; + private byte[] mBroadcastCode; + + // BluetoothLeBroadcastSubgroup + private long mCodecId; + private BluetoothLeAudioContentMetadata mContentMetadata; + private BluetoothLeAudioCodecConfigMetadata mConfigMetadata; + private BluetoothLeBroadcastChannel mChannel; + + // BluetoothLeAudioCodecConfigMetadata + private long mAudioLocation; + + // BluetoothLeAudioContentMetadata + private String mLanguage; + private String mProgramInfo; + + // BluetoothLeBroadcastChannel + private boolean mIsSelected; + private int mChannelIndex; + + + LocalBluetoothLeBroadcastMetadata(BluetoothLeBroadcastMetadata metadata) { + mSourceAddressType = metadata.getSourceAddressType(); + mSourceDevice = metadata.getSourceDevice(); + mSourceAdvertisingSid = metadata.getSourceAdvertisingSid(); + mBroadcastId = metadata.getBroadcastId(); + mPaSyncInterval = metadata.getPaSyncInterval(); + mIsEncrypted = metadata.isEncrypted(); + mBroadcastCode = metadata.getBroadcastCode(); + mPresentationDelayMicros = metadata.getPresentationDelayMicros(); + mSubgroupList = metadata.getSubgroups(); + } + + public void setBroadcastCode(byte[] code) { + mBroadcastCode = code; + } + + public int getBroadcastId() { + return mBroadcastId; + } + + public String convertToQrCodeString() { + return new StringBuilder() + .append(BluetoothBroadcastUtils.SCHEME_BT_BROADCAST_METADATA) + .append(BluetoothBroadcastUtils.PREFIX_BT_ADDRESS_TYPE) + .append(METADATA_START).append(mSourceAddressType).append(METADATA_END) + .append(BluetoothBroadcastUtils.DELIMITER_QR_CODE) + .append(BluetoothBroadcastUtils.PREFIX_BT_DEVICE) + .append(METADATA_START).append(mSourceDevice).append(METADATA_END) + .append(BluetoothBroadcastUtils.DELIMITER_QR_CODE) + .append(BluetoothBroadcastUtils.PREFIX_BT_ADVERTISING_SID) + .append(METADATA_START).append(mSourceAdvertisingSid).append(METADATA_END) + .append(BluetoothBroadcastUtils.DELIMITER_QR_CODE) + .append(BluetoothBroadcastUtils.PREFIX_BT_BROADCAST_ID) + .append(METADATA_START).append(mBroadcastId).append(METADATA_END) + .append(BluetoothBroadcastUtils.DELIMITER_QR_CODE) + .append(BluetoothBroadcastUtils.PREFIX_BT_SYNC_INTERVAL) + .append(METADATA_START).append(mPaSyncInterval).append(METADATA_END) + .append(BluetoothBroadcastUtils.DELIMITER_QR_CODE) + .append(BluetoothBroadcastUtils.PREFIX_BT_IS_ENCRYPTED) + .append(METADATA_START).append(mIsEncrypted).append(METADATA_END) + .append(BluetoothBroadcastUtils.DELIMITER_QR_CODE) + .append(BluetoothBroadcastUtils.PREFIX_BT_BROADCAST_CODE) + .append(METADATA_START).append(Arrays.toString(mBroadcastCode)).append(METADATA_END) + .append(BluetoothBroadcastUtils.DELIMITER_QR_CODE) + .append(BluetoothBroadcastUtils.PREFIX_BT_PRESENTATION_DELAY) + .append(METADATA_START).append(mPresentationDelayMicros).append(METADATA_END) + .append(BluetoothBroadcastUtils.DELIMITER_QR_CODE) + .append(BluetoothBroadcastUtils.PREFIX_BT_SUBGROUPS) + .append(METADATA_START).append(mSubgroupList).append(METADATA_END) + .append(BluetoothBroadcastUtils.DELIMITER_QR_CODE) + .toString(); + } + + /** + * Example : prefix is with the “BT:”, and end by the Android Version. + * BT:T:<1>;D:<00:11:22:AA:BB:CC>;AS:<1>;B:…;V:T;; + * + * @return BluetoothLeBroadcastMetadata + */ + public BluetoothLeBroadcastMetadata convertToBroadcastMetadata(String qrCodeString) { + if (DEBUG) { + Log.d(TAG, "Convert " + qrCodeString + "to BluetoothLeBroadcastMetadata"); + } + Pattern pattern = Pattern.compile(PATTERN_REGEX); + Matcher match = pattern.matcher(qrCodeString); + if (match.find()) { + ArrayList<String> resultList = new ArrayList<>(); + resultList.add(match.group(1)); + mSourceAddressType = Integer.parseInt(resultList.get(0)); + mSourceDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice( + resultList.get(1)); + mSourceAdvertisingSid = Integer.parseInt(resultList.get(2)); + mBroadcastId = Integer.parseInt(resultList.get(3)); + mPaSyncInterval = Integer.parseInt(resultList.get(4)); + mIsEncrypted = Boolean.valueOf(resultList.get(5)); + mBroadcastCode = resultList.get(6).getBytes(); + mPresentationDelayMicros = Integer.parseInt(resultList.get(7)); + mSubgroup = convertToSubgroup(resultList.get(8)); + + if (DEBUG) { + Log.d(TAG, "Converted qrCodeString result: " + match.group()); + } + + return new BluetoothLeBroadcastMetadata.Builder() + .setSourceDevice(mSourceDevice, mSourceAddressType) + .setSourceAdvertisingSid(mSourceAdvertisingSid) + .setBroadcastId(mBroadcastId) + .setPaSyncInterval(mPaSyncInterval) + .setEncrypted(mIsEncrypted) + .setBroadcastCode(mBroadcastCode) + .setPresentationDelayMicros(mPresentationDelayMicros) + .addSubgroup(mSubgroup) + .build(); + } else { + if (DEBUG) { + Log.d(TAG, + "The match fail, can not convert it to BluetoothLeBroadcastMetadata."); + } + return null; + } + } + + private BluetoothLeBroadcastSubgroup convertToSubgroup(String subgroupString) { + if (DEBUG) { + Log.d(TAG, "Convert " + subgroupString + "to BluetoothLeBroadcastSubgroup"); + } + Pattern pattern = Pattern.compile(PATTERN_REGEX); + Matcher match = pattern.matcher(subgroupString); + if (match.find()) { + ArrayList<String> resultList = new ArrayList<>(); + resultList.add(match.group(1)); + mCodecId = Long.getLong(resultList.get(0)); + mConfigMetadata = convertToConfigMetadata(resultList.get(1)); + mContentMetadata = convertToContentMetadata(resultList.get(2)); + mChannel = convertToChannel(resultList.get(3), mConfigMetadata); + + if (DEBUG) { + Log.d(TAG, "Converted subgroupString result: " + match.group()); + } + + return new BluetoothLeBroadcastSubgroup.Builder() + .setCodecId(mCodecId) + .setCodecSpecificConfig(mConfigMetadata) + .setContentMetadata(mContentMetadata) + .addChannel(mChannel) + .build(); + } else { + if (DEBUG) { + Log.d(TAG, + "The match fail, can not convert it to BluetoothLeBroadcastSubgroup."); + } + return null; + } + } + + private BluetoothLeAudioCodecConfigMetadata convertToConfigMetadata( + String configMetadataString) { + if (DEBUG) { + Log.d(TAG, + "Convert " + configMetadataString + "to BluetoothLeAudioCodecConfigMetadata"); + } + Pattern pattern = Pattern.compile(PATTERN_REGEX); + Matcher match = pattern.matcher(configMetadataString); + if (match.find()) { + ArrayList<String> resultList = new ArrayList<>(); + resultList.add(match.group(1)); + mAudioLocation = Long.getLong(resultList.get(0)); + + if (DEBUG) { + Log.d(TAG, "Converted configMetadataString result: " + match.group()); + } + + return new BluetoothLeAudioCodecConfigMetadata.Builder() + .setAudioLocation(mAudioLocation) + .build(); + } else { + if (DEBUG) { + Log.d(TAG, + "The match fail, can not convert it to " + + "BluetoothLeAudioCodecConfigMetadata."); + } + return null; + } + } + + private BluetoothLeAudioContentMetadata convertToContentMetadata(String contentMetadataString) { + if (DEBUG) { + Log.d(TAG, "Convert " + contentMetadataString + "to BluetoothLeAudioContentMetadata"); + } + Pattern pattern = Pattern.compile(PATTERN_REGEX); + Matcher match = pattern.matcher(contentMetadataString); + if (match.find()) { + ArrayList<String> resultList = new ArrayList<>(); + resultList.add(match.group(1)); + mProgramInfo = resultList.get(0); + mLanguage = resultList.get(1); + + if (DEBUG) { + Log.d(TAG, "Converted contentMetadataString result: " + match.group()); + } + + return new BluetoothLeAudioContentMetadata.Builder() + .setProgramInfo(mProgramInfo) + .setLanguage(mLanguage) + .build(); + } else { + if (DEBUG) { + Log.d(TAG, + "The match fail, can not convert it to BluetoothLeAudioContentMetadata."); + } + return null; + } + } + + private BluetoothLeBroadcastChannel convertToChannel(String channelString, + BluetoothLeAudioCodecConfigMetadata configMetadata) { + if (DEBUG) { + Log.d(TAG, "Convert " + channelString + "to BluetoothLeBroadcastChannel"); + } + Pattern pattern = Pattern.compile(PATTERN_REGEX); + Matcher match = pattern.matcher(channelString); + if (match.find()) { + ArrayList<String> resultList = new ArrayList<>(); + resultList.add(match.group(1)); + mIsSelected = Boolean.valueOf(resultList.get(0)); + mChannelIndex = Integer.parseInt(resultList.get(1)); + + if (DEBUG) { + Log.d(TAG, "Converted channelString result: " + match.group()); + } + + return new BluetoothLeBroadcastChannel.Builder() + .setSelected(mIsSelected) + .setChannelIndex(mChannelIndex) + .setCodecMetadata(configMetadata) + .build(); + } else { + if (DEBUG) { + Log.d(TAG, + "The match fail, can not convert it to BluetoothLeBroadcastChannel."); + } + return null; + } + } +} |