diff --git a/src/com/android/settings/bluetooth/BluetoothBroadcastDialog.java b/src/com/android/settings/bluetooth/BluetoothBroadcastDialog.java index b2636a63d30..dd06b679910 100644 --- a/src/com/android/settings/bluetooth/BluetoothBroadcastDialog.java +++ b/src/com/android/settings/bluetooth/BluetoothBroadcastDialog.java @@ -41,15 +41,18 @@ import com.android.settingslib.media.MediaOutputConstants; * nearby broadcast sources. */ public class BluetoothBroadcastDialog extends InstrumentedDialogFragment { + public static final String KEY_APP_LABEL = "app_label"; public static final String KEY_DEVICE_ADDRESS = BluetoothFindBroadcastsFragment.KEY_DEVICE_ADDRESS; + public static final String KEY_MEDIA_STREAMING = "media_streaming"; private static final String TAG = "BTBroadcastsDialog"; private static final CharSequence UNKNOWN_APP_LABEL = "unknown"; private Context mContext; private CharSequence mCurrentAppLabel = UNKNOWN_APP_LABEL; private String mDeviceAddress; + private boolean mIsMediaStreaming; private LocalBluetoothManager mLocalBluetoothManager; private AlertDialog mAlertDialog; @@ -59,6 +62,7 @@ public class BluetoothBroadcastDialog extends InstrumentedDialogFragment { mContext = getActivity(); mCurrentAppLabel = getActivity().getIntent().getCharSequenceExtra(KEY_APP_LABEL); mDeviceAddress = getActivity().getIntent().getStringExtra(KEY_DEVICE_ADDRESS); + mIsMediaStreaming = getActivity().getIntent().getBooleanExtra(KEY_MEDIA_STREAMING, false); mLocalBluetoothManager = Utils.getLocalBtManager(mContext); setShowsDialog(true); } @@ -75,16 +79,21 @@ public class BluetoothBroadcastDialog extends InstrumentedDialogFragment { mContext.getString(R.string.bluetooth_broadcast_dialog_broadcast_message)); Button broadcastBtn = layout.findViewById(com.android.settingslib.R.id.positive_btn); - if (TextUtils.isEmpty(mCurrentAppLabel)) { - broadcastBtn.setText(mContext.getString(R.string.bluetooth_broadcast_dialog_title)); - } else { - broadcastBtn.setText(mContext.getString( + if (isBroadcastSupported() && mIsMediaStreaming) { + broadcastBtn.setVisibility(View.VISIBLE); + if (TextUtils.isEmpty(mCurrentAppLabel)) { + broadcastBtn.setText(mContext.getString(R.string.bluetooth_broadcast_dialog_title)); + } else { + broadcastBtn.setText(mContext.getString( R.string.bluetooth_broadcast_dialog_broadcast_app, String.valueOf(mCurrentAppLabel))); + } + broadcastBtn.setOnClickListener((view) -> { + launchMediaOutputBroadcastDialog(); + }); + } else { + broadcastBtn.setVisibility(View.GONE); } - broadcastBtn.setOnClickListener((view) -> { - launchMediaOutputBroadcastDialog(); - }); Button findBroadcastBtn = layout.findViewById(com.android.settingslib.R.id.negative_btn); findBroadcastBtn.setText(mContext.getString(R.string.bluetooth_find_broadcast)); @@ -169,4 +178,10 @@ public class BluetoothBroadcastDialog extends InstrumentedDialogFragment { .setPackage(MediaOutputConstants.SETTINGS_PACKAGE_NAME) .setAction(MediaOutputConstants.ACTION_CLOSE_PANEL)); } + + boolean isBroadcastSupported() { + LocalBluetoothLeBroadcast broadcast = + mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile(); + return broadcast != null; + } } diff --git a/src/com/android/settings/bluetooth/QrCodeScanModeFragment.java b/src/com/android/settings/bluetooth/QrCodeScanModeFragment.java index dcf89ca9d0e..0253aa6b748 100644 --- a/src/com/android/settings/bluetooth/QrCodeScanModeFragment.java +++ b/src/com/android/settings/bluetooth/QrCodeScanModeFragment.java @@ -36,16 +36,15 @@ import android.view.ViewOutlineProvider; import android.view.accessibility.AccessibilityEvent; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; + import com.android.settings.core.InstrumentedFragment; import com.android.settingslib.R; import com.android.settingslib.bluetooth.BluetoothBroadcastUtils; import com.android.settingslib.bluetooth.BluetoothUtils; -import com.android.settingslib.core.lifecycle.ObservableFragment; import com.android.settingslib.qrcode.QrCamera; -import androidx.annotation.NonNull; -import androidx.annotation.StringRes; - public class QrCodeScanModeFragment extends InstrumentedFragment implements TextureView.SurfaceTextureListener, QrCamera.ScannerCallback { @@ -232,8 +231,7 @@ public class QrCodeScanModeFragment extends InstrumentedFragment implements } private void updateSummary() { - mSummary.setText(getString(R.string.bt_le_audio_scan_qr_code_scanner, - null /* broadcast_name*/));; + mSummary.setText(getString(R.string.bt_le_audio_scan_qr_code_scanner)); } @Override diff --git a/src/com/android/settings/notification/MediaVolumePreferenceController.java b/src/com/android/settings/notification/MediaVolumePreferenceController.java index 05c8e033930..2466b7747a3 100644 --- a/src/com/android/settings/notification/MediaVolumePreferenceController.java +++ b/src/com/android/settings/notification/MediaVolumePreferenceController.java @@ -29,6 +29,7 @@ import androidx.core.graphics.drawable.IconCompat; import androidx.slice.builders.ListBuilder; import androidx.slice.builders.SliceAction; +import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.bluetooth.BluetoothBroadcastDialog; @@ -90,13 +91,16 @@ public class MediaVolumePreferenceController extends VolumeSeekBarPreferenceCont return R.drawable.ic_media_stream_off; } - private boolean isSupportEndItem() { - return getWorker() != null - && getWorker().getActiveLocalMediaController() != null - && isConnectedBLEDevice(); + @VisibleForTesting + boolean isSupportEndItem() { + return isConnectedBLEDevice(); } private boolean isConnectedBLEDevice() { + if (getWorker() == null) { + Log.d(TAG, "The Worker is null"); + return false; + } mMediaDevice = getWorker().getCurrentConnectedMediaDevice(); if (mMediaDevice != null) { return mMediaDevice.isBLEDevice(); @@ -133,6 +137,8 @@ public class MediaVolumePreferenceController extends VolumeSeekBarPreferenceCont Utils.getApplicationLabel(mContext, getWorker().getPackageName())); intent.putExtra(BluetoothBroadcastDialog.KEY_DEVICE_ADDRESS, bluetoothDevice.getAddress()); + intent.putExtra(BluetoothBroadcastDialog.KEY_MEDIA_STREAMING, getWorker() != null + && getWorker().getActiveLocalMediaController() != null); pi = PendingIntent.getActivity(context, 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); diff --git a/tests/robotests/src/com/android/settings/notification/MediaVolumePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/MediaVolumePreferenceControllerTest.java index 7cfcaffb97d..56e83bb90ae 100644 --- a/tests/robotests/src/com/android/settings/notification/MediaVolumePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/MediaVolumePreferenceControllerTest.java @@ -16,29 +16,71 @@ package com.android.settings.notification; +import static com.android.settings.slices.CustomSliceRegistry.VOLUME_MEDIA_URI; + import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.app.PendingIntent; import android.content.Context; +import android.content.Intent; import android.media.AudioManager; +import android.media.session.MediaController; +import android.net.Uri; + +import androidx.slice.builders.SliceAction; + +import com.android.settings.media.MediaOutputIndicatorWorker; +import com.android.settings.slices.SliceBackgroundWorker; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.media.BluetoothMediaDevice; +import com.android.settingslib.media.MediaDevice; +import com.android.settingslib.media.MediaOutputConstants; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; @RunWith(RobolectricTestRunner.class) +@Config(shadows = MediaVolumePreferenceControllerTest.ShadowSliceBackgroundWorker.class) public class MediaVolumePreferenceControllerTest { + private static final String ACTION_LAUNCH_BROADCAST_DIALOG = + "android.settings.MEDIA_BROADCAST_DIALOG"; + private static MediaOutputIndicatorWorker sMediaOutputIndicatorWorker; + private MediaVolumePreferenceController mController; private Context mContext; + @Mock + private MediaController mMediaController; + @Mock + private MediaDevice mDevice1; + @Mock + private MediaDevice mDevice2; + @Before public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; mController = new MediaVolumePreferenceController(mContext); + sMediaOutputIndicatorWorker = spy( + new MediaOutputIndicatorWorker(mContext, VOLUME_MEDIA_URI)); + when(mDevice1.isBLEDevice()).thenReturn(true); + when(mDevice2.isBLEDevice()).thenReturn(false); } @Test @@ -68,4 +110,83 @@ public class MediaVolumePreferenceControllerTest { public void isPublicSlice_returnTrue() { assertThat(mController.isPublicSlice()).isTrue(); } + + @Test + public void isSupportEndItem_withBleDevice_returnsTrue() { + doReturn(mDevice1).when(sMediaOutputIndicatorWorker).getCurrentConnectedMediaDevice(); + + assertThat(mController.isSupportEndItem()).isTrue(); + } + + @Test + public void isSupportEndItem_withNonBleDevice_returnsFalse() { + doReturn(mDevice2).when(sMediaOutputIndicatorWorker).getCurrentConnectedMediaDevice(); + + assertThat(mController.isSupportEndItem()).isFalse(); + } + + @Test + public void getSliceEndItem_NotSupportEndItem_getsNullSliceAction() { + doReturn(mDevice2).when(sMediaOutputIndicatorWorker).getCurrentConnectedMediaDevice(); + + final SliceAction sliceAction = mController.getSliceEndItem(mContext); + + assertThat(sliceAction).isNull(); + } + + @Test + public void getSliceEndItem_deviceIsBroadcasting_getsBroadcastIntent() { + doReturn(mDevice1).when(sMediaOutputIndicatorWorker).getCurrentConnectedMediaDevice(); + doReturn(true).when(sMediaOutputIndicatorWorker).isDeviceBroadcasting(); + doReturn(mMediaController).when(sMediaOutputIndicatorWorker) + .getActiveLocalMediaController(); + + final SliceAction sliceAction = mController.getSliceEndItem(mContext); + + final PendingIntent endItemPendingIntent = sliceAction.getAction(); + final PendingIntent expectedToggleIntent = getBroadcastIntent( + MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG); + assertThat(endItemPendingIntent).isEqualTo(expectedToggleIntent); + } + + @Test + public void getSliceEndItem_deviceIsNotBroadcasting_getsActivityIntent() { + final MediaDevice device = mock(BluetoothMediaDevice.class); + final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class); + when(((BluetoothMediaDevice) device).getCachedDevice()).thenReturn(cachedDevice); + when(device.isBLEDevice()).thenReturn(true); + doReturn(device).when(sMediaOutputIndicatorWorker).getCurrentConnectedMediaDevice(); + doReturn(false).when(sMediaOutputIndicatorWorker).isDeviceBroadcasting(); + doReturn(mMediaController).when(sMediaOutputIndicatorWorker) + .getActiveLocalMediaController(); + + final SliceAction sliceAction = mController.getSliceEndItem(mContext); + + final PendingIntent endItemPendingIntent = sliceAction.getAction(); + final PendingIntent expectedPendingIntent = + getActivityIntent(ACTION_LAUNCH_BROADCAST_DIALOG); + assertThat(endItemPendingIntent).isEqualTo(expectedPendingIntent); + } + + @Implements(SliceBackgroundWorker.class) + public static class ShadowSliceBackgroundWorker { + + @Implementation + public static SliceBackgroundWorker getInstance(Uri uri) { + return sMediaOutputIndicatorWorker; + } + } + + private PendingIntent getBroadcastIntent(String action) { + final Intent intent = new Intent(action); + intent.setPackage(MediaOutputConstants.SYSTEMUI_PACKAGE_NAME); + return PendingIntent.getBroadcast(mContext, 0 /* requestCode */, intent, + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); + } + + private PendingIntent getActivityIntent(String action) { + final Intent intent = new Intent(action); + return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); + } }