Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f956509b authored by Chelsea Hao's avatar Chelsea Hao Committed by Android (Google) Code Review
Browse files

Merge "Show qr code in "Share your audio" dialog" into main

parents a9c090df b6ba9c3b
Loading
Loading
Loading
Loading
+16 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.settings.connecteddevice.audiosharing;

import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
@@ -147,7 +148,7 @@ public class AudioSharingDialogFactory {
        /**
         * Sets the custom image of the dialog custom body.
         *
         * @param iconRes The text to be used for the title.
         * @param iconRes The iconRes to be used for the image.
         * @return This builder.
         */
        @NonNull
@@ -158,6 +159,20 @@ public class AudioSharingDialogFactory {
            return this;
        }

        /**
         * Sets the custom image of the dialog custom body.
         *
         * @param bitmap The bitmap to be used for the image.
         * @return This builder.
         */
        @NonNull
        public AudioSharingDialogFactory.DialogBuilder setCustomImage(Bitmap bitmap) {
            ImageView image = mCustomBody.findViewById(R.id.description_image);
            image.setImageBitmap(bitmap);
            image.setVisibility(View.VISIBLE);
            return this;
        }

        /**
         * Sets the custom message of the dialog custom body.
         *
+31 −11
Original line number Diff line number Diff line
@@ -17,10 +17,13 @@
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.audiostreams.AudioStreamsQrCodeFragment.getQrCodeBitmap;
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_PAIR_AND_JOIN_SHARING;

import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.util.Log;
import android.util.Pair;
@@ -48,6 +51,7 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
    private static final String TAG = "AudioSharingDialog";

    private static final String BUNDLE_KEY_DEVICE_ITEMS = "bundle_key_device_items";
    private static final String BUNDLE_KEY_BROADCAST_METADATA = "bundle_key_broadcast_metadata";

    // The host creates an instance of this dialog fragment must implement this interface to receive
    // event callbacks.
@@ -80,12 +84,14 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
     *
     * @param host        The Fragment this dialog will be hosted.
     * @param deviceItems The connected device items eligible for audio sharing.
     * @param metadata    The audio sharing metadata, nullable.
     * @param listener    The callback to handle the user action on this dialog.
     * @param eventData   The eventData to log with for dialog onClick events.
     */
    public static void show(
            @Nullable Fragment host,
            @NonNull List<AudioSharingDeviceItem> deviceItems,
            @Nullable BluetoothLeBroadcastMetadata metadata,
            @NonNull DialogEventListener listener,
            @NonNull Pair<Integer, Object>[] eventData) {
        if (host == null) {
@@ -116,6 +122,9 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
            Log.d(TAG, "Show up the dialog.");
            final Bundle bundle = new Bundle();
            bundle.putParcelableList(BUNDLE_KEY_DEVICE_ITEMS, deviceItems);
            if (metadata != null) {
                bundle.putParcelable(BUNDLE_KEY_BROADCAST_METADATA, metadata);
            }
            AudioSharingDialogFragment dialogFrag = new AudioSharingDialogFragment();
            dialogFrag.setArguments(bundle);
            dialogFrag.show(manager, TAG);
@@ -150,7 +159,6 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
        }
        if (deviceItems.isEmpty()) {
            builder.setTitle(R.string.audio_sharing_share_dialog_title)
                    .setCustomImage(R.drawable.audio_sharing_guidance)
                    .setCustomMessage(R.string.audio_sharing_dialog_connect_device_content)
                    .setCustomPositiveButton(
                            R.string.audio_sharing_pair_button_label,
@@ -172,17 +180,29 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
                                    launcher.setResultListener(sHost, SHARE_THEN_PAIR_REQUEST_CODE);
                                }
                                launcher.launch();
                            })
                            });
            BluetoothLeBroadcastMetadata metadata = arguments.getParcelable(
                    BUNDLE_KEY_BROADCAST_METADATA, BluetoothLeBroadcastMetadata.class);
            Bitmap qrCodeBitmap = metadata == null ? null : getQrCodeBitmap(metadata,
                    getContext()).orElse(null);
            if (qrCodeBitmap != null) {
                builder.setCustomImage(qrCodeBitmap)
                        .setCustomNegativeButton(com.android.settings.R.string.cancel,
                                v -> onCancelClick());
            } else {
                builder.setCustomImage(R.drawable.audio_sharing_guidance)
                        .setCustomNegativeButton(
                                R.string.audio_sharing_qrcode_button_label,
                                v -> {
                                    onCancelClick();
                                    new SubSettingLauncher(getContext())
                                            .setTitleRes(R.string.audio_streams_qr_code_page_title)
                                        .setDestination(AudioStreamsQrCodeFragment.class.getName())
                                            .setDestination(
                                                    AudioStreamsQrCodeFragment.class.getName())
                                            .setSourceMetricsCategory(getMetricsCategory())
                                            .launch();
                                });
            }
        } else if (deviceItems.size() == 1) {
            AudioSharingDeviceItem deviceItem = Iterables.getOnlyElement(deviceItems);
            builder.setTitle(
+7 −1
Original line number Diff line number Diff line
@@ -723,10 +723,16 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
                        cleanUpStatesForStartSharing();
                    }
                };
        BluetoothLeBroadcastMetadata metadata = mBroadcast == null ? null
                : mBroadcast.getLatestBluetoothLeBroadcastMetadata();
        AudioSharingUtils.postOnMainThread(
                mContext,
                () -> AudioSharingDialogFragment.show(
                        mFragment, mDeviceItemsForSharing, listener, eventData));
                        mFragment,
                        mDeviceItemsForSharing,
                        metadata,
                        listener,
                        eventData));
    }

    private void showErrorDialog() {
+6 −3
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.settings.connecteddevice.audiosharing.audiostreams;

import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.util.Log;
@@ -69,7 +70,7 @@ public class AudioStreamsQrCodeFragment extends InstrumentedFragment {
                    if (broadcastMetadata == null) {
                        return;
                    }
                    Bitmap bm = getQrCodeBitmap(broadcastMetadata).orElse(null);
                    Bitmap bm = getQrCodeBitmap(broadcastMetadata, getActivity()).orElse(null);
                    if (bm == null) {
                        return;
                    }
@@ -100,7 +101,9 @@ public class AudioStreamsQrCodeFragment extends InstrumentedFragment {
                });
    }

    private Optional<Bitmap> getQrCodeBitmap(@Nullable BluetoothLeBroadcastMetadata metadata) {
    /** Gets an optional bitmap from metadata. */
    public static Optional<Bitmap> getQrCodeBitmap(@Nullable BluetoothLeBroadcastMetadata metadata,
            Context context) {
        if (metadata == null) {
            Log.d(TAG, "getQrCodeBitmap: broadcastMetadata is empty!");
            return Optional.empty();
@@ -113,7 +116,7 @@ public class AudioStreamsQrCodeFragment extends InstrumentedFragment {
        Log.d(TAG, "getQrCodeBitmap: metadata : " + metadata);
        try {
            int qrcodeSize =
                    getResources().getDimensionPixelSize(R.dimen.audio_streams_qrcode_size);
                    context.getResources().getDimensionPixelSize(R.dimen.audio_streams_qrcode_size);
            Bitmap bitmap = QrCodeGenerator.encodeQrCode(metadataStr, qrcodeSize);
            return Optional.of(bitmap);
        } catch (WriterException e) {
+59 −8
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;

import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.bluetooth.BluetoothStatusCodes;
import android.content.Context;
import android.platform.test.flag.junit.SetFlagsRule;
@@ -44,6 +45,7 @@ import com.android.settings.R;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settingslib.bluetooth.BluetoothLeBroadcastMetadataExt;
import com.android.settingslib.flags.Flags;

import org.junit.After;
@@ -87,6 +89,11 @@ public class AudioSharingDialogFragmentTest {
    private static final Pair<Integer, Object> TEST_EVENT_DATA = Pair.create(1, 1);
    private static final Pair<Integer, Object>[] TEST_EVENT_DATA_LIST =
            new Pair[] {TEST_EVENT_DATA};
    private static final String METADATA_STR =
            "BLUETOOTH:UUID:184F;BN:VGVzdA==;AT:1;AD:00A1A1A1A1A1;BI:1E240;BC:VGVzdENvZGU=;"
                    + "MD:BgNwVGVzdA==;AS:1;PI:A0;NS:1;BS:3;NB:2;SM:BQNUZXN0BARlbmc=;;";
    private static final BluetoothLeBroadcastMetadata METADATA =
            BluetoothLeBroadcastMetadataExt.INSTANCE.convertToBroadcastMetadata(METADATA_STR);

    private Fragment mParent;
    private FakeFeatureFactory mFeatureFactory;
@@ -123,7 +130,7 @@ public class AudioSharingDialogFragmentTest {
    public void onCreateDialog_flagOff_dialogNotExist() {
        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
        AudioSharingDialogFragment.show(
                mParent, new ArrayList<>(), EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
                mParent, new ArrayList<>(), null, EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
        shadowMainLooper().idle();
        AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
        assertThat(dialog).isNull();
@@ -133,17 +140,18 @@ public class AudioSharingDialogFragmentTest {
    public void onCreateDialog_unattachedFragment_dialogNotExist() {
        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
        AudioSharingDialogFragment.show(
                new Fragment(), new ArrayList<>(), EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
                new Fragment(), new ArrayList<>(), null, EMPTY_EVENT_LISTENER,
                TEST_EVENT_DATA_LIST);
        shadowMainLooper().idle();
        AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
        assertThat(dialog).isNull();
    }

    @Test
    public void onCreateDialog_flagOn_noExtraConnectedDevice() {
    public void onCreateDialog_flagOn_qrCodeBitmapNull_noExtraConnectedDevice() {
        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
        AudioSharingDialogFragment.show(
                mParent, new ArrayList<>(), EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
                mParent, new ArrayList<>(), null, EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
        shadowMainLooper().idle();

        AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
@@ -176,6 +184,7 @@ public class AudioSharingDialogFragmentTest {
        AudioSharingDialogFragment.show(
                mParent,
                new ArrayList<>(),
                null,
                new AudioSharingDialogFragment.DialogEventListener() {
                    @Override
                    public void onPositiveClick() {
@@ -201,12 +210,13 @@ public class AudioSharingDialogFragmentTest {
    }

    @Test
    public void onCreateDialog_noExtraConnectedDevice_showQRCode() {
    public void onCreateDialog_noExtraConnectedDevice_showQRCodeButton() {
        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
        AtomicBoolean isQrCodeBtnClicked = new AtomicBoolean(false);
        AudioSharingDialogFragment.show(
                mParent,
                new ArrayList<>(),
                null,
                new AudioSharingDialogFragment.DialogEventListener() {
                    @Override
                    public void onCancelClick() {
@@ -219,6 +229,8 @@ public class AudioSharingDialogFragmentTest {
        assertThat(dialog).isNotNull();
        Button qrCodeBtn = dialog.findViewById(R.id.negative_btn);
        assertThat(qrCodeBtn).isNotNull();
        assertThat(qrCodeBtn.getText().toString())
                .isEqualTo(mParent.getString(R.string.audio_sharing_qrcode_button_label));
        qrCodeBtn.performClick();
        shadowMainLooper().idle();

@@ -231,12 +243,47 @@ public class AudioSharingDialogFragmentTest {
        assertThat(dialog.isShowing()).isFalse();
    }

    @Test
    public void onCreateDialog_noExtraConnectedDevice_hasMetadata_showCancelButton() {
        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
        AtomicBoolean isCancelBtnClicked = new AtomicBoolean(false);
        AudioSharingDialogFragment.show(
                mParent,
                new ArrayList<>(),
                METADATA,
                new AudioSharingDialogFragment.DialogEventListener() {
                    @Override
                    public void onCancelClick() {
                        isCancelBtnClicked.set(true);
                    }
                },
                TEST_EVENT_DATA_LIST);
        shadowMainLooper().idle();
        AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
        assertThat(dialog).isNotNull();
        ImageView image = dialog.findViewById(R.id.description_image);
        assertThat(image).isNotNull();
        Button cancelBtn = dialog.findViewById(R.id.negative_btn);
        assertThat(cancelBtn).isNotNull();
        cancelBtn.performClick();
        shadowMainLooper().idle();

        verify(mFeatureFactory.metricsFeatureProvider)
                .action(
                        any(Context.class),
                        eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED),
                        eq(TEST_EVENT_DATA));
        assertThat(isCancelBtnClicked.get()).isTrue();
        assertThat(dialog.isShowing()).isFalse();
    }

    @Test
    public void onCreateDialog_flagOn_singleExtraConnectedDevice() {
        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
        ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
        list.add(TEST_DEVICE_ITEM1);
        AudioSharingDialogFragment.show(mParent, list, EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
        AudioSharingDialogFragment.show(mParent, list, null, EMPTY_EVENT_LISTENER,
                TEST_EVENT_DATA_LIST);
        shadowMainLooper().idle();

        AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
@@ -273,7 +320,8 @@ public class AudioSharingDialogFragmentTest {
        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
        ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
        list.add(TEST_DEVICE_ITEM1);
        AudioSharingDialogFragment.show(mParent, list, EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
        AudioSharingDialogFragment.show(mParent, list, null, EMPTY_EVENT_LISTENER,
                TEST_EVENT_DATA_LIST);
        shadowMainLooper().idle();

        AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
@@ -300,6 +348,7 @@ public class AudioSharingDialogFragmentTest {
        AudioSharingDialogFragment.show(
                mParent,
                list,
                null,
                new AudioSharingDialogFragment.DialogEventListener() {
                    @Override
                    public void onItemClick(@NonNull AudioSharingDeviceItem item) {
@@ -332,7 +381,8 @@ public class AudioSharingDialogFragmentTest {
        list.add(TEST_DEVICE_ITEM1);
        list.add(TEST_DEVICE_ITEM2);
        list.add(TEST_DEVICE_ITEM3);
        AudioSharingDialogFragment.show(mParent, list, EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
        AudioSharingDialogFragment.show(mParent, list, null, EMPTY_EVENT_LISTENER,
                TEST_EVENT_DATA_LIST);
        shadowMainLooper().idle();

        AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
@@ -371,6 +421,7 @@ public class AudioSharingDialogFragmentTest {
        AudioSharingDialogFragment.show(
                mParent,
                list,
                null,
                new AudioSharingDialogFragment.DialogEventListener() {
                    @Override
                    public void onCancelClick() {
Loading