diff --git a/res/values/strings.xml b/res/values/strings.xml index ef02a1099ef..ccb0e43475c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1613,6 +1613,8 @@ Advanced Bluetooth When Bluetooth is turned on, your device can communicate with other nearby Bluetooth devices. + + When Bluetooth is turned on, your device can communicate with other nearby Bluetooth devices.\n\nTo improve device experience, apps and services can still scan for nearby devices at any time, even when Bluetooth is off. This can be used, for example, to improve location-based features and services. you can change this in scanning settings. @@ -6692,6 +6694,8 @@ + + Account for content diff --git a/res/xml/bluetooth_screen.xml b/res/xml/bluetooth_screen.xml new file mode 100644 index 00000000000..ec255202407 --- /dev/null +++ b/res/xml/bluetooth_screen.xml @@ -0,0 +1,19 @@ + + + \ No newline at end of file diff --git a/res/xml/connected_devices.xml b/res/xml/connected_devices.xml index 030428f9fb6..390a33de9fd 100644 --- a/res/xml/connected_devices.xml +++ b/res/xml/connected_devices.xml @@ -42,14 +42,12 @@ android:fragment="com.android.settings.connecteddevice.PreviouslyConnectedDeviceDashboardFragment" settings:allowDividerAbove="true"/> - + settings:allowDividerAbove="true"/> getRawDataToIndex(Context context, + boolean enabled) { + final List result = new ArrayList<>(); + + // Add the activity title + SearchIndexableRaw data = new SearchIndexableRaw(context); + data.title = context.getString(R.string.bluetooth_settings_title); + data.screenTitle = context.getString(R.string.settings_label); + data.keywords = context.getString(R.string.keywords_bluetooth_settings); + data.intentTargetPackage = context.getPackageName(); + data.intentTargetClass = BluetoothDashboardFragment.class.getName(); + data.intentAction = new SubSettingLauncher(context) + .setDestination(ScanningSettings.class.getName()) + .setSourceMetricsCategory(MetricsProto.MetricsEvent.BLUETOOTH_FRAGMENT) + .toIntent() + .getAction(); + data.key = KEY_BLUETOOTH_SCREEN; + result.add(data); + + return result; + } + + @Override + public List getNonIndexableKeys(Context context) { + final List keys = super.getNonIndexableKeys(context); + BluetoothManager manager = + (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); + if (manager != null) { + BluetoothAdapter adapter = manager.getAdapter(); + final int status = adapter != null + ? TogglePreferenceController.AVAILABLE + : TogglePreferenceController.DISABLED_UNSUPPORTED; + if (status != TogglePreferenceController.AVAILABLE) { + keys.add(KEY_BLUETOOTH_SCREEN); + } + } + + return keys; + } + }; +} diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java index 942fd7bd0b4..2b55ab12f18 100644 --- a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java +++ b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java @@ -22,7 +22,6 @@ import android.support.annotation.VisibleForTesting; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; -import com.android.settings.bluetooth.BluetoothSwitchPreferenceController; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.SummaryLoader; import com.android.settings.nfc.NfcPreferenceController; @@ -77,13 +76,8 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment { new NfcPreferenceController(context); controllers.add(nfcPreferenceController); - final BluetoothSwitchPreferenceController bluetoothPreferenceController = - new BluetoothSwitchPreferenceController(context); - controllers.add(bluetoothPreferenceController); - if (lifecycle != null) { lifecycle.addObserver(nfcPreferenceController); - lifecycle.addObserver(bluetoothPreferenceController); } return controllers; diff --git a/src/com/android/settings/search/SearchIndexableResourcesImpl.java b/src/com/android/settings/search/SearchIndexableResourcesImpl.java index 33bc2e0eee8..3b58c64ed36 100644 --- a/src/com/android/settings/search/SearchIndexableResourcesImpl.java +++ b/src/com/android/settings/search/SearchIndexableResourcesImpl.java @@ -23,6 +23,7 @@ import com.android.settings.DisplaySettings; import com.android.settings.LegalSettings; import com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment; import com.android.settings.connecteddevice.PreviouslyConnectedDeviceDashboardFragment; +import com.android.settings.connecteddevice.BluetoothDashboardFragment; import com.android.settings.datausage.DataUsageSummaryLegacy; import com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment; import com.android.settings.accessibility.AccessibilitySettings; @@ -185,6 +186,7 @@ public class SearchIndexableResourcesImpl implements SearchIndexableResources { addIndex(VibrationSettings.class); addIndex(RecentLocationRequestSeeAllFragment.class); addIndex(PreviouslyConnectedDeviceDashboardFragment.class); + addIndex(BluetoothDashboardFragment.class); } @Override diff --git a/src/com/android/settings/utils/AnnotationSpan.java b/src/com/android/settings/utils/AnnotationSpan.java index c70cba53bee..e6457dac793 100644 --- a/src/com/android/settings/utils/AnnotationSpan.java +++ b/src/com/android/settings/utils/AnnotationSpan.java @@ -80,6 +80,7 @@ public class AnnotationSpan extends URLSpan { */ public static class LinkInfo { private static final String TAG = "AnnotationSpan.LinkInfo"; + public static final String DEFAULT_ANNOTATION = "link"; private final String mAnnotation; private final Boolean mActionable; private final View.OnClickListener mListener; diff --git a/tests/robotests/assets/grandfather_invalid_base_preference_controller_constructor b/tests/robotests/assets/grandfather_invalid_base_preference_controller_constructor index 85cf92b8955..7faa14afcdd 100644 --- a/tests/robotests/assets/grandfather_invalid_base_preference_controller_constructor +++ b/tests/robotests/assets/grandfather_invalid_base_preference_controller_constructor @@ -5,7 +5,6 @@ com.android.settings.applications.appinfo.AppMemoryPreferenceController com.android.settings.applications.appinfo.InstantAppButtonsPreferenceController com.android.settings.bluetooth.BluetoothDeviceNamePreferenceController com.android.settings.bluetooth.BluetoothDeviceRenamePreferenceController -com.android.settings.bluetooth.BluetoothSwitchPreferenceController com.android.settings.connecteddevice.ConnectedDeviceGroupController com.android.settings.connecteddevice.SavedDeviceGroupController com.android.settings.datausage.DataUsageSummaryPreferenceController diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothEnablerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothEnablerTest.java index 3895d423fdf..d9e4e6b6ac2 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothEnablerTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothEnablerTest.java @@ -37,9 +37,11 @@ import android.view.View; import android.widget.Switch; import com.android.settings.R; -import com.android.settings.bluetooth.BluetoothSwitchPreferenceController.SwitchController; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; +import com.android.settings.widget.SwitchBar; +import com.android.settings.widget.SwitchBarController; +import com.android.settings.widget.SwitchWidgetController; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import com.android.settingslib.RestrictedSwitchPreference; import com.android.settingslib.bluetooth.LocalBluetoothAdapter; @@ -77,9 +79,11 @@ public class BluetoothEnablerTest { private LocalBluetoothManager mBluetoothManager; @Mock private LocalBluetoothAdapter mBluetoothAdapter; + @Mock + private SwitchWidgetController.OnSwitchChangeListener mCallback; private Context mContext; - private SwitchController mSwitchController; + private SwitchWidgetController mSwitchController; private BluetoothEnabler mBluetoothEnabler; @Before @@ -89,7 +93,7 @@ public class BluetoothEnablerTest { when(mBluetoothManager.getBluetoothAdapter()).thenReturn(mBluetoothAdapter); mRestrictedSwitchPreference = new RestrictedSwitchPreference(mContext); - mSwitchController = spy(new SwitchController(mRestrictedSwitchPreference)); + mSwitchController = spy(new SwitchBarController(new SwitchBar(mContext))); mBluetoothEnabler = new BluetoothEnabler( mContext, mSwitchController, @@ -99,6 +103,7 @@ public class BluetoothEnablerTest { mRestrictionUtils); mHolder = PreferenceViewHolder.createInstanceForTests(mock(View.class)); mRestrictedSwitchPreference.onBindViewHolder(mHolder); + mBluetoothEnabler.setToggleCallback(mCallback); } @Test @@ -110,6 +115,15 @@ public class BluetoothEnablerTest { verify(mMetricsFeatureProvider).action(mContext, 123, false); } + @Test + public void onSwitchToggled_shouldTriggerCallback() { + // WHEN the switch is toggled... + mBluetoothEnabler.onSwitchToggled(false); + + // THEN the callback is triggered + verify(mCallback).onSwitchToggled(false); + } + @Test public void maybeEnforceRestrictions_noRestrictions() { // GIVEN there are no restrictions set... diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothSwitchPreferenceControllerTest.java index a05859d9bce..ccd57f5d66f 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothSwitchPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothSwitchPreferenceControllerTest.java @@ -17,21 +17,21 @@ package com.android.settings.bluetooth; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doReturn; + +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import android.content.Context; -import android.support.v14.preference.SwitchPreference; -import android.support.v7.preference.PreferenceScreen; +import android.provider.Settings; -import com.android.settings.core.BasePreferenceController; +import com.android.settings.R; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; -import com.android.settingslib.bluetooth.LocalBluetoothAdapter; +import com.android.settings.utils.AnnotationSpan; +import com.android.settings.widget.SwitchWidgetController; import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.widget.FooterPreference; import org.junit.Before; import org.junit.Test; @@ -44,17 +44,16 @@ import org.robolectric.RuntimeEnvironment; @RunWith(SettingsRobolectricTestRunner.class) public class BluetoothSwitchPreferenceControllerTest { + public static final String BLUETOOTH_INFO_STRING = "When Bluetooth is turned on, your device" + + " can communicate with other nearby Bluetooth devices."; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private LocalBluetoothManager mBluetoothManager; @Mock - private PreferenceScreen mScreen; - @Mock - private SwitchPreference mPreference; - @Mock private RestrictionUtils mRestrictionUtils; @Mock - private LocalBluetoothAdapter mLocalBluetoothAdapter; + private SwitchWidgetController mSwitchController; + private FooterPreference mFooterPreference; private Context mContext; private BluetoothSwitchPreferenceController mController; @@ -62,70 +61,52 @@ public class BluetoothSwitchPreferenceControllerTest { public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application.getApplicationContext()); + mFooterPreference = new FooterPreference(mContext); FakeFeatureFactory.setupForTest(); mController = - new BluetoothSwitchPreferenceController(mContext, mBluetoothManager, mRestrictionUtils); - when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); - when(mPreference.getKey()).thenReturn(mController.getPreferenceKey()); + new BluetoothSwitchPreferenceController(mContext, mBluetoothManager, mRestrictionUtils, + mSwitchController, mFooterPreference); } @Test - public void testGetAvailabilityStatus_adapterNull_returnDisabled() { - mController.mBluetoothAdapter = null; + public void updateText_bluetoothOffScanningOn() { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 1); + mController.updateText(false); + AnnotationSpan.LinkInfo info = new AnnotationSpan.LinkInfo( + AnnotationSpan.LinkInfo.DEFAULT_ANNOTATION, mController); + CharSequence text = AnnotationSpan.linkify( + mContext.getText(R.string.bluetooth_scanning_on_info_message), info); - assertThat(mController.getAvailabilityStatus()) - .isEqualTo(BasePreferenceController.DISABLED_UNSUPPORTED); + assertThat(mFooterPreference.getTitle()).isEqualTo(text); } @Test - public void testGetAvailabilityStatus_adapterExisted_returnAvailable() { - mController.mBluetoothAdapter = mLocalBluetoothAdapter; + public void updateText_bluetoothOffScanningOff() { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0); + mController.updateText(false); + + assertThat(mFooterPreference.getTitle()).isEqualTo(BLUETOOTH_INFO_STRING); - assertThat(mController.getAvailabilityStatus()) - .isEqualTo(BasePreferenceController.AVAILABLE); } @Test - public void testOnStart_shouldRegisterPreferenceChangeListener() { - mController.displayPreference(mScreen); - mController.onStart(); + public void updateText_bluetoothOnScanningOff() { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0); + mController.updateText(true); - verify(mPreference).setOnPreferenceChangeListener( - any(BluetoothSwitchPreferenceController.SwitchController.class)); + assertThat(mFooterPreference.getTitle()).isEqualTo(BLUETOOTH_INFO_STRING); } @Test - public void testOnStop_shouldRegisterPreferenceChangeListener() { - mController.displayPreference(mScreen); - mController.onStart(); + public void updateText_bluetoothOnScanningOn() { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 1); + mController.updateText(true); - mController.onStop(); - - verify(mPreference).setOnPreferenceChangeListener(null); - } - - @Test - public void testIsChecked_adapterNull_returnFalse() { - mController.mBluetoothAdapter = null; - - assertThat(mController.isChecked()).isFalse(); - } - - @Test - public void testIsChecked_adapterExisted_returnFromAdapter() { - mController.mBluetoothAdapter = mLocalBluetoothAdapter; - doReturn(true).when(mLocalBluetoothAdapter).isEnabled(); - - assertThat(mController.isChecked()).isTrue(); - } - - @Test - public void testSetChecked_adapterExisted() { - mController.mBluetoothAdapter = mLocalBluetoothAdapter; - - mController.setChecked(true); - - verify(mLocalBluetoothAdapter).setBluetoothEnabled(true); + assertThat(mFooterPreference.getTitle()).isEqualTo(BLUETOOTH_INFO_STRING); } }