From 1872151b4fbb0fddfc3ced8d31ca0f5454e8a32b Mon Sep 17 00:00:00 2001 From: SongFerngWang Date: Wed, 24 May 2023 12:33:21 +0800 Subject: [PATCH] The BluetoothDevicePreference register the MetadataChanged The bluetooth device preference needs to refresh UI after MetadataChanged Fix: 282877247 Test: make RunSettingsRoboTests ROBOTEST_FILTER=BluetoothDevicePreferenceTest Change-Id: I02cb07a6b255242e4877089ce2f3b7559ce02362 --- .../bluetooth/BluetoothDevicePreference.java | 55 ++++++++++++++++++- .../BluetoothDevicePreferenceTest.java | 28 +++++++++- 2 files changed, 80 insertions(+), 3 deletions(-) diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java index 751a168beeb..5256f3d6596 100644 --- a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java +++ b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java @@ -19,6 +19,7 @@ package com.android.settings.bluetooth; import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH; import android.app.settings.SettingsEnums; +import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.Context; import android.content.DialogInterface; @@ -48,6 +49,8 @@ import com.android.settingslib.utils.ThreadUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.RejectedExecutionException; /** @@ -71,6 +74,10 @@ public final class BluetoothDevicePreference extends GearPreference { private final CachedBluetoothDevice mCachedDevice; private final UserManager mUserManager; + + private Set mBluetoothDevices; + @VisibleForTesting + BluetoothAdapter mBluetoothAdapter; private final boolean mShowDevicesWithoutNames; private final long mCurrentTime; private final int mType; @@ -78,12 +85,23 @@ public final class BluetoothDevicePreference extends GearPreference { private AlertDialog mDisconnectDialog; private String contentDescription = null; private boolean mHideSecondTarget = false; - private boolean mIsCallbackRemoved = false; + private boolean mIsCallbackRemoved = true; @VisibleForTesting boolean mNeedNotifyHierarchyChanged = false; /* Talk-back descriptions for various BT icons */ Resources mResources; final BluetoothDevicePreferenceCallback mCallback; + @VisibleForTesting + final BluetoothAdapter.OnMetadataChangedListener mMetadataListener = + new BluetoothAdapter.OnMetadataChangedListener() { + @Override + public void onMetadataChanged(BluetoothDevice device, int key, byte[] value) { + Log.d(TAG, String.format("Metadata updated in Device %s: %d = %s.", + device.getAnonymizedAddress(), + key, value == null ? null : new String(value))); + onPreferenceAttributesChanged(); + } + }; private class BluetoothDevicePreferenceCallback implements CachedBluetoothDevice.Callback { @@ -98,6 +116,7 @@ public final class BluetoothDevicePreference extends GearPreference { super(context, null); mResources = getContext().getResources(); mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); + mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); mShowDevicesWithoutNames = showDeviceWithoutNames; if (sDimAlpha == Integer.MIN_VALUE) { @@ -108,7 +127,6 @@ public final class BluetoothDevicePreference extends GearPreference { mCachedDevice = cachedDevice; mCallback = new BluetoothDevicePreferenceCallback(); - mCachedDevice.registerCallback(mCallback); mCurrentTime = System.currentTimeMillis(); mType = type; @@ -141,6 +159,7 @@ public final class BluetoothDevicePreference extends GearPreference { super.onPrepareForRemoval(); if (!mIsCallbackRemoved) { mCachedDevice.unregisterCallback(mCallback); + unregisterMetadataChangedListener(); mIsCallbackRemoved = true; } if (mDisconnectDialog != null) { @@ -154,6 +173,7 @@ public final class BluetoothDevicePreference extends GearPreference { super.onAttached(); if (mIsCallbackRemoved) { mCachedDevice.registerCallback(mCallback); + registerMetadataChangedListener(); mIsCallbackRemoved = false; } onPreferenceAttributesChanged(); @@ -164,10 +184,41 @@ public final class BluetoothDevicePreference extends GearPreference { super.onDetached(); if (!mIsCallbackRemoved) { mCachedDevice.unregisterCallback(mCallback); + unregisterMetadataChangedListener(); mIsCallbackRemoved = true; } } + private void registerMetadataChangedListener() { + if (mBluetoothDevices == null) { + mBluetoothDevices = new HashSet<>(); + } + mBluetoothDevices.clear(); + if (mCachedDevice.getDevice() != null) { + mBluetoothDevices.add(mCachedDevice.getDevice()); + } + for (CachedBluetoothDevice cbd : mCachedDevice.getMemberDevice()) { + mBluetoothDevices.add(cbd.getDevice()); + } + if (mBluetoothDevices.isEmpty()) { + Log.d(TAG, "No BT device to register."); + return; + } + mBluetoothDevices.forEach(bd -> + mBluetoothAdapter.addOnMetadataChangedListener(bd, + getContext().getMainExecutor(), mMetadataListener)); + } + + private void unregisterMetadataChangedListener() { + if (mBluetoothDevices == null || mBluetoothDevices.isEmpty()) { + Log.d(TAG, "No BT device to unregister."); + return; + } + mBluetoothDevices.forEach( + bd -> mBluetoothAdapter.removeOnMetadataChangedListener(bd, mMetadataListener)); + mBluetoothDevices.clear(); + } + public CachedBluetoothDevice getBluetoothDevice() { return mCachedDevice; } diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java index 412eca13ec9..03113421d3f 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.Context; import android.graphics.drawable.Drawable; @@ -77,7 +78,17 @@ public class BluetoothDevicePreferenceTest { @Mock private CachedBluetoothDevice mCachedDevice3; @Mock + private BluetoothDevice mBluetoothDevice; + @Mock + private BluetoothDevice mBluetoothDevice1; + @Mock + private BluetoothDevice mBluetoothDevice2; + @Mock + private BluetoothDevice mBluetoothDevice3; + @Mock private Drawable mDrawable; + @Mock + private BluetoothAdapter mBluetoothAdapter; private FakeFeatureFactory mFakeFeatureFactory; private MetricsFeatureProvider mMetricsFeatureProvider; @@ -94,17 +105,22 @@ public class BluetoothDevicePreferenceTest { when(mCachedBluetoothDevice.getAddress()).thenReturn(MAC_ADDRESS); when(mCachedBluetoothDevice.getDrawableWithDescription()) .thenReturn(new Pair<>(mDrawable, FAKE_DESCRIPTION)); + when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); when(mCachedDevice1.getAddress()).thenReturn(MAC_ADDRESS_2); when(mCachedDevice1.getDrawableWithDescription()) .thenReturn(new Pair<>(mDrawable, FAKE_DESCRIPTION)); + when(mCachedDevice1.getDevice()).thenReturn(mBluetoothDevice1); when(mCachedDevice2.getAddress()).thenReturn(MAC_ADDRESS_3); when(mCachedDevice2.getDrawableWithDescription()) .thenReturn(new Pair<>(mDrawable, FAKE_DESCRIPTION)); + when(mCachedDevice2.getDevice()).thenReturn(mBluetoothDevice2); when(mCachedDevice3.getAddress()).thenReturn(MAC_ADDRESS_4); when(mCachedDevice3.getDrawableWithDescription()) .thenReturn(new Pair<>(mDrawable, FAKE_DESCRIPTION)); + when(mCachedDevice3.getDevice()).thenReturn(mBluetoothDevice3); mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, SHOW_DEVICES_WITHOUT_NAMES, BluetoothDevicePreference.SortType.TYPE_DEFAULT); + mPreference.mBluetoothAdapter = mBluetoothAdapter; } @Test @@ -279,15 +295,25 @@ public class BluetoothDevicePreferenceTest { @Test public void onAttached_callbackNotRemoved_doNotRegisterCallback() { mPreference.onAttached(); + // After the onAttached(), the callback is registered. - verify(mCachedBluetoothDevice, never()).unregisterCallback(any()); + // If it goes to the onAttached() again, then it do not register again, since the + // callback is not removed. + mPreference.onAttached(); + + verify(mCachedBluetoothDevice, times(1)).registerCallback(any()); + verify(mBluetoothAdapter, times(1)).addOnMetadataChangedListener(any(), any(), any()); } @Test public void onAttached_callbackRemoved_registerCallback() { + mPreference.onAttached(); + mPreference.onPrepareForRemoval(); mPreference.onAttached(); + verify(mCachedBluetoothDevice, times(1)).unregisterCallback(any()); verify(mCachedBluetoothDevice, times(2)).registerCallback(any()); + verify(mBluetoothAdapter, times(2)).addOnMetadataChangedListener(any(), any(), any()); } }