[LE Audio] To fix the condition of the broadcast icon display
- The broadcast icon will be displayed when the device is connected to the LE Audio device. - The broadcast option dialog will show the "Broadcast" option when the media is streaming. Otherwise, it will not show. Bug: 235923182 Test: manual test Test: make RunSettingsRoboTests ROBOTEST_FILTER=MediaVolumePreferenceControllerTest Change-Id: Ib225d185b6f15463f4fae809e0cdaa25920d52af
This commit is contained in:
@@ -41,15 +41,18 @@ import com.android.settingslib.media.MediaOutputConstants;
|
|||||||
* nearby broadcast sources.
|
* nearby broadcast sources.
|
||||||
*/
|
*/
|
||||||
public class BluetoothBroadcastDialog extends InstrumentedDialogFragment {
|
public class BluetoothBroadcastDialog extends InstrumentedDialogFragment {
|
||||||
|
|
||||||
public static final String KEY_APP_LABEL = "app_label";
|
public static final String KEY_APP_LABEL = "app_label";
|
||||||
public static final String KEY_DEVICE_ADDRESS =
|
public static final String KEY_DEVICE_ADDRESS =
|
||||||
BluetoothFindBroadcastsFragment.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 String TAG = "BTBroadcastsDialog";
|
||||||
private static final CharSequence UNKNOWN_APP_LABEL = "unknown";
|
private static final CharSequence UNKNOWN_APP_LABEL = "unknown";
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private CharSequence mCurrentAppLabel = UNKNOWN_APP_LABEL;
|
private CharSequence mCurrentAppLabel = UNKNOWN_APP_LABEL;
|
||||||
private String mDeviceAddress;
|
private String mDeviceAddress;
|
||||||
|
private boolean mIsMediaStreaming;
|
||||||
private LocalBluetoothManager mLocalBluetoothManager;
|
private LocalBluetoothManager mLocalBluetoothManager;
|
||||||
private AlertDialog mAlertDialog;
|
private AlertDialog mAlertDialog;
|
||||||
|
|
||||||
@@ -59,6 +62,7 @@ public class BluetoothBroadcastDialog extends InstrumentedDialogFragment {
|
|||||||
mContext = getActivity();
|
mContext = getActivity();
|
||||||
mCurrentAppLabel = getActivity().getIntent().getCharSequenceExtra(KEY_APP_LABEL);
|
mCurrentAppLabel = getActivity().getIntent().getCharSequenceExtra(KEY_APP_LABEL);
|
||||||
mDeviceAddress = getActivity().getIntent().getStringExtra(KEY_DEVICE_ADDRESS);
|
mDeviceAddress = getActivity().getIntent().getStringExtra(KEY_DEVICE_ADDRESS);
|
||||||
|
mIsMediaStreaming = getActivity().getIntent().getBooleanExtra(KEY_MEDIA_STREAMING, false);
|
||||||
mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
|
mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
|
||||||
setShowsDialog(true);
|
setShowsDialog(true);
|
||||||
}
|
}
|
||||||
@@ -75,6 +79,8 @@ public class BluetoothBroadcastDialog extends InstrumentedDialogFragment {
|
|||||||
mContext.getString(R.string.bluetooth_broadcast_dialog_broadcast_message));
|
mContext.getString(R.string.bluetooth_broadcast_dialog_broadcast_message));
|
||||||
|
|
||||||
Button broadcastBtn = layout.findViewById(com.android.settingslib.R.id.positive_btn);
|
Button broadcastBtn = layout.findViewById(com.android.settingslib.R.id.positive_btn);
|
||||||
|
if (isBroadcastSupported() && mIsMediaStreaming) {
|
||||||
|
broadcastBtn.setVisibility(View.VISIBLE);
|
||||||
if (TextUtils.isEmpty(mCurrentAppLabel)) {
|
if (TextUtils.isEmpty(mCurrentAppLabel)) {
|
||||||
broadcastBtn.setText(mContext.getString(R.string.bluetooth_broadcast_dialog_title));
|
broadcastBtn.setText(mContext.getString(R.string.bluetooth_broadcast_dialog_title));
|
||||||
} else {
|
} else {
|
||||||
@@ -85,6 +91,9 @@ public class BluetoothBroadcastDialog extends InstrumentedDialogFragment {
|
|||||||
broadcastBtn.setOnClickListener((view) -> {
|
broadcastBtn.setOnClickListener((view) -> {
|
||||||
launchMediaOutputBroadcastDialog();
|
launchMediaOutputBroadcastDialog();
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
broadcastBtn.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
Button findBroadcastBtn = layout.findViewById(com.android.settingslib.R.id.negative_btn);
|
Button findBroadcastBtn = layout.findViewById(com.android.settingslib.R.id.negative_btn);
|
||||||
findBroadcastBtn.setText(mContext.getString(R.string.bluetooth_find_broadcast));
|
findBroadcastBtn.setText(mContext.getString(R.string.bluetooth_find_broadcast));
|
||||||
@@ -169,4 +178,10 @@ public class BluetoothBroadcastDialog extends InstrumentedDialogFragment {
|
|||||||
.setPackage(MediaOutputConstants.SETTINGS_PACKAGE_NAME)
|
.setPackage(MediaOutputConstants.SETTINGS_PACKAGE_NAME)
|
||||||
.setAction(MediaOutputConstants.ACTION_CLOSE_PANEL));
|
.setAction(MediaOutputConstants.ACTION_CLOSE_PANEL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isBroadcastSupported() {
|
||||||
|
LocalBluetoothLeBroadcast broadcast =
|
||||||
|
mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
|
||||||
|
return broadcast != null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -36,16 +36,15 @@ import android.view.ViewOutlineProvider;
|
|||||||
import android.view.accessibility.AccessibilityEvent;
|
import android.view.accessibility.AccessibilityEvent;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
|
|
||||||
import com.android.settings.core.InstrumentedFragment;
|
import com.android.settings.core.InstrumentedFragment;
|
||||||
import com.android.settingslib.R;
|
import com.android.settingslib.R;
|
||||||
import com.android.settingslib.bluetooth.BluetoothBroadcastUtils;
|
import com.android.settingslib.bluetooth.BluetoothBroadcastUtils;
|
||||||
import com.android.settingslib.bluetooth.BluetoothUtils;
|
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||||
import com.android.settingslib.core.lifecycle.ObservableFragment;
|
|
||||||
import com.android.settingslib.qrcode.QrCamera;
|
import com.android.settingslib.qrcode.QrCamera;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.StringRes;
|
|
||||||
|
|
||||||
public class QrCodeScanModeFragment extends InstrumentedFragment implements
|
public class QrCodeScanModeFragment extends InstrumentedFragment implements
|
||||||
TextureView.SurfaceTextureListener,
|
TextureView.SurfaceTextureListener,
|
||||||
QrCamera.ScannerCallback {
|
QrCamera.ScannerCallback {
|
||||||
@@ -232,8 +231,7 @@ public class QrCodeScanModeFragment extends InstrumentedFragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateSummary() {
|
private void updateSummary() {
|
||||||
mSummary.setText(getString(R.string.bt_le_audio_scan_qr_code_scanner,
|
mSummary.setText(getString(R.string.bt_le_audio_scan_qr_code_scanner));
|
||||||
null /* broadcast_name*/));;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -29,6 +29,7 @@ import androidx.core.graphics.drawable.IconCompat;
|
|||||||
import androidx.slice.builders.ListBuilder;
|
import androidx.slice.builders.ListBuilder;
|
||||||
import androidx.slice.builders.SliceAction;
|
import androidx.slice.builders.SliceAction;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.Utils;
|
import com.android.settings.Utils;
|
||||||
import com.android.settings.bluetooth.BluetoothBroadcastDialog;
|
import com.android.settings.bluetooth.BluetoothBroadcastDialog;
|
||||||
@@ -90,13 +91,16 @@ public class MediaVolumePreferenceController extends VolumeSeekBarPreferenceCont
|
|||||||
return R.drawable.ic_media_stream_off;
|
return R.drawable.ic_media_stream_off;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSupportEndItem() {
|
@VisibleForTesting
|
||||||
return getWorker() != null
|
boolean isSupportEndItem() {
|
||||||
&& getWorker().getActiveLocalMediaController() != null
|
return isConnectedBLEDevice();
|
||||||
&& isConnectedBLEDevice();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isConnectedBLEDevice() {
|
private boolean isConnectedBLEDevice() {
|
||||||
|
if (getWorker() == null) {
|
||||||
|
Log.d(TAG, "The Worker is null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
mMediaDevice = getWorker().getCurrentConnectedMediaDevice();
|
mMediaDevice = getWorker().getCurrentConnectedMediaDevice();
|
||||||
if (mMediaDevice != null) {
|
if (mMediaDevice != null) {
|
||||||
return mMediaDevice.isBLEDevice();
|
return mMediaDevice.isBLEDevice();
|
||||||
@@ -133,6 +137,8 @@ public class MediaVolumePreferenceController extends VolumeSeekBarPreferenceCont
|
|||||||
Utils.getApplicationLabel(mContext, getWorker().getPackageName()));
|
Utils.getApplicationLabel(mContext, getWorker().getPackageName()));
|
||||||
intent.putExtra(BluetoothBroadcastDialog.KEY_DEVICE_ADDRESS,
|
intent.putExtra(BluetoothBroadcastDialog.KEY_DEVICE_ADDRESS,
|
||||||
bluetoothDevice.getAddress());
|
bluetoothDevice.getAddress());
|
||||||
|
intent.putExtra(BluetoothBroadcastDialog.KEY_MEDIA_STREAMING, getWorker() != null
|
||||||
|
&& getWorker().getActiveLocalMediaController() != null);
|
||||||
|
|
||||||
pi = PendingIntent.getActivity(context, 0 /* requestCode */, intent,
|
pi = PendingIntent.getActivity(context, 0 /* requestCode */, intent,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
||||||
|
@@ -16,29 +16,71 @@
|
|||||||
|
|
||||||
package com.android.settings.notification;
|
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 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.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.media.AudioManager;
|
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.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.annotation.Implementation;
|
||||||
|
import org.robolectric.annotation.Implements;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
@Config(shadows = MediaVolumePreferenceControllerTest.ShadowSliceBackgroundWorker.class)
|
||||||
public class MediaVolumePreferenceControllerTest {
|
public class MediaVolumePreferenceControllerTest {
|
||||||
|
|
||||||
|
private static final String ACTION_LAUNCH_BROADCAST_DIALOG =
|
||||||
|
"android.settings.MEDIA_BROADCAST_DIALOG";
|
||||||
|
private static MediaOutputIndicatorWorker sMediaOutputIndicatorWorker;
|
||||||
|
|
||||||
private MediaVolumePreferenceController mController;
|
private MediaVolumePreferenceController mController;
|
||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private MediaController mMediaController;
|
||||||
|
@Mock
|
||||||
|
private MediaDevice mDevice1;
|
||||||
|
@Mock
|
||||||
|
private MediaDevice mDevice2;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
mContext = RuntimeEnvironment.application;
|
mContext = RuntimeEnvironment.application;
|
||||||
mController = new MediaVolumePreferenceController(mContext);
|
mController = new MediaVolumePreferenceController(mContext);
|
||||||
|
sMediaOutputIndicatorWorker = spy(
|
||||||
|
new MediaOutputIndicatorWorker(mContext, VOLUME_MEDIA_URI));
|
||||||
|
when(mDevice1.isBLEDevice()).thenReturn(true);
|
||||||
|
when(mDevice2.isBLEDevice()).thenReturn(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -68,4 +110,83 @@ public class MediaVolumePreferenceControllerTest {
|
|||||||
public void isPublicSlice_returnTrue() {
|
public void isPublicSlice_returnTrue() {
|
||||||
assertThat(mController.isPublicSlice()).isTrue();
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user