Bluetooth: Always scan while on pairing or DevicePicker page

* Modified DeviceListPreferenceFragment to have enable/disable scanning
  methods. In ENABLE state, each onScanningStateChanged(false) will
  restart another round of scanning
* Subclasses of DeviceListPreferenceFragment should call enable/disable
  scanning when scanning is needed for long period of time
* Currently, BluetoothPairingDetail and DevicePickerFragment call
  enableScanning() when Bluetooth is turned ON and call disableScanning
  when some device is picked in their lists
* Both BluetoothPairingDetail and DevicePickerFragment will re-enable
  scanning if pairing failed for selected device
* Added associated unit tests as well

Bug: 32172815
Test: make, pair Bluetooth device, send file over Bluetooth Opp
Change-Id: I99325e06aadd7b00e7a7ba6d6c282a6831859d8b
This commit is contained in:
Jack He
2017-05-30 23:05:46 -07:00
parent fe23da579d
commit c11af01481
5 changed files with 210 additions and 51 deletions

View File

@@ -82,7 +82,7 @@ public class BluetoothPairingDetail extends DeviceListPreferenceFragment impleme
// Make the device only visible to connected devices.
mLocalAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
mLocalAdapter.stopScanning();
disableScanning();
}
@Override
@@ -98,25 +98,29 @@ public class BluetoothPairingDetail extends DeviceListPreferenceFragment impleme
return MetricsEvent.BLUETOOTH;
}
@VisibleForTesting
void startScanning() {
if (mAvailableDevicesCategory != null) {
removeAllDevices();
@Override
void enableScanning() {
// Clear all device states before first scan
if (!mInitialScanStarted) {
if (mAvailableDevicesCategory != null) {
removeAllDevices();
}
mLocalManager.getCachedDeviceManager().clearNonBondedDevices();
mInitialScanStarted = true;
}
mLocalManager.getCachedDeviceManager().clearNonBondedDevices();
mInitialScanStarted = true;
mLocalAdapter.startScanning(true);
super.enableScanning();
}
@Override
void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
mLocalAdapter.stopScanning();
disableScanning();
super.onDevicePreferenceClick(btPreference);
}
@Override
public void onScanningStateChanged(boolean started) {
super.onScanningStateChanged(started);
started |= mScanEnabled;
mAvailableDevicesCategory.setProgress(started);
}
@@ -131,14 +135,10 @@ public class BluetoothPairingDetail extends DeviceListPreferenceFragment impleme
R.string.bluetooth_preference_found_devices,
BluetoothDeviceFilter.UNBONDED_DEVICE_FILTER, mInitialScanStarted);
updateFooterPreference(mFooterPreference);
if (!mInitialScanStarted) {
startScanning();
}
// mLocalAdapter.setScanMode is internally synchronized so it is okay for multiple
// threads to execute.
mLocalAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
enableScanning();
break;
case BluetoothAdapter.STATE_OFF:
@@ -158,6 +158,15 @@ public class BluetoothPairingDetail extends DeviceListPreferenceFragment impleme
if (bondState == BluetoothDevice.BOND_BONDED) {
// If one device is connected(bonded), then close this fragment.
finish();
return;
}
if (mSelectedDevice != null && cachedDevice != null) {
BluetoothDevice device = cachedDevice.getDevice();
if (device != null && mSelectedDevice.equals(device)
&& bondState == BluetoothDevice.BOND_NONE) {
// If currently selected device failed to bond, restart scanning
enableScanning();
}
}
}

View File

@@ -54,6 +54,9 @@ public abstract class DeviceListPreferenceFragment extends
private BluetoothDeviceFilter.Filter mFilter;
@VisibleForTesting
boolean mScanEnabled;
BluetoothDevice mSelectedDevice;
LocalBluetoothAdapter mLocalAdapter;
@@ -216,8 +219,25 @@ public abstract class DeviceListPreferenceFragment extends
}
}
@VisibleForTesting
void enableScanning() {
// LocalBluetoothAdapter already handles repeated scan requests
mLocalAdapter.startScanning(true);
mScanEnabled = true;
}
@VisibleForTesting
void disableScanning() {
mLocalAdapter.stopScanning();
mScanEnabled = false;
}
@Override
public void onScanningStateChanged(boolean started) {}
public void onScanningStateChanged(boolean started) {
if (!started && mScanEnabled) {
mLocalAdapter.startScanning(true);
}
}
@Override
public void onBluetoothStateChanged(int bluetoothState) {}

View File

@@ -25,7 +25,6 @@ import android.os.Bundle;
import android.os.UserManager;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
@@ -41,7 +40,6 @@ import java.util.List;
* connection management.
*/
public final class DevicePickerFragment extends DeviceListPreferenceFragment {
private static final int MENU_ID_REFRESH = Menu.FIRST;
private static final String KEY_BT_DEVICE_LIST = "bt_device_list";
private static final String TAG = "DevicePickerFragment";
@@ -52,7 +50,7 @@ public final class DevicePickerFragment extends DeviceListPreferenceFragment {
private boolean mNeedAuth;
private String mLaunchPackage;
private String mLaunchClass;
private boolean mStartScanOnStart;
private boolean mScanAllowed;
@Override
void initPreferencesFromPreferenceScreen() {
@@ -66,22 +64,9 @@ public final class DevicePickerFragment extends DeviceListPreferenceFragment {
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.add(Menu.NONE, MENU_ID_REFRESH, 0, R.string.bluetooth_search_for_devices)
.setEnabled(true)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_ID_REFRESH:
mLocalAdapter.startScanning(true);
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public int getMetricsCategory() {
return MetricsEvent.BLUETOOTH_DEVICE_PICKER;
@@ -92,8 +77,7 @@ public final class DevicePickerFragment extends DeviceListPreferenceFragment {
super.onCreate(savedInstanceState);
getActivity().setTitle(getString(R.string.device_picker));
UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
mStartScanOnStart = !um.hasUserRestriction(DISALLOW_CONFIG_BLUETOOTH)
&& (savedInstanceState == null); // don't start scan after rotation
mScanAllowed = !um.hasUserRestriction(DISALLOW_CONFIG_BLUETOOTH);
setHasOptionsMenu(true);
}
@@ -102,12 +86,18 @@ public final class DevicePickerFragment extends DeviceListPreferenceFragment {
super.onStart();
addCachedDevices();
mSelectedDevice = null;
if (mStartScanOnStart) {
mLocalAdapter.startScanning(true);
mStartScanOnStart = false;
if (mScanAllowed) {
enableScanning();
}
}
@Override
public void onStop() {
// Try disable scanning no matter what, no effect if enableScanning has not been called
disableScanning();
super.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
@@ -121,7 +111,7 @@ public final class DevicePickerFragment extends DeviceListPreferenceFragment {
@Override
void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
mLocalAdapter.stopScanning();
disableScanning();
LocalBluetoothPreferences.persistSelectedDeviceInPicker(
getActivity(), mSelectedDevice.getAddress());
if ((btPreference.getCachedDevice().getBondState() ==
@@ -135,12 +125,15 @@ public final class DevicePickerFragment extends DeviceListPreferenceFragment {
public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice,
int bondState) {
BluetoothDevice device = cachedDevice.getDevice();
if (!device.equals(mSelectedDevice)) {
return;
}
if (bondState == BluetoothDevice.BOND_BONDED) {
BluetoothDevice device = cachedDevice.getDevice();
if (device.equals(mSelectedDevice)) {
sendDevicePickedIntent(device);
finish();
}
sendDevicePickedIntent(device);
finish();
} else if (bondState == BluetoothDevice.BOND_NONE) {
enableScanning();
}
}
@@ -149,7 +142,7 @@ public final class DevicePickerFragment extends DeviceListPreferenceFragment {
super.onBluetoothStateChanged(bluetoothState);
if (bluetoothState == BluetoothAdapter.STATE_ON) {
mLocalAdapter.startScanning(false);
enableScanning();
}
}