Merge "Fix logging spam in DashboardFragment."
diff --git a/src/com/android/settings/ChooseLockGeneric.java b/src/com/android/settings/ChooseLockGeneric.java
index 06858b7..3a1f501 100644
--- a/src/com/android/settings/ChooseLockGeneric.java
+++ b/src/com/android/settings/ChooseLockGeneric.java
@@ -298,7 +298,11 @@
                 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT,
                         mForFingerprint);
                 intent.putExtra(EXTRA_HIDE_DRAWER, mHideDrawer);
-                startActivityForResult(intent, ENABLE_ENCRYPTION_REQUEST);
+                startActivityForResult(
+                        intent,
+                        mIsSetNewPassword && mHasChallenge
+                                ? CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST
+                                : ENABLE_ENCRYPTION_REQUEST);
             } else {
                 if (mForChangeCredRequiredForBoot) {
                     // Welp, couldn't change it. Oh well.
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingController.java b/src/com/android/settings/bluetooth/BluetoothPairingController.java
index 38b30a8..ce82612 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingController.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingController.java
@@ -188,7 +188,7 @@
      *
      * @return - The message ID to show the user.
      */
-    public int getDeviceVariantMessageID() {
+    public int getDeviceVariantMessageId() {
         switch (mType) {
             case BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS:
             case BluetoothDevice.PAIRING_VARIANT_PIN:
@@ -198,7 +198,7 @@
                 return R.string.bluetooth_enter_passkey_other_device;
 
             default:
-                return -1;
+                return INVALID_DIALOG_TYPE;
         }
     }
 
@@ -208,7 +208,7 @@
      *
      * @return - The message ID to show the user.
      */
-    public int getDeviceVariantMessageHint() {
+    public int getDeviceVariantMessageHintId() {
         switch (mType) {
             case BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS:
                 return R.string.bluetooth_pin_values_hint_16_digits;
@@ -218,7 +218,7 @@
                 return R.string.bluetooth_pin_values_hint;
 
             default:
-                return -1;
+                return INVALID_DIALOG_TYPE;
         }
     }
 
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java b/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java
index d4247c0..abeb862 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java
@@ -45,10 +45,9 @@
     private static final String TAG = "BTPairingDialogFragment";
 
     private AlertDialog.Builder mBuilder;
-    private BluetoothPairingController mPairingController;
     private AlertDialog mDialog;
+    private BluetoothPairingController mPairingController;
     private EditText mPairingView;
-
     /**
      * The interface we expect a listener to implement. Typically this should be done by
      * the controller.
@@ -106,11 +105,25 @@
     }
 
     /**
+     * Used in testing to get a reference to the dialog.
+     * @return - The fragments current dialog
+     */
+    protected AlertDialog getmDialog() {
+        return mDialog;
+    }
+
+    /**
      * Sets the controller that the fragment should use. this method MUST be called
      * before you try to show the dialog or an error will be thrown. An implementation
-     * of a pairing controller can be found at {@link BluetoothPairingController}.
+     * of a pairing controller can be found at {@link BluetoothPairingController}. A
+     * 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) {
+            throw new IllegalStateException("The controller can only be set once. "
+                    + "Forcibly replacing it will lead to undefined behavior");
+        }
         mPairingController = pairingController;
     }
 
@@ -146,7 +159,7 @@
         mBuilder.setPositiveButton(getString(android.R.string.ok), this);
         mBuilder.setNegativeButton(getString(android.R.string.cancel), this);
         AlertDialog dialog = mBuilder.create();
-        dialog.getButton(Dialog.BUTTON_POSITIVE).setEnabled(false);
+        dialog.setOnShowListener(d -> mDialog.getButton(Dialog.BUTTON_POSITIVE).setEnabled(false));
         return dialog;
     }
 
@@ -171,6 +184,7 @@
 
         mPairingView = pairingView;
 
+        pairingView.setInputType(InputType.TYPE_CLASS_NUMBER);
         pairingView.addTextChangedListener(this);
         alphanumericPin.setOnCheckedChangeListener((buttonView, isChecked) -> {
             // change input type for soft keyboard to numeric or alphanumeric
@@ -181,15 +195,21 @@
             }
         });
 
-        int messageId = mPairingController.getDeviceVariantMessageID();
-        int messageIdHint = mPairingController.getDeviceVariantMessageHint();
+        int messageId = mPairingController.getDeviceVariantMessageId();
+        int messageIdHint = mPairingController.getDeviceVariantMessageHintId();
         int maxLength = mPairingController.getDeviceMaxPasskeyLength();
         alphanumericPin.setVisibility(mPairingController.pairingCodeIsAlphanumeric()
                 ? View.VISIBLE : View.GONE);
-
-        messageViewCaptionHint.setText(messageIdHint);
-        messageView2.setText(messageId);
-        pairingView.setInputType(InputType.TYPE_CLASS_NUMBER);
+        if (messageId != BluetoothPairingController.INVALID_DIALOG_TYPE) {
+            messageView2.setText(messageId);
+        } else {
+            messageView2.setVisibility(View.GONE);
+        }
+        if (messageIdHint != BluetoothPairingController.INVALID_DIALOG_TYPE) {
+            messageViewCaptionHint.setText(messageIdHint);
+        } else {
+            messageViewCaptionHint.setVisibility(View.GONE);
+        }
         pairingView.setFilters(new InputFilter[]{
                 new LengthFilter(maxLength)});
 
@@ -203,10 +223,8 @@
         mBuilder.setTitle(getString(R.string.bluetooth_pairing_request,
                 mPairingController.getDeviceName()));
         mBuilder.setView(createView());
-        mBuilder.setPositiveButton(getString(R.string.bluetooth_pairing_accept),
-                this);
-        mBuilder.setNegativeButton(getString(R.string.bluetooth_pairing_decline),
-                this);
+        mBuilder.setPositiveButton(getString(R.string.bluetooth_pairing_accept), this);
+        mBuilder.setNegativeButton(getString(R.string.bluetooth_pairing_decline), this);
         AlertDialog dialog = mBuilder.create();
         return dialog;
     }
diff --git a/src/com/android/settings/bluetooth/BluetoothSettings.java b/src/com/android/settings/bluetooth/BluetoothSettings.java
index 3dfcfc7..9b222fa 100644
--- a/src/com/android/settings/bluetooth/BluetoothSettings.java
+++ b/src/com/android/settings/bluetooth/BluetoothSettings.java
@@ -180,13 +180,13 @@
     }
 
     @Override
-    public void onResume() {
-        // resume BluetoothEnabler before calling super.onResume() so we don't get
+    public void onStart() {
+        // resume BluetoothEnabler before calling super.onStart() so we don't get
         // any onDeviceAdded() callbacks before setting up view in updateContent()
         if (mBluetoothEnabler != null) {
             mBluetoothEnabler.resume(getActivity());
         }
-        super.onResume();
+        super.onStart();
 
         mInitiateDiscoverable = true;
 
@@ -206,8 +206,8 @@
     }
 
     @Override
-    public void onPause() {
-        super.onPause();
+    public void onStop() {
+        super.onStop();
         if (mBluetoothEnabler != null) {
             mBluetoothEnabler.pause();
         }
diff --git a/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java b/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
index e6fcbcb..c132163 100644
--- a/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
+++ b/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
@@ -98,8 +98,8 @@
     abstract void addPreferencesForActivity();
 
     @Override
-    public void onResume() {
-        super.onResume();
+    public void onStart() {
+        super.onStart();
         if (mLocalManager == null || isUiRestricted()) return;
 
         mLocalManager.setForegroundActivity(getActivity());
@@ -109,8 +109,8 @@
     }
 
     @Override
-    public void onPause() {
-        super.onPause();
+    public void onStop() {
+        super.onStop();
         if (mLocalManager == null || isUiRestricted()) {
             return;
         }
diff --git a/src/com/android/settings/bluetooth/DevicePickerFragment.java b/src/com/android/settings/bluetooth/DevicePickerFragment.java
index 3fbd7bd..066f5d2 100644
--- a/src/com/android/settings/bluetooth/DevicePickerFragment.java
+++ b/src/com/android/settings/bluetooth/DevicePickerFragment.java
@@ -47,7 +47,7 @@
     private boolean mNeedAuth;
     private String mLaunchPackage;
     private String mLaunchClass;
-    private boolean mStartScanOnResume;
+    private boolean mStartScanOnStart;
 
     @Override
     void addPreferencesForActivity() {
@@ -94,18 +94,18 @@
         super.onCreate(savedInstanceState);
         getActivity().setTitle(getString(R.string.device_picker));
         UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
-        mStartScanOnResume = !um.hasUserRestriction(DISALLOW_CONFIG_BLUETOOTH)
+        mStartScanOnStart = !um.hasUserRestriction(DISALLOW_CONFIG_BLUETOOTH)
                 && (savedInstanceState == null);  // don't start scan after rotation
         setHasOptionsMenu(true);
     }
 
     @Override
-    public void onResume() {
-        super.onResume();
+    public void onStart() {
+        super.onStart();
         addCachedDevices();
-        if (mStartScanOnResume) {
+        if (mStartScanOnStart) {
             mLocalAdapter.startScanning(true);
-            mStartScanOnResume = false;
+            mStartScanOnStart = false;
         }
     }
 
diff --git a/tests/robotests/src/com/android/settings/SettingsRobolectricTestRunner.java b/tests/robotests/src/com/android/settings/SettingsRobolectricTestRunner.java
new file mode 100644
index 0000000..e156716
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/SettingsRobolectricTestRunner.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings;
+
+import org.junit.runners.model.InitializationError;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.manifest.AndroidManifest;
+import org.robolectric.res.Fs;
+import org.robolectric.res.ResourcePath;
+
+import java.util.List;
+
+/**
+ * Custom test runner for the testing of BluetoothPairingDialogs. This is needed because the
+ * default behavior for robolectric is just to grab the resource directory in the target package.
+ * We want to override this to add several spanning different projects.
+ */
+public class SettingsRobolectricTestRunner extends RobolectricTestRunner {
+
+    /**
+     * We don't actually want to change this behavior, so we just call super.
+     */
+    public SettingsRobolectricTestRunner(Class<?> testClass) throws InitializationError {
+        super(testClass);
+    }
+
+    /**
+     * We are going to create our own custom manifest so that we can add multiple resource
+     * paths to it. This lets us access resources in both Settings and SettingsLib in our tests.
+     */
+    @Override
+    protected AndroidManifest getAppManifest(Config config) {
+        // Using the manifest file's relative path, we can figure out the application directory.
+        final String appRoot = "packages/apps/Settings";
+        final String manifestPath = appRoot + "/AndroidManifest.xml";
+        final String resDir = appRoot + "/res";
+        final String assetsDir = appRoot + "/assets";
+
+        // By adding any resources from libraries we need to the AndroidManifest, we can access
+        // them from within the parallel universe's resource loader.
+        final AndroidManifest manifest = new AndroidManifest(Fs.fileFromPath(manifestPath),
+                Fs.fileFromPath(resDir), Fs.fileFromPath(assetsDir)) {
+            @Override
+            public List<ResourcePath> getIncludedResourcePaths() {
+                List<ResourcePath> paths = super.getIncludedResourcePaths();
+                paths.add(new ResourcePath(
+                        getPackageName(),
+                        Fs.fileFromPath("./packages/apps/Settings/res"),
+                        null));
+                paths.add(new ResourcePath(
+                        getPackageName(),
+                        Fs.fileFromPath("./frameworks/base/packages/SettingsLib/res"),
+                        null));
+                return paths;
+            }
+        };
+
+        // Set the package name to the renamed one
+        manifest.setPackageName("com.android.settings");
+        return manifest;
+    }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingDialogTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingDialogTest.java
new file mode 100644
index 0000000..004e4f9
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingDialogTest.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.AlertDialog;
+import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.TextView;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.R;
+import com.android.settings.TestConfig;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.util.FragmentTestUtil;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class BluetoothPairingDialogTest {
+
+    private static final String FILLER = "text that goes in a view";
+    private static final String FAKE_DEVICE_NAME = "Fake Bluetooth Device";
+
+    @Mock
+    private BluetoothPairingController controller;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void dialogUpdatesControllerWithUserInput() {
+        // set the correct dialog type
+        when(controller.getDialogType()).thenReturn(BluetoothPairingController.USER_ENTRY_DIALOG);
+
+        // we don't care about these for this test
+        when(controller.getDeviceVariantMessageId())
+                .thenReturn(BluetoothPairingController.INVALID_DIALOG_TYPE);
+        when(controller.getDeviceVariantMessageHintId())
+                .thenReturn(BluetoothPairingController.INVALID_DIALOG_TYPE);
+
+        // build fragment
+        BluetoothPairingDialogFragment frag = makeFragment();
+
+        // test that controller is updated on text change
+        frag.afterTextChanged(new SpannableStringBuilder(FILLER));
+        verify(controller, times(1)).updateUserInput(any());
+    }
+
+    @Test
+    public void dialogEnablesSubmitButtonOnValidationFromController() {
+        // set the correct dialog type
+        when(controller.getDialogType()).thenReturn(BluetoothPairingController.USER_ENTRY_DIALOG);
+
+        // we don't care about these for this test
+        when(controller.getDeviceVariantMessageId())
+                .thenReturn(BluetoothPairingController.INVALID_DIALOG_TYPE);
+        when(controller.getDeviceVariantMessageHintId())
+                .thenReturn(BluetoothPairingController.INVALID_DIALOG_TYPE);
+
+        // force the controller to say that any passkey is valid
+        when(controller.isPasskeyValid(any())).thenReturn(true);
+
+        // build fragment
+        BluetoothPairingDialogFragment frag = makeFragment();
+
+        // test that the positive button is enabled when passkey is valid
+        frag.afterTextChanged(new SpannableStringBuilder(FILLER));
+        View button = frag.getmDialog().getButton(AlertDialog.BUTTON_POSITIVE);
+        assertThat(button).isNotNull();
+        assertThat(button.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void dialogDoesNotAskForPairCodeOnConsentVariant() {
+        // set the dialog variant to confirmation/consent
+        when(controller.getDialogType()).thenReturn(BluetoothPairingController.CONFIRMATION_DIALOG);
+
+        // build the fragment
+        BluetoothPairingDialogFragment frag = makeFragment();
+
+        // check that the input field used by the entry dialog fragment does not exist
+        View view = frag.getmDialog().findViewById(R.id.text);
+        assertThat(view).isNull();
+    }
+
+    @Test
+    public void dialogAsksForPairCodeOnUserEntryVariant() {
+        // set the dialog variant to user entry
+        when(controller.getDialogType()).thenReturn(BluetoothPairingController.USER_ENTRY_DIALOG);
+
+        // we don't care about these for this test
+        when(controller.getDeviceVariantMessageId())
+                .thenReturn(BluetoothPairingController.INVALID_DIALOG_TYPE);
+        when(controller.getDeviceVariantMessageHintId())
+                .thenReturn(BluetoothPairingController.INVALID_DIALOG_TYPE);
+
+        // build the fragment
+        BluetoothPairingDialogFragment frag = makeFragment();
+
+        // check that the pin/passkey input field is visible to the user
+        View view = frag.getmDialog().findViewById(R.id.text);
+        assertThat(view.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void dialogDisplaysPairCodeOnDisplayPasskeyVariant() {
+        // set the dialog variant to display passkey
+        when(controller.getDialogType())
+                .thenReturn(BluetoothPairingController.DISPLAY_PASSKEY_DIALOG);
+
+        // ensure that the controller returns good values to indicate a passkey needs to be shown
+        when(controller.isDisplayPairingKeyVariant()).thenReturn(true);
+        when(controller.hasPairingContent()).thenReturn(true);
+        when(controller.getPairingContent()).thenReturn(FILLER);
+
+        // build the fragment
+        BluetoothPairingDialogFragment frag = makeFragment();
+
+        // get the relevant views
+        View messagePairing = frag.getmDialog().findViewById(R.id.pairing_code_message);
+        TextView pairingViewContent =
+                (TextView) frag.getmDialog().findViewById(R.id.pairing_subhead);
+        View pairingViewCaption = frag.getmDialog().findViewById(R.id.pairing_caption);
+
+        // check that the relevant views are visible and that the passkey is shown
+        assertThat(messagePairing.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(pairingViewCaption.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(pairingViewContent.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(TextUtils.equals(FILLER, pairingViewContent.getText())).isTrue();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void dialogThrowsExceptionIfNoControllerSet() {
+        // instantiate a fragment
+        BluetoothPairingDialogFragment frag = new BluetoothPairingDialogFragment();
+
+        // this should throw an error
+        FragmentTestUtil.startFragment(frag);
+        fail("Starting the fragment with no controller set should have thrown an exception.");
+    }
+
+    @Test
+    public void dialogCallsHookOnPositiveButtonPress() {
+        // 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());
+    }
+
+    @Test
+    public void dialogCallsHookOnNegativeButtonPress() {
+        // 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());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void dialogDoesNotAllowSwappingController() {
+        // instantiate a fragment
+        BluetoothPairingDialogFragment frag = new BluetoothPairingDialogFragment();
+        frag.setPairingController(controller);
+
+        // this should throw an error
+        frag.setPairingController(controller);
+        fail("Setting the controller multiple times should throw an exception.");
+    }
+
+    @Test
+    public void dialogPositiveButtonDisabledWhenUserInputInvalid() {
+        // set the correct dialog type
+        when(controller.getDialogType()).thenReturn(BluetoothPairingController.USER_ENTRY_DIALOG);
+
+        // we don't care about these for this test
+        when(controller.getDeviceVariantMessageId())
+                .thenReturn(BluetoothPairingController.INVALID_DIALOG_TYPE);
+        when(controller.getDeviceVariantMessageHintId())
+                .thenReturn(BluetoothPairingController.INVALID_DIALOG_TYPE);
+
+        // force the controller to say that any passkey is valid
+        when(controller.isPasskeyValid(any())).thenReturn(false);
+
+        // build fragment
+        BluetoothPairingDialogFragment frag = makeFragment();
+
+        // test that the positive button is enabled when passkey is valid
+        frag.afterTextChanged(new SpannableStringBuilder(FILLER));
+        View button = frag.getmDialog().getButton(AlertDialog.BUTTON_POSITIVE);
+        assertThat(button).isNotNull();
+        assertThat(button.isEnabled()).isFalse();
+    }
+
+    @Test
+    public void dialogShowsContactSharingCheckboxWhenBluetoothProfileNotReady() {
+        // set the dialog variant to confirmation/consent
+        when(controller.getDialogType()).thenReturn(BluetoothPairingController.CONFIRMATION_DIALOG);
+
+        // set a fake device name and pretend the profile has not been set up for it
+        when(controller.getDeviceName()).thenReturn(FAKE_DEVICE_NAME);
+        when(controller.isProfileReady()).thenReturn(false);
+
+        // build the fragment
+        BluetoothPairingDialogFragment frag = makeFragment();
+
+        // verify that the checkbox is visible and that the device name is correct
+        CheckBox sharingCheckbox = (CheckBox) frag.getmDialog()
+                .findViewById(R.id.phonebook_sharing_message_confirm_pin);
+        assertThat(sharingCheckbox.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(sharingCheckbox.getText().toString().contains(FAKE_DEVICE_NAME)).isTrue();
+    }
+
+    @Test
+    public void dialogHidesContactSharingCheckboxWhenBluetoothProfileIsReady() {
+        // set the dialog variant to confirmation/consent
+        when(controller.getDialogType()).thenReturn(BluetoothPairingController.CONFIRMATION_DIALOG);
+
+        // set a fake device name and pretend the profile has been set up for it
+        when(controller.getDeviceName()).thenReturn(FAKE_DEVICE_NAME);
+        when(controller.isProfileReady()).thenReturn(true);
+
+        // build the fragment
+        BluetoothPairingDialogFragment frag = makeFragment();
+
+        // verify that the checkbox is gone
+        CheckBox sharingCheckbox = (CheckBox) frag.getmDialog()
+                .findViewById(R.id.phonebook_sharing_message_confirm_pin);
+        assertThat(sharingCheckbox.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void dialogShowsMessageOnPinEntryView() {
+        // set the correct dialog type
+        when(controller.getDialogType()).thenReturn(BluetoothPairingController.USER_ENTRY_DIALOG);
+
+        // Set the message id to something specific to verify later
+        when(controller.getDeviceVariantMessageId()).thenReturn(R.string.cancel);
+        when(controller.getDeviceVariantMessageHintId())
+                .thenReturn(BluetoothPairingController.INVALID_DIALOG_TYPE);
+
+        // build the fragment
+        BluetoothPairingDialogFragment frag = makeFragment();
+
+        // verify message is what we expect it to be and is visible
+        TextView message = (TextView) frag.getmDialog().findViewById(R.id.message_below_pin);
+        assertThat(message.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(TextUtils.equals(frag.getString(R.string.cancel), message.getText())).isTrue();
+    }
+
+    @Test
+    public void dialogShowsMessageHintOnPinEntryView() {
+        // set the correct dialog type
+        when(controller.getDialogType()).thenReturn(BluetoothPairingController.USER_ENTRY_DIALOG);
+
+        // Set the message id hint to something specific to verify later
+        when(controller.getDeviceVariantMessageHintId()).thenReturn(R.string.cancel);
+        when(controller.getDeviceVariantMessageId())
+                .thenReturn(BluetoothPairingController.INVALID_DIALOG_TYPE);
+
+        // build the fragment
+        BluetoothPairingDialogFragment frag = makeFragment();
+
+        // verify message is what we expect it to be and is visible
+        TextView hint = (TextView) frag.getmDialog().findViewById(R.id.pin_values_hint);
+        assertThat(hint.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(TextUtils.equals(frag.getString(R.string.cancel), hint.getText())).isTrue();
+    }
+
+    @Test
+    public void dialogHidesMessageAndHintWhenNotProvidedOnPinEntryView() {
+        // set the correct dialog type
+        when(controller.getDialogType()).thenReturn(BluetoothPairingController.USER_ENTRY_DIALOG);
+
+        // Set the id's to what is returned when it is not provided
+        when(controller.getDeviceVariantMessageHintId())
+                .thenReturn(BluetoothPairingController.INVALID_DIALOG_TYPE);
+        when(controller.getDeviceVariantMessageId())
+                .thenReturn(BluetoothPairingController.INVALID_DIALOG_TYPE);
+
+        // build the fragment
+        BluetoothPairingDialogFragment frag = makeFragment();
+
+        // verify message is what we expect it to be and is visible
+        TextView hint = (TextView) frag.getmDialog().findViewById(R.id.pin_values_hint);
+        assertThat(hint.getVisibility()).isEqualTo(View.GONE);
+        TextView message = (TextView) frag.getmDialog().findViewById(R.id.message_below_pin);
+        assertThat(message.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    private BluetoothPairingDialogFragment makeFragment() {
+        BluetoothPairingDialogFragment frag = new BluetoothPairingDialogFragment();
+        frag.setPairingController(controller);
+        FragmentTestUtil.startFragment(frag);
+        assertThat(frag.getmDialog()).isNotNull();
+        return frag;
+    }
+}