From 563c4a6557e61451973311e66482c81f877b8c90 Mon Sep 17 00:00:00 2001 From: Antony Sargent Date: Tue, 15 Aug 2017 09:31:31 -0700 Subject: [PATCH] Fix rotation bug in Bluetooth pairing PIN dialog BluetoothPairingDialogFragment has code that makes the OK button on the dialog disabled until the user has entered at least one character into the PIN field. However it didn't properly handle the case where the user had entered some text and then rotated the screen - because it always marked the OK button as disabled during onShow even if it already had some content. This CL fixes that by looking at the text content and only disabling the OK button if the content is empty. Bug: 36514895 Test: make RunSettingsRoboTests Change-Id: I4e8e70089a862e67b20ff614bbaa64fc2b641fd4 --- .../BluetoothPairingDialogFragment.java | 19 +++++++++- .../bluetooth/BluetoothPairingDialogTest.java | 35 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java b/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java index f95ce46d51c..1aac0ff1c18 100644 --- a/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java +++ b/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java @@ -25,6 +25,7 @@ import android.text.Editable; import android.text.InputFilter; import android.text.InputFilter.LengthFilter; import android.text.InputType; +import android.text.TextUtils; import android.text.TextWatcher; import android.util.Log; import android.view.View; @@ -34,6 +35,7 @@ import android.widget.CheckBox; import android.widget.EditText; import android.widget.TextView; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; @@ -185,6 +187,19 @@ public class BluetoothPairingDialogFragment extends InstrumentedDialogFragment i return dialog; } + /** + * Helper method to return the text of the pin entry field - this exists primarily to help us + * simulate having existing text when the dialog is recreated, for example after a screen + * rotation. + */ + @VisibleForTesting + CharSequence getPairingViewText() { + if (mPairingView != null) { + return mPairingView.getText(); + } + return null; + } + /** * Returns a dialog with UI elements that allow a user to provide input. */ @@ -196,7 +211,9 @@ public class BluetoothPairingDialogFragment extends InstrumentedDialogFragment i mBuilder.setNegativeButton(getString(android.R.string.cancel), this); AlertDialog dialog = mBuilder.create(); dialog.setOnShowListener(d -> { - mDialog.getButton(Dialog.BUTTON_POSITIVE).setEnabled(false); + if (TextUtils.isEmpty(getPairingViewText())) { + mDialog.getButton(Dialog.BUTTON_POSITIVE).setEnabled(false); + } if (mPairingView != null && mPairingView.requestFocus()) { InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingDialogTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingDialogTest.java index 7a6ae79e2f9..fba11de8066 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingDialogTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingDialogTest.java @@ -28,6 +28,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.AlertDialog; +import android.app.Dialog; import android.content.Context; import android.text.SpannableStringBuilder; import android.text.TextUtils; @@ -47,6 +48,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowAlertDialog; import org.robolectric.shadows.ShadowApplication; import org.robolectric.util.FragmentTestUtil; @@ -412,6 +414,39 @@ public class BluetoothPairingDialogTest { verify(dialogActivity, times(1)).dismiss(); } + @Test + public void rotateDialog_nullPinText_okButtonEnabled() { + userEntryDialogExistingTextTest(null); + } + + @Test + public void rotateDialog_emptyPinText_okButtonEnabled() { + userEntryDialogExistingTextTest(""); + } + + @Test + public void rotateDialog_nonEmptyPinText_okButtonEnabled() { + userEntryDialogExistingTextTest("test"); + } + + // Runs a test simulating the user entry dialog type in a situation like device rotation, where + // the dialog fragment gets created and we already have some existing text entered into the + // pin field. + private void userEntryDialogExistingTextTest(CharSequence existingText) { + when(controller.getDialogType()).thenReturn(BluetoothPairingController.USER_ENTRY_DIALOG); + when(controller.getDeviceVariantMessageHintId()) + .thenReturn(BluetoothPairingController.INVALID_DIALOG_TYPE); + when(controller.getDeviceVariantMessageId()) + .thenReturn(BluetoothPairingController.INVALID_DIALOG_TYPE); + + BluetoothPairingDialogFragment fragment = spy(new BluetoothPairingDialogFragment()); + when(fragment.getPairingViewText()).thenReturn(existingText); + setupFragment(fragment); + AlertDialog dialog = ShadowAlertDialog.getLatestAlertDialog(); + boolean expected = !TextUtils.isEmpty(existingText); + assertThat(dialog.getButton(Dialog.BUTTON_POSITIVE).isEnabled()).isEqualTo(expected); + } + private void setupFragment(BluetoothPairingDialogFragment frag) { assertThat(frag.isPairingControllerSet()).isFalse(); frag.setPairingController(controller);