From 76d8145f1548cd076a31bb4b0fb6bbdc58a109d5 Mon Sep 17 00:00:00 2001 From: Haijie Hong Date: Mon, 15 Jan 2024 17:30:04 +0800 Subject: [PATCH] Add BT extra options in device details page Bug: 319562236 Test: make RunSettingsRoboTests ROBOTEST_FILTER=BluetoothDetailsExtraOptionsControllerTest Change-Id: Ifab39d2bd19044d60f090f4a0419d1e20b2ad925 --- res/xml/bluetooth_device_details_fragment.xml | 3 + ...luetoothDetailsExtraOptionsController.java | 88 ++++++++++++++++++ .../BluetoothDeviceDetailsFragment.java | 3 + .../bluetooth/BluetoothFeatureProvider.java | 13 +++ .../BluetoothFeatureProviderImpl.java | 11 +++ ...oothDetailsExtraOptionsControllerTest.java | 89 +++++++++++++++++++ 6 files changed, 207 insertions(+) create mode 100644 src/com/android/settings/bluetooth/BluetoothDetailsExtraOptionsController.java create mode 100644 tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsExtraOptionsControllerTest.java diff --git a/res/xml/bluetooth_device_details_fragment.xml b/res/xml/bluetooth_device_details_fragment.xml index 12ed8ebdd83..d260554f937 100644 --- a/res/xml/bluetooth_device_details_fragment.xml +++ b/res/xml/bluetooth_device_details_fragment.xml @@ -80,6 +80,9 @@ + + diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsExtraOptionsController.java b/src/com/android/settings/bluetooth/BluetoothDetailsExtraOptionsController.java new file mode 100644 index 00000000000..ddaf5e5ccf3 --- /dev/null +++ b/src/com/android/settings/bluetooth/BluetoothDetailsExtraOptionsController.java @@ -0,0 +1,88 @@ +/* + * 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.bluetooth; + +import android.content.Context; + +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceScreen; + +import com.android.settings.overlay.FeatureFactory; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.utils.ThreadUtils; + +import dagger.internal.Preconditions; + +import java.util.List; + +public class BluetoothDetailsExtraOptionsController extends BluetoothDetailsController { + + private static final String KEY_BLUETOOTH_EXTRA_OPTIONS = "bt_extra_options"; + + @VisibleForTesting @Nullable + PreferenceCategory mOptionsContainer; + @Nullable PreferenceScreen mPreferenceScreen; + + public BluetoothDetailsExtraOptionsController( + Context context, + PreferenceFragmentCompat fragment, + CachedBluetoothDevice device, + Lifecycle lifecycle) { + super(context, fragment, device, lifecycle); + } + + @Override + public String getPreferenceKey() { + return KEY_BLUETOOTH_EXTRA_OPTIONS; + } + + @Override + protected void init(PreferenceScreen screen) { + mPreferenceScreen = screen; + mOptionsContainer = screen.findPreference(getPreferenceKey()); + refresh(); + } + + @Override + protected void refresh() { + ThreadUtils.postOnBackgroundThread( + () -> { + List options = + FeatureFactory.getFeatureFactory() + .getBluetoothFeatureProvider() + .getBluetoothExtraOptions(mContext, mCachedDevice); + ThreadUtils.postOnMainThread( + () -> { + if (mOptionsContainer != null) { + mOptionsContainer.removeAll(); + for (Preference option : options) { + mOptionsContainer.addPreference(option); + } + setVisible( + Preconditions.checkNotNull(mPreferenceScreen), + getPreferenceKey(), + !options.isEmpty()); + } + }); + }); + } +} diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java index cfe79629c58..5e41a202812 100644 --- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java +++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java @@ -328,6 +328,9 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment mCachedDevice, lifecycle)); controllers.add(new BluetoothDetailsDataSyncController(context, this, mCachedDevice, lifecycle)); + controllers.add( + new BluetoothDetailsExtraOptionsController( + context, this, mCachedDevice, lifecycle)); } return controllers; } diff --git a/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java b/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java index 1bc71848fc8..d44e4b24872 100644 --- a/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java +++ b/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java @@ -22,6 +22,10 @@ import android.content.Context; import android.media.Spatializer; import android.net.Uri; +import androidx.preference.Preference; + +import com.android.settingslib.bluetooth.CachedBluetoothDevice; + import java.util.List; /** @@ -60,4 +64,13 @@ public interface BluetoothFeatureProvider { * @return the Spatializer instance */ Spatializer getSpatializer(Context context); + + /** + * Gets bluetooth device extra options + * + * @param context Context + * @param device the bluetooth device + * @return the extra bluetooth preference list + */ + List getBluetoothExtraOptions(Context context, CachedBluetoothDevice device); } diff --git a/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.java b/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.java index ba02020916e..014a0f3f99a 100644 --- a/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.java +++ b/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.java @@ -23,7 +23,12 @@ import android.media.AudioManager; import android.media.Spatializer; import android.net.Uri; +import androidx.preference.Preference; + import com.android.settingslib.bluetooth.BluetoothUtils; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; + +import com.google.common.collect.ImmutableList; import java.util.List; @@ -54,4 +59,10 @@ public class BluetoothFeatureProviderImpl implements BluetoothFeatureProvider { AudioManager audioManager = context.getSystemService(AudioManager.class); return audioManager.getSpatializer(); } + + @Override + public List getBluetoothExtraOptions(Context context, + CachedBluetoothDevice device) { + return ImmutableList.of(); + } } diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsExtraOptionsControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsExtraOptionsControllerTest.java new file mode 100644 index 00000000000..f0630201a50 --- /dev/null +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsExtraOptionsControllerTest.java @@ -0,0 +1,89 @@ +/* + * 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.bluetooth; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.bluetooth.BluetoothDevice; + +import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreferenceCompat; + +import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settingslib.core.lifecycle.Lifecycle; + +import com.google.common.collect.ImmutableList; + +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.shadows.ShadowLooper; + +@RunWith(RobolectricTestRunner.class) +public class BluetoothDetailsExtraOptionsControllerTest extends BluetoothDetailsControllerTestBase { + + private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C"; + @Mock private BluetoothDevice mBluetoothDevice; + @Mock private Lifecycle mExtraOptionsLifecycle; + @Mock private PreferenceCategory mOptionsContainer; + @Mock private PreferenceScreen mPreferenceScreen; + + private BluetoothDetailsExtraOptionsController mController; + private BluetoothFeatureProvider mFeatureProvider; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = spy(RuntimeEnvironment.application); + when(mCachedDevice.getAddress()).thenReturn(MAC_ADDRESS); + when(mCachedDevice.getDevice()).thenReturn(mBluetoothDevice); + when(mBluetoothDevice.getAnonymizedAddress()).thenReturn(MAC_ADDRESS); + + final FakeFeatureFactory fakeFeatureFactory = FakeFeatureFactory.setupForTest(); + mFeatureProvider = fakeFeatureFactory.getBluetoothFeatureProvider(); + + mController = + new BluetoothDetailsExtraOptionsController( + mContext, mFragment, mCachedDevice, mExtraOptionsLifecycle); + } + + @Test + public void displayPreference_removeAndAddPreferences() { + Preference preference1 = new SwitchPreferenceCompat(mContext); + Preference preference2 = new SwitchPreferenceCompat(mContext); + when(mFeatureProvider.getBluetoothExtraOptions(mContext, mCachedDevice)) + .thenReturn(ImmutableList.of(preference1, preference2)); + when(mPreferenceScreen.findPreference(mController.getPreferenceKey())) + .thenReturn(mOptionsContainer); + + mController.displayPreference(mPreferenceScreen); + ShadowLooper.idleMainLooper(); + + verify(mOptionsContainer).removeAll(); + verify(mOptionsContainer).addPreference(preference1); + verify(mOptionsContainer).addPreference(preference2); + } +}