Add Hearable control slice in bluetooth device detail settings
Bug: 229048602
Test: make -j64 RunSettingsRoboTests
Change-Id: I850aaee9bf7518c9f9de065fbbd1eb4919fc62ee
diff --git a/res/xml/bluetooth_device_details_fragment.xml b/res/xml/bluetooth_device_details_fragment.xml
index f6c0af6..b44a93d 100644
--- a/res/xml/bluetooth_device_details_fragment.xml
+++ b/res/xml/bluetooth_device_details_fragment.xml
@@ -47,6 +47,11 @@
settings:allowDividerBelow="true"/>
<com.android.settings.slices.SlicePreference
+ android:key="bt_extra_control"
+ settings:controller="com.android.settings.slices.SlicePreferenceController"
+ settings:allowDividerAbove="true"/>
+
+ <com.android.settings.slices.SlicePreference
android:key="bt_device_slice"
settings:controller="com.android.settings.slices.BlockingSlicePrefController"
settings:allowDividerBelow="true"
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index 6d443ee..fdf0f38 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -22,12 +22,18 @@
import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
+import android.net.Uri;
import android.os.Bundle;
import android.provider.DeviceConfig;
+import android.text.TextUtils;
import android.util.Log;
+import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
import androidx.annotation.VisibleForTesting;
@@ -36,12 +42,14 @@
import com.android.settings.dashboard.RestrictedDashboardFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.slices.BlockingSlicePrefController;
+import com.android.settings.slices.SlicePreferenceController;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.ArrayList;
+import java.util.IllegalFormatException;
import java.util.List;
public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment {
@@ -61,6 +69,7 @@
@VisibleForTesting
interface TestDataFactory {
CachedBluetoothDevice getDevice(String deviceAddress);
+
LocalBluetoothManager getManager(Context context);
}
@@ -127,6 +136,49 @@
use(BlockingSlicePrefController.class).setSliceUri(sliceEnabled
? featureProvider.getBluetoothDeviceSettingsUri(mCachedDevice.getDevice())
: null);
+ updateExtraControlUri(/* viewWidth */ 0);
+ }
+
+ private void updateExtraControlUri(int viewWidth) {
+ BluetoothFeatureProvider featureProvider = FeatureFactory.getFactory(
+ getContext()).getBluetoothFeatureProvider(getContext());
+ boolean sliceEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
+ SettingsUIDeviceConfig.BT_SLICE_SETTINGS_ENABLED, true);
+ Uri controlUri = null;
+ String uri = featureProvider.getBluetoothDeviceControlUri(mCachedDevice.getDevice());
+ if (!TextUtils.isEmpty(uri)) {
+ try {
+ controlUri = Uri.parse(String.format(uri, viewWidth));
+ } catch (IllegalFormatException | NullPointerException exception) {
+ Log.d(TAG, "unable to parse uri");
+ controlUri = null;
+ }
+ }
+ use(SlicePreferenceController.class).setSliceUri(sliceEnabled ? controlUri : null);
+ }
+
+ private final ViewTreeObserver.OnGlobalLayoutListener mOnGlobalLayoutListener =
+ new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ View view = getView();
+ if (view == null) {
+ return;
+ }
+ updateExtraControlUri(view.getWidth());
+ view.getViewTreeObserver().removeOnGlobalLayoutListener(
+ mOnGlobalLayoutListener);
+ }
+ };
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = super.onCreateView(inflater, container, savedInstanceState);
+ if (view != null) {
+ view.getViewTreeObserver().addOnGlobalLayoutListener(mOnGlobalLayoutListener);
+ }
+ return view;
}
@Override
diff --git a/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java b/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java
index 582a26c..51ef8e2 100644
--- a/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java
+++ b/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java
@@ -26,8 +26,17 @@
/**
* Get the {@link Uri} that represents extra settings for a specific bluetooth device
+ *
* @param bluetoothDevice bluetooth device
* @return {@link Uri} for extra settings
*/
Uri getBluetoothDeviceSettingsUri(BluetoothDevice bluetoothDevice);
+
+ /**
+ * Get the {@link Uri} that represents extra control for a specific bluetooth device
+ *
+ * @param bluetoothDevice bluetooth device
+ * @return {@link String} uri string for extra control
+ */
+ String getBluetoothDeviceControlUri(BluetoothDevice bluetoothDevice);
}
diff --git a/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.java b/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.java
index cd75951..04d3ec4 100644
--- a/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.java
+++ b/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.java
@@ -20,6 +20,8 @@
import android.content.Context;
import android.net.Uri;
+import com.android.settingslib.bluetooth.BluetoothUtils;
+
/**
* Impl of {@link BluetoothFeatureProvider}
*/
@@ -37,4 +39,9 @@
BluetoothDevice.METADATA_ENHANCED_SETTINGS_UI_URI);
return uriByte == null ? null : Uri.parse(new String(uriByte));
}
+
+ @Override
+ public String getBluetoothDeviceControlUri(BluetoothDevice bluetoothDevice) {
+ return BluetoothUtils.getControlUriMetaData(bluetoothDevice);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothFeatureProviderImplTest.java
index 9ab1d87..3d40bfc 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothFeatureProviderImplTest.java
@@ -33,6 +33,11 @@
@RunWith(RobolectricTestRunner.class)
public class BluetoothFeatureProviderImplTest {
private static final String SETTINGS_URI = "content://test.provider/settings_uri";
+ private static final String CONTROL_METADATA =
+ "<HEARABLE_CONTROL_SLICE_WITH_WIDTH>" + SETTINGS_URI
+ + "</HEARABLE_CONTROL_SLICE_WITH_WIDTH>";
+ private static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25;
+
private BluetoothFeatureProvider mBluetoothFeatureProvider;
@Mock
@@ -54,4 +59,13 @@
final Uri uri = mBluetoothFeatureProvider.getBluetoothDeviceSettingsUri(mBluetoothDevice);
assertThat(uri.toString()).isEqualTo(SETTINGS_URI);
}
+
+ @Test
+ public void getBluetoothDeviceControlUri_returnsCorrectUri() {
+ when(mBluetoothDevice.getMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS)).thenReturn(
+ CONTROL_METADATA.getBytes());
+ assertThat(
+ mBluetoothFeatureProvider.getBluetoothDeviceControlUri(mBluetoothDevice)).isEqualTo(
+ SETTINGS_URI);
+ }
}