From 19ba3202634762e4670827568b79b45f5793b1ca Mon Sep 17 00:00:00 2001 From: Jack He Date: Wed, 31 May 2017 18:37:28 -0700 Subject: [PATCH] Bluetooth: Only show devices when their names are resolved * Add a developer menu option to allow name-less devices to be shown when a Bluetooth developer needs it, but hide it for non-developer users. * Set BluetoothDevicePreference to invisible when CachedBluetoothDevice does not have a name besides MAC address and the above developer option is false. * This affects BluetoothPairingDetail and DevicePickerFragment, but does not affect BluetoothSettings. BluetoothSettings will show all paired devices regardless whether an user friendly name exists. Bug: 34685932 Test: pair Bluetooth device, send file over Bluetooth, unit tests Change-Id: Idd7ad4b1671dfdcf3204efb50eddb6dae1065aa5 --- res/xml/development_prefs.xml | 5 ++ .../bluetooth/BluetoothDevicePreference.java | 12 +++-- .../settings/bluetooth/BluetoothSettings.java | 2 + .../DeviceListPreferenceFragment.java | 15 +++++- .../development/DevelopmentSettings.java | 21 ++++++++ .../BluetoothDevicePreferenceTest.java | 52 ++++++++++++++++++- 6 files changed, 102 insertions(+), 5 deletions(-) diff --git a/res/xml/development_prefs.xml b/res/xml/development_prefs.xml index 89924467221..1846a8c43e0 100644 --- a/res/xml/development_prefs.xml +++ b/res/xml/development_prefs.xml @@ -209,6 +209,11 @@ android:entries="@array/usb_configuration_titles" android:entryValues="@array/usb_configuration_values" /> + + mDevicePreferenceMap = new WeakHashMap(); + boolean mShowDevicesWithoutNames; + DeviceListPreferenceFragment(String restrictedKey) { super(restrictedKey); mFilter = BluetoothDeviceFilter.ALL_FILTER; @@ -103,6 +110,8 @@ public abstract class DeviceListPreferenceFragment extends @Override public void onStart() { super.onStart(); + mShowDevicesWithoutNames = SystemProperties.getBoolean( + BLUETOOTH_SHOW_DEVICES_WITHOUT_NAMES_PROPERTY, false); if (mLocalManager == null || isUiRestricted()) return; mLocalManager.setForegroundActivity(getActivity()); @@ -181,7 +190,7 @@ public abstract class DeviceListPreferenceFragment extends BluetoothDevicePreference preference = (BluetoothDevicePreference) getCachedPreference(key); if (preference == null) { - preference = new BluetoothDevicePreference(getPrefContext(), cachedDevice); + preference = new BluetoothDevicePreference(getPrefContext(), cachedDevice, this); preference.setKey(key); mDeviceListGroup.addPreference(preference); } else { @@ -271,4 +280,8 @@ public abstract class DeviceListPreferenceFragment extends * Return the key of the {@link PreferenceGroup} that contains the bluetooth devices */ public abstract String getDeviceListKey(); + + public boolean shouldShowDevicesWithoutNames() { + return mShowDevicesWithoutNames; + } } diff --git a/src/com/android/settings/development/DevelopmentSettings.java b/src/com/android/settings/development/DevelopmentSettings.java index b442449640b..ce8acc20642 100644 --- a/src/com/android/settings/development/DevelopmentSettings.java +++ b/src/com/android/settings/development/DevelopmentSettings.java @@ -199,6 +199,10 @@ public class DevelopmentSettings extends RestrictedSettingsFragment private static final String FORCE_RESIZABLE_KEY = "force_resizable_activities"; private static final String COLOR_TEMPERATURE_KEY = "color_temperature"; + private static final String BLUETOOTH_SHOW_DEVICES_WITHOUT_NAMES_KEY = + "bluetooth_show_devices_without_names"; + private static final String BLUETOOTH_SHOW_DEVICES_WITHOUT_NAMES_PROPERTY = + "persist.bluetooth.showdeviceswithoutnames"; private static final String BLUETOOTH_DISABLE_ABSOLUTE_VOLUME_KEY = "bluetooth_disable_absolute_volume"; private static final String BLUETOOTH_DISABLE_ABSOLUTE_VOLUME_PROPERTY = @@ -282,6 +286,7 @@ public class DevelopmentSettings extends RestrictedSettingsFragment private SwitchPreference mWifiAggressiveHandover; private SwitchPreference mMobileDataAlwaysOn; private SwitchPreference mTetheringHardwareOffload; + private SwitchPreference mBluetoothShowDevicesWithoutNames; private SwitchPreference mBluetoothDisableAbsVolume; private SwitchPreference mBluetoothEnableInbandRinging; @@ -498,6 +503,8 @@ public class DevelopmentSettings extends RestrictedSettingsFragment mLogpersist = null; } mUsbConfiguration = addListPreference(USB_CONFIGURATION_KEY); + mBluetoothShowDevicesWithoutNames = + findAndInitSwitchPref(BLUETOOTH_SHOW_DEVICES_WITHOUT_NAMES_KEY); mBluetoothDisableAbsVolume = findAndInitSwitchPref(BLUETOOTH_DISABLE_ABSOLUTE_VOLUME_KEY); mBluetoothEnableInbandRinging = findAndInitSwitchPref(BLUETOOTH_ENABLE_INBAND_RINGING_KEY); if (!BluetoothHeadset.isInbandRingingSupported(getContext())) { @@ -838,6 +845,7 @@ public class DevelopmentSettings extends RestrictedSettingsFragment if (mColorTemperaturePreference != null) { updateColorTemperature(); } + updateBluetoothShowDevicesWithoutUserFriendlyNameOptions(); updateBluetoothDisableAbsVolumeOptions(); updateBluetoothEnableInbandRingingOptions(); updateBluetoothA2dpConfigurationValues(); @@ -1468,6 +1476,17 @@ public class DevelopmentSettings extends RestrictedSettingsFragment mWifiManager.setAllowScansWithTraffic(mWifiAllowScansWithTraffic.isChecked() ? 1 : 0); } + private void updateBluetoothShowDevicesWithoutUserFriendlyNameOptions() { + updateSwitchPreference(mBluetoothShowDevicesWithoutNames, + SystemProperties.getBoolean( + BLUETOOTH_SHOW_DEVICES_WITHOUT_NAMES_PROPERTY, false)); + } + + private void writeBluetoothShowDevicesWithoutUserFriendlyNameOptions() { + SystemProperties.set(BLUETOOTH_SHOW_DEVICES_WITHOUT_NAMES_PROPERTY, + mBluetoothShowDevicesWithoutNames.isChecked() ? "true" : "false"); + } + private void updateBluetoothDisableAbsVolumeOptions() { updateSwitchPreference(mBluetoothDisableAbsVolume, SystemProperties.getBoolean(BLUETOOTH_DISABLE_ABSOLUTE_VOLUME_PROPERTY, false)); @@ -2532,6 +2551,8 @@ public class DevelopmentSettings extends RestrictedSettingsFragment writeUSBAudioOptions(); } else if (preference == mForceResizable) { writeForceResizableOptions(); + } else if (preference == mBluetoothShowDevicesWithoutNames) { + writeBluetoothShowDevicesWithoutUserFriendlyNameOptions(); } else if (preference == mBluetoothDisableAbsVolume) { writeBluetoothDisableAbsVolumeOptions(); } else if (preference == mBluetoothEnableInbandRinging) { diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java index b16e5bc0474..a1db5de77e8 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java @@ -39,6 +39,8 @@ import org.robolectric.annotation.Config; import org.robolectric.util.ReflectionHelpers; import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -52,6 +54,8 @@ public class BluetoothDevicePreferenceTest { private Context mContext; @Mock private CachedBluetoothDevice mCachedBluetoothDevice; + @Mock + private DeviceListPreferenceFragment mDeviceListPreferenceFragment; private FakeFeatureFactory mFakeFeatureFactory; private MetricsFeatureProvider mMetricsFeatureProvider; @@ -64,7 +68,8 @@ public class BluetoothDevicePreferenceTest { FakeFeatureFactory.setupForTest(mContext); mFakeFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext); mMetricsFeatureProvider = mFakeFeatureFactory.getMetricsFeatureProvider(); - mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice); + mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, + mDeviceListPreferenceFragment); } @Test @@ -151,4 +156,49 @@ public class BluetoothDevicePreferenceTest { assertThat(mPreference.getIcon()).isEqualTo( mContext.getDrawable(R.drawable.ic_settings_print)); } + + @Test + public void testVisible_notVisibleThenVisible() { + when(mDeviceListPreferenceFragment.shouldShowDevicesWithoutNames()).thenReturn(false); + final boolean[] humanReadableName = {false}; + doAnswer(invocation -> humanReadableName[0]).when(mCachedBluetoothDevice) + .hasHumanReadableName(); + BluetoothDevicePreference preference = + new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, + mDeviceListPreferenceFragment); + assertThat(preference.isVisible()).isFalse(); + humanReadableName[0] = true; + preference.onDeviceAttributesChanged(); + assertThat(preference.isVisible()).isTrue(); + } + + @Test + public void testVisible_visibleThenNotVisible() { + when(mDeviceListPreferenceFragment.shouldShowDevicesWithoutNames()).thenReturn(false); + final boolean[] humanReadableName = {true}; + doAnswer(invocation -> humanReadableName[0]).when(mCachedBluetoothDevice) + .hasHumanReadableName(); + BluetoothDevicePreference preference = + new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, + mDeviceListPreferenceFragment); + assertThat(preference.isVisible()).isTrue(); + humanReadableName[0] = false; + preference.onDeviceAttributesChanged(); + assertThat(preference.isVisible()).isFalse(); + } + + @Test + public void testVisible_alwaysVisibleWhenEnabled() { + when(mDeviceListPreferenceFragment.shouldShowDevicesWithoutNames()).thenReturn(true); + final boolean[] humanReadableName = {true}; + doAnswer(invocation -> humanReadableName[0]).when(mCachedBluetoothDevice) + .hasHumanReadableName(); + BluetoothDevicePreference preference = + new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, + mDeviceListPreferenceFragment); + assertThat(preference.isVisible()).isTrue(); + humanReadableName[0] = false; + preference.onDeviceAttributesChanged(); + assertThat(preference.isVisible()).isTrue(); + } }