From aec55438414f8c71aedfb8235784baa290c037b0 Mon Sep 17 00:00:00 2001 From: jackqdyulei Date: Tue, 21 Nov 2017 10:44:21 -0800 Subject: [PATCH] Add preference group for saved devcies. Currently it only contains bluetooth devices. Bug: 3240835 Test: RunSettingsRoboTests Change-Id: Ief102e7174a4c4610dbda6b728419b303ff928f9 --- res/xml/connected_devices.xml | 4 + .../settings/bluetooth/BluetoothDeviceUpdater.java | 15 ++- .../bluetooth/ConnectedBluetoothDeviceUpdater.java | 12 +-- .../bluetooth/SavedBluetoothDeviceUpdater.java | 58 +++++++++++ .../ConnectedDeviceDashboardFragment.java | 5 +- .../SavedDeviceGroupController.java | 109 +++++++++++++++++++++ .../bluetooth/BluetoothDeviceUpdaterTest.java | 4 +- .../bluetooth/SavedBluetoothDeviceUpdaterTest.java | 108 ++++++++++++++++++++ 8 files changed, 299 insertions(+), 16 deletions(-) create mode 100644 src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java create mode 100644 src/com/android/settings/connecteddevice/SavedDeviceGroupController.java create mode 100644 tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java diff --git a/res/xml/connected_devices.xml b/res/xml/connected_devices.xml index d24dd51755..497a485166 100644 --- a/res/xml/connected_devices.xml +++ b/res/xml/connected_devices.xml @@ -22,4 +22,8 @@ + + diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java index e053bc9df2..127730ba39 100644 --- a/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java +++ b/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java @@ -149,9 +149,22 @@ public abstract class BluetoothDeviceUpdater implements BluetoothCallback { } /** + * Return {@code true} if {@code cachedBluetoothDevice} matches this + * {@link BluetoothDeviceUpdater} and should stay in the list, otherwise return {@code false} + */ + public abstract boolean isFilterMatched(CachedBluetoothDevice cachedBluetoothDevice); + + /** * Update whether to show {@cde cachedBluetoothDevice} in the list. */ - abstract public void update(CachedBluetoothDevice cachedBluetoothDevice); + protected void update(CachedBluetoothDevice cachedBluetoothDevice) { + if (isFilterMatched(cachedBluetoothDevice)) { + // Add the preference if it is new one + addPreference(cachedBluetoothDevice); + } else { + removePreference(cachedBluetoothDevice); + } + } /** * Add the {@link Preference} that represents the {@code cachedDevice} diff --git a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java index 239e4051a4..deab29f624 100644 --- a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java +++ b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java @@ -51,16 +51,8 @@ public class ConnectedBluetoothDeviceUpdater extends BluetoothDeviceUpdater { } @Override - public void update(CachedBluetoothDevice cachedDevice) { + public boolean isFilterMatched(CachedBluetoothDevice cachedDevice) { final BluetoothDevice device = cachedDevice.getDevice(); - final boolean filterMatch = - device.getBondState() == BluetoothDevice.BOND_BONDED && device.isConnected(); - - if (filterMatch) { - // Add the preference if it is new one - addPreference(cachedDevice); - } else { - removePreference(cachedDevice); - } + return device.getBondState() == BluetoothDevice.BOND_BONDED && device.isConnected(); } } diff --git a/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java new file mode 100644 index 0000000000..da7679a5e0 --- /dev/null +++ b/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.bluetooth; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.support.annotation.VisibleForTesting; + +import com.android.settings.connecteddevice.DevicePreferenceCallback; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.LocalBluetoothManager; + +/** + * Maintain and update saved bluetooth devices(bonded but not connected) + */ +public class SavedBluetoothDeviceUpdater extends BluetoothDeviceUpdater { + + public SavedBluetoothDeviceUpdater(DashboardFragment fragment, + DevicePreferenceCallback devicePreferenceCallback) { + super(fragment, devicePreferenceCallback); + } + + @VisibleForTesting + SavedBluetoothDeviceUpdater(DashboardFragment fragment, + DevicePreferenceCallback devicePreferenceCallback, + LocalBluetoothManager localBluetoothManager) { + super(fragment, devicePreferenceCallback, localBluetoothManager); + } + + @Override + public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { + if (state == BluetoothAdapter.STATE_CONNECTED) { + removePreference(cachedDevice); + } else if (state == BluetoothAdapter.STATE_DISCONNECTED) { + addPreference(cachedDevice); + } + } + + @Override + public boolean isFilterMatched(CachedBluetoothDevice cachedDevice) { + final BluetoothDevice device = cachedDevice.getDevice(); + return device.getBondState() == BluetoothDevice.BOND_BONDED && !device.isConnected(); + } +} diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java index 14acd89a60..8b0e568ed9 100644 --- a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java +++ b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java @@ -62,9 +62,8 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment { final List controllers = new ArrayList<>(); final Lifecycle lifecycle = getLifecycle(); - final ConnectedDeviceGroupController connectedDeviceGroupController = - new ConnectedDeviceGroupController(this, lifecycle); - controllers.add(connectedDeviceGroupController); + controllers.add(new ConnectedDeviceGroupController(this, lifecycle)); + controllers.add(new SavedDeviceGroupController(this, lifecycle)); return controllers; } diff --git a/src/com/android/settings/connecteddevice/SavedDeviceGroupController.java b/src/com/android/settings/connecteddevice/SavedDeviceGroupController.java new file mode 100644 index 0000000000..74450477dd --- /dev/null +++ b/src/com/android/settings/connecteddevice/SavedDeviceGroupController.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.connecteddevice; + +import android.support.annotation.VisibleForTesting; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceGroup; +import android.support.v7.preference.PreferenceScreen; + +import com.android.settings.bluetooth.BluetoothDeviceUpdater; +import com.android.settings.bluetooth.SavedBluetoothDeviceUpdater; +import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnStart; +import com.android.settingslib.core.lifecycle.events.OnStop; + +/** + * Controller to maintain the {@link PreferenceGroup} for all + * saved devices. It uses {@link DevicePreferenceCallback} to add/remove {@link Preference} + */ +public class SavedDeviceGroupController extends AbstractPreferenceController + implements PreferenceControllerMixin, LifecycleObserver, OnStart, OnStop, + DevicePreferenceCallback { + + private static final String KEY = "saved_device_list"; + + @VisibleForTesting + PreferenceGroup mPreferenceGroup; + private BluetoothDeviceUpdater mBluetoothDeviceUpdater; + + public SavedDeviceGroupController(DashboardFragment fragment, Lifecycle lifecycle) { + super(fragment.getContext()); + init(lifecycle, new SavedBluetoothDeviceUpdater(fragment, SavedDeviceGroupController.this)); + } + + @VisibleForTesting + SavedDeviceGroupController(DashboardFragment fragment, Lifecycle lifecycle, + BluetoothDeviceUpdater bluetoothDeviceUpdater) { + super(fragment.getContext()); + init(lifecycle, bluetoothDeviceUpdater); + } + + @Override + public void onStart() { + mBluetoothDeviceUpdater.registerCallback(); + } + + @Override + public void onStop() { + mBluetoothDeviceUpdater.unregisterCallback(); + } + + @Override + public void displayPreference(PreferenceScreen screen) { + mPreferenceGroup = (PreferenceGroup) screen.findPreference(KEY); + mPreferenceGroup.setVisible(false); + mBluetoothDeviceUpdater.setPrefContext(screen.getContext()); + mBluetoothDeviceUpdater.forceUpdate(); + } + + @Override + public boolean isAvailable() { + return true; + } + + @Override + public String getPreferenceKey() { + return KEY; + } + + @Override + public void onDeviceAdded(Preference preference) { + if (mPreferenceGroup.getPreferenceCount() == 0) { + mPreferenceGroup.setVisible(true); + } + mPreferenceGroup.addPreference(preference); + } + + @Override + public void onDeviceRemoved(Preference preference) { + mPreferenceGroup.removePreference(preference); + if (mPreferenceGroup.getPreferenceCount() == 0) { + mPreferenceGroup.setVisible(false); + } + } + + private void init(Lifecycle lifecycle, BluetoothDeviceUpdater bluetoothDeviceUpdater) { + if (lifecycle != null) { + lifecycle.addObserver(this); + } + mBluetoothDeviceUpdater = bluetoothDeviceUpdater; + } +} diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceUpdaterTest.java index 525f70e4da..d5abd936c2 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceUpdaterTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceUpdaterTest.java @@ -73,8 +73,8 @@ public class BluetoothDeviceUpdaterTest { mBluetoothDeviceUpdater = new BluetoothDeviceUpdater(mDashboardFragment, mDevicePreferenceCallback, null) { @Override - public void update(CachedBluetoothDevice cachedBluetoothDevice) { - // do nothing + public boolean isFilterMatched(CachedBluetoothDevice cachedBluetoothDevice) { + return true; } }; mBluetoothDeviceUpdater.setPrefContext(mContext); diff --git a/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java new file mode 100644 index 0000000000..d0f367e93d --- /dev/null +++ b/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +package com.android.settings.bluetooth; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.content.Context; + +import com.android.settings.TestConfig; +import com.android.settings.connecteddevice.DevicePreferenceCallback; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O) +public class SavedBluetoothDeviceUpdaterTest { + @Mock + private DashboardFragment mDashboardFragment; + @Mock + private DevicePreferenceCallback mDevicePreferenceCallback; + @Mock + private CachedBluetoothDevice mCachedBluetoothDevice; + @Mock + private BluetoothDevice mBluetoothDevice; + + private Context mContext; + private BluetoothDeviceUpdater mBluetoothDeviceUpdater; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = RuntimeEnvironment.application; + doReturn(mContext).when(mDashboardFragment).getContext(); + doReturn(mBluetoothDevice).when(mCachedBluetoothDevice).getDevice(); + + mBluetoothDeviceUpdater = spy(new SavedBluetoothDeviceUpdater(mDashboardFragment, + mDevicePreferenceCallback, null)); + mBluetoothDeviceUpdater.setPrefContext(mContext); + doNothing().when(mBluetoothDeviceUpdater).addPreference(any()); + doNothing().when(mBluetoothDeviceUpdater).removePreference(any()); + } + + @Test + public void testUpdate_filterMatch_addPreference() { + doReturn(BluetoothDevice.BOND_BONDED).when(mBluetoothDevice).getBondState(); + doReturn(false).when(mBluetoothDevice).isConnected(); + + mBluetoothDeviceUpdater.update(mCachedBluetoothDevice); + + verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); + } + + @Test + public void testUpdate_filterNotMatch_removePreference() { + doReturn(BluetoothDevice.BOND_NONE).when(mBluetoothDevice).getBondState(); + doReturn(true).when(mBluetoothDevice).isConnected(); + + mBluetoothDeviceUpdater.update(mCachedBluetoothDevice); + + verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); + } + + @Test + public void testOnConnectionStateChanged_deviceConnected_removePreference() { + mBluetoothDeviceUpdater.onConnectionStateChanged(mCachedBluetoothDevice, + BluetoothAdapter.STATE_CONNECTED); + + verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); + } + + @Test + public void testOnConnectionStateChanged_deviceDisconnected_addPreference() { + mBluetoothDeviceUpdater.onConnectionStateChanged(mCachedBluetoothDevice, + BluetoothAdapter.STATE_DISCONNECTED); + + verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); + } + +} -- 2.11.0