Merge "[LE] Broadcast API integration for MediaOutputBroadcastDialog" into tm-dev

This commit is contained in:
Betty Chang
2022-04-29 13:58:28 +00:00
committed by Android (Google) Code Review
4 changed files with 159 additions and 46 deletions

View File

@@ -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>

View File

@@ -2293,6 +2293,11 @@
<string name="media_output_broadcast_starting">Starting&#8230;</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>

View File

@@ -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);
}
}
}

View File

@@ -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) {