diff options
4 files changed, 159 insertions, 46 deletions
diff --git a/packages/SystemUI/res/layout/media_output_broadcast_update_dialog.xml b/packages/SystemUI/res/layout/media_output_broadcast_update_dialog.xml index 8b7a019b791b..89dcbcc5929f 100644 --- a/packages/SystemUI/res/layout/media_output_broadcast_update_dialog.xml +++ b/packages/SystemUI/res/layout/media_output_broadcast_update_dialog.xml @@ -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>
\ No newline at end of file diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index e1fa5752e2d3..6cc61b4706f6 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2293,6 +2293,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> diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java index 9b3b3ce6109f..dd4f1d6c9015 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java @@ -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); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java index 0fbec3baffa6..8723f4fd63bb 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java @@ -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) { |