Loading src/com/android/settings/bluetooth/BluetoothBroadcastDialog.java +22 −7 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); } Loading @@ -75,6 +79,8 @@ 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 (isBroadcastSupported() && mIsMediaStreaming) { broadcastBtn.setVisibility(View.VISIBLE); if (TextUtils.isEmpty(mCurrentAppLabel)) { broadcastBtn.setText(mContext.getString(R.string.bluetooth_broadcast_dialog_title)); } else { Loading @@ -85,6 +91,9 @@ public class BluetoothBroadcastDialog extends InstrumentedDialogFragment { broadcastBtn.setOnClickListener((view) -> { launchMediaOutputBroadcastDialog(); }); } else { broadcastBtn.setVisibility(View.GONE); } Button findBroadcastBtn = layout.findViewById(com.android.settingslib.R.id.negative_btn); findBroadcastBtn.setText(mContext.getString(R.string.bluetooth_find_broadcast)); Loading Loading @@ -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; } } src/com/android/settings/bluetooth/QrCodeScanModeFragment.java +4 −6 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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 Loading src/com/android/settings/notification/MediaVolumePreferenceController.java +10 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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); Loading tests/robotests/src/com/android/settings/notification/MediaVolumePreferenceControllerTest.java +121 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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); } } Loading
src/com/android/settings/bluetooth/BluetoothBroadcastDialog.java +22 −7 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); } Loading @@ -75,6 +79,8 @@ 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 (isBroadcastSupported() && mIsMediaStreaming) { broadcastBtn.setVisibility(View.VISIBLE); if (TextUtils.isEmpty(mCurrentAppLabel)) { broadcastBtn.setText(mContext.getString(R.string.bluetooth_broadcast_dialog_title)); } else { Loading @@ -85,6 +91,9 @@ public class BluetoothBroadcastDialog extends InstrumentedDialogFragment { broadcastBtn.setOnClickListener((view) -> { launchMediaOutputBroadcastDialog(); }); } else { broadcastBtn.setVisibility(View.GONE); } Button findBroadcastBtn = layout.findViewById(com.android.settingslib.R.id.negative_btn); findBroadcastBtn.setText(mContext.getString(R.string.bluetooth_find_broadcast)); Loading Loading @@ -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; } }
src/com/android/settings/bluetooth/QrCodeScanModeFragment.java +4 −6 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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 Loading
src/com/android/settings/notification/MediaVolumePreferenceController.java +10 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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); Loading
tests/robotests/src/com/android/settings/notification/MediaVolumePreferenceControllerTest.java +121 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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); } }