Split BluetoothSettings into two pages

This cl splits the BluetoothSettings into paired device page and
pairing page, including small changes about:
1. Refactor the pages so they could get as much as static preference
from xml file rather than dynamically add/remove them everytime.
2. Remove creating method in BluetoothDeviceNamePreferenceController
and add it in xml file
3. Create BluetoothPairingDetail page, basically move the logic from
BluetoothSettings.
4. Make pairing preference clickable and jump to BluetoothPairingDetail
5. Add and update bunch of tests

Bug: 35877041
Test: RunSettingsRoboTests
Change-Id: Ief9e9690c612f7b46c58e866e5cecc511af642c8
This commit is contained in:
jackqdyulei
2017-05-10 14:57:16 -07:00
parent 5333ecd1fb
commit 52ccb49fbe
14 changed files with 704 additions and 224 deletions

View File

@@ -19,7 +19,6 @@ package com.android.settings.bluetooth;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -29,10 +28,8 @@ import android.os.Bundle;
import android.provider.Settings;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceScreen;
import android.text.BidiFormatter;
import android.text.Spannable;
import android.text.style.TextAppearanceSpan;
import android.util.Log;
@@ -74,11 +71,9 @@ import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
* connection management.
*
*/
// TODO: Refactor this fragment
public class BluetoothSettings extends DeviceListPreferenceFragment implements Indexable {
private static final String TAG = "BluetoothSettings";
private static final int MENU_ID_SCAN = Menu.FIRST;
private static final int MENU_ID_SHOW_RECEIVED = Menu.FIRST + 1;
/* Private intent to show the list of received files */
@@ -87,47 +82,32 @@ public class BluetoothSettings extends DeviceListPreferenceFragment implements I
private static final String BTOPP_PACKAGE =
"com.android.bluetooth";
private static final String KEY_PAIRED_DEVICES = "paired_devices";
private static final int PAIRED_DEVICE_ORDER = 1;
private static final int PAIRING_PREF_ORDER = 2;
private static View mSettingsDialogView = null;
@VisibleForTesting
static final String KEY_PAIRED_DEVICES = "paired_devices";
@VisibleForTesting
static final String KEY_FOOTER_PREF = "footer_preference";
private BluetoothEnabler mBluetoothEnabler;
private PreferenceGroup mPairedDevicesCategory;
private PreferenceGroup mAvailableDevicesCategory;
private Preference mDeviceNamePreference;
@VisibleForTesting
PreferenceGroup mPairedDevicesCategory;
@VisibleForTesting
FooterPreference mFooterPreference;
private Preference mPairingPreference;
private boolean mAvailableDevicesCategoryIsPresent;
private boolean mInitialScanStarted;
private boolean mInitiateDiscoverable;
private BluetoothEnabler mBluetoothEnabler;
private SwitchBar mSwitchBar;
private final IntentFilter mIntentFilter;
private BluetoothDeviceNamePreferenceController mDeviceNamePrefController;
private BluetoothPairingPreferenceController mPairingPrefController;
@VisibleForTesting
BluetoothPairingPreferenceController mPairingPrefController;
// For Search
@VisibleForTesting
static final String DATA_KEY_REFERENCE = "main_toggle_bluetooth";
// accessed from inner class (not private to avoid thunks)
FooterPreference mMyDevicePreference;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
final int state =
intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
if (state == BluetoothAdapter.STATE_ON) {
mInitiateDiscoverable = true;
}
}
};
public BluetoothSettings() {
super(DISALLOW_CONFIG_BLUETOOTH);
mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
@@ -141,15 +121,13 @@ public class BluetoothSettings extends DeviceListPreferenceFragment implements I
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mInitialScanStarted = false;
mInitiateDiscoverable = true;
final SettingsActivity activity = (SettingsActivity) getActivity();
mSwitchBar = activity.getSwitchBar();
mBluetoothEnabler = new BluetoothEnabler(activity, new SwitchBarController(mSwitchBar),
mMetricsFeatureProvider, Utils.getLocalBtManager(activity),
MetricsEvent.ACTION_BLUETOOTH_TOGGLE);
mMetricsFeatureProvider, Utils.getLocalBtManager(activity),
MetricsEvent.ACTION_BLUETOOTH_TOGGLE);
mBluetoothEnabler.setupSwitchController();
}
@@ -161,28 +139,11 @@ public class BluetoothSettings extends DeviceListPreferenceFragment implements I
}
@Override
void addPreferencesForActivity() {
final Context prefContext = getPrefContext();
mDeviceNamePreference = mDeviceNamePrefController.createBluetoothDeviceNamePreference(
getPreferenceScreen(), 1 /* order */);
mPairedDevicesCategory = new PreferenceCategory(prefContext);
mPairedDevicesCategory.setKey(KEY_PAIRED_DEVICES);
mPairedDevicesCategory.setOrder(2);
getPreferenceScreen().addPreference(mPairedDevicesCategory);
mAvailableDevicesCategory = new BluetoothProgressCategory(prefContext);
mAvailableDevicesCategory.setSelectable(false);
mAvailableDevicesCategory.setOrder(3);
getPreferenceScreen().addPreference(mAvailableDevicesCategory);
mMyDevicePreference = mFooterPreferenceMixin.createFooterPreference();
mMyDevicePreference.setSelectable(false);
mPairingPreference = mPairingPrefController.createBluetoothPairingPreference();
setHasOptionsMenu(true);
void initPreferencesFromPreferenceScreen() {
mPairingPreference = mPairingPrefController.createBluetoothPairingPreference(
PAIRING_PREF_ORDER);
mFooterPreference = (FooterPreference) findPreference(KEY_FOOTER_PREF);
mPairedDevicesCategory = (PreferenceGroup) findPreference(KEY_PAIRED_DEVICES);
}
@Override
@@ -193,19 +154,14 @@ public class BluetoothSettings extends DeviceListPreferenceFragment implements I
mBluetoothEnabler.resume(getActivity());
}
super.onStart();
mInitiateDiscoverable = true;
if (isUiRestricted()) {
setDeviceListGroup(getPreferenceScreen());
getPreferenceScreen().removeAll();
if (!isUiRestrictedByOnlyAdmin()) {
getEmptyTextView().setText(R.string.bluetooth_empty_list_user_restricted);
}
removeAllDevices();
return;
}
getActivity().registerReceiver(mReceiver, mIntentFilter);
if (mLocalAdapter != null) {
updateContent(mLocalAdapter.getBluetoothState());
}
@@ -224,8 +180,6 @@ public class BluetoothSettings extends DeviceListPreferenceFragment implements I
if (isUiRestricted()) {
return;
}
getActivity().unregisterReceiver(mReceiver);
}
@Override
@@ -234,13 +188,6 @@ public class BluetoothSettings extends DeviceListPreferenceFragment implements I
// If the user is not allowed to configure bluetooth, do not show the menu.
if (isUiRestricted()) return;
boolean bluetoothIsEnabled = mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON;
boolean isDiscovering = mLocalAdapter.isDiscovering();
int textId = isDiscovering ? R.string.bluetooth_searching_for_devices :
R.string.bluetooth_search_for_devices;
menu.add(Menu.NONE, MENU_ID_SCAN, 0, textId)
.setEnabled(bluetoothIsEnabled && !isDiscovering)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
menu.add(Menu.NONE, MENU_ID_SHOW_RECEIVED, 0, R.string.bluetooth_show_received_files)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
super.onCreateOptionsMenu(menu, inflater);
@@ -249,14 +196,6 @@ public class BluetoothSettings extends DeviceListPreferenceFragment implements I
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_ID_SCAN:
if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON) {
mMetricsFeatureProvider.action(getActivity(),
MetricsEvent.ACTION_BLUETOOTH_SCAN);
startScanning();
}
return true;
case MENU_ID_SHOW_RECEIVED:
mMetricsFeatureProvider.action(getActivity(),
MetricsEvent.ACTION_BLUETOOTH_FILES);
@@ -268,104 +207,37 @@ public class BluetoothSettings extends DeviceListPreferenceFragment implements I
return super.onOptionsItemSelected(item);
}
private void startScanning() {
if (isUiRestricted()) {
return;
}
if (!mAvailableDevicesCategoryIsPresent) {
getPreferenceScreen().addPreference(mAvailableDevicesCategory);
mAvailableDevicesCategoryIsPresent = true;
}
if (mAvailableDevicesCategory != null) {
setDeviceListGroup(mAvailableDevicesCategory);
removeAllDevices();
}
mLocalManager.getCachedDeviceManager().clearNonBondedDevices();
mAvailableDevicesCategory.removeAll();
mInitialScanStarted = true;
mLocalAdapter.startScanning(true);
}
@Override
void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
mLocalAdapter.stopScanning();
super.onDevicePreferenceClick(btPreference);
}
private void addDeviceCategory(PreferenceGroup preferenceGroup, int titleId,
BluetoothDeviceFilter.Filter filter, boolean addCachedDevices) {
cacheRemoveAllPrefs(preferenceGroup);
preferenceGroup.setTitle(titleId);
setFilter(filter);
setDeviceListGroup(preferenceGroup);
if (addCachedDevices) {
addCachedDevices();
}
preferenceGroup.setEnabled(true);
removeCachedPrefs(preferenceGroup);
public String getDeviceListKey() {
return KEY_PAIRED_DEVICES;
}
private void updateContent(int bluetoothState) {
final PreferenceScreen preferenceScreen = getPreferenceScreen();
int messageId = 0;
switch (bluetoothState) {
case BluetoothAdapter.STATE_ON:
displayEmptyMessage(false);
mDevicePreferenceMap.clear();
if (isUiRestricted()) {
messageId = R.string.bluetooth_empty_list_user_restricted;
break;
}
getPreferenceScreen().removeAll();
getPreferenceScreen().addPreference(mDeviceNamePreference);
getPreferenceScreen().addPreference(mPairedDevicesCategory);
getPreferenceScreen().addPreference(mAvailableDevicesCategory);
getPreferenceScreen().addPreference(mMyDevicePreference);
// Paired devices category
addDeviceCategory(mPairedDevicesCategory,
R.string.bluetooth_preference_paired_devices,
BluetoothDeviceFilter.BONDED_DEVICE_FILTER, true);
mPairedDevicesCategory.addPreference(mPairingPreference);
int numberOfPairedDevices = mPairedDevicesCategory.getPreferenceCount();
updateFooterPreference(mFooterPreference);
if (isUiRestricted() || numberOfPairedDevices <= 0) {
if (preferenceScreen.findPreference(KEY_PAIRED_DEVICES) != null) {
preferenceScreen.removePreference(mPairedDevicesCategory);
}
} else {
if (preferenceScreen.findPreference(KEY_PAIRED_DEVICES) == null) {
preferenceScreen.addPreference(mPairedDevicesCategory);
}
}
// Available devices category
addDeviceCategory(mAvailableDevicesCategory,
R.string.bluetooth_preference_found_devices,
BluetoothDeviceFilter.UNBONDED_DEVICE_FILTER, mInitialScanStarted);
if (!mInitialScanStarted) {
startScanning();
}
updateMyDevicePreference(mMyDevicePreference);
getActivity().invalidateOptionsMenu();
// mLocalAdapter.setScanMode is internally synchronized so it is okay for multiple
// threads to execute.
if (mInitiateDiscoverable) {
// Make the device visible to other devices.
mLocalAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
mInitiateDiscoverable = false;
}
mLocalAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
return; // not break
case BluetoothAdapter.STATE_TURNING_OFF:
messageId = R.string.bluetooth_turning_off;
mLocalAdapter.stopScanning();
break;
case BluetoothAdapter.STATE_OFF:
@@ -377,12 +249,10 @@ public class BluetoothSettings extends DeviceListPreferenceFragment implements I
case BluetoothAdapter.STATE_TURNING_ON:
messageId = R.string.bluetooth_turning_on;
mInitialScanStarted = false;
break;
}
setDeviceListGroup(preferenceScreen);
removeAllDevices();
displayEmptyMessage(true);
if (messageId != 0) {
getEmptyTextView().setText(messageId);
}
@@ -421,18 +291,21 @@ public class BluetoothSettings extends DeviceListPreferenceFragment implements I
}
});
}
getPreferenceScreen().removeAll();
setTextSpan(emptyView.getText(), briefText);
}
@VisibleForTesting
void displayEmptyMessage(boolean display) {
final Activity activity = getActivity();
activity.findViewById(android.R.id.list_container).setVisibility(
display ? View.INVISIBLE : View.VISIBLE);
activity.findViewById(android.R.id.empty).setVisibility(
display ? View.VISIBLE : View.GONE);
}
@Override
public void onBluetoothStateChanged(int bluetoothState) {
super.onBluetoothStateChanged(bluetoothState);
// If BT is turned off/on staying in the same BT Settings screen
// discoverability to be set again
if (BluetoothAdapter.STATE_ON == bluetoothState) {
mInitiateDiscoverable = true;
}
updateContent(bluetoothState);
}
@@ -440,15 +313,14 @@ public class BluetoothSettings extends DeviceListPreferenceFragment implements I
public void onScanningStateChanged(boolean started) {
super.onScanningStateChanged(started);
// Update options' enabled state
if (getActivity() != null) {
getActivity().invalidateOptionsMenu();
final Activity activity = getActivity();
if (activity != null) {
activity.invalidateOptionsMenu();
}
}
@Override
public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
setDeviceListGroup(getPreferenceScreen());
removeAllDevices();
updateContent(mLocalAdapter.getBluetoothState());
}
@@ -457,20 +329,11 @@ public class BluetoothSettings extends DeviceListPreferenceFragment implements I
if (text instanceof Spannable) {
Spannable boldSpan = (Spannable) text;
boldSpan.setSpan(
new TextAppearanceSpan(getActivity(), android.R.style.TextAppearance_Medium), 0,
briefText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
new TextAppearanceSpan(getActivity(), android.R.style.TextAppearance_Medium), 0,
briefText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
@VisibleForTesting
void updateMyDevicePreference(Preference myDevicePreference) {
final BidiFormatter bidiFormatter = BidiFormatter.getInstance();
myDevicePreference.setTitle(getString(
R.string.bluetooth_footer_mac_message,
bidiFormatter.unicodeWrap(mLocalAdapter.getAddress())));
}
@VisibleForTesting
void setLocalBluetoothAdapter(LocalBluetoothAdapter localAdapter) {
mLocalAdapter = localAdapter;
@@ -504,6 +367,7 @@ public class BluetoothSettings extends DeviceListPreferenceFragment implements I
*/
@Override
void initDevicePreference(BluetoothDevicePreference preference) {
preference.setOrder(PAIRED_DEVICE_ORDER);
CachedBluetoothDevice cachedDevice = preference.getCachedDevice();
if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
// Only paired device have an associated advanced settings screen
@@ -531,7 +395,8 @@ public class BluetoothSettings extends DeviceListPreferenceFragment implements I
List<PreferenceController> controllers = new ArrayList<>();
mDeviceNamePrefController = new BluetoothDeviceNamePreferenceController(context,
this, getLifecycle());
mPairingPrefController = new BluetoothPairingPreferenceController(context, this);
mPairingPrefController = new BluetoothPairingPreferenceController(context, this,
(SettingsActivity) getActivity());
controllers.add(mDeviceNamePrefController);
controllers.add(mPairingPrefController);