OSDN Git Service

Bluetooth: Only show devices when their names are resolved
authorJack He <siyuanh@google.com>
Thu, 1 Jun 2017 01:37:28 +0000 (18:37 -0700)
committerJack He <siyuanh@google.com>
Fri, 25 Aug 2017 23:27:30 +0000 (16:27 -0700)
* 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
src/com/android/settings/bluetooth/BluetoothDevicePreference.java
src/com/android/settings/bluetooth/BluetoothSettings.java
src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
src/com/android/settings/development/DevelopmentSettings.java
tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java

index 8992446..1846a8c 100644 (file)
             android:entryValues="@array/usb_configuration_values" />
 
         <SwitchPreference
+            android:key="bluetooth_show_devices_without_names"
+            android:title="@string/bluetooth_show_devices_without_names"
+            android:summary="@string/bluetooth_show_devices_without_names_summary"/>
+
+        <SwitchPreference
             android:key="bluetooth_disable_absolute_volume"
             android:title="@string/bluetooth_disable_absolute_volume"
             android:summary="@string/bluetooth_disable_absolute_volume_summary"/>
index 7b81018..084b50e 100644 (file)
@@ -54,16 +54,17 @@ public final class BluetoothDevicePreference extends GearPreference implements
     private final UserManager mUserManager;
 
     private AlertDialog mDisconnectDialog;
-
     private String contentDescription = null;
-
+    private DeviceListPreferenceFragment mDeviceListPreferenceFragment;
     /* Talk-back descriptions for various BT icons */
     Resources mResources;
 
-    public BluetoothDevicePreference(Context context, CachedBluetoothDevice cachedDevice) {
+    public BluetoothDevicePreference(Context context, CachedBluetoothDevice cachedDevice,
+            DeviceListPreferenceFragment deviceListPreferenceFragment) {
         super(context, null);
         mResources = getContext().getResources();
         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        mDeviceListPreferenceFragment = deviceListPreferenceFragment;
 
         if (sDimAlpha == Integer.MIN_VALUE) {
             TypedValue outValue = new TypedValue();
@@ -131,6 +132,11 @@ public final class BluetoothDevicePreference extends GearPreference implements
         // Used to gray out the item
         setEnabled(!mCachedDevice.isBusy());
 
+        // Device is only visible in the UI if it has a valid name besides MAC address or when user
+        // allows showing devices without user-friendly name in developer settings
+        setVisible(mDeviceListPreferenceFragment.shouldShowDevicesWithoutNames()
+                || mCachedDevice.hasHumanReadableName());
+
         // This could affect ordering, so notify that
         notifyHierarchyChanged();
     }
index bd86c4b..361bc2f 100644 (file)
@@ -140,6 +140,8 @@ public class BluetoothSettings extends DeviceListPreferenceFragment implements I
             mBluetoothEnabler.resume(getActivity());
         }
         super.onStart();
+        // Always show paired devices regardless whether user-friendly name exists
+        mShowDevicesWithoutNames = true;
         if (isUiRestricted()) {
             getPreferenceScreen().removeAll();
             if (!isUiRestrictedByOnlyAdmin()) {
index ca06e3c..0485e69 100644 (file)
@@ -19,6 +19,7 @@ package com.android.settings.bluetooth;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.os.Bundle;
+import android.os.SystemProperties;
 import android.support.annotation.VisibleForTesting;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceCategory;
@@ -52,6 +53,10 @@ public abstract class DeviceListPreferenceFragment extends
 
     private static final String KEY_BT_SCAN = "bt_scan";
 
+    // Copied from DevelopmentSettings.java
+    private static final String BLUETOOTH_SHOW_DEVICES_WITHOUT_NAMES_PROPERTY =
+            "persist.bluetooth.showdeviceswithoutnames";
+
     private BluetoothDeviceFilter.Filter mFilter;
 
     @VisibleForTesting
@@ -68,6 +73,8 @@ public abstract class DeviceListPreferenceFragment extends
     final WeakHashMap<CachedBluetoothDevice, BluetoothDevicePreference> mDevicePreferenceMap =
             new WeakHashMap<CachedBluetoothDevice, BluetoothDevicePreference>();
 
+    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;
+    }
 }
index b442449..ce8acc2 100644 (file)
@@ -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) {
index b16e5bc..a1db5de 100644 (file)
@@ -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();
+    }
 }