Update audio sharing dialog text.

Also add a radius to the qr code image.

Test: atest
Bug: 381775542
Flag: com.android.settingslib.flags.enable_le_audio_sharing
Change-Id: I6b06b02f63bc46ec20b7a9e0aa236f2547a5f612
This commit is contained in:
chelseahao
2025-01-24 13:12:24 +08:00
committed by Chelsea Hao
parent b6ba9c3bbc
commit e7ccbf436e
9 changed files with 90 additions and 29 deletions

View File

@@ -45,8 +45,8 @@
<ImageView <ImageView
android:id="@+id/qrcode_view" android:id="@+id/qrcode_view"
android:layout_width="@dimen/qrcode_size" android:layout_width="wrap_content"
android:layout_height="@dimen/qrcode_size" android:layout_height="wrap_content"
android:contentDescription="@string/qr_code_content_description" android:contentDescription="@string/qr_code_content_description"
android:focusable="true" /> android:focusable="true" />

View File

@@ -38,11 +38,11 @@
<ImageView <ImageView
android:id="@+id/qrcode_view" android:id="@+id/qrcode_view"
android:layout_width="@dimen/qrcode_size" android:layout_width="wrap_content"
android:layout_height="@dimen/qrcode_size" android:layout_height="wrap_content"
android:contentDescription="@string/qr_code_content_description" android:contentDescription="@string/qr_code_content_description"
android:focusable="true" android:focusable="true"
android:paddingTop="70dp"/> android:layout_marginTop="70dp"/>
<TextView <TextView
android:id="@+id/password" android:id="@+id/password"

View File

@@ -47,6 +47,15 @@
android:paddingBottom="24dp" android:paddingBottom="24dp"
android:visibility="gone" /> android:visibility="gone" />
<TextView
android:id="@+id/description_text_2"
style="@style/DeviceAudioSharingText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingBottom="24dp"
android:visibility="gone" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/device_btn_list" android:id="@+id/device_btn_list"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@@ -528,6 +528,7 @@
<dimen name="contrast_button_horizontal_spacing">16dp</dimen> <dimen name="contrast_button_horizontal_spacing">16dp</dimen>
<dimen name="audio_streams_qrcode_size">264dp</dimen> <dimen name="audio_streams_qrcode_size">264dp</dimen>
<dimen name="audio_streams_qrcode_margin">1.8dp</dimen>
<dimen name="audio_streams_qrcode_preview_size">300dp</dimen> <dimen name="audio_streams_qrcode_preview_size">300dp</dimen>
<dimen name="audio_streams_qrcode_preview_radius">30dp</dimen> <dimen name="audio_streams_qrcode_preview_radius">30dp</dimen>
<dimen name="audio_streams_qrcode_scanner_fragment_padding">16dp</dimen> <dimen name="audio_streams_qrcode_scanner_fragment_padding">16dp</dimen>

View File

@@ -13873,6 +13873,10 @@
<string name="audio_sharing_close_button_label">Close</string> <string name="audio_sharing_close_button_label">Close</string>
<!-- Content for audio sharing share dialog with no device, ask users to connect device [CHAR LIMIT=none]--> <!-- Content for audio sharing share dialog with no device, ask users to connect device [CHAR LIMIT=none]-->
<string name="audio_sharing_dialog_connect_device_content">Connect another pair of compatible headphones, or share your stream\'s name and password with the other person</string> <string name="audio_sharing_dialog_connect_device_content">Connect another pair of compatible headphones, or share your stream\'s name and password with the other person</string>
<!-- Content for audio sharing share dialog with no device, ask users to scan qr code [CHAR LIMIT=none]-->
<string name="audio_sharing_dialog_qr_code_content">Let others scan this code and listen to your audio\n\nStream name: <xliff:g example="Pixel 8" id="stream_name">%1$s</xliff:g>\nPassword: <xliff:g example="123456" id="password">%2$s</xliff:g></string>
<!-- Content for audio sharing share dialog with no device, ask users to pair new device [CHAR LIMIT=none]-->
<string name="audio_sharing_dialog_pair_new_device_content">or pair another set of compatible headphones</string>
<!-- Content for audio sharing share dialog with no device, ask users to pair device [CHAR LIMIT=none]--> <!-- Content for audio sharing share dialog with no device, ask users to pair device [CHAR LIMIT=none]-->
<string name="audio_sharing_dialog_pair_device_content">Pair another set of compatible headphones, or share your audio stream QR code with the other person</string> <string name="audio_sharing_dialog_pair_device_content">Pair another set of compatible headphones, or share your audio stream QR code with the other person</string>
<!-- Text for sharing audio sharing state [CHAR LIMIT=none]--> <!-- Text for sharing audio sharing state [CHAR LIMIT=none]-->

View File

@@ -18,7 +18,7 @@ package com.android.settings.connecteddevice.audiosharing;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.graphics.Bitmap; import android.graphics.drawable.Drawable;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
@@ -162,13 +162,13 @@ public class AudioSharingDialogFactory {
/** /**
* Sets the custom image of the dialog custom body. * Sets the custom image of the dialog custom body.
* *
* @param bitmap The bitmap to be used for the image. * @param drawable The drawable to be used for the image.
* @return This builder. * @return This builder.
*/ */
@NonNull @NonNull
public AudioSharingDialogFactory.DialogBuilder setCustomImage(Bitmap bitmap) { public AudioSharingDialogFactory.DialogBuilder setCustomImage(Drawable drawable) {
ImageView image = mCustomBody.findViewById(R.id.description_image); ImageView image = mCustomBody.findViewById(R.id.description_image);
image.setImageBitmap(bitmap); image.setImageDrawable(drawable);
image.setVisibility(View.VISIBLE); image.setVisibility(View.VISIBLE);
return this; return this;
} }
@@ -202,6 +202,21 @@ public class AudioSharingDialogFactory {
return this; return this;
} }
/**
* Sets the custom message below image.
*
* @param messageRes Resource ID of the string to be used for the message body.
* @return This builder.
*/
@NonNull
public AudioSharingDialogFactory.DialogBuilder setCustomMessage2(
@StringRes int messageRes) {
TextView subTitle = mCustomBody.findViewById(R.id.description_text_2);
subTitle.setText(messageRes);
subTitle.setVisibility(View.VISIBLE);
return this;
}
/** /**
* Sets the custom device actions of the dialog custom body. * Sets the custom device actions of the dialog custom body.
* *

View File

@@ -17,13 +17,13 @@
package com.android.settings.connecteddevice.audiosharing; package com.android.settings.connecteddevice.audiosharing;
import static com.android.settings.connecteddevice.audiosharing.AudioSharingDashboardFragment.SHARE_THEN_PAIR_REQUEST_CODE; import static com.android.settings.connecteddevice.audiosharing.AudioSharingDashboardFragment.SHARE_THEN_PAIR_REQUEST_CODE;
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsQrCodeFragment.getQrCodeBitmap; import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsQrCodeFragment.getQrCodeDrawable;
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_PAIR_AND_JOIN_SHARING; import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_PAIR_AND_JOIN_SHARING;
import android.app.Dialog; import android.app.Dialog;
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothLeBroadcastMetadata; import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.graphics.Bitmap; import android.graphics.drawable.Drawable;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
@@ -45,6 +45,7 @@ import com.android.settingslib.bluetooth.BluetoothUtils;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
public class AudioSharingDialogFragment extends InstrumentedDialogFragment { public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
@@ -159,7 +160,6 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
} }
if (deviceItems.isEmpty()) { if (deviceItems.isEmpty()) {
builder.setTitle(R.string.audio_sharing_share_dialog_title) builder.setTitle(R.string.audio_sharing_share_dialog_title)
.setCustomMessage(R.string.audio_sharing_dialog_connect_device_content)
.setCustomPositiveButton( .setCustomPositiveButton(
R.string.audio_sharing_pair_button_label, R.string.audio_sharing_pair_button_label,
v -> { v -> {
@@ -183,14 +183,23 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
}); });
BluetoothLeBroadcastMetadata metadata = arguments.getParcelable( BluetoothLeBroadcastMetadata metadata = arguments.getParcelable(
BUNDLE_KEY_BROADCAST_METADATA, BluetoothLeBroadcastMetadata.class); BUNDLE_KEY_BROADCAST_METADATA, BluetoothLeBroadcastMetadata.class);
Bitmap qrCodeBitmap = metadata == null ? null : getQrCodeBitmap(metadata, Drawable qrCodeDrawable = metadata == null ? null : getQrCodeDrawable(metadata,
getContext()).orElse(null); getContext()).orElse(null);
if (qrCodeBitmap != null) { if (qrCodeDrawable != null) {
builder.setCustomImage(qrCodeBitmap) builder.setCustomImage(qrCodeDrawable)
.setCustomNegativeButton(com.android.settings.R.string.cancel, .setCustomMessage(
getString(
R.string.audio_sharing_dialog_qr_code_content,
metadata.getBroadcastName(),
new String(
metadata.getBroadcastCode(),
StandardCharsets.UTF_8)))
.setCustomMessage2(R.string.audio_sharing_dialog_pair_new_device_content)
.setCustomNegativeButton(R.string.audio_streams_dialog_close,
v -> onCancelClick()); v -> onCancelClick());
} else { } else {
builder.setCustomImage(R.drawable.audio_sharing_guidance) builder.setCustomImage(R.drawable.audio_sharing_guidance)
.setCustomMessage(R.string.audio_sharing_dialog_connect_device_content)
.setCustomNegativeButton( .setCustomNegativeButton(
R.string.audio_sharing_qrcode_button_label, R.string.audio_sharing_qrcode_button_label,
v -> { v -> {

View File

@@ -19,7 +19,9 @@ package com.android.settings.connecteddevice.audiosharing.audiostreams;
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothLeBroadcastMetadata; import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.content.Context; import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@@ -30,6 +32,8 @@ import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.bluetooth.Utils; import com.android.settings.bluetooth.Utils;
@@ -70,15 +74,16 @@ public class AudioStreamsQrCodeFragment extends InstrumentedFragment {
if (broadcastMetadata == null) { if (broadcastMetadata == null) {
return; return;
} }
Bitmap bm = getQrCodeBitmap(broadcastMetadata, getActivity()).orElse(null); Drawable drawable = getQrCodeDrawable(broadcastMetadata, getActivity()).orElse(
if (bm == null) { null);
if (drawable == null) {
return; return;
} }
ThreadUtils.postOnMainThread( ThreadUtils.postOnMainThread(
() -> { () -> {
((ImageView) view.requireViewById(R.id.qrcode_view)) ((ImageView) view.requireViewById(R.id.qrcode_view))
.setImageBitmap(bm); .setImageDrawable(drawable);
if (broadcastMetadata.getBroadcastCode() != null) { if (broadcastMetadata.getBroadcastCode() != null) {
String password = String password =
new String( new String(
@@ -101,28 +106,33 @@ public class AudioStreamsQrCodeFragment extends InstrumentedFragment {
}); });
} }
/** Gets an optional bitmap from metadata. */ /** Gets an optional drawable from metadata. */
public static Optional<Bitmap> getQrCodeBitmap(@Nullable BluetoothLeBroadcastMetadata metadata, public static Optional<Drawable> getQrCodeDrawable(
@Nullable BluetoothLeBroadcastMetadata metadata,
Context context) { Context context) {
if (metadata == null) { if (metadata == null) {
Log.d(TAG, "getQrCodeBitmap: broadcastMetadata is empty!"); Log.d(TAG, "getQrCodeDrawable: broadcastMetadata is empty!");
return Optional.empty(); return Optional.empty();
} }
String metadataStr = BluetoothLeBroadcastMetadataExt.INSTANCE.toQrCodeString(metadata); String metadataStr = BluetoothLeBroadcastMetadataExt.INSTANCE.toQrCodeString(metadata);
if (metadataStr.isEmpty()) { if (metadataStr.isEmpty()) {
Log.d(TAG, "getQrCodeBitmap: metadataStr is empty!"); Log.d(TAG, "getQrCodeDrawable: metadataStr is empty!");
return Optional.empty(); return Optional.empty();
} }
Log.d(TAG, "getQrCodeBitmap: metadata : " + metadata); Log.d(TAG, "getQrCodeDrawable: metadata : " + metadata);
try { try {
int qrcodeSize = Resources resources = context.getResources();
context.getResources().getDimensionPixelSize(R.dimen.audio_streams_qrcode_size); int qrcodeSize = resources.getDimensionPixelSize(R.dimen.audio_streams_qrcode_size);
Bitmap bitmap = QrCodeGenerator.encodeQrCode(metadataStr, qrcodeSize); int margin = resources.getDimensionPixelSize(R.dimen.audio_streams_qrcode_margin);
return Optional.of(bitmap); Bitmap bitmap = QrCodeGenerator.encodeQrCode(metadataStr, qrcodeSize, margin);
RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(resources, bitmap);
drawable.setCornerRadius(resources.getDimensionPixelSize(
R.dimen.audio_streams_qrcode_preview_radius));
return Optional.of(drawable);
} catch (WriterException e) { } catch (WriterException e) {
Log.d( Log.d(
TAG, TAG,
"getQrCodeBitmap: broadcastMetadata " "getQrCodeDrawable: broadcastMetadata "
+ metadata + metadata
+ " qrCode generation exception " + " qrCode generation exception "
+ e); + e);

View File

@@ -60,6 +60,7 @@ import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow; import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.androidx.fragment.FragmentController; import org.robolectric.shadows.androidx.fragment.FragmentController;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@@ -263,6 +264,18 @@ public class AudioSharingDialogFragmentTest {
assertThat(dialog).isNotNull(); assertThat(dialog).isNotNull();
ImageView image = dialog.findViewById(R.id.description_image); ImageView image = dialog.findViewById(R.id.description_image);
assertThat(image).isNotNull(); assertThat(image).isNotNull();
TextView text = dialog.findViewById(R.id.description_text);
assertThat(text).isNotNull();
assertThat(METADATA).isNotNull();
assertThat(text.getText().toString()).isEqualTo(
mParent.getString(R.string.audio_sharing_dialog_qr_code_content,
METADATA.getBroadcastName(), new String(
METADATA.getBroadcastCode(),
StandardCharsets.UTF_8)));
TextView textBottom = dialog.findViewById(R.id.description_text_2);
assertThat(textBottom).isNotNull();
assertThat(textBottom.getText().toString()).isEqualTo(
mParent.getString(R.string.audio_sharing_dialog_pair_new_device_content));
Button cancelBtn = dialog.findViewById(R.id.negative_btn); Button cancelBtn = dialog.findViewById(R.id.negative_btn);
assertThat(cancelBtn).isNotNull(); assertThat(cancelBtn).isNotNull();
cancelBtn.performClick(); cancelBtn.performClick();