diff --git a/src/com/android/settings/ChooseLockGeneric.java b/src/com/android/settings/ChooseLockGeneric.java index a01ecf794d6..845f8cb0702 100644 --- a/src/com/android/settings/ChooseLockGeneric.java +++ b/src/com/android/settings/ChooseLockGeneric.java @@ -185,22 +185,15 @@ public class ChooseLockGeneric extends SettingsActivity { ENCRYPT_REQUESTED_DISABLED); } - int targetUser = Utils.getSecureTargetUser( + // a) If this is started from other user, use that user id. + // b) If this is started from the same user, read the extra if this is launched + // from Settings app itself. + // c) Otherwise, use UserHandle.myUserId(). + mUserId = Utils.getSecureTargetUser( getActivity().getActivityToken(), UserManager.get(getActivity()), - null, + getArguments(), getActivity().getIntent().getExtras()).getIdentifier(); - if (ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(chooseLockAction) - || !mLockPatternUtils.isSeparateProfileChallengeAllowed(targetUser)) { - // Always use parent if explicitely requested or if profile challenge is not - // supported - Bundle arguments = getArguments(); - mUserId = Utils.getUserIdFromBundle(getContext(), arguments != null ? arguments - : getActivity().getIntent().getExtras()); - } else { - mUserId = targetUser; - } - if (ACTION_SET_NEW_PASSWORD.equals(chooseLockAction) && UserManager.get(getActivity()).isManagedProfile(mUserId) && mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId)) { @@ -255,6 +248,8 @@ public class ChooseLockGeneric extends SettingsActivity { } else if (KEY_SKIP_FINGERPRINT.equals(key)) { Intent chooseLockGenericIntent = new Intent(getActivity(), ChooseLockGeneric.class); chooseLockGenericIntent.setAction(getIntent().getAction()); + // Forward the target user id to ChooseLockGeneric. + chooseLockGenericIntent.putExtra(Intent.EXTRA_USER_ID, mUserId); chooseLockGenericIntent.putExtra(PASSWORD_CONFIRMED, mPasswordConfirmed); startActivityForResult(chooseLockGenericIntent, SKIP_FINGERPRINT_REQUEST); return true; @@ -342,6 +337,8 @@ public class ChooseLockGeneric extends SettingsActivity { if (data != null) { intent.putExtras(data.getExtras()); } + // Forward the target user id to fingerprint setup page. + intent.putExtra(Intent.EXTRA_USER_ID, mUserId); startActivity(intent); finish(); } else if (requestCode == SKIP_FINGERPRINT_REQUEST) { diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 835757c5e01..80dcd74bad6 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -104,6 +104,7 @@ import java.util.List; import java.util.Locale; import static android.content.Intent.EXTRA_USER; +import static android.content.Intent.EXTRA_USER_ID; import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH; import static android.text.format.DateUtils.FORMAT_SHOW_DATE; @@ -636,16 +637,21 @@ public final class Utils extends com.android.settingslib.Utils { /** * Returns the target user for a Settings activity. - * - * The target user can be either the current user, the user that launched this activity or - * the user contained as an extra in the arguments or intent extras. - * + *

+ * User would be retrieved in this order: + *

+ *

* Note: This is secure in the sense that it only returns a target user different to the current * one if the app launching this activity is the Settings app itself, running in the same user * or in one that is in the same profile group, or if the user id is provided by the system. */ public static UserHandle getSecureTargetUser(IBinder activityToken, - UserManager um, @Nullable Bundle arguments, @Nullable Bundle intentExtras) { + UserManager um, @Nullable Bundle arguments, @Nullable Bundle intentExtras) { UserHandle currentUser = new UserHandle(UserHandle.myUserId()); IActivityManager am = ActivityManager.getService(); try { @@ -660,16 +666,14 @@ public final class Utils extends com.android.settingslib.Utils { return launchedFromUser; } } - UserHandle extrasUser = intentExtras != null - ? (UserHandle) intentExtras.getParcelable(EXTRA_USER) : null; + UserHandle extrasUser = getUserHandleFromBundle(intentExtras); if (extrasUser != null && !extrasUser.equals(currentUser)) { // Check it's secure if (launchedFromSettingsApp && isProfileOf(um, extrasUser)) { return extrasUser; } } - UserHandle argumentsUser = arguments != null - ? (UserHandle) arguments.getParcelable(EXTRA_USER) : null; + UserHandle argumentsUser = getUserHandleFromBundle(arguments); if (argumentsUser != null && !argumentsUser.equals(currentUser)) { // Check it's secure if (launchedFromSettingsApp && isProfileOf(um, argumentsUser)) { @@ -681,7 +685,26 @@ public final class Utils extends com.android.settingslib.Utils { Log.v(TAG, "Could not talk to activity manager.", e); } return currentUser; - } + } + + /** + * Lookup both {@link Intent#EXTRA_USER} and {@link Intent#EXTRA_USER_ID} in the bundle + * and return the {@link UserHandle} object. Return {@code null} if nothing is found. + */ + private static @Nullable UserHandle getUserHandleFromBundle(Bundle bundle) { + if (bundle == null) { + return null; + } + final UserHandle user = bundle.getParcelable(EXTRA_USER); + if (user != null) { + return user; + } + final int userId = bundle.getInt(EXTRA_USER_ID, -1); + if (userId != -1) { + return UserHandle.of(userId); + } + return null; + } /** * Returns the target user for a Settings activity. diff --git a/src/com/android/settings/password/FingerprintManagerWrapper.java b/src/com/android/settings/password/FingerprintManagerWrapper.java new file mode 100644 index 00000000000..b00f7868e61 --- /dev/null +++ b/src/com/android/settings/password/FingerprintManagerWrapper.java @@ -0,0 +1,47 @@ +/* + * 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.password; + +import android.annotation.NonNull; +import android.hardware.fingerprint.FingerprintManager; + +import com.android.internal.util.Preconditions; + +/** + * Wrapper of {@link FingerprintManager}. Workaround for roboelectic testing. See + * {@link IFingerprintManager} for details. + */ +public class FingerprintManagerWrapper implements IFingerprintManager { + private @NonNull FingerprintManager mFingerprintManager; + + public FingerprintManagerWrapper(@NonNull FingerprintManager fingerprintManager) { + Preconditions.checkNotNull(fingerprintManager); + mFingerprintManager = fingerprintManager; + } + + public boolean isHardwareDetected() { + return mFingerprintManager.isHardwareDetected(); + } + + public boolean hasEnrolledFingerprints(int userId) { + return mFingerprintManager.hasEnrolledFingerprints(userId); + } + + public long preEnroll() { + return mFingerprintManager.preEnroll(); + } +} diff --git a/src/com/android/settings/password/IFingerprintManager.java b/src/com/android/settings/password/IFingerprintManager.java new file mode 100644 index 00000000000..15a92425888 --- /dev/null +++ b/src/com/android/settings/password/IFingerprintManager.java @@ -0,0 +1,31 @@ +/* + * 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.password; + +/** + * This is the workaround to allow us test {@link SetNewPasswordController} which uses a new hidden + * API {@link android.hardware.fingerprint.FingerprintManager#hasEnrolledFingerprints(int)} that + * roboelectric does not support yet. Having roboelectic to support latest platform API is tracked + * in b/30995831. + */ +public interface IFingerprintManager { + boolean isHardwareDetected(); + + boolean hasEnrolledFingerprints(int userId); + + long preEnroll(); +} diff --git a/src/com/android/settings/password/SetNewPasswordActivity.java b/src/com/android/settings/password/SetNewPasswordActivity.java index 6ca90a4d21d..585f4f473e5 100644 --- a/src/com/android/settings/password/SetNewPasswordActivity.java +++ b/src/com/android/settings/password/SetNewPasswordActivity.java @@ -16,23 +16,26 @@ package com.android.settings.password; -import android.annotation.Nullable; +import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD; +import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD; + import android.app.Activity; import android.app.admin.DevicePolicyManager; import android.content.Intent; import android.os.Bundle; +import android.util.Log; import com.android.settings.ChooseLockGeneric; import com.android.settings.SetupChooseLockGeneric; import com.android.settings.Utils; - /** * Trampolines {@link DevicePolicyManager#ACTION_SET_NEW_PASSWORD} and * {@link DevicePolicyManager#ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} intent to the appropriate UI * activity for handling set new password. */ public class SetNewPasswordActivity extends Activity implements SetNewPasswordController.Ui { + private static final String TAG = "SetNewPasswordActivity"; private String mNewPasswordAction; private SetNewPasswordController mSetNewPasswordController; @@ -41,19 +44,23 @@ public class SetNewPasswordActivity extends Activity implements SetNewPasswordCo super.onCreate(savedState); mNewPasswordAction = getIntent().getAction(); - mSetNewPasswordController = new SetNewPasswordController(this, this); + if (!ACTION_SET_NEW_PASSWORD.equals(mNewPasswordAction) + && !ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(mNewPasswordAction)) { + Log.e(TAG, "Unexpected action to launch this activity"); + finish(); + return; + } + mSetNewPasswordController = SetNewPasswordController.create(this, this, getIntent()); mSetNewPasswordController.dispatchSetNewPasswordIntent(); } @Override - public void launchChooseLock(@Nullable Bundle chooseLockFingerprintExtras) { + public void launchChooseLock(Bundle chooseLockFingerprintExtras) { final boolean isInSetupWizard = !Utils.isDeviceProvisioned(this); Intent intent = isInSetupWizard ? new Intent(this, SetupChooseLockGeneric.class) : new Intent(this, ChooseLockGeneric.class); intent.setAction(mNewPasswordAction); - if (chooseLockFingerprintExtras != null) { - intent.putExtras(chooseLockFingerprintExtras); - } + intent.putExtras(chooseLockFingerprintExtras); startActivity(intent); finish(); } diff --git a/src/com/android/settings/password/SetNewPasswordController.java b/src/com/android/settings/password/SetNewPasswordController.java index 03afa762ee9..00cf33e6cb8 100644 --- a/src/com/android/settings/password/SetNewPasswordController.java +++ b/src/com/android/settings/password/SetNewPasswordController.java @@ -16,18 +16,23 @@ package com.android.settings.password; +import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD; +import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT; +import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.Nullable; +import android.app.ActivityManager; import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.hardware.fingerprint.FingerprintManager; import android.os.Bundle; -import android.os.UserHandle; +import android.os.UserManager; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.widget.LockPatternUtils; import com.android.settings.ChooseLockGeneric; import com.android.settings.ChooseLockSettingsHelper; import com.android.settings.Utils; @@ -43,31 +48,52 @@ final class SetNewPasswordController { interface Ui { /** Starts the {@link ChooseLockGeneric} activity with the given extras. */ - void launchChooseLock(@Nullable Bundle chooseLockFingerprintExtras); + void launchChooseLock(Bundle chooseLockFingerprintExtras); } - private final int mCurrentUserId; + /** + * Which user is setting new password. + */ + private final int mTargetUserId; private final PackageManager mPackageManager; - @Nullable private final FingerprintManager mFingerprintManager; + @Nullable private final IFingerprintManager mFingerprintManager; private final DevicePolicyManager mDevicePolicyManager; private final Ui mUi; - public SetNewPasswordController(Context context, Ui ui) { - this(context.getUserId(), + public static SetNewPasswordController create(Context context, Ui ui, Intent intent) { + // Trying to figure out which user is setting new password. If it is + // ACTION_SET_NEW_PARENT_PROFILE_PASSWORD or the calling user is not allowed to set + // separate profile challenge, it is the current user to set new password. Otherwise, + // it is the user who starts this activity setting new password. + int userId = ActivityManager.getCurrentUser(); + if (ACTION_SET_NEW_PASSWORD.equals(intent.getAction())) { + final int callingUserId = Utils.getSecureTargetUser(context.getActivityToken(), + UserManager.get(context), null, intent.getExtras()).getIdentifier(); + final LockPatternUtils lockPatternUtils = new LockPatternUtils(context); + if (lockPatternUtils.isSeparateProfileChallengeAllowed(callingUserId)) { + userId = callingUserId; + } + } + // Create a wrapper of FingerprintManager for testing, see IFingerPrintManager for details. + final FingerprintManager fingerprintManager = Utils.getFingerprintManagerOrNull(context); + final IFingerprintManager fingerprintManagerWrapper = + fingerprintManager == null + ? null + : new FingerprintManagerWrapper(fingerprintManager); + return new SetNewPasswordController(userId, context.getPackageManager(), - Utils.getFingerprintManagerOrNull(context), - (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE), - ui); + fingerprintManagerWrapper, + (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE), ui); } @VisibleForTesting SetNewPasswordController( - int currentUserId, + int targetUserId, PackageManager packageManager, - FingerprintManager fingerprintManager, + IFingerprintManager fingerprintManager, DevicePolicyManager devicePolicyManager, Ui ui) { - mCurrentUserId = currentUserId; + mTargetUserId = targetUserId; mPackageManager = checkNotNull(packageManager); mFingerprintManager = fingerprintManager; mDevicePolicyManager = checkNotNull(devicePolicyManager); @@ -78,38 +104,38 @@ final class SetNewPasswordController { * Dispatches the set new password intent to the correct activity that handles it. */ public void dispatchSetNewPasswordIntent() { + final Bundle extras; if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT) && mFingerprintManager != null && mFingerprintManager.isHardwareDetected() - && !mFingerprintManager.hasEnrolledFingerprints() + && !mFingerprintManager.hasEnrolledFingerprints(mTargetUserId) && !isFingerprintDisabledByAdmin()) { - mUi.launchChooseLock(getFingerprintChooseLockExtras()); + extras = getFingerprintChooseLockExtras(); } else { - mUi.launchChooseLock(null); + extras = new Bundle(); } + // No matter we show fingerprint options or not, we should tell the next activity which + // user is setting new password. + extras.putInt(Intent.EXTRA_USER_ID, mTargetUserId); + mUi.launchChooseLock(extras); } private Bundle getFingerprintChooseLockExtras() { Bundle chooseLockExtras = new Bundle(); - if (mFingerprintManager != null) { - long challenge = mFingerprintManager.preEnroll(); - chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, - DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); - chooseLockExtras.putBoolean( - ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true); - chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true); - chooseLockExtras.putLong(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge); - chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, true); - if (mCurrentUserId != UserHandle.USER_NULL) { - chooseLockExtras.putInt(Intent.EXTRA_USER_ID, mCurrentUserId); - } - } + long challenge = mFingerprintManager.preEnroll(); + chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, + PASSWORD_QUALITY_SOMETHING); + chooseLockExtras.putBoolean( + ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true); + chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true); + chooseLockExtras.putLong(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge); + chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, true); return chooseLockExtras; } private boolean isFingerprintDisabledByAdmin() { - int disabledFeatures = mDevicePolicyManager.getKeyguardDisabledFeatures( - null, mCurrentUserId); - return (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT) != 0; + int disabledFeatures = + mDevicePolicyManager.getKeyguardDisabledFeatures(null, mTargetUserId); + return (disabledFeatures & KEYGUARD_DISABLE_FINGERPRINT) != 0; } } diff --git a/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java b/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java index 4c110087777..573f5d86951 100644 --- a/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java +++ b/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java @@ -18,6 +18,7 @@ package com.android.settings.password; import android.content.ComponentName; import android.content.Intent; +import android.os.Bundle; import android.provider.Settings; import com.android.settings.ChooseLockGeneric; @@ -59,7 +60,9 @@ public class SetNewPasswordActivityTest { public void testChooseLockGeneric() { Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 1); - SetNewPasswordActivity activity = Robolectric.setupActivity(SetNewPasswordActivity.class); + SetNewPasswordActivity activity = + Robolectric.buildActivity(SetNewPasswordActivity.class).get(); + activity.launchChooseLock(new Bundle()); ShadowActivity shadowActivity = shadowOf(activity); Intent intent = shadowActivity.getNextStartedActivityForResult().intent; @@ -71,7 +74,9 @@ public class SetNewPasswordActivityTest { public void testSetupChooseLockGeneric() { Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0); - SetNewPasswordActivity activity = Robolectric.setupActivity(SetNewPasswordActivity.class); + SetNewPasswordActivity activity = + Robolectric.buildActivity(SetNewPasswordActivity.class).get(); + activity.launchChooseLock(new Bundle()); ShadowActivity shadowActivity = shadowOf(activity); Intent intent = shadowActivity.getNextStartedActivityForResult().intent; diff --git a/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java b/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java index 2921b301ea2..ab01360910e 100644 --- a/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java +++ b/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java @@ -20,10 +20,11 @@ import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Intent; import android.content.pm.PackageManager; -import android.hardware.fingerprint.FingerprintManager; import android.os.Bundle; + import com.android.settings.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -38,6 +39,7 @@ import static com.android.settings.ChooseLockGeneric.ChooseLockGenericFragment.M import static com.android.settings.ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE; import static com.android.settings.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT; import static com.android.settings.ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE; +import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; @@ -45,17 +47,18 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; + /** * Tests for {@link SetNewPasswordController}. */ @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public final class SetNewPasswordControllerTest { - private static final int CURRENT_UID = 101; + private static final int CURRENT_USER_ID = 101; private static final long FINGERPRINT_CHALLENGE = -9876512313131L; @Mock PackageManager mPackageManager; - @Mock FingerprintManager mFingerprintManager; + @Mock IFingerprintManager mFingerprintManager; @Mock DevicePolicyManager mDevicePolicyManager; @Mock private SetNewPasswordController.Ui mUi; @@ -64,9 +67,8 @@ public final class SetNewPasswordControllerTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mSetNewPasswordController = new SetNewPasswordController( - CURRENT_UID, mPackageManager, mFingerprintManager, mDevicePolicyManager, mUi); + CURRENT_USER_ID, mPackageManager, mFingerprintManager, mDevicePolicyManager, mUi); when(mFingerprintManager.preEnroll()).thenReturn(FINGERPRINT_CHALLENGE); when(mPackageManager.hasSystemFeature(eq(FEATURE_FINGERPRINT))).thenReturn(true); @@ -77,7 +79,7 @@ public final class SetNewPasswordControllerTest { // GIVEN the device supports fingerprint. when(mFingerprintManager.isHardwareDetected()).thenReturn(true); // GIVEN there are no enrolled fingerprints. - when(mFingerprintManager.hasEnrolledFingerprints()).thenReturn(false); + when(mFingerprintManager.hasEnrolledFingerprints(CURRENT_USER_ID)).thenReturn(false); // GIVEN DPC does not disallow fingerprint for keyguard usage. when(mDevicePolicyManager.getKeyguardDisabledFeatures(any(ComponentName.class))) .thenReturn(0); @@ -101,7 +103,9 @@ public final class SetNewPasswordControllerTest { mSetNewPasswordController.dispatchSetNewPasswordIntent(); // THEN the choose lock activity is launched without fingerprint extras. - verify(mUi).launchChooseLock(null); + ArgumentCaptor bundleArgumentCaptor = ArgumentCaptor.forClass(Bundle.class); + verify(mUi).launchChooseLock(bundleArgumentCaptor.capture()); + assertBundleContainsUserIdOnly(bundleArgumentCaptor.getValue()); } @Test @@ -109,7 +113,7 @@ public final class SetNewPasswordControllerTest { // GIVEN the device does NOT support fingerprint. when(mFingerprintManager.isHardwareDetected()).thenReturn(false); // GIVEN there are no enrolled fingerprints. - when(mFingerprintManager.hasEnrolledFingerprints()).thenReturn(false); + when(mFingerprintManager.hasEnrolledFingerprints(CURRENT_USER_ID)).thenReturn(false); // GIVEN DPC does not disallow fingerprint for keyguard usage. when(mDevicePolicyManager.getKeyguardDisabledFeatures(any(ComponentName.class))) .thenReturn(0); @@ -117,8 +121,10 @@ public final class SetNewPasswordControllerTest { // WHEN the controller dispatches a set new password intent. mSetNewPasswordController.dispatchSetNewPasswordIntent(); - // THEN the choose lock activity is launched without fingerprint extras. - verify(mUi).launchChooseLock(null); + // THEN the choose lock activity is launched without a bundle contains user id only. + ArgumentCaptor bundleArgumentCaptor = ArgumentCaptor.forClass(Bundle.class); + verify(mUi).launchChooseLock(bundleArgumentCaptor.capture()); + assertBundleContainsUserIdOnly(bundleArgumentCaptor.getValue()); } @Test @@ -126,7 +132,7 @@ public final class SetNewPasswordControllerTest { // GIVEN the device supports fingerprint. when(mFingerprintManager.isHardwareDetected()).thenReturn(true); // GIVEN there are no enrolled fingerprints. - when(mFingerprintManager.hasEnrolledFingerprints()).thenReturn(true); + when(mFingerprintManager.hasEnrolledFingerprints(CURRENT_USER_ID)).thenReturn(true); // GIVEN DPC does not disallow fingerprint for keyguard usage. when(mDevicePolicyManager.getKeyguardDisabledFeatures(any(ComponentName.class))) .thenReturn(0); @@ -134,8 +140,10 @@ public final class SetNewPasswordControllerTest { // WHEN the controller dispatches a set new password intent. mSetNewPasswordController.dispatchSetNewPasswordIntent(); - // THEN the choose lock activity is launched without fingerprint extras. - verify(mUi).launchChooseLock(null); + // THEN the choose lock activity is launched without a bundle contains user id only. + ArgumentCaptor bundleArgumentCaptor = ArgumentCaptor.forClass(Bundle.class); + verify(mUi).launchChooseLock(bundleArgumentCaptor.capture()); + assertBundleContainsUserIdOnly(bundleArgumentCaptor.getValue()); } @Test @@ -143,7 +151,7 @@ public final class SetNewPasswordControllerTest { // GIVEN the device supports fingerprint. when(mFingerprintManager.isHardwareDetected()).thenReturn(true); // GIVEN there is an enrolled fingerprint. - when(mFingerprintManager.hasEnrolledFingerprints()).thenReturn(true); + when(mFingerprintManager.hasEnrolledFingerprints(CURRENT_USER_ID)).thenReturn(true); // GIVEN DPC disallows fingerprint for keyguard usage. when(mDevicePolicyManager.getKeyguardDisabledFeatures(any(ComponentName.class))) .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT); @@ -151,8 +159,10 @@ public final class SetNewPasswordControllerTest { // WHEN the controller dispatches a set new password intent. mSetNewPasswordController.dispatchSetNewPasswordIntent(); - // THEN the choose lock activity is launched without fingerprint extras. - verify(mUi).launchChooseLock(null); + // THEN the choose lock activity is launched without a bundle contains user id only. + ArgumentCaptor bundleArgumentCaptor = ArgumentCaptor.forClass(Bundle.class); + verify(mUi).launchChooseLock(bundleArgumentCaptor.capture()); + assertBundleContainsUserIdOnly(bundleArgumentCaptor.getValue()); } private void compareFingerprintExtras(Bundle actualBundle) { @@ -175,7 +185,12 @@ public final class SetNewPasswordControllerTest { actualBundle.getBoolean(EXTRA_KEY_FOR_FINGERPRINT)); assertEquals( "User id must be equaled to the input one.", - CURRENT_UID, + CURRENT_USER_ID, actualBundle.getInt(Intent.EXTRA_USER_ID)); } + + private void assertBundleContainsUserIdOnly(Bundle actualBundle) { + assertThat(actualBundle.size()).isEqualTo(1); + assertThat(actualBundle.getInt(Intent.EXTRA_USER_ID)).isEqualTo(CURRENT_USER_ID); + } }