Loading res/xml/bluetooth_audio_sharing.xml +5 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,11 @@ xmlns:settings="http://schemas.android.com/apk/res-auto" android:title="@string/audio_sharing_title"> <com.android.settingslib.widget.TopIntroPreference android:key="audio_sharing_top_intro" android:title="Let others listen to your media along with you using their own compatible headphones" settings:searchable="false" /> <PreferenceCategory android:key="audio_sharing_device_volume_group" android:title="Devices listening" Loading res/xml/connected_devices.xml +25 −25 Original line number Diff line number Diff line Loading @@ -23,8 +23,8 @@ <com.android.settings.slices.SlicePreference android:key="bt_nearby_slice" android:title="@string/summary_placeholder" settings:controller="com.android.settings.slices.SlicePreferenceController" settings:allowDividerBelow="true"/> settings:allowDividerBelow="true" settings:controller="com.android.settings.slices.SlicePreferenceController" /> <PreferenceCategory android:key="audio_sharing_device_list" Loading @@ -32,11 +32,11 @@ settings:controller="com.android.settings.connecteddevice.audiosharing.AudioSharingDevicePreferenceController"> <Preference android:fragment="com.android.settings.connecteddevice.audiosharing.AudioSharingDashboardFragment" android:key="connected_device_audio_sharing_settings" android:title="@string/audio_sharing_title" android:icon="@drawable/ic_bt_audio_sharing" android:key="connected_device_audio_sharing_settings" android:order="10" settings:controller="com.android.settings.connecteddevice.audiosharing.AudioSharingPreferenceController"/> android:title="@string/audio_sharing_title" settings:searchable="false" /> </PreferenceCategory> <PreferenceCategory Loading @@ -50,15 +50,15 @@ settings:controller="com.android.settings.connecteddevice.ConnectedDeviceGroupController" /> <com.android.settingslib.RestrictedPreference android:key="add_bt_devices" android:title="@string/bluetooth_pairing_pref_title" android:fragment="com.android.settings.bluetooth.BluetoothPairingDetail" android:icon="@drawable/ic_add_24dp" android:key="add_bt_devices" android:summary="@string/connected_device_add_device_summary" android:fragment="com.android.settings.bluetooth.BluetoothPairingDetail" android:title="@string/bluetooth_pairing_pref_title" settings:controller="com.android.settings.connecteddevice.AddDevicePreferenceController" settings:keywords="@string/keywords_add_bt_device" settings:userRestriction="no_config_bluetooth" settings:useAdminDisabledSummary="true" settings:controller="com.android.settings.connecteddevice.AddDevicePreferenceController"/> settings:userRestriction="no_config_bluetooth" /> <PreferenceCategory android:key="previously_connected_devices" Loading @@ -66,12 +66,12 @@ settings:controller="com.android.settings.connecteddevice.PreviouslyConnectedDevicePreferenceController"> <Preference android:key="previously_connected_devices_see_all" android:title="@string/previous_connected_see_all" android:fragment="com.android.settings.connecteddevice.PreviouslyConnectedDeviceDashboardFragment" android:icon="@drawable/ic_chevron_right_24dp" android:key="previously_connected_devices_see_all" android:order="10" settings:searchable="false" android:fragment="com.android.settings.connecteddevice.PreviouslyConnectedDeviceDashboardFragment"/> android:title="@string/previous_connected_see_all" settings:searchable="false" /> </PreferenceCategory> <PreferenceCategory Loading @@ -81,27 +81,27 @@ "com.android.settings.connecteddevice.fastpair.FastPairDevicePreferenceController"> <Preference android:key="fast_pair_devices_see_all" android:title="@string/connected_device_fast_pair_device_see_all" android:fragment= "com.android.settings.connecteddevice.fastpair.FastPairDeviceDashboardFragment" android:icon="@drawable/ic_chevron_right_24dp" android:key="fast_pair_devices_see_all" android:order="10" settings:searchable="false" android:fragment= "com.android.settings.connecteddevice.fastpair.FastPairDeviceDashboardFragment"/> android:title="@string/connected_device_fast_pair_device_see_all" settings:searchable="false" /> </PreferenceCategory> <Preference android:fragment="com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment" android:key="connection_preferences" android:title="@string/connected_device_connections_title" android:summary="@string/summary_placeholder" android:fragment="com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment" android:title="@string/connected_device_connections_title" settings:allowDividerAbove="true" settings:controller="com.android.settings.connecteddevice.AdvancedConnectedDeviceController" /> <com.android.settingslib.widget.FooterPreference android:key="discoverable_footer" android:title="@string/bluetooth_off_footer" android:selectable="false" android:title="@string/bluetooth_off_footer" settings:controller="com.android.settings.connecteddevice.DiscoverableFooterPreferenceController"> </com.android.settingslib.widget.FooterPreference> Loading res/xml/connected_devices_advanced.xml +23 −21 Original line number Diff line number Diff line Loading @@ -21,54 +21,56 @@ <Preference android:fragment="com.android.settings.connecteddevice.BluetoothDashboardFragment" android:key="bluetooth_switchbar_screen" android:title="@string/bluetooth_settings_title" android:icon="@*android:drawable/ic_settings_bluetooth" android:order="-9"/> android:key="bluetooth_switchbar_screen" android:order="-10" android:title="@string/bluetooth_settings_title" /> <Preference android:fragment="com.android.settings.connecteddevice.audiosharing.AudioSharingDashboardFragment" android:icon="@drawable/ic_bt_audio_sharing" android:key="audio_sharing_settings" android:order="-9" android:title="@string/audio_sharing_title" android:icon="@drawable/ic_bt_audio_sharing" settings:controller="com.android.settings.connecteddevice.audiosharing.AudioSharingPreferenceController"/> settings:controller="com.android.settings.connecteddevice.audiosharing.AudioSharingPreferenceController" settings:searchable="true" /> <com.android.settingslib.RestrictedPreference android:fragment="com.android.settings.connecteddevice.NfcAndPaymentFragment" android:key="nfc_and_payment_settings" android:title="@string/nfc_quick_toggle_title" android:icon="@drawable/ic_nfc" android:key="nfc_and_payment_settings" android:order="-7" settings:searchable="false" android:title="@string/nfc_quick_toggle_title" settings:controller="com.android.settings.connecteddevice.NfcAndPaymentFragmentController" settings:userRestriction="no_near_field_communication_radio" settings:useAdminDisabledSummary="true"/> settings:searchable="false" settings:useAdminDisabledSummary="true" settings:userRestriction="no_near_field_communication_radio" /> <Preference android:fragment="com.android.settings.wfd.WifiDisplaySettings" android:key="wifi_display_settings" android:title="@string/wifi_display_settings_title" android:icon="@drawable/ic_cast_24dp" android:key="wifi_display_settings" android:order="-6" android:title="@string/wifi_display_settings_title" settings:controller="com.android.settings.wfd.WifiDisplayPreferenceController" settings:keywords="@string/keywords_wifi_display_settings" /> <com.android.settingslib.RestrictedPreference android:fragment="com.android.settings.print.PrintSettingsFragment" android:icon="@*android:drawable/ic_settings_print" android:key="connected_device_printing" android:title="@string/print_settings" android:order="-3" android:summary="@string/summary_placeholder" android:icon="@*android:drawable/ic_settings_print" android:fragment="com.android.settings.print.PrintSettingsFragment" android:order="-3"/> android:title="@string/print_settings" /> <com.android.settingslib.RestrictedSwitchPreference android:key="uwb_settings" android:title="@string/uwb_settings_title" android:order="100" android:summary="@string/summary_placeholder" android:title="@string/uwb_settings_title" settings:controller="com.android.settings.uwb.UwbPreferenceController" settings:userRestriction="no_ultra_wideband_radio" settings:useAdminDisabledSummary="true"/> settings:useAdminDisabledSummary="true" settings:userRestriction="no_ultra_wideband_radio" /> <PreferenceCategory android:key="dashboard_tile_placeholder" Loading src/com/android/settings/connecteddevice/audiosharing/AudioSharingPreferenceController.java +104 −3 Original line number Diff line number Diff line Loading @@ -16,22 +16,123 @@ package com.android.settings.connecteddevice.audiosharing; import android.bluetooth.BluetoothLeBroadcast; import android.bluetooth.BluetoothLeBroadcastMetadata; import android.content.Context; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.lifecycle.DefaultLifecycleObserver; import androidx.lifecycle.LifecycleOwner; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.bluetooth.Utils; import com.android.settings.core.BasePreferenceController; import com.android.settingslib.bluetooth.BluetoothCallback; import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast; import com.android.settingslib.bluetooth.LocalBluetoothManager; import java.util.concurrent.Executor; import java.util.concurrent.Executors; public class AudioSharingPreferenceController extends BasePreferenceController { public class AudioSharingPreferenceController extends BasePreferenceController implements DefaultLifecycleObserver, BluetoothCallback { private static final String TAG = "AudioSharingPreferenceController"; private Context mContext; private final LocalBluetoothManager mLocalBtManager; private final Executor mExecutor; @Nullable private LocalBluetoothLeBroadcast mBroadcast = null; @Nullable private Preference mPreference; private final BluetoothLeBroadcast.Callback mBroadcastCallback = new BluetoothLeBroadcast.Callback() { @Override public void onBroadcastStarted(int reason, int broadcastId) { if (mPreference != null) { refreshSummary(mPreference); } } @Override public void onBroadcastStartFailed(int reason) {} @Override public void onBroadcastMetadataChanged( int broadcastId, @NonNull BluetoothLeBroadcastMetadata metadata) {} @Override public void onBroadcastStopped(int reason, int broadcastId) { if (mPreference != null) { refreshSummary(mPreference); } } @Override public void onBroadcastStopFailed(int reason) {} @Override public void onBroadcastUpdated(int reason, int broadcastId) {} @Override public void onBroadcastUpdateFailed(int reason, int broadcastId) {} @Override public void onPlaybackStarted(int reason, int broadcastId) {} @Override public void onPlaybackStopped(int reason, int broadcastId) {} }; public AudioSharingPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); mContext = context; mLocalBtManager = Utils.getLocalBtManager(context); if (mLocalBtManager != null) { mBroadcast = mLocalBtManager.getProfileManager().getLeAudioBroadcastProfile(); } mExecutor = Executors.newSingleThreadExecutor(); } @Override public void onStart(@NonNull LifecycleOwner owner) { if (mLocalBtManager != null) { mLocalBtManager.getEventManager().registerCallback(this); } if (mBroadcast != null) { mBroadcast.registerServiceCallBack(mExecutor, mBroadcastCallback); } } @Override public void onStop(@NonNull LifecycleOwner owner) { if (mLocalBtManager != null) { mLocalBtManager.getEventManager().unregisterCallback(this); } if (mBroadcast != null) { mBroadcast.unregisterServiceCallBack(mBroadcastCallback); } } @Override public void displayPreference(@NonNull PreferenceScreen screen) { super.displayPreference(screen); mPreference = screen.findPreference(getPreferenceKey()); } @Override public int getAvailabilityStatus() { return AudioSharingUtils.isFeatureEnabled() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } @Override public CharSequence getSummary() { return AudioSharingUtils.isBroadcasting(mLocalBtManager) ? "On" : "Off"; } @Override public void onBluetoothStateChanged(@AdapterState int bluetoothState) { if (mPreference != null) { refreshSummary(mPreference); } } } tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingPreferenceControllerTest.java 0 → 100644 +160 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.connecteddevice.audiosharing; import static android.bluetooth.BluetoothAdapter.STATE_OFF; import static android.bluetooth.BluetoothAdapter.STATE_ON; import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothLeBroadcast; import android.bluetooth.BluetoothStatusCodes; import android.content.Context; import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import androidx.lifecycle.LifecycleOwner; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; import com.android.settings.bluetooth.Utils; import com.android.settings.flags.Flags; import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; import com.android.settings.testutils.shadow.ShadowBluetoothUtils; import com.android.settingslib.bluetooth.BluetoothEventManager; import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; import com.android.settingslib.core.lifecycle.Lifecycle; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; @RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothUtils.class}) public class AudioSharingPreferenceControllerTest { private static final String PREF_KEY = "audio_sharing_settings"; private static final String SUMMARY_ON = "On"; private static final String SUMMARY_OFF = "Off"; @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); @Spy Context mContext = ApplicationProvider.getApplicationContext(); @Mock private PreferenceScreen mScreen; @Mock private LocalBluetoothManager mLocalBtManager; @Mock private BluetoothEventManager mBtEventManager; @Mock private LocalBluetoothProfileManager mLocalBtProfileManager; @Mock private LocalBluetoothLeBroadcast mBroadcast; private AudioSharingPreferenceController mController; private ShadowBluetoothAdapter mShadowBluetoothAdapter; private LocalBluetoothManager mLocalBluetoothManager; private Lifecycle mLifecycle; private LifecycleOwner mLifecycleOwner; private Preference mPreference; @Before public void setUp() { mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter()); mShadowBluetoothAdapter.setEnabled(true); mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported( BluetoothStatusCodes.FEATURE_SUPPORTED); mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported( BluetoothStatusCodes.FEATURE_SUPPORTED); mLifecycleOwner = () -> mLifecycle; mLifecycle = new Lifecycle(mLifecycleOwner); ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBtManager; mLocalBluetoothManager = Utils.getLocalBtManager(mContext); when(mLocalBluetoothManager.getEventManager()).thenReturn(mBtEventManager); when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBtProfileManager); when(mLocalBtProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast); mController = new AudioSharingPreferenceController(mContext, PREF_KEY); mPreference = new Preference(mContext); when(mScreen.findPreference(PREF_KEY)).thenReturn(mPreference); } @Test public void onStart_registerCallback() { mController.onStart(mLifecycleOwner); verify(mBtEventManager).registerCallback(mController); verify(mBroadcast).registerServiceCallBack(any(), any(BluetoothLeBroadcast.Callback.class)); } @Test public void onStop_unregisterCallback() { mController.onStop(mLifecycleOwner); verify(mBtEventManager).unregisterCallback(mController); verify(mBroadcast).unregisterServiceCallBack(any(BluetoothLeBroadcast.Callback.class)); } @Test @RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING) public void getAvailabilityStatus_flagOn() { assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); } @Test @RequiresFlagsDisabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING) public void getAvailabilityStatus_flagOff() { assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); } @Test public void getSummary_broadcastOn() { when(mBroadcast.isEnabled(any())).thenReturn(true); assertThat(mController.getSummary().toString()).isEqualTo(SUMMARY_ON); } @Test public void getSummary_broadcastOff() { when(mBroadcast.isEnabled(any())).thenReturn(false); assertThat(mController.getSummary().toString()).isEqualTo(SUMMARY_OFF); } @Test public void onBluetoothStateChanged_refreshSummary() { mController.displayPreference(mScreen); when(mBroadcast.isEnabled(any())).thenReturn(true); mController.onBluetoothStateChanged(STATE_ON); assertThat(mPreference.getSummary().toString()).isEqualTo(SUMMARY_ON); when(mBroadcast.isEnabled(any())).thenReturn(false); mController.onBluetoothStateChanged(STATE_OFF); assertThat(mPreference.getSummary().toString()).isEqualTo(SUMMARY_OFF); } } Loading
res/xml/bluetooth_audio_sharing.xml +5 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,11 @@ xmlns:settings="http://schemas.android.com/apk/res-auto" android:title="@string/audio_sharing_title"> <com.android.settingslib.widget.TopIntroPreference android:key="audio_sharing_top_intro" android:title="Let others listen to your media along with you using their own compatible headphones" settings:searchable="false" /> <PreferenceCategory android:key="audio_sharing_device_volume_group" android:title="Devices listening" Loading
res/xml/connected_devices.xml +25 −25 Original line number Diff line number Diff line Loading @@ -23,8 +23,8 @@ <com.android.settings.slices.SlicePreference android:key="bt_nearby_slice" android:title="@string/summary_placeholder" settings:controller="com.android.settings.slices.SlicePreferenceController" settings:allowDividerBelow="true"/> settings:allowDividerBelow="true" settings:controller="com.android.settings.slices.SlicePreferenceController" /> <PreferenceCategory android:key="audio_sharing_device_list" Loading @@ -32,11 +32,11 @@ settings:controller="com.android.settings.connecteddevice.audiosharing.AudioSharingDevicePreferenceController"> <Preference android:fragment="com.android.settings.connecteddevice.audiosharing.AudioSharingDashboardFragment" android:key="connected_device_audio_sharing_settings" android:title="@string/audio_sharing_title" android:icon="@drawable/ic_bt_audio_sharing" android:key="connected_device_audio_sharing_settings" android:order="10" settings:controller="com.android.settings.connecteddevice.audiosharing.AudioSharingPreferenceController"/> android:title="@string/audio_sharing_title" settings:searchable="false" /> </PreferenceCategory> <PreferenceCategory Loading @@ -50,15 +50,15 @@ settings:controller="com.android.settings.connecteddevice.ConnectedDeviceGroupController" /> <com.android.settingslib.RestrictedPreference android:key="add_bt_devices" android:title="@string/bluetooth_pairing_pref_title" android:fragment="com.android.settings.bluetooth.BluetoothPairingDetail" android:icon="@drawable/ic_add_24dp" android:key="add_bt_devices" android:summary="@string/connected_device_add_device_summary" android:fragment="com.android.settings.bluetooth.BluetoothPairingDetail" android:title="@string/bluetooth_pairing_pref_title" settings:controller="com.android.settings.connecteddevice.AddDevicePreferenceController" settings:keywords="@string/keywords_add_bt_device" settings:userRestriction="no_config_bluetooth" settings:useAdminDisabledSummary="true" settings:controller="com.android.settings.connecteddevice.AddDevicePreferenceController"/> settings:userRestriction="no_config_bluetooth" /> <PreferenceCategory android:key="previously_connected_devices" Loading @@ -66,12 +66,12 @@ settings:controller="com.android.settings.connecteddevice.PreviouslyConnectedDevicePreferenceController"> <Preference android:key="previously_connected_devices_see_all" android:title="@string/previous_connected_see_all" android:fragment="com.android.settings.connecteddevice.PreviouslyConnectedDeviceDashboardFragment" android:icon="@drawable/ic_chevron_right_24dp" android:key="previously_connected_devices_see_all" android:order="10" settings:searchable="false" android:fragment="com.android.settings.connecteddevice.PreviouslyConnectedDeviceDashboardFragment"/> android:title="@string/previous_connected_see_all" settings:searchable="false" /> </PreferenceCategory> <PreferenceCategory Loading @@ -81,27 +81,27 @@ "com.android.settings.connecteddevice.fastpair.FastPairDevicePreferenceController"> <Preference android:key="fast_pair_devices_see_all" android:title="@string/connected_device_fast_pair_device_see_all" android:fragment= "com.android.settings.connecteddevice.fastpair.FastPairDeviceDashboardFragment" android:icon="@drawable/ic_chevron_right_24dp" android:key="fast_pair_devices_see_all" android:order="10" settings:searchable="false" android:fragment= "com.android.settings.connecteddevice.fastpair.FastPairDeviceDashboardFragment"/> android:title="@string/connected_device_fast_pair_device_see_all" settings:searchable="false" /> </PreferenceCategory> <Preference android:fragment="com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment" android:key="connection_preferences" android:title="@string/connected_device_connections_title" android:summary="@string/summary_placeholder" android:fragment="com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment" android:title="@string/connected_device_connections_title" settings:allowDividerAbove="true" settings:controller="com.android.settings.connecteddevice.AdvancedConnectedDeviceController" /> <com.android.settingslib.widget.FooterPreference android:key="discoverable_footer" android:title="@string/bluetooth_off_footer" android:selectable="false" android:title="@string/bluetooth_off_footer" settings:controller="com.android.settings.connecteddevice.DiscoverableFooterPreferenceController"> </com.android.settingslib.widget.FooterPreference> Loading
res/xml/connected_devices_advanced.xml +23 −21 Original line number Diff line number Diff line Loading @@ -21,54 +21,56 @@ <Preference android:fragment="com.android.settings.connecteddevice.BluetoothDashboardFragment" android:key="bluetooth_switchbar_screen" android:title="@string/bluetooth_settings_title" android:icon="@*android:drawable/ic_settings_bluetooth" android:order="-9"/> android:key="bluetooth_switchbar_screen" android:order="-10" android:title="@string/bluetooth_settings_title" /> <Preference android:fragment="com.android.settings.connecteddevice.audiosharing.AudioSharingDashboardFragment" android:icon="@drawable/ic_bt_audio_sharing" android:key="audio_sharing_settings" android:order="-9" android:title="@string/audio_sharing_title" android:icon="@drawable/ic_bt_audio_sharing" settings:controller="com.android.settings.connecteddevice.audiosharing.AudioSharingPreferenceController"/> settings:controller="com.android.settings.connecteddevice.audiosharing.AudioSharingPreferenceController" settings:searchable="true" /> <com.android.settingslib.RestrictedPreference android:fragment="com.android.settings.connecteddevice.NfcAndPaymentFragment" android:key="nfc_and_payment_settings" android:title="@string/nfc_quick_toggle_title" android:icon="@drawable/ic_nfc" android:key="nfc_and_payment_settings" android:order="-7" settings:searchable="false" android:title="@string/nfc_quick_toggle_title" settings:controller="com.android.settings.connecteddevice.NfcAndPaymentFragmentController" settings:userRestriction="no_near_field_communication_radio" settings:useAdminDisabledSummary="true"/> settings:searchable="false" settings:useAdminDisabledSummary="true" settings:userRestriction="no_near_field_communication_radio" /> <Preference android:fragment="com.android.settings.wfd.WifiDisplaySettings" android:key="wifi_display_settings" android:title="@string/wifi_display_settings_title" android:icon="@drawable/ic_cast_24dp" android:key="wifi_display_settings" android:order="-6" android:title="@string/wifi_display_settings_title" settings:controller="com.android.settings.wfd.WifiDisplayPreferenceController" settings:keywords="@string/keywords_wifi_display_settings" /> <com.android.settingslib.RestrictedPreference android:fragment="com.android.settings.print.PrintSettingsFragment" android:icon="@*android:drawable/ic_settings_print" android:key="connected_device_printing" android:title="@string/print_settings" android:order="-3" android:summary="@string/summary_placeholder" android:icon="@*android:drawable/ic_settings_print" android:fragment="com.android.settings.print.PrintSettingsFragment" android:order="-3"/> android:title="@string/print_settings" /> <com.android.settingslib.RestrictedSwitchPreference android:key="uwb_settings" android:title="@string/uwb_settings_title" android:order="100" android:summary="@string/summary_placeholder" android:title="@string/uwb_settings_title" settings:controller="com.android.settings.uwb.UwbPreferenceController" settings:userRestriction="no_ultra_wideband_radio" settings:useAdminDisabledSummary="true"/> settings:useAdminDisabledSummary="true" settings:userRestriction="no_ultra_wideband_radio" /> <PreferenceCategory android:key="dashboard_tile_placeholder" Loading
src/com/android/settings/connecteddevice/audiosharing/AudioSharingPreferenceController.java +104 −3 Original line number Diff line number Diff line Loading @@ -16,22 +16,123 @@ package com.android.settings.connecteddevice.audiosharing; import android.bluetooth.BluetoothLeBroadcast; import android.bluetooth.BluetoothLeBroadcastMetadata; import android.content.Context; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.lifecycle.DefaultLifecycleObserver; import androidx.lifecycle.LifecycleOwner; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.bluetooth.Utils; import com.android.settings.core.BasePreferenceController; import com.android.settingslib.bluetooth.BluetoothCallback; import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast; import com.android.settingslib.bluetooth.LocalBluetoothManager; import java.util.concurrent.Executor; import java.util.concurrent.Executors; public class AudioSharingPreferenceController extends BasePreferenceController { public class AudioSharingPreferenceController extends BasePreferenceController implements DefaultLifecycleObserver, BluetoothCallback { private static final String TAG = "AudioSharingPreferenceController"; private Context mContext; private final LocalBluetoothManager mLocalBtManager; private final Executor mExecutor; @Nullable private LocalBluetoothLeBroadcast mBroadcast = null; @Nullable private Preference mPreference; private final BluetoothLeBroadcast.Callback mBroadcastCallback = new BluetoothLeBroadcast.Callback() { @Override public void onBroadcastStarted(int reason, int broadcastId) { if (mPreference != null) { refreshSummary(mPreference); } } @Override public void onBroadcastStartFailed(int reason) {} @Override public void onBroadcastMetadataChanged( int broadcastId, @NonNull BluetoothLeBroadcastMetadata metadata) {} @Override public void onBroadcastStopped(int reason, int broadcastId) { if (mPreference != null) { refreshSummary(mPreference); } } @Override public void onBroadcastStopFailed(int reason) {} @Override public void onBroadcastUpdated(int reason, int broadcastId) {} @Override public void onBroadcastUpdateFailed(int reason, int broadcastId) {} @Override public void onPlaybackStarted(int reason, int broadcastId) {} @Override public void onPlaybackStopped(int reason, int broadcastId) {} }; public AudioSharingPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); mContext = context; mLocalBtManager = Utils.getLocalBtManager(context); if (mLocalBtManager != null) { mBroadcast = mLocalBtManager.getProfileManager().getLeAudioBroadcastProfile(); } mExecutor = Executors.newSingleThreadExecutor(); } @Override public void onStart(@NonNull LifecycleOwner owner) { if (mLocalBtManager != null) { mLocalBtManager.getEventManager().registerCallback(this); } if (mBroadcast != null) { mBroadcast.registerServiceCallBack(mExecutor, mBroadcastCallback); } } @Override public void onStop(@NonNull LifecycleOwner owner) { if (mLocalBtManager != null) { mLocalBtManager.getEventManager().unregisterCallback(this); } if (mBroadcast != null) { mBroadcast.unregisterServiceCallBack(mBroadcastCallback); } } @Override public void displayPreference(@NonNull PreferenceScreen screen) { super.displayPreference(screen); mPreference = screen.findPreference(getPreferenceKey()); } @Override public int getAvailabilityStatus() { return AudioSharingUtils.isFeatureEnabled() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } @Override public CharSequence getSummary() { return AudioSharingUtils.isBroadcasting(mLocalBtManager) ? "On" : "Off"; } @Override public void onBluetoothStateChanged(@AdapterState int bluetoothState) { if (mPreference != null) { refreshSummary(mPreference); } } }
tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingPreferenceControllerTest.java 0 → 100644 +160 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.connecteddevice.audiosharing; import static android.bluetooth.BluetoothAdapter.STATE_OFF; import static android.bluetooth.BluetoothAdapter.STATE_ON; import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothLeBroadcast; import android.bluetooth.BluetoothStatusCodes; import android.content.Context; import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import androidx.lifecycle.LifecycleOwner; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; import com.android.settings.bluetooth.Utils; import com.android.settings.flags.Flags; import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; import com.android.settings.testutils.shadow.ShadowBluetoothUtils; import com.android.settingslib.bluetooth.BluetoothEventManager; import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; import com.android.settingslib.core.lifecycle.Lifecycle; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; @RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothUtils.class}) public class AudioSharingPreferenceControllerTest { private static final String PREF_KEY = "audio_sharing_settings"; private static final String SUMMARY_ON = "On"; private static final String SUMMARY_OFF = "Off"; @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); @Spy Context mContext = ApplicationProvider.getApplicationContext(); @Mock private PreferenceScreen mScreen; @Mock private LocalBluetoothManager mLocalBtManager; @Mock private BluetoothEventManager mBtEventManager; @Mock private LocalBluetoothProfileManager mLocalBtProfileManager; @Mock private LocalBluetoothLeBroadcast mBroadcast; private AudioSharingPreferenceController mController; private ShadowBluetoothAdapter mShadowBluetoothAdapter; private LocalBluetoothManager mLocalBluetoothManager; private Lifecycle mLifecycle; private LifecycleOwner mLifecycleOwner; private Preference mPreference; @Before public void setUp() { mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter()); mShadowBluetoothAdapter.setEnabled(true); mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported( BluetoothStatusCodes.FEATURE_SUPPORTED); mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported( BluetoothStatusCodes.FEATURE_SUPPORTED); mLifecycleOwner = () -> mLifecycle; mLifecycle = new Lifecycle(mLifecycleOwner); ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBtManager; mLocalBluetoothManager = Utils.getLocalBtManager(mContext); when(mLocalBluetoothManager.getEventManager()).thenReturn(mBtEventManager); when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBtProfileManager); when(mLocalBtProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast); mController = new AudioSharingPreferenceController(mContext, PREF_KEY); mPreference = new Preference(mContext); when(mScreen.findPreference(PREF_KEY)).thenReturn(mPreference); } @Test public void onStart_registerCallback() { mController.onStart(mLifecycleOwner); verify(mBtEventManager).registerCallback(mController); verify(mBroadcast).registerServiceCallBack(any(), any(BluetoothLeBroadcast.Callback.class)); } @Test public void onStop_unregisterCallback() { mController.onStop(mLifecycleOwner); verify(mBtEventManager).unregisterCallback(mController); verify(mBroadcast).unregisterServiceCallBack(any(BluetoothLeBroadcast.Callback.class)); } @Test @RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING) public void getAvailabilityStatus_flagOn() { assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); } @Test @RequiresFlagsDisabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING) public void getAvailabilityStatus_flagOff() { assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); } @Test public void getSummary_broadcastOn() { when(mBroadcast.isEnabled(any())).thenReturn(true); assertThat(mController.getSummary().toString()).isEqualTo(SUMMARY_ON); } @Test public void getSummary_broadcastOff() { when(mBroadcast.isEnabled(any())).thenReturn(false); assertThat(mController.getSummary().toString()).isEqualTo(SUMMARY_OFF); } @Test public void onBluetoothStateChanged_refreshSummary() { mController.displayPreference(mScreen); when(mBroadcast.isEnabled(any())).thenReturn(true); mController.onBluetoothStateChanged(STATE_ON); assertThat(mPreference.getSummary().toString()).isEqualTo(SUMMARY_ON); when(mBroadcast.isEnabled(any())).thenReturn(false); mController.onBluetoothStateChanged(STATE_OFF); assertThat(mPreference.getSummary().toString()).isEqualTo(SUMMARY_OFF); } }