From 4f636b90b8a41bfa3a57678e51d42547c1ba2229 Mon Sep 17 00:00:00 2001 From: timhypeng Date: Fri, 11 May 2018 14:38:22 +0800 Subject: [PATCH 1/2] Add bluetooth discoverable footer preference in connected devices page * Dynamicly add preference in controller * Add test cases for DiscoverableFooterPreferenceController Bug: 79294219 Test: make -j50 RunSettingsRoboTests Change-Id: Id4c1e86c9a0a0cd69d8106a18f2cf4a0fa31782b Merged-In: Id4c1e86c9a0a0cd69d8106a18f2cf4a0fa31782b --- .../ConnectedDeviceDashboardFragment.java | 18 ++++ ...iscoverableFooterPreferenceController.java | 69 +++++++++++++ ...verableFooterPreferenceControllerTest.java | 96 +++++++++++++++++++ .../shadow/ShadowBluetoothAdapter.java | 36 +++++++ .../shadow/ShadowLocalBluetoothAdapter.java | 36 +++++++ 5 files changed, 255 insertions(+) create mode 100644 src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceController.java create mode 100644 tests/robotests/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceControllerTest.java create mode 100644 tests/robotests/src/com/android/settings/testutils/shadow/ShadowBluetoothAdapter.java create mode 100644 tests/robotests/src/com/android/settings/testutils/shadow/ShadowLocalBluetoothAdapter.java diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java index 26ff930558a..8495fa18fb9 100644 --- a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java +++ b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java @@ -26,7 +26,10 @@ import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.SummaryLoader; import com.android.settings.nfc.NfcPreferenceController; import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.core.lifecycle.Lifecycle; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -59,12 +62,27 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment { return R.xml.connected_devices; } + @Override + protected List createPreferenceControllers(Context context) { + return buildPreferenceControllers(context); + } + + private static List buildPreferenceControllers(Context context) { + final List controllers = new ArrayList<>(); + final DiscoverableFooterPreferenceController discoverableFooterPreferenceController = + new DiscoverableFooterPreferenceController(context); + controllers.add(discoverableFooterPreferenceController); + + return controllers; + } + @Override public void onAttach(Context context) { super.onAttach(context); use(AvailableMediaDeviceGroupController.class).init(this); use(ConnectedDeviceGroupController.class).init(this); use(PreviouslyConnectedDevicePreferenceController.class).init(this); + use(DiscoverableFooterPreferenceController.class).init(this); } @VisibleForTesting diff --git a/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceController.java b/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceController.java new file mode 100644 index 00000000000..d8d2433f15b --- /dev/null +++ b/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceController.java @@ -0,0 +1,69 @@ +/* + * 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.connecteddevice; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.support.v7.preference.PreferenceScreen; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.settings.core.BasePreferenceController; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settingslib.widget.FooterPreference; +import com.android.settingslib.widget.FooterPreferenceMixin; + +/** + * Controller that shows and updates the bluetooth device name + */ +public class DiscoverableFooterPreferenceController extends BasePreferenceController { + private static final String KEY = "discoverable_footer_preference"; + + private FooterPreference mPreference; + private FooterPreferenceMixin mFooterPreferenceMixin; + + + public DiscoverableFooterPreferenceController(Context context) { super(context, KEY); } + + public void init(DashboardFragment fragment) { + mFooterPreferenceMixin = new FooterPreferenceMixin(fragment, fragment.getLifecycle()); + } + + @VisibleForTesting + void init(FooterPreferenceMixin footerPreferenceMixin, FooterPreference preference) { + mFooterPreferenceMixin = footerPreferenceMixin; + mPreference = preference; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + addFooterPreference(screen); + } + + @Override + public int getAvailabilityStatus() { + return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH) + ? AVAILABLE + : UNSUPPORTED_ON_DEVICE; + } + + private void addFooterPreference(PreferenceScreen screen) { + mPreference = mFooterPreferenceMixin.createFooterPreference(); + mPreference.setKey(KEY); + screen.addPreference(mPreference); + } +} \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceControllerTest.java new file mode 100644 index 00000000000..5664d277bb6 --- /dev/null +++ b/tests/robotests/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceControllerTest.java @@ -0,0 +1,96 @@ +/* + * Copyright 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.connecteddevice; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.support.v7.preference.PreferenceScreen; + +import com.android.settings.core.BasePreferenceController; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; +import com.android.settings.testutils.shadow.ShadowBluetoothPan; +import com.android.settings.testutils.shadow.ShadowLocalBluetoothAdapter; +import com.android.settingslib.widget.FooterPreference; +import com.android.settingslib.widget.FooterPreferenceMixin; + +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(shadows = {ShadowBluetoothPan.class, ShadowBluetoothAdapter.class, + ShadowLocalBluetoothAdapter.class}) +public class DiscoverableFooterPreferenceControllerTest { + @Mock + private PackageManager mPackageManager; + @Mock + private PreferenceScreen mScreen; + @Mock + private FooterPreferenceMixin mFooterPreferenceMixin; + + private Context mContext; + private DiscoverableFooterPreferenceController mDiscoverableFooterPreferenceController; + private FooterPreference mPreference; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + doReturn(mPackageManager).when(mContext).getPackageManager(); + mDiscoverableFooterPreferenceController = + new DiscoverableFooterPreferenceController(mContext); + mPreference = spy(new FooterPreference(mContext)); + mDiscoverableFooterPreferenceController.init(mFooterPreferenceMixin, mPreference); + } + + @Test + public void getAvailabilityStatus_noBluetoothFeature_returnUnSupported() { + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)).thenReturn(false); + + assertThat(mDiscoverableFooterPreferenceController.getAvailabilityStatus()).isEqualTo( + BasePreferenceController.UNSUPPORTED_ON_DEVICE); + } + + @Test + public void getAvailabilityStatus_BluetoothFeature_returnSupported() { + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)).thenReturn(true); + + assertThat(mDiscoverableFooterPreferenceController.getAvailabilityStatus()).isEqualTo( + BasePreferenceController.AVAILABLE); + } + + @Test + public void displayPreference() { + when(mFooterPreferenceMixin.createFooterPreference()).thenReturn(mPreference); + mDiscoverableFooterPreferenceController.displayPreference(mScreen); + + verify(mPreference).setKey(anyString()); + verify(mScreen).addPreference(mPreference); + } +} diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowBluetoothAdapter.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowBluetoothAdapter.java new file mode 100644 index 00000000000..2bd2ec33aaa --- /dev/null +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowBluetoothAdapter.java @@ -0,0 +1,36 @@ +/* + * 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.testutils.shadow; + +import android.bluetooth.BluetoothAdapter; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +import java.util.ArrayList; +import java.util.List; + +@Implements(value = BluetoothAdapter.class, inheritImplementationMethods = true) +public class ShadowBluetoothAdapter extends org.robolectric.shadows.ShadowBluetoothAdapter { + /** + * Do nothing, implement it to avoid null pointer error inside BluetoothAdapter + */ + @Implementation + public List getSupportedProfiles() { + return new ArrayList(); + } +} diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLocalBluetoothAdapter.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLocalBluetoothAdapter.java new file mode 100644 index 00000000000..d215e2abfeb --- /dev/null +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLocalBluetoothAdapter.java @@ -0,0 +1,36 @@ +/* + * 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.testutils.shadow; + +import com.android.settingslib.bluetooth.LocalBluetoothAdapter; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +@Implements(LocalBluetoothAdapter.class) +public class ShadowLocalBluetoothAdapter { + + private static String sName; + + @Implementation + public String getName() { + return sName; + } + + public static void setName(String name) { + sName = name; + } +} From 78eb5a81ba4b1236b6764a540546de3a84ca0c3f Mon Sep 17 00:00:00 2001 From: timhypeng Date: Fri, 11 May 2018 15:41:10 +0800 Subject: [PATCH 2/2] Make device discoverable in Connected Devices settings page * Set preference title by bluetooth state * Enable bluetooth discoverable mode in Connected device page * Add more test cases for DiscoverableFooterPreferenceController Bug: 79294219 Test: make -j50 RunSettingsRoboTests Change-Id: I6d4f8ec3870c43bf48e9666eabd60068aa8950bb Merged-In: I6d4f8ec3870c43bf48e9666eabd60068aa8950bb --- .../ConnectedDeviceDashboardFragment.java | 15 ++- ...iscoverableFooterPreferenceController.java | 84 +++++++++++++++- .../ConnectedDeviceDashboardFragmentTest.java | 3 +- ...verableFooterPreferenceControllerTest.java | 98 +++++++++++++++++-- 4 files changed, 186 insertions(+), 14 deletions(-) diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java index 8495fa18fb9..81ba65cdef9 100644 --- a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java +++ b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java @@ -64,15 +64,20 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment { @Override protected List createPreferenceControllers(Context context) { - return buildPreferenceControllers(context); + return buildPreferenceControllers(context, getLifecycle()); } - private static List buildPreferenceControllers(Context context) { + private static List buildPreferenceControllers(Context context, + Lifecycle lifecycle) { final List controllers = new ArrayList<>(); final DiscoverableFooterPreferenceController discoverableFooterPreferenceController = new DiscoverableFooterPreferenceController(context); controllers.add(discoverableFooterPreferenceController); + if (lifecycle != null) { + lifecycle.addObserver(discoverableFooterPreferenceController); + } + return controllers; } @@ -135,6 +140,12 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment { return Arrays.asList(sir); } + @Override + public List createPreferenceControllers(Context + context) { + return buildPreferenceControllers(context, null /* lifecycle */); + } + @Override public List getNonIndexableKeys(Context context) { List keys = super.getNonIndexableKeys(context); diff --git a/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceController.java b/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceController.java index d8d2433f15b..6d2b7154b4c 100644 --- a/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceController.java +++ b/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceController.java @@ -16,36 +16,79 @@ package com.android.settings.connecteddevice; +import android.bluetooth.BluetoothAdapter; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; import android.support.v7.preference.PreferenceScreen; +import android.text.BidiFormatter; +import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; +import com.android.settings.bluetooth.AlwaysDiscoverable; +import com.android.settings.bluetooth.Utils; import com.android.settings.core.BasePreferenceController; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.R; +import com.android.settingslib.bluetooth.LocalBluetoothAdapter; +import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.core.lifecycle.events.OnPause; +import com.android.settingslib.core.lifecycle.events.OnResume; +import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.widget.FooterPreference; import com.android.settingslib.widget.FooterPreferenceMixin; /** * Controller that shows and updates the bluetooth device name */ -public class DiscoverableFooterPreferenceController extends BasePreferenceController { +public class DiscoverableFooterPreferenceController extends BasePreferenceController + implements LifecycleObserver, OnResume, OnPause { private static final String KEY = "discoverable_footer_preference"; - private FooterPreference mPreference; + @VisibleForTesting + BroadcastReceiver mBluetoothChangedReceiver; private FooterPreferenceMixin mFooterPreferenceMixin; + private FooterPreference mPreference; + private LocalBluetoothManager mLocalManager; + private LocalBluetoothAdapter mLocalAdapter; + private AlwaysDiscoverable mAlwaysDiscoverable; + public DiscoverableFooterPreferenceController(Context context) { + super(context, KEY); + mLocalManager = Utils.getLocalBtManager(context); + if (mLocalManager == null) { + return; + } + mLocalAdapter = mLocalManager.getBluetoothAdapter(); + mAlwaysDiscoverable = new AlwaysDiscoverable(context, mLocalAdapter); + initReceiver(); + } - public DiscoverableFooterPreferenceController(Context context) { super(context, KEY); } + private void initReceiver() { + mBluetoothChangedReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { + final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, + BluetoothAdapter.ERROR); + updateFooterPreferenceTitle(state); + } + } + }; + } public void init(DashboardFragment fragment) { mFooterPreferenceMixin = new FooterPreferenceMixin(fragment, fragment.getLifecycle()); } @VisibleForTesting - void init(FooterPreferenceMixin footerPreferenceMixin, FooterPreference preference) { + void init(FooterPreferenceMixin footerPreferenceMixin, FooterPreference preference, + AlwaysDiscoverable alwaysDiscoverable) { mFooterPreferenceMixin = footerPreferenceMixin; mPreference = preference; + mAlwaysDiscoverable = alwaysDiscoverable; } @Override @@ -66,4 +109,37 @@ public class DiscoverableFooterPreferenceController extends BasePreferenceContro mPreference.setKey(KEY); screen.addPreference(mPreference); } + + @Override + public void onResume() { + mContext.registerReceiver(mBluetoothChangedReceiver, + new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)); + mAlwaysDiscoverable.start(); + updateFooterPreferenceTitle(mLocalAdapter.getState()); + } + + @Override + public void onPause() { + mContext.unregisterReceiver(mBluetoothChangedReceiver); + mAlwaysDiscoverable.stop(); + } + + private void updateFooterPreferenceTitle (int bluetoothState) { + if (bluetoothState == BluetoothAdapter.STATE_ON) { + mPreference.setTitle(getPreferenceTitle()); + } else { + mPreference.setTitle(R.string.bluetooth_off_footer); + } + } + + private CharSequence getPreferenceTitle() { + final String deviceName = mLocalAdapter.getName(); + if (TextUtils.isEmpty(deviceName)) { + return null; + } + + return TextUtils.expandTemplate( + mContext.getText(R.string.bluetooth_device_name_summary), + BidiFormatter.getInstance().unicodeWrap(deviceName)); + } } \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java index 90641792639..fd1ec157b65 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java @@ -32,6 +32,7 @@ import android.provider.SearchIndexableResource; import com.android.settings.R; import com.android.settings.nfc.NfcPreferenceController; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; import com.android.settings.testutils.shadow.ShadowBluetoothPan; import com.android.settings.testutils.shadow.ShadowConnectivityManager; import com.android.settings.testutils.shadow.ShadowUserManager; @@ -48,7 +49,7 @@ import java.util.List; @RunWith(SettingsRobolectricTestRunner.class) @Config(shadows = {ShadowBluetoothPan.class, ShadowUserManager.class, - ShadowConnectivityManager.class}) + ShadowConnectivityManager.class, ShadowBluetoothAdapter.class}) public class ConnectedDeviceDashboardFragmentTest { @Mock private PackageManager mPackageManager; diff --git a/tests/robotests/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceControllerTest.java index 5664d277bb6..8cad0bfe70d 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceControllerTest.java @@ -16,18 +16,23 @@ package com.android.settings.connecteddevice; import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.bluetooth.BluetoothAdapter; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; import android.support.v7.preference.PreferenceScreen; +import android.text.BidiFormatter; +import android.text.TextUtils; import com.android.settings.core.BasePreferenceController; +import com.android.settings.bluetooth.AlwaysDiscoverable; +import com.android.settings.R; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; import com.android.settings.testutils.shadow.ShadowBluetoothPan; @@ -41,32 +46,49 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; +import org.robolectric.Shadows; import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowApplication; + +import java.util.ArrayList; +import java.util.List; @RunWith(SettingsRobolectricTestRunner.class) @Config(shadows = {ShadowBluetoothPan.class, ShadowBluetoothAdapter.class, ShadowLocalBluetoothAdapter.class}) public class DiscoverableFooterPreferenceControllerTest { + private static final String DEVICE_NAME = "device name"; + private static final String KEY = "discoverable_footer_preference"; + @Mock private PackageManager mPackageManager; @Mock private PreferenceScreen mScreen; @Mock private FooterPreferenceMixin mFooterPreferenceMixin; + @Mock + private AlwaysDiscoverable mAlwaysDiscoverable; private Context mContext; - private DiscoverableFooterPreferenceController mDiscoverableFooterPreferenceController; private FooterPreference mPreference; + private DiscoverableFooterPreferenceController mDiscoverableFooterPreferenceController; + private BroadcastReceiver mBluetoothChangedReceiver; + private ShadowApplication mShadowApplication; @Before public void setUp() { MockitoAnnotations.initMocks(this); + mShadowApplication = Shadows.shadowOf(RuntimeEnvironment.application); mContext = spy(RuntimeEnvironment.application); + doReturn(mPackageManager).when(mContext).getPackageManager(); mDiscoverableFooterPreferenceController = new DiscoverableFooterPreferenceController(mContext); mPreference = spy(new FooterPreference(mContext)); - mDiscoverableFooterPreferenceController.init(mFooterPreferenceMixin, mPreference); + mDiscoverableFooterPreferenceController.init(mFooterPreferenceMixin, mPreference, + mAlwaysDiscoverable); + mBluetoothChangedReceiver = mDiscoverableFooterPreferenceController + .mBluetoothChangedReceiver; } @Test @@ -78,7 +100,7 @@ public class DiscoverableFooterPreferenceControllerTest { } @Test - public void getAvailabilityStatus_BluetoothFeature_returnSupported() { + public void getAvailabilityStatus_BluetoothFeature_returnAvailable() { when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)).thenReturn(true); assertThat(mDiscoverableFooterPreferenceController.getAvailabilityStatus()).isEqualTo( @@ -90,7 +112,69 @@ public class DiscoverableFooterPreferenceControllerTest { when(mFooterPreferenceMixin.createFooterPreference()).thenReturn(mPreference); mDiscoverableFooterPreferenceController.displayPreference(mScreen); - verify(mPreference).setKey(anyString()); + verify(mPreference).setKey(KEY); verify(mScreen).addPreference(mPreference); } -} + + @Test + public void onResume() { + mDiscoverableFooterPreferenceController.onResume(); + assertThat(getRegisteredBroadcastReceivers()).contains(mBluetoothChangedReceiver); + verify(mAlwaysDiscoverable).start(); + } + + @Test + public void onPause() { + mDiscoverableFooterPreferenceController.onResume(); + mDiscoverableFooterPreferenceController.onPause(); + + assertThat(getRegisteredBroadcastReceivers()).doesNotContain(mBluetoothChangedReceiver); + verify(mAlwaysDiscoverable).stop(); + } + + @Test + public void onBluetoothStateChanged_bluetoothOn_updateTitle() { + ShadowLocalBluetoothAdapter.setName(DEVICE_NAME); + sendBluetoothStateChangedIntent(BluetoothAdapter.STATE_ON); + + assertThat(mPreference.getTitle()).isEqualTo(generateTitle(DEVICE_NAME)); + } + + @Test + public void onBluetoothStateChanged_bluetoothOff_updateTitle(){ + ShadowLocalBluetoothAdapter.setName(DEVICE_NAME); + sendBluetoothStateChangedIntent(BluetoothAdapter.STATE_OFF); + + assertThat(mPreference.getTitle()).isEqualTo(generateTitle(null)); + } + + private CharSequence generateTitle(String deviceName) { + if (deviceName == null) { + return mContext.getString(R.string.bluetooth_off_footer); + + } else { + return TextUtils.expandTemplate( + mContext.getText(R.string.bluetooth_device_name_summary), + BidiFormatter.getInstance().unicodeWrap(deviceName)); + } + } + + private void sendBluetoothStateChangedIntent(int state) { + Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); + intent.putExtra(BluetoothAdapter.EXTRA_STATE, state); + mBluetoothChangedReceiver.onReceive(mContext, intent); + } + + /** + * Return a list of all the registered broadcast receivers + */ + private List getRegisteredBroadcastReceivers() { + List registeredBroadcastReceivers = new ArrayList(); + List registeredReceivers = + mShadowApplication.getRegisteredReceivers(); + for (ShadowApplication.Wrapper wrapper : registeredReceivers) { + registeredBroadcastReceivers.add(wrapper.getBroadcastReceiver()); + } + return registeredBroadcastReceivers; + } +} \ No newline at end of file