<PreferenceCategory
android:key="connected_device_list"
android:title="@string/connected_device_connected_title"/>
+
+ <PreferenceCategory
+ android:key="saved_device_list"
+ android:title="@string/connected_device_saved_title"/>
</PreferenceScreen>
}
/**
+ * 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}
}
@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();
}
}
--- /dev/null
+/*
+ * 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();
+ }
+}
final List<AbstractPreferenceController> 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;
}
--- /dev/null
+/*
+ * 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;
+ }
+}
mBluetoothDeviceUpdater = new BluetoothDeviceUpdater(mDashboardFragment,
mDevicePreferenceCallback, null) {
@Override
- public void update(CachedBluetoothDevice cachedBluetoothDevice) {
- // do nothing
+ public boolean isFilterMatched(CachedBluetoothDevice cachedBluetoothDevice) {
+ return true;
}
};
mBluetoothDeviceUpdater.setPrefContext(mContext);
--- /dev/null
+/*
+ * 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);
+ }
+
+}