OSDN Git Service

DO NOT MERGE: Fix DPM.ACTION_SET_NEW_PASSWORD
authorTony Mak <tonymak@google.com>
Mon, 12 Dec 2016 02:29:55 +0000 (02:29 +0000)
committerTony Mak <tonymak@google.com>
Mon, 12 Dec 2016 02:35:42 +0000 (02:35 +0000)
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

src/com/android/settings/ChooseLockGeneric.java
src/com/android/settings/Utils.java
src/com/android/settings/password/FingerprintManagerWrapper.java [new file with mode: 0644]
src/com/android/settings/password/IFingerprintManager.java [new file with mode: 0644]
src/com/android/settings/password/SetNewPasswordActivity.java
src/com/android/settings/password/SetNewPasswordController.java

index d109eb1..e059041 100644 (file)
@@ -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) {
index dd62c6f..eec269f 100644 (file)
@@ -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.
-     *
+     * <p>
+     * User would be retrieved in this order:
+     * <ul>
+     * <li> If this activity is launched from other user, return that user id.
+     * <li> If this is launched from the Settings app in same user, return the user contained as an
+     *      extra in the arguments or intent extras.
+     * <li> Otherwise, return UserHandle.myUserId().
+     * </ul>
+     * <p>
      * 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 (file)
index 0000000..b00f786
--- /dev/null
@@ -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 (file)
index 0000000..15a9242
--- /dev/null
@@ -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();
+}
index 7cdf006..b06da02 100644 (file)
 
 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();
     }
index 470723b..b2b20d9 100644 (file)
 
 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;
     }
 }