[LE] Broadcast API integration for MediaOutputBroadcastDialog
Bug: 222674827 Test: Manual test Change-Id: I465129c445c23180e6e97832a58da07075d08569
This commit is contained in:
@@ -19,11 +19,19 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="?android:attr/dialogPreferredPadding"
|
||||
android:paddingRight="?android:attr/dialogPreferredPadding">
|
||||
android:paddingRight="?android:attr/dialogPreferredPadding"
|
||||
android:orientation="vertical">
|
||||
<EditText
|
||||
android:id="@+id/broadcast_edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="48dp"
|
||||
android:textAlignment="viewStart"/>
|
||||
<TextView
|
||||
android:id="@+id/broadcast_error_message"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
style="@style/TextAppearance.ErrorText"
|
||||
android:visibility="invisible"/>
|
||||
</LinearLayout>
|
||||
@@ -2290,6 +2290,11 @@
|
||||
<string name="media_output_broadcast_starting">Starting…</string>
|
||||
<!-- The button text when Broadcast start failed [CHAR LIMIT=60] -->
|
||||
<string name="media_output_broadcast_start_failed">Can\u2019t broadcast</string>
|
||||
<!-- The error message when Broadcast name/code update failed [CHAR LIMIT=60] -->
|
||||
<string name="media_output_broadcast_update_error">Can\u2019t save. Try again.</string>
|
||||
<!-- The error message when Broadcast name/code update failed and can't change again[CHAR LIMIT=60] -->
|
||||
<string name="media_output_broadcast_last_update_error">Can\u2019t save.</string>
|
||||
|
||||
|
||||
<!-- Label for clip data when copying the build number off QS [CHAR LIMIT=NONE]-->
|
||||
<string name="build_number_clip_data_label">Build number</string>
|
||||
|
||||
@@ -59,11 +59,14 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
|
||||
private ImageView mBroadcastCodeEye;
|
||||
private Boolean mIsPasswordHide = true;
|
||||
private ImageView mBroadcastCodeEdit;
|
||||
private Button mStopButton;
|
||||
private AlertDialog mAlertDialog;
|
||||
private TextView mBroadcastErrorMessage;
|
||||
|
||||
static final int METADATA_BROADCAST_NAME = 0;
|
||||
static final int METADATA_BROADCAST_CODE = 1;
|
||||
|
||||
private static final int MAX_BROADCAST_INFO_UPDATE = 3;
|
||||
|
||||
MediaOutputBroadcastDialog(Context context, boolean aboveStatusbar,
|
||||
BroadcastSender broadcastSender, MediaOutputController mediaOutputController) {
|
||||
super(context, broadcastSender, mediaOutputController);
|
||||
@@ -118,14 +121,18 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
|
||||
return View.VISIBLE;
|
||||
}
|
||||
|
||||
// TODO(b/222674827): To get the information from BluetoothLeBroadcastMetadata(Broadcast code)
|
||||
// and BluetoothLeAudioContentMetadata(Program info) when start Broadcast is successful.
|
||||
private String getBroadcastMetaDataInfo(int metaData) {
|
||||
switch (metaData) {
|
||||
@Override
|
||||
public void onStopButtonClick() {
|
||||
mMediaOutputController.stopBluetoothLeBroadcast();
|
||||
dismiss();
|
||||
}
|
||||
|
||||
private String getBroadcastMetadataInfo(int metadata) {
|
||||
switch (metadata) {
|
||||
case METADATA_BROADCAST_NAME:
|
||||
return "";
|
||||
return mMediaOutputController.getBroadcastName();
|
||||
case METADATA_BROADCAST_CODE:
|
||||
return "";
|
||||
return mMediaOutputController.getBroadcastCode();
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
@@ -164,13 +171,8 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
|
||||
launchBroadcastUpdatedDialog(true, mBroadcastCode.getText().toString());
|
||||
});
|
||||
|
||||
mBroadcastName.setText(getBroadcastMetaDataInfo(METADATA_BROADCAST_NAME));
|
||||
mBroadcastCode.setText(getBroadcastMetaDataInfo(METADATA_BROADCAST_CODE));
|
||||
|
||||
mStopButton = getDialogView().requireViewById(R.id.stop);
|
||||
mStopButton.setOnClickListener(v -> {
|
||||
stopBroadcast();
|
||||
});
|
||||
mBroadcastName.setText(getBroadcastMetadataInfo(METADATA_BROADCAST_NAME));
|
||||
mBroadcastCode.setText(getBroadcastMetadataInfo(METADATA_BROADCAST_CODE));
|
||||
}
|
||||
|
||||
private void inflateBroadcastInfoArea() {
|
||||
@@ -179,16 +181,16 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
|
||||
}
|
||||
|
||||
private void setQrCodeView() {
|
||||
//get the MetaData, and convert to BT QR code format.
|
||||
String broadcastMetaData = getBroadcastMetaData();
|
||||
if (broadcastMetaData.isEmpty()) {
|
||||
//get the Metadata, and convert to BT QR code format.
|
||||
String broadcastMetadata = getBroadcastMetadata();
|
||||
if (broadcastMetadata.isEmpty()) {
|
||||
//TDOD(b/226708424) Error handling for unable to generate the QR code bitmap
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final int qrcodeSize = getContext().getResources().getDimensionPixelSize(
|
||||
R.dimen.media_output_qrcode_size);
|
||||
final Bitmap bmp = QrCodeGenerator.encodeQrCode(broadcastMetaData, qrcodeSize);
|
||||
final Bitmap bmp = QrCodeGenerator.encodeQrCode(broadcastMetadata, qrcodeSize);
|
||||
mBroadcastQrCodeView.setImageBitmap(bmp);
|
||||
} catch (WriterException e) {
|
||||
//TDOD(b/226708424) Error handling for unable to generate the QR code bitmap
|
||||
@@ -203,50 +205,87 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
|
||||
mIsPasswordHide = !mIsPasswordHide;
|
||||
}
|
||||
|
||||
private void launchBroadcastUpdatedDialog(boolean isPassword, String editString) {
|
||||
private void launchBroadcastUpdatedDialog(boolean isBroadcastCode, String editString) {
|
||||
final View layout = LayoutInflater.from(mContext).inflate(
|
||||
R.layout.media_output_broadcast_update_dialog, null);
|
||||
final EditText editText = layout.requireViewById(R.id.broadcast_edit_text);
|
||||
editText.setText(editString);
|
||||
final AlertDialog alertDialog = new Builder(mContext)
|
||||
.setTitle(isPassword ? R.string.media_output_broadcast_code
|
||||
mBroadcastErrorMessage = layout.requireViewById(R.id.broadcast_error_message);
|
||||
mAlertDialog = new Builder(mContext)
|
||||
.setTitle(isBroadcastCode ? R.string.media_output_broadcast_code
|
||||
: R.string.media_output_broadcast_name)
|
||||
.setView(layout)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(R.string.media_output_broadcast_dialog_save,
|
||||
(d, w) -> {
|
||||
updateBroadcast(isPassword, editText.getText().toString());
|
||||
updateBroadcastInfo(isBroadcastCode, editText.getText().toString());
|
||||
})
|
||||
.create();
|
||||
|
||||
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
|
||||
SystemUIDialog.setShowForAllUsers(alertDialog, true);
|
||||
SystemUIDialog.registerDismissListener(alertDialog);
|
||||
alertDialog.show();
|
||||
mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
|
||||
SystemUIDialog.setShowForAllUsers(mAlertDialog, true);
|
||||
SystemUIDialog.registerDismissListener(mAlertDialog);
|
||||
mAlertDialog.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO(b/222674827): The method should be get the BluetoothLeBroadcastMetadata after
|
||||
* starting the Broadcast session successfully. Then we will follow the BT QR code format
|
||||
* that convert BluetoothLeBroadcastMetadata object to String format.
|
||||
*/
|
||||
private String getBroadcastMetaData() {
|
||||
return "TEST";
|
||||
private String getBroadcastMetadata() {
|
||||
return mMediaOutputController.getBroadcastMetadata();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO(b/222676140): These method are about the LE Audio Broadcast API. The framework APIS
|
||||
* will be wrapped in SettingsLib. And the UI will be executed through it.
|
||||
*/
|
||||
private void updateBroadcast(boolean isPassword, String updatedString) {
|
||||
private void updateBroadcastInfo(boolean isBroadcastCode, String updatedString) {
|
||||
Button positiveBtn = mAlertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
|
||||
if (positiveBtn != null) {
|
||||
positiveBtn.setEnabled(false);
|
||||
}
|
||||
|
||||
if (isBroadcastCode) {
|
||||
handleBroadcastCodeUpdated(updatedString);
|
||||
} else {
|
||||
handleBroadcastNameUpdated(updatedString);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO(b/222676140): These method are about the LE Audio Broadcast API. The framework APIS
|
||||
* will be wrapped in SettingsLib. And the UI will be executed through it.
|
||||
*/
|
||||
private void stopBroadcast() {
|
||||
dismiss();
|
||||
private void handleBroadcastNameUpdated(String name) {
|
||||
// TODO(b/230473995) Add the retry mechanism and error handling when update fails
|
||||
String currentName = mMediaOutputController.getBroadcastName();
|
||||
int retryCount = MAX_BROADCAST_INFO_UPDATE;
|
||||
mMediaOutputController.setBroadcastName(name);
|
||||
if (!mMediaOutputController.updateBluetoothLeBroadcast()) {
|
||||
mMediaOutputController.setBroadcastName(currentName);
|
||||
handleLeUpdateBroadcastFailed(retryCount);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleBroadcastCodeUpdated(String newPassword) {
|
||||
// TODO(b/230473995) Add the retry mechanism and error handling when update fails
|
||||
String currentPassword = mMediaOutputController.getBroadcastCode();
|
||||
int retryCount = MAX_BROADCAST_INFO_UPDATE;
|
||||
if (!mMediaOutputController.stopBluetoothLeBroadcast()) {
|
||||
mMediaOutputController.setBroadcastCode(currentPassword);
|
||||
handleLeUpdateBroadcastFailed(retryCount);
|
||||
return;
|
||||
}
|
||||
|
||||
mMediaOutputController.setBroadcastCode(newPassword);
|
||||
if (!mMediaOutputController.startBluetoothLeBroadcast()) {
|
||||
mMediaOutputController.setBroadcastCode(currentPassword);
|
||||
handleLeUpdateBroadcastFailed(retryCount);
|
||||
return;
|
||||
}
|
||||
|
||||
mAlertDialog.dismiss();
|
||||
}
|
||||
|
||||
private void handleLeUpdateBroadcastFailed(int retryCount) {
|
||||
final Button positiveBtn = mAlertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
|
||||
mBroadcastErrorMessage.setVisibility(View.VISIBLE);
|
||||
if (retryCount < MAX_BROADCAST_INFO_UPDATE) {
|
||||
if (positiveBtn != null) {
|
||||
positiveBtn.setEnabled(true);
|
||||
}
|
||||
mBroadcastErrorMessage.setText(R.string.media_output_broadcast_update_error);
|
||||
} else {
|
||||
mBroadcastErrorMessage.setText(R.string.media_output_broadcast_last_update_error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,6 @@ import com.android.settingslib.Utils;
|
||||
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.media.BluetoothMediaDevice;
|
||||
import com.android.settingslib.media.InfoMediaManager;
|
||||
import com.android.settingslib.media.LocalMediaManager;
|
||||
import com.android.settingslib.media.MediaDevice;
|
||||
@@ -79,6 +78,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
|
||||
import com.android.systemui.statusbar.phone.SystemUIDialog;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -678,6 +678,56 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
|
||||
mDialogLaunchAnimator.showFromView(dialog, mediaOutputDialog);
|
||||
}
|
||||
|
||||
String getBroadcastName() {
|
||||
LocalBluetoothLeBroadcast broadcast =
|
||||
mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
|
||||
if (broadcast == null) {
|
||||
Log.d(TAG, "getBroadcastName: LE Audio Broadcast is null");
|
||||
return "";
|
||||
}
|
||||
return broadcast.getProgramInfo();
|
||||
}
|
||||
|
||||
void setBroadcastName(String broadcastName) {
|
||||
LocalBluetoothLeBroadcast broadcast =
|
||||
mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
|
||||
if (broadcast == null) {
|
||||
Log.d(TAG, "setBroadcastName: LE Audio Broadcast is null");
|
||||
return;
|
||||
}
|
||||
broadcast.setProgramInfo(broadcastName);
|
||||
}
|
||||
|
||||
String getBroadcastCode() {
|
||||
LocalBluetoothLeBroadcast broadcast =
|
||||
mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
|
||||
if (broadcast == null) {
|
||||
Log.d(TAG, "getBroadcastCode: LE Audio Broadcast is null");
|
||||
return "";
|
||||
}
|
||||
return new String(broadcast.getBroadcastCode(), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
void setBroadcastCode(String broadcastCode) {
|
||||
LocalBluetoothLeBroadcast broadcast =
|
||||
mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
|
||||
if (broadcast == null) {
|
||||
Log.d(TAG, "setBroadcastCode: LE Audio Broadcast is null");
|
||||
return;
|
||||
}
|
||||
broadcast.setBroadcastCode(broadcastCode.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
String getBroadcastMetadata() {
|
||||
LocalBluetoothLeBroadcast broadcast =
|
||||
mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
|
||||
if (broadcast == null) {
|
||||
Log.d(TAG, "getBroadcastMetadata: LE Audio Broadcast is null");
|
||||
return "";
|
||||
}
|
||||
return broadcast.getLocalBluetoothLeBroadcastMetaData().convertToQrCodeString();
|
||||
}
|
||||
|
||||
boolean isActiveRemoteDevice(@NonNull MediaDevice device) {
|
||||
final List<String> features = device.getFeatures();
|
||||
return (features.contains(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK)
|
||||
@@ -723,6 +773,17 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean updateBluetoothLeBroadcast() {
|
||||
LocalBluetoothLeBroadcast broadcast =
|
||||
mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
|
||||
if (broadcast == null) {
|
||||
Log.d(TAG, "The broadcast profile is null");
|
||||
return false;
|
||||
}
|
||||
broadcast.updateBroadcast(getAppSourceName(), /*language*/ null);
|
||||
return true;
|
||||
}
|
||||
|
||||
void registerLeBroadcastServiceCallBack(
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull BluetoothLeBroadcast.Callback callback) {
|
||||
|
||||
Reference in New Issue
Block a user