Merge "Bluetooth: Dismiss pairing dialog on user click" into oc-dev

This commit is contained in:
TreeHugger Robot
2017-04-27 00:32:11 +00:00
committed by Android (Google) Code Review
4 changed files with 118 additions and 18 deletions

View File

@@ -24,16 +24,17 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.annotation.VisibleForTesting;
/**
* BluetoothPairingDialog asks the user to enter a PIN / Passkey / simple confirmation
* for pairing with a remote Bluetooth device. It is an activity that appears as a dialog.
*/
public final class BluetoothPairingDialog extends Activity {
public class BluetoothPairingDialog extends Activity {
public static final String FRAGMENT_TAG = "bluetooth.pairing.fragment";
private BluetoothPairingController mBluetoothPairingController;
private boolean mReceiverRegistered;
private boolean mReceiverRegistered = false;
/**
* Dismiss the dialog if the bond state changes to bonded or none,
@@ -62,23 +63,26 @@ public final class BluetoothPairingDialog extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean fragmentFound = true;
BluetoothPairingDialogFragment bluetoothFragment =
(BluetoothPairingDialogFragment) getFragmentManager()
.findFragmentByTag(FRAGMENT_TAG);
Intent intent = getIntent();
mBluetoothPairingController = new BluetoothPairingController(intent, this);
// check if the fragment exists already
// build the dialog fragment
boolean fragmentFound = true;
// check if the fragment has been preloaded
BluetoothPairingDialogFragment bluetoothFragment =
(BluetoothPairingDialogFragment) getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
// dismiss the fragment if it is already used
if (bluetoothFragment != null && (bluetoothFragment.isPairingControllerSet()
|| bluetoothFragment.isPairingDialogActivitySet())) {
bluetoothFragment.dismiss();
bluetoothFragment = null;
}
// build a new fragment if it is null
if (bluetoothFragment == null) {
fragmentFound = false;
bluetoothFragment = new BluetoothPairingDialogFragment();
}
// set the controller
bluetoothFragment.setPairingController(mBluetoothPairingController);
bluetoothFragment.setPairingDialogActivity(this);
// pass the fragment to the manager when it is created from scratch
if (!fragmentFound) {
bluetoothFragment.show(getFragmentManager(), FRAGMENT_TAG);
@@ -101,8 +105,15 @@ public final class BluetoothPairingDialog extends Activity {
}
}
private void dismiss() {
@VisibleForTesting
void dismiss() {
if (!isFinishing()) {
BluetoothPairingDialogFragment bluetoothFragment =
(BluetoothPairingDialogFragment) getFragmentManager()
.findFragmentByTag(FRAGMENT_TAG);
if (bluetoothFragment != null) {
bluetoothFragment.dismiss();
}
finish();
}
}

View File

@@ -47,6 +47,7 @@ public class BluetoothPairingDialogFragment extends InstrumentedDialogFragment i
private AlertDialog.Builder mBuilder;
private AlertDialog mDialog;
private BluetoothPairingController mPairingController;
private BluetoothPairingDialog mPairingDialogActivity;
private EditText mPairingView;
/**
* The interface we expect a listener to implement. Typically this should be done by
@@ -61,9 +62,13 @@ public class BluetoothPairingDialogFragment extends InstrumentedDialogFragment i
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
if (mPairingController == null) {
if (!isPairingControllerSet()) {
throw new IllegalStateException(
"Must call setPairingController() before showing dialog");
"Must call setPairingController() before showing dialog");
}
if (!isPairingDialogActivitySet()) {
throw new IllegalStateException(
"Must call setPairingDialogActivity() before showing dialog");
}
mBuilder = new AlertDialog.Builder(getActivity());
mDialog = setupDialog();
@@ -97,6 +102,7 @@ public class BluetoothPairingDialogFragment extends InstrumentedDialogFragment i
} else if (which == DialogInterface.BUTTON_NEGATIVE) {
mPairingController.onDialogNegativeClick(this);
}
mPairingDialogActivity.dismiss();
}
@Override
@@ -119,14 +125,41 @@ public class BluetoothPairingDialogFragment extends InstrumentedDialogFragment i
* controller may not be substituted once it is assigned. Forcibly switching a
* controller for a new one will lead to undefined behavior.
*/
public void setPairingController(BluetoothPairingController pairingController) {
if (mPairingController != null) {
void setPairingController(BluetoothPairingController pairingController) {
if (isPairingControllerSet()) {
throw new IllegalStateException("The controller can only be set once. "
+ "Forcibly replacing it will lead to undefined behavior");
}
mPairingController = pairingController;
}
/**
* Checks whether mPairingController is set
* @return True when mPairingController is set, False otherwise
*/
boolean isPairingControllerSet() {
return mPairingController != null;
}
/**
* Sets the BluetoothPairingDialog activity that started this fragment
* @param pairingDialogActivity The pairing dialog activty that started this fragment
*/
void setPairingDialogActivity(BluetoothPairingDialog pairingDialogActivity) {
if (isPairingDialogActivitySet()) {
throw new IllegalStateException("The pairing dialog activity can only be set once");
}
mPairingDialogActivity = pairingDialogActivity;
}
/**
* Checks whether mPairingDialogActivity is set
* @return True when mPairingDialogActivity is set, False otherwise
*/
boolean isPairingDialogActivitySet() {
return mPairingDialogActivity != null;
}
/**
* Creates the appropriate type of dialog and returns it.
*/

View File

@@ -52,7 +52,7 @@ public final class BluetoothPairingRequest extends BroadcastReceiver {
if (powerManager.isInteractive() && shouldShowDialog) {
// Since the screen is on and the BT-related activity is in the foreground,
// just open the dialog
context.startActivity(pairingIntent);
context.startActivityAsUser(pairingIntent, UserHandle.CURRENT);
} else {
// Put up a notification that leads to the dialog
intent.setClass(context, BluetoothPairingService.class);

View File

@@ -54,9 +54,13 @@ public class BluetoothPairingDialogTest {
@Mock
private BluetoothPairingController controller;
@Mock
private BluetoothPairingDialog dialogActivity;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
doNothing().when(dialogActivity).dismiss();
}
@Test
@@ -214,6 +218,17 @@ public class BluetoothPairingDialogTest {
fail("Setting the controller multiple times should throw an exception.");
}
@Test(expected = IllegalStateException.class)
public void dialogDoesNotAllowSwappingActivity() {
// instantiate a fragment
BluetoothPairingDialogFragment frag = new BluetoothPairingDialogFragment();
frag.setPairingDialogActivity(dialogActivity);
// this should throw an error
frag.setPairingDialogActivity(dialogActivity);
fail("Setting the dialog activity multiple times should throw an exception.");
}
@Test
public void dialogPositiveButtonDisabledWhenUserInputInvalid() {
// set the correct dialog type
@@ -342,11 +357,52 @@ public class BluetoothPairingDialogTest {
.contains(device);
}
@Test
public void pairingDialogDismissedOnPositiveClick() {
// set the dialog variant to confirmation/consent
when(controller.getDialogType()).thenReturn(BluetoothPairingController.CONFIRMATION_DIALOG);
// we don't care what this does, just that it is called
doNothing().when(controller).onDialogPositiveClick(any());
// build the fragment
BluetoothPairingDialogFragment frag = makeFragment();
// click the button and verify that the controller hook was called
frag.onClick(frag.getmDialog(), AlertDialog.BUTTON_POSITIVE);
verify(controller, times(1)).onDialogPositiveClick(any());
verify(dialogActivity, times(1)).dismiss();
}
@Test
public void pairingDialogDismissedOnNegativeClick() {
// set the dialog variant to confirmation/consent
when(controller.getDialogType()).thenReturn(BluetoothPairingController.CONFIRMATION_DIALOG);
// we don't care what this does, just that it is called
doNothing().when(controller).onDialogNegativeClick(any());
// build the fragment
BluetoothPairingDialogFragment frag = makeFragment();
// click the button and verify that the controller hook was called
frag.onClick(frag.getmDialog(), AlertDialog.BUTTON_NEGATIVE);
verify(controller, times(1)).onDialogNegativeClick(any());
verify(dialogActivity, times(1)).dismiss();
}
private BluetoothPairingDialogFragment makeFragment() {
BluetoothPairingDialogFragment frag = new BluetoothPairingDialogFragment();
assertThat(frag.isPairingControllerSet()).isFalse();
frag.setPairingController(controller);
assertThat(frag.isPairingDialogActivitySet()).isFalse();
frag.setPairingDialogActivity(dialogActivity);
FragmentTestUtil.startFragment(frag);
assertThat(frag.getmDialog()).isNotNull();
assertThat(frag.isPairingControllerSet()).isTrue();
assertThat(frag.isPairingDialogActivitySet()).isTrue();
return frag;
}
}