From: Tony Mak Date: Mon, 12 Dec 2016 02:29:55 +0000 (+0000) Subject: DO NOT MERGE: Fix DPM.ACTION_SET_NEW_PASSWORD X-Git-Tag: android-x86-7.1-r1~46^2 X-Git-Url: http://git.osdn.net/view?p=android-x86%2Fpackages-apps-Settings.git;a=commitdiff_plain;h=8a2f28a6295809d3f25e1a1a78cae9a932767e0b DO NOT MERGE: Fix DPM.ACTION_SET_NEW_PASSWORD This is a cherry-pick of ag/1640561. 1. Context.getActivityToken is not available in n mr2, passed the token from the activity to the controller instead. 2. Haven't pick the tests from master to mr2 branch because robotest is not set up in mr2 branch. Fix: 32959373 Change-Id: I2f73d01ab11e91b337beb90c05bbcb857dfd40dc --- diff --git a/src/com/android/settings/ChooseLockGeneric.java b/src/com/android/settings/ChooseLockGeneric.java index d109eb1a2c..e0590415f4 100644 --- a/src/com/android/settings/ChooseLockGeneric.java +++ b/src/com/android/settings/ChooseLockGeneric.java @@ -186,22 +186,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) && Utils.isManagedProfile(UserManager.get(getActivity()), mUserId) && mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId)) { @@ -256,6 +249,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; @@ -343,6 +338,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 dd62c6fa4b..eec269fca9 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -102,6 +102,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; @@ -651,16 +652,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 = ActivityManagerNative.getDefault(); try { @@ -675,16 +681,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)) { @@ -696,7 +700,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 0000000000..b00f7868e6 --- /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 0000000000..15a9242588 --- /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 7cdf006746..b06da024b5 100644 --- a/src/com/android/settings/password/SetNewPasswordActivity.java +++ b/src/com/android/settings/password/SetNewPasswordActivity.java @@ -16,13 +16,18 @@ 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 @@ -30,6 +35,7 @@ import com.android.settings.ChooseLockGeneric; * 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; @@ -38,17 +44,22 @@ 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(), getActivityToken()); mSetNewPasswordController.dispatchSetNewPasswordIntent(); } @Override - public void launchChooseLock(@Nullable Bundle chooseLockFingerprintExtras) { + public void launchChooseLock(Bundle chooseLockFingerprintExtras) { Intent intent = new Intent(this, ChooseLockGeneric.class) .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 470723b12f..b2b20d9697 100644 --- a/src/com/android/settings/password/SetNewPasswordController.java +++ b/src/com/android/settings/password/SetNewPasswordController.java @@ -16,20 +16,27 @@ 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.IBinder; +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; /** * Business logic for {@link SetNewPasswordActivity}. @@ -42,31 +49,54 @@ 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, + IBinder activityToken) { + // 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(activityToken, + 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 = + (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE); + final IFingerprintManager fingerprintManagerWrapper = + fingerprintManager == null + ? null + : new FingerprintManagerWrapper(fingerprintManager); + return new SetNewPasswordController(userId, context.getPackageManager(), - (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE), - (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); @@ -77,38 +107,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; } }