Loading src/com/android/settings/homepage/contextualcards/slices/BluetoothUpdateWorker.java 0 → 100644 +96 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.homepage.contextualcards.slices; import android.content.Context; import android.net.Uri; import android.util.Log; import com.android.settings.bluetooth.Utils; import com.android.settings.slices.SliceBackgroundWorker; import com.android.settingslib.bluetooth.BluetoothCallback; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.LocalBluetoothManager; public class BluetoothUpdateWorker extends SliceBackgroundWorker implements BluetoothCallback { private static final String TAG = "BluetoothUpdateWorker"; private final Context mContext; private final Uri mUri; private final LocalBluetoothManager mLocalBluetoothManager; public BluetoothUpdateWorker(Context context, Uri uri) { super(context, uri); mContext = context; mUri = uri; mLocalBluetoothManager = Utils.getLocalBtManager(mContext); } @Override protected void onSlicePinned() { if (mLocalBluetoothManager == null) { Log.i(TAG, "onSlicePinned() Bluetooth is unsupported."); return; } mLocalBluetoothManager.getEventManager().registerCallback(this); } @Override protected void onSliceUnpinned() { if (mLocalBluetoothManager == null) { Log.i(TAG, "onSliceUnpinned() Bluetooth is unsupported."); return; } mLocalBluetoothManager.getEventManager().unregisterCallback(this); } @Override public void close() { } @Override public void onAclConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { notifySliceChange(); } @Override public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) { notifySliceChange(); } @Override public void onBluetoothStateChanged(int bluetoothState) { notifySliceChange(); } @Override public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { notifySliceChange(); } @Override public void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state, int bluetoothProfile) { notifySliceChange(); } private void notifySliceChange() { mContext.getContentResolver().notifyChange(mUri, null); } } No newline at end of file src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSlice.java +12 −25 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.settings.homepage.contextualcards.slices; import android.app.PendingIntent; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; Loading @@ -28,7 +27,6 @@ import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; Loading @@ -55,10 +53,9 @@ import com.android.settingslib.core.instrumentation.Instrumentable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * TODO(b/114807655): Contextual Home Page - Connected Device Loading @@ -66,11 +63,7 @@ import java.util.Map; * Show connected device info if one is currently connected. UI for connected device should * match Connected Devices > Currently Connected Devices * * This Slice will show multiple currently connected devices, which includes: * 1) Bluetooth. * 2) Docks. * ... * TODO Other device types are under checking to support, will update later. * TODO This class will be refactor for Bluetooth connected devices only. */ public class ConnectedDeviceSlice implements CustomSliceable { Loading Loading @@ -138,7 +131,6 @@ public class ConnectedDeviceSlice implements CustomSliceable { .setAccentColor(Utils.getColorAccentDefaultColor(mContext)); // Get row builders by connected devices, e.g. Bluetooth. // TODO Add other type connected devices, e.g. Docks. final List<ListBuilder.RowBuilder> rows = getBluetoothRowBuilder(primarySliceAction); // Return a header with IsError flag, if no connected devices. Loading Loading @@ -181,13 +173,18 @@ public class ConnectedDeviceSlice implements CustomSliceable { public void onNotifyChange(Intent intent) { } @Override public Class getBackgroundWorkerClass() { return BluetoothUpdateWorker.class; } @VisibleForTesting List<CachedBluetoothDevice> getBluetoothConnectedDevices() { final List<CachedBluetoothDevice> connectedBluetoothList = new ArrayList<>(); // If Bluetooth is disable, skip to get the bluetooth devices. if (!BluetoothAdapter.getDefaultAdapter().isEnabled()) { Log.d(TAG, "Cannot get Bluetooth connected devices, Bluetooth is disabled."); Log.i(TAG, "Cannot get Bluetooth connected devices, Bluetooth is disabled."); return connectedBluetoothList; } Loading @@ -195,25 +192,15 @@ public class ConnectedDeviceSlice implements CustomSliceable { final LocalBluetoothManager bluetoothManager = com.android.settings.bluetooth.Utils.getLocalBtManager(mContext); if (bluetoothManager == null) { Log.d(TAG, "Cannot get Bluetooth connected devices, Bluetooth is not supported."); Log.i(TAG, "Cannot get Bluetooth connected devices, Bluetooth is unsupported."); return connectedBluetoothList; } final Collection<CachedBluetoothDevice> cachedDevices = bluetoothManager.getCachedDeviceManager().getCachedDevicesCopy(); // Get all connected Bluetooth devices and use Map to filter duplicated Bluetooth. final Map<BluetoothDevice, CachedBluetoothDevice> connectedBluetoothMap = new ArrayMap<>(); for (CachedBluetoothDevice device : cachedDevices) { if (device.isConnected() && !connectedBluetoothMap.containsKey(device.getDevice())) { connectedBluetoothMap.put(device.getDevice(), device); } } // Sort connected Bluetooth devices. connectedBluetoothList.addAll(connectedBluetoothMap.values()); Collections.sort(connectedBluetoothList, COMPARATOR); return connectedBluetoothList; // Get connected Bluetooth devices and sort them. return cachedDevices.stream().filter(device -> device.isConnected()).sorted( COMPARATOR).collect(Collectors.toList()); } @VisibleForTesting Loading tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothUpdateWorkerTest.java 0 → 100644 +90 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.homepage.contextualcards.slices; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.ContentResolver; import android.content.Context; import android.net.Uri; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @RunWith(SettingsRobolectricTestRunner.class) @Config(shadows = {ShadowBluetoothAdapter.class}) public class BluetoothUpdateWorkerTest { private static final Uri URI = Uri.parse("content://com.android.settings.slices/test"); private BluetoothUpdateWorker mBluetoothUpdateWorker; private ContentResolver mResolver; private Context mContext; @Before public void setUp() { mContext = spy(RuntimeEnvironment.application); mBluetoothUpdateWorker = new BluetoothUpdateWorker(mContext, URI); mResolver = mock(ContentResolver.class); doReturn(mResolver).when(mContext).getContentResolver(); } @Test public void onAclConnectionStateChanged_shouldNotifyChange() { mBluetoothUpdateWorker.onAclConnectionStateChanged(null, 0); verify(mResolver).notifyChange(URI, null); } @Test public void onActiveDeviceChanged_shouldNotifyChange() { mBluetoothUpdateWorker.onActiveDeviceChanged(null, 0); verify(mResolver).notifyChange(URI, null); } @Test public void onBluetoothStateChanged_shouldNotifyChange() { mBluetoothUpdateWorker.onBluetoothStateChanged(0); verify(mResolver).notifyChange(URI, null); } @Test public void onConnectionStateChanged_shouldNotifyChange() { mBluetoothUpdateWorker.onConnectionStateChanged(null, 0); verify(mResolver).notifyChange(URI, null); } @Test public void onProfileConnectionStateChanged_shouldNotifyChange() { mBluetoothUpdateWorker.onProfileConnectionStateChanged(null, 0, 0); verify(mResolver).notifyChange(URI, null); } } No newline at end of file Loading
src/com/android/settings/homepage/contextualcards/slices/BluetoothUpdateWorker.java 0 → 100644 +96 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.homepage.contextualcards.slices; import android.content.Context; import android.net.Uri; import android.util.Log; import com.android.settings.bluetooth.Utils; import com.android.settings.slices.SliceBackgroundWorker; import com.android.settingslib.bluetooth.BluetoothCallback; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.LocalBluetoothManager; public class BluetoothUpdateWorker extends SliceBackgroundWorker implements BluetoothCallback { private static final String TAG = "BluetoothUpdateWorker"; private final Context mContext; private final Uri mUri; private final LocalBluetoothManager mLocalBluetoothManager; public BluetoothUpdateWorker(Context context, Uri uri) { super(context, uri); mContext = context; mUri = uri; mLocalBluetoothManager = Utils.getLocalBtManager(mContext); } @Override protected void onSlicePinned() { if (mLocalBluetoothManager == null) { Log.i(TAG, "onSlicePinned() Bluetooth is unsupported."); return; } mLocalBluetoothManager.getEventManager().registerCallback(this); } @Override protected void onSliceUnpinned() { if (mLocalBluetoothManager == null) { Log.i(TAG, "onSliceUnpinned() Bluetooth is unsupported."); return; } mLocalBluetoothManager.getEventManager().unregisterCallback(this); } @Override public void close() { } @Override public void onAclConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { notifySliceChange(); } @Override public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) { notifySliceChange(); } @Override public void onBluetoothStateChanged(int bluetoothState) { notifySliceChange(); } @Override public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { notifySliceChange(); } @Override public void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state, int bluetoothProfile) { notifySliceChange(); } private void notifySliceChange() { mContext.getContentResolver().notifyChange(mUri, null); } } No newline at end of file
src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSlice.java +12 −25 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.settings.homepage.contextualcards.slices; import android.app.PendingIntent; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; Loading @@ -28,7 +27,6 @@ import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; Loading @@ -55,10 +53,9 @@ import com.android.settingslib.core.instrumentation.Instrumentable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * TODO(b/114807655): Contextual Home Page - Connected Device Loading @@ -66,11 +63,7 @@ import java.util.Map; * Show connected device info if one is currently connected. UI for connected device should * match Connected Devices > Currently Connected Devices * * This Slice will show multiple currently connected devices, which includes: * 1) Bluetooth. * 2) Docks. * ... * TODO Other device types are under checking to support, will update later. * TODO This class will be refactor for Bluetooth connected devices only. */ public class ConnectedDeviceSlice implements CustomSliceable { Loading Loading @@ -138,7 +131,6 @@ public class ConnectedDeviceSlice implements CustomSliceable { .setAccentColor(Utils.getColorAccentDefaultColor(mContext)); // Get row builders by connected devices, e.g. Bluetooth. // TODO Add other type connected devices, e.g. Docks. final List<ListBuilder.RowBuilder> rows = getBluetoothRowBuilder(primarySliceAction); // Return a header with IsError flag, if no connected devices. Loading Loading @@ -181,13 +173,18 @@ public class ConnectedDeviceSlice implements CustomSliceable { public void onNotifyChange(Intent intent) { } @Override public Class getBackgroundWorkerClass() { return BluetoothUpdateWorker.class; } @VisibleForTesting List<CachedBluetoothDevice> getBluetoothConnectedDevices() { final List<CachedBluetoothDevice> connectedBluetoothList = new ArrayList<>(); // If Bluetooth is disable, skip to get the bluetooth devices. if (!BluetoothAdapter.getDefaultAdapter().isEnabled()) { Log.d(TAG, "Cannot get Bluetooth connected devices, Bluetooth is disabled."); Log.i(TAG, "Cannot get Bluetooth connected devices, Bluetooth is disabled."); return connectedBluetoothList; } Loading @@ -195,25 +192,15 @@ public class ConnectedDeviceSlice implements CustomSliceable { final LocalBluetoothManager bluetoothManager = com.android.settings.bluetooth.Utils.getLocalBtManager(mContext); if (bluetoothManager == null) { Log.d(TAG, "Cannot get Bluetooth connected devices, Bluetooth is not supported."); Log.i(TAG, "Cannot get Bluetooth connected devices, Bluetooth is unsupported."); return connectedBluetoothList; } final Collection<CachedBluetoothDevice> cachedDevices = bluetoothManager.getCachedDeviceManager().getCachedDevicesCopy(); // Get all connected Bluetooth devices and use Map to filter duplicated Bluetooth. final Map<BluetoothDevice, CachedBluetoothDevice> connectedBluetoothMap = new ArrayMap<>(); for (CachedBluetoothDevice device : cachedDevices) { if (device.isConnected() && !connectedBluetoothMap.containsKey(device.getDevice())) { connectedBluetoothMap.put(device.getDevice(), device); } } // Sort connected Bluetooth devices. connectedBluetoothList.addAll(connectedBluetoothMap.values()); Collections.sort(connectedBluetoothList, COMPARATOR); return connectedBluetoothList; // Get connected Bluetooth devices and sort them. return cachedDevices.stream().filter(device -> device.isConnected()).sorted( COMPARATOR).collect(Collectors.toList()); } @VisibleForTesting Loading
tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothUpdateWorkerTest.java 0 → 100644 +90 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.homepage.contextualcards.slices; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.ContentResolver; import android.content.Context; import android.net.Uri; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @RunWith(SettingsRobolectricTestRunner.class) @Config(shadows = {ShadowBluetoothAdapter.class}) public class BluetoothUpdateWorkerTest { private static final Uri URI = Uri.parse("content://com.android.settings.slices/test"); private BluetoothUpdateWorker mBluetoothUpdateWorker; private ContentResolver mResolver; private Context mContext; @Before public void setUp() { mContext = spy(RuntimeEnvironment.application); mBluetoothUpdateWorker = new BluetoothUpdateWorker(mContext, URI); mResolver = mock(ContentResolver.class); doReturn(mResolver).when(mContext).getContentResolver(); } @Test public void onAclConnectionStateChanged_shouldNotifyChange() { mBluetoothUpdateWorker.onAclConnectionStateChanged(null, 0); verify(mResolver).notifyChange(URI, null); } @Test public void onActiveDeviceChanged_shouldNotifyChange() { mBluetoothUpdateWorker.onActiveDeviceChanged(null, 0); verify(mResolver).notifyChange(URI, null); } @Test public void onBluetoothStateChanged_shouldNotifyChange() { mBluetoothUpdateWorker.onBluetoothStateChanged(0); verify(mResolver).notifyChange(URI, null); } @Test public void onConnectionStateChanged_shouldNotifyChange() { mBluetoothUpdateWorker.onConnectionStateChanged(null, 0); verify(mResolver).notifyChange(URI, null); } @Test public void onProfileConnectionStateChanged_shouldNotifyChange() { mBluetoothUpdateWorker.onProfileConnectionStateChanged(null, 0, 0); verify(mResolver).notifyChange(URI, null); } } No newline at end of file