[Settings] Avoid NPE if BT device is changed by framework.
- Do not register only one BT device for primary to avoid primary BT devcie change to another. - Register and unregister all BT devices Bug: 280236099 Test: atest passed Change-Id: I610144c7f8f649e40d99cf1dc7f50d1f3b80f109
This commit is contained in:
@@ -57,7 +57,9 @@ import com.android.settingslib.widget.LayoutPreference;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -92,6 +94,7 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
final Map<String, Bitmap> mIconCache;
|
final Map<String, Bitmap> mIconCache;
|
||||||
private CachedBluetoothDevice mCachedDevice;
|
private CachedBluetoothDevice mCachedDevice;
|
||||||
|
private Set<BluetoothDevice> mBluetoothDevices;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
BluetoothAdapter mBluetoothAdapter;
|
BluetoothAdapter mBluetoothAdapter;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -142,23 +145,13 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
|
|||||||
if (!isAvailable()) {
|
if (!isAvailable()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mIsRegisterCallback = true;
|
registerBluetoothDevice();
|
||||||
mCachedDevice.registerCallback(this);
|
|
||||||
mBluetoothAdapter.addOnMetadataChangedListener(mCachedDevice.getDevice(),
|
|
||||||
mContext.getMainExecutor(), mMetadataListener);
|
|
||||||
|
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
if (!mIsRegisterCallback) {
|
unRegisterBluetoothDevice();
|
||||||
return;
|
|
||||||
}
|
|
||||||
mCachedDevice.unregisterCallback(this);
|
|
||||||
mBluetoothAdapter.removeOnMetadataChangedListener(mCachedDevice.getDevice(),
|
|
||||||
mMetadataListener);
|
|
||||||
mIsRegisterCallback = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -176,6 +169,40 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
|
|||||||
mCachedDevice = cachedBluetoothDevice;
|
mCachedDevice = cachedBluetoothDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void registerBluetoothDevice() {
|
||||||
|
if (mBluetoothDevices == null) {
|
||||||
|
mBluetoothDevices = new HashSet<>();
|
||||||
|
}
|
||||||
|
mBluetoothDevices.clear();
|
||||||
|
if (mCachedDevice.getDevice() != null) {
|
||||||
|
mBluetoothDevices.add(mCachedDevice.getDevice());
|
||||||
|
}
|
||||||
|
mCachedDevice.getMemberDevice().forEach(cbd -> {
|
||||||
|
if (cbd != null) {
|
||||||
|
mBluetoothDevices.add(cbd.getDevice());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (mBluetoothDevices.isEmpty()) {
|
||||||
|
Log.d(TAG, "No BT devcie to register.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mCachedDevice.registerCallback(this);
|
||||||
|
mBluetoothDevices.forEach(bd ->
|
||||||
|
mBluetoothAdapter.addOnMetadataChangedListener(bd,
|
||||||
|
mContext.getMainExecutor(), mMetadataListener));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unRegisterBluetoothDevice() {
|
||||||
|
if (mBluetoothDevices == null || mBluetoothDevices.isEmpty()) {
|
||||||
|
Log.d(TAG, "No BT devcie to unregister.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mCachedDevice.unregisterCallback(this);
|
||||||
|
mBluetoothDevices.forEach(bd -> mBluetoothAdapter.removeOnMetadataChangedListener(bd,
|
||||||
|
mMetadataListener));
|
||||||
|
mBluetoothDevices.clear();
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void refresh() {
|
void refresh() {
|
||||||
if (mLayoutPreference != null && mCachedDevice != null) {
|
if (mLayoutPreference != null && mCachedDevice != null) {
|
||||||
|
@@ -56,6 +56,9 @@ import org.robolectric.RobolectricTestRunner;
|
|||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
@Config(shadows = {ShadowEntityHeaderController.class, ShadowDeviceConfig.class})
|
@Config(shadows = {ShadowEntityHeaderController.class, ShadowDeviceConfig.class})
|
||||||
public class AdvancedBluetoothDetailsHeaderControllerTest {
|
public class AdvancedBluetoothDetailsHeaderControllerTest {
|
||||||
@@ -380,40 +383,68 @@ public class AdvancedBluetoothDetailsHeaderControllerTest {
|
|||||||
SettingsUIDeviceConfig.BT_ADVANCED_HEADER_ENABLED, "true", true);
|
SettingsUIDeviceConfig.BT_ADVANCED_HEADER_ENABLED, "true", true);
|
||||||
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
|
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
|
||||||
.thenReturn("true".getBytes());
|
.thenReturn("true".getBytes());
|
||||||
|
Set<CachedBluetoothDevice> cacheBluetoothDevices = new HashSet<>();
|
||||||
|
when(mCachedDevice.getMemberDevice()).thenReturn(cacheBluetoothDevices);
|
||||||
|
|
||||||
mController.onStart();
|
mController.onStart();
|
||||||
|
|
||||||
|
verify(mCachedDevice).registerCallback(mController);
|
||||||
verify(mBluetoothAdapter).addOnMetadataChangedListener(mBluetoothDevice,
|
verify(mBluetoothAdapter).addOnMetadataChangedListener(mBluetoothDevice,
|
||||||
mContext.getMainExecutor(), mController.mMetadataListener);
|
mContext.getMainExecutor(), mController.mMetadataListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onStop_isRegisterCallback_unregisterCallback() {
|
public void onStart_notAvailable_notNeedToRegisterCallback() {
|
||||||
mController.mIsRegisterCallback = true;
|
|
||||||
|
|
||||||
mController.onStop();
|
|
||||||
|
|
||||||
verify(mBluetoothAdapter).removeOnMetadataChangedListener(mBluetoothDevice,
|
|
||||||
mController.mMetadataListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onStart_notAvailable_registerCallback() {
|
|
||||||
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
|
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
|
||||||
.thenReturn("false".getBytes());
|
.thenReturn("false".getBytes());
|
||||||
|
|
||||||
mController.onStart();
|
mController.onStart();
|
||||||
|
|
||||||
|
verify(mCachedDevice, never()).registerCallback(mController);
|
||||||
verify(mBluetoothAdapter, never()).addOnMetadataChangedListener(mBluetoothDevice,
|
verify(mBluetoothAdapter, never()).addOnMetadataChangedListener(mBluetoothDevice,
|
||||||
mContext.getMainExecutor(), mController.mMetadataListener);
|
mContext.getMainExecutor(), mController.mMetadataListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onStop_notRegisterCallback_unregisterCallback() {
|
public void onStart_isAvailableButNoBluetoothDevice_notNeedToRegisterCallback() {
|
||||||
mController.mIsRegisterCallback = false;
|
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI,
|
||||||
|
SettingsUIDeviceConfig.BT_ADVANCED_HEADER_ENABLED, "true", true);
|
||||||
|
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
|
||||||
|
.thenReturn("true".getBytes());
|
||||||
|
when(mCachedDevice.getDevice()).thenReturn(null);
|
||||||
|
Set<CachedBluetoothDevice> cacheBluetoothDevices = new HashSet<>();
|
||||||
|
when(mCachedDevice.getMemberDevice()).thenReturn(cacheBluetoothDevices);
|
||||||
|
|
||||||
|
mController.onStart();
|
||||||
|
|
||||||
|
verify(mCachedDevice, never()).registerCallback(mController);
|
||||||
|
verify(mBluetoothAdapter, never()).addOnMetadataChangedListener(mBluetoothDevice,
|
||||||
|
mContext.getMainExecutor(), mController.mMetadataListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onStop_availableAndHasBluetoothDevice_unregisterCallback() {
|
||||||
|
onStart_isAvailable_registerCallback();
|
||||||
|
|
||||||
mController.onStop();
|
mController.onStop();
|
||||||
|
|
||||||
|
verify(mCachedDevice).unregisterCallback(mController);
|
||||||
|
verify(mBluetoothAdapter).removeOnMetadataChangedListener(mBluetoothDevice,
|
||||||
|
mController.mMetadataListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onStop_noBluetoothDevice_noNeedToUnregisterCallback() {
|
||||||
|
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI,
|
||||||
|
SettingsUIDeviceConfig.BT_ADVANCED_HEADER_ENABLED, "true", true);
|
||||||
|
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
|
||||||
|
.thenReturn("true".getBytes());
|
||||||
|
when(mCachedDevice.getDevice()).thenReturn(null);
|
||||||
|
|
||||||
|
mController.onStart();
|
||||||
|
mController.onStop();
|
||||||
|
|
||||||
|
verify(mCachedDevice, never()).unregisterCallback(mController);
|
||||||
verify(mBluetoothAdapter, never()).removeOnMetadataChangedListener(mBluetoothDevice,
|
verify(mBluetoothAdapter, never()).removeOnMetadataChangedListener(mBluetoothDevice,
|
||||||
mController.mMetadataListener);
|
mController.mMetadataListener);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user