Merge "Unlock all users before moving or migrating."

This commit is contained in:
Jeff Sharkey
2018-01-04 22:25:01 +00:00
committed by Android (Google) Code Review
7 changed files with 169 additions and 26 deletions

View File

@@ -3064,6 +3064,9 @@
\n\nDon\u2019t remove the <xliff:g id="name" example="SD card">^2</xliff:g> during the move. \n\nDon\u2019t remove the <xliff:g id="name" example="SD card">^2</xliff:g> during the move.
</string> </string>
<!-- Body of lock screen challenge message explaining that the given user must be unlocked before data can be moved [CHAR LIMIT=64] -->
<string name="storage_wizard_move_unlock">To move data you need to unlock user <xliff:g id="app" example="Joey">^1</xliff:g>.</string>
<!-- Title of wizard step showing app move progress [CHAR LIMIT=32] --> <!-- Title of wizard step showing app move progress [CHAR LIMIT=32] -->
<string name="storage_wizard_move_progress_title">Moving <xliff:g id="app" example="Calculator">^1</xliff:g>\u2026</string> <string name="storage_wizard_move_progress_title">Moving <xliff:g id="app" example="Calculator">^1</xliff:g>\u2026</string>
<!-- Body of wizard step showing app move progress [CHAR LIMIT=NONE] --> <!-- Body of wizard step showing app move progress [CHAR LIMIT=NONE] -->

View File

@@ -106,6 +106,7 @@ import android.widget.TabWidget;
import com.android.internal.app.UnlaunchableAppActivity; import com.android.internal.app.UnlaunchableAppActivity;
import com.android.internal.util.ArrayUtils; import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternUtils;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settings.wrapper.DevicePolicyManagerWrapper; import com.android.settings.wrapper.DevicePolicyManagerWrapper;
import com.android.settings.wrapper.FingerprintManagerWrapper; import com.android.settings.wrapper.FingerprintManagerWrapper;
@@ -995,20 +996,37 @@ public final class Utils extends com.android.settingslib.Utils {
} }
/** /**
* Returns the user id present in the bundle with {@link Intent#EXTRA_USER_ID} if it * Returns the user id present in the bundle with
* belongs to the current user. * {@link Intent#EXTRA_USER_ID} if it belongs to the current user.
* *
* @throws SecurityException if the given userId does not belong to the current user group. * @throws SecurityException if the given userId does not belong to the
* current user group.
*/ */
public static int getUserIdFromBundle(Context context, Bundle bundle) { public static int getUserIdFromBundle(Context context, Bundle bundle) {
return getUserIdFromBundle(context, bundle, false);
}
/**
* Returns the user id present in the bundle with
* {@link Intent#EXTRA_USER_ID} if it belongs to the current user.
*
* @param isInternal indicating if the caller is "internal" to the system,
* meaning we're willing to trust extras like
* {@link ChooseLockSettingsHelper#EXTRA_ALLOW_ANY_USER}.
* @throws SecurityException if the given userId does not belong to the
* current user group.
*/
public static int getUserIdFromBundle(Context context, Bundle bundle, boolean isInternal) {
if (bundle == null) { if (bundle == null) {
return getCredentialOwnerUserId(context); return getCredentialOwnerUserId(context);
} }
final boolean allowAnyUser = isInternal
&& bundle.getBoolean(ChooseLockSettingsHelper.EXTRA_ALLOW_ANY_USER, false);
int userId = bundle.getInt(Intent.EXTRA_USER_ID, UserHandle.myUserId()); int userId = bundle.getInt(Intent.EXTRA_USER_ID, UserHandle.myUserId());
if (userId == LockPatternUtils.USER_FRP) { if (userId == LockPatternUtils.USER_FRP) {
return enforceSystemUser(context, userId); return allowAnyUser ? userId : enforceSystemUser(context, userId);
} else { } else {
return enforceSameOwner(context, userId); return allowAnyUser ? userId : enforceSameOwner(context, userId);
} }
} }

View File

@@ -16,22 +16,28 @@
package com.android.settings.deviceinfo; package com.android.settings.deviceinfo;
import static com.android.settings.deviceinfo.StorageSettings.TAG;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.os.Bundle; import android.os.Bundle;
import android.os.UserManager;
import android.os.storage.DiskInfo; import android.os.storage.DiskInfo;
import android.os.storage.StorageManager; import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo; import android.os.storage.VolumeInfo;
import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.password.ChooseLockSettingsHelper;
import java.util.Objects; import java.util.Objects;
import static com.android.settings.deviceinfo.StorageSettings.TAG;
public class StorageWizardMigrateConfirm extends StorageWizardBase { public class StorageWizardMigrateConfirm extends StorageWizardBase {
private static final int REQUEST_CREDENTIAL = 100;
private MigrateEstimateTask mEstimate; private MigrateEstimateTask mEstimate;
@Override @Override
@@ -75,9 +81,22 @@ public class StorageWizardMigrateConfirm extends StorageWizardBase {
@Override @Override
public void onNavigateNext() { public void onNavigateNext() {
int moveId; // Ensure that all users are unlocked so that we can move their data
if (StorageManager.isFileEncryptedNativeOrEmulated()) {
for (UserInfo user : getSystemService(UserManager.class).getUsers()) {
if (!StorageManager.isUserKeyUnlocked(user.id)) {
Log.d(TAG, "User " + user.id + " is currently locked; requesting unlock");
final CharSequence description = TextUtils.expandTemplate(
getText(R.string.storage_wizard_move_unlock), user.name);
new ChooseLockSettingsHelper(this).launchConfirmationActivityForAnyUser(
REQUEST_CREDENTIAL, null, null, description, user.id);
return;
}
}
}
// We only expect exceptions from StorageManagerService#setPrimaryStorageUuid // We only expect exceptions from StorageManagerService#setPrimaryStorageUuid
int moveId;
try { try {
moveId = getPackageManager().movePrimaryStorage(mVolume); moveId = getPackageManager().movePrimaryStorage(mVolume);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
@@ -108,4 +127,22 @@ public class StorageWizardMigrateConfirm extends StorageWizardBase {
startActivity(intent); startActivity(intent);
finishAffinity(); finishAffinity();
} }
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CREDENTIAL) {
if (resultCode == RESULT_OK) {
// Credentials confirmed, so storage should be unlocked; let's
// go look for the next locked user.
onNavigateNext();
} else {
// User wasn't able to confirm credentials, so we're okay
// landing back at the wizard page again, where they read
// instructions again and tap "Next" to try again.
Log.w(TAG, "Failed to confirm credentials");
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
} }

View File

@@ -16,20 +16,30 @@
package com.android.settings.deviceinfo; package com.android.settings.deviceinfo;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import com.android.internal.util.Preconditions;
import com.android.settings.R;
import static android.content.Intent.EXTRA_PACKAGE_NAME; import static android.content.Intent.EXTRA_PACKAGE_NAME;
import static android.content.Intent.EXTRA_TITLE; import static android.content.Intent.EXTRA_TITLE;
import static android.content.pm.PackageManager.EXTRA_MOVE_ID; import static android.content.pm.PackageManager.EXTRA_MOVE_ID;
import static android.os.storage.VolumeInfo.EXTRA_VOLUME_ID; import static android.os.storage.VolumeInfo.EXTRA_VOLUME_ID;
import static com.android.settings.deviceinfo.StorageSettings.TAG;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.os.Bundle;
import android.os.UserManager;
import android.os.storage.StorageManager;
import android.text.TextUtils;
import android.util.Log;
import com.android.internal.util.Preconditions;
import com.android.settings.R;
import com.android.settings.password.ChooseLockSettingsHelper;
public class StorageWizardMoveConfirm extends StorageWizardBase { public class StorageWizardMoveConfirm extends StorageWizardBase {
private static final int REQUEST_CREDENTIAL = 100;
private String mPackageName; private String mPackageName;
private ApplicationInfo mApp; private ApplicationInfo mApp;
@@ -66,6 +76,20 @@ public class StorageWizardMoveConfirm extends StorageWizardBase {
@Override @Override
public void onNavigateNext() { public void onNavigateNext() {
// Ensure that all users are unlocked so that we can move their data
if (StorageManager.isFileEncryptedNativeOrEmulated()) {
for (UserInfo user : getSystemService(UserManager.class).getUsers()) {
if (!StorageManager.isUserKeyUnlocked(user.id)) {
Log.d(TAG, "User " + user.id + " is currently locked; requesting unlock");
final CharSequence description = TextUtils.expandTemplate(
getText(R.string.storage_wizard_move_unlock), user.name);
new ChooseLockSettingsHelper(this).launchConfirmationActivityForAnyUser(
REQUEST_CREDENTIAL, null, null, description, user.id);
return;
}
}
}
// Kick off move before we transition // Kick off move before we transition
final String appName = getPackageManager().getApplicationLabel(mApp).toString(); final String appName = getPackageManager().getApplicationLabel(mApp).toString();
final int moveId = getPackageManager().movePackage(mPackageName, mVolume); final int moveId = getPackageManager().movePackage(mPackageName, mVolume);
@@ -77,4 +101,22 @@ public class StorageWizardMoveConfirm extends StorageWizardBase {
startActivity(intent); startActivity(intent);
finishAffinity(); finishAffinity();
} }
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CREDENTIAL) {
if (resultCode == RESULT_OK) {
// Credentials confirmed, so storage should be unlocked; let's
// go look for the next locked user.
onNavigateNext();
} else {
// User wasn't able to confirm credentials, so we're okay
// landing back at the wizard page again, where they read
// instructions again and tap "Next" to try again.
Log.w(TAG, "Failed to confirm credentials");
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
} }

View File

@@ -23,6 +23,7 @@ import android.app.KeyguardManager;
import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManager;
import android.content.Intent; import android.content.Intent;
import android.content.IntentSender; import android.content.IntentSender;
import android.os.Bundle;
import android.os.UserManager; import android.os.UserManager;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
@@ -42,6 +43,12 @@ public final class ChooseLockSettingsHelper {
public static final String EXTRA_KEY_FOR_FINGERPRINT = "for_fingerprint"; public static final String EXTRA_KEY_FOR_FINGERPRINT = "for_fingerprint";
public static final String EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT = "for_cred_req_boot"; public static final String EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT = "for_cred_req_boot";
/**
* When invoked via {@link ConfirmLockPassword.InternalActivity}, this flag
* controls if we relax the enforcement of
* {@link Utils#enforceSameOwner(android.content.Context, int)}.
*/
public static final String EXTRA_ALLOW_ANY_USER = "allow_any_user";
@VisibleForTesting LockPatternUtils mLockPatternUtils; @VisibleForTesting LockPatternUtils mLockPatternUtils;
private Activity mActivity; private Activity mActivity;
@@ -200,25 +207,47 @@ public final class ChooseLockSettingsHelper {
external, true, challenge, Utils.enforceSameOwner(mActivity, userId)); external, true, challenge, Utils.enforceSameOwner(mActivity, userId));
} }
/**
* Variant that allows you to prompt for credentials of any user, including
* those which aren't associated with the current user. As an example, this
* is useful when unlocking the storage for secondary users.
*/
public boolean launchConfirmationActivityForAnyUser(int request,
@Nullable CharSequence title, @Nullable CharSequence header,
@Nullable CharSequence description, int userId) {
final Bundle extras = new Bundle();
extras.putBoolean(EXTRA_ALLOW_ANY_USER, true);
return launchConfirmationActivity(request, title, header, description, false,
false, true, 0, userId, extras);
}
private boolean launchConfirmationActivity(int request, @Nullable CharSequence title, private boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
@Nullable CharSequence header, @Nullable CharSequence description, @Nullable CharSequence header, @Nullable CharSequence description,
boolean returnCredentials, boolean external, boolean hasChallenge, boolean returnCredentials, boolean external, boolean hasChallenge,
long challenge, int userId) { long challenge, int userId) {
return launchConfirmationActivity(request, title, header, description, returnCredentials, return launchConfirmationActivity(request, title, header, description, returnCredentials,
external, hasChallenge, challenge, userId, null /* alternateButton */); external, hasChallenge, challenge, userId, null /* alternateButton */, null);
}
private boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
@Nullable CharSequence header, @Nullable CharSequence description,
boolean returnCredentials, boolean external, boolean hasChallenge,
long challenge, int userId, Bundle extras) {
return launchConfirmationActivity(request, title, header, description, returnCredentials,
external, hasChallenge, challenge, userId, null /* alternateButton */, extras);
} }
public boolean launchFrpConfirmationActivity(int request, @Nullable CharSequence header, public boolean launchFrpConfirmationActivity(int request, @Nullable CharSequence header,
@Nullable CharSequence description, @Nullable CharSequence alternateButton) { @Nullable CharSequence description, @Nullable CharSequence alternateButton) {
return launchConfirmationActivity(request, null /* title */, header, description, return launchConfirmationActivity(request, null /* title */, header, description,
false /* returnCredentials */, true /* external */, false /* hasChallenge */, false /* returnCredentials */, true /* external */, false /* hasChallenge */,
0 /* challenge */, LockPatternUtils.USER_FRP, alternateButton); 0 /* challenge */, LockPatternUtils.USER_FRP, alternateButton, null);
} }
private boolean launchConfirmationActivity(int request, @Nullable CharSequence title, private boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
@Nullable CharSequence header, @Nullable CharSequence description, @Nullable CharSequence header, @Nullable CharSequence description,
boolean returnCredentials, boolean external, boolean hasChallenge, boolean returnCredentials, boolean external, boolean hasChallenge,
long challenge, int userId, @Nullable CharSequence alternateButton) { long challenge, int userId, @Nullable CharSequence alternateButton, Bundle extras) {
final int effectiveUserId = UserManager.get(mActivity).getCredentialOwnerProfile(userId); final int effectiveUserId = UserManager.get(mActivity).getCredentialOwnerProfile(userId);
boolean launched = false; boolean launched = false;
@@ -228,7 +257,7 @@ public final class ChooseLockSettingsHelper {
returnCredentials || hasChallenge returnCredentials || hasChallenge
? ConfirmLockPattern.InternalActivity.class ? ConfirmLockPattern.InternalActivity.class
: ConfirmLockPattern.class, returnCredentials, external, : ConfirmLockPattern.class, returnCredentials, external,
hasChallenge, challenge, userId, alternateButton); hasChallenge, challenge, userId, alternateButton, extras);
break; break;
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
@@ -240,7 +269,7 @@ public final class ChooseLockSettingsHelper {
returnCredentials || hasChallenge returnCredentials || hasChallenge
? ConfirmLockPassword.InternalActivity.class ? ConfirmLockPassword.InternalActivity.class
: ConfirmLockPassword.class, returnCredentials, external, : ConfirmLockPassword.class, returnCredentials, external,
hasChallenge, challenge, userId, alternateButton); hasChallenge, challenge, userId, alternateButton, extras);
break; break;
} }
return launched; return launched;
@@ -249,7 +278,7 @@ public final class ChooseLockSettingsHelper {
private boolean launchConfirmationActivity(int request, CharSequence title, CharSequence header, private boolean launchConfirmationActivity(int request, CharSequence title, CharSequence header,
CharSequence message, Class<?> activityClass, boolean returnCredentials, CharSequence message, Class<?> activityClass, boolean returnCredentials,
boolean external, boolean hasChallenge, long challenge, boolean external, boolean hasChallenge, long challenge,
int userId, @Nullable CharSequence alternateButton) { int userId, @Nullable CharSequence alternateButton, Bundle extras) {
final boolean frp = (userId == LockPatternUtils.USER_FRP); final boolean frp = (userId == LockPatternUtils.USER_FRP);
final Intent intent = new Intent(); final Intent intent = new Intent();
intent.putExtra(ConfirmDeviceCredentialBaseFragment.TITLE_TEXT, title); intent.putExtra(ConfirmDeviceCredentialBaseFragment.TITLE_TEXT, title);
@@ -266,6 +295,9 @@ public final class ChooseLockSettingsHelper {
intent.putExtra(SettingsActivity.EXTRA_HIDE_DRAWER, true); intent.putExtra(SettingsActivity.EXTRA_HIDE_DRAWER, true);
intent.putExtra(Intent.EXTRA_USER_ID, userId); intent.putExtra(Intent.EXTRA_USER_ID, userId);
intent.putExtra(KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL, alternateButton); intent.putExtra(KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL, alternateButton);
if (extras != null) {
intent.putExtras(extras);
}
intent.setClassName(ConfirmDeviceCredentialBaseFragment.PACKAGE, activityClass.getName()); intent.setClassName(ConfirmDeviceCredentialBaseFragment.PACKAGE, activityClass.getName());
if (external) { if (external) {
intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);

View File

@@ -45,10 +45,15 @@ public abstract class ConfirmDeviceCredentialBaseActivity extends SettingsActivi
private boolean mIsKeyguardLocked = false; private boolean mIsKeyguardLocked = false;
private ConfirmCredentialTheme mConfirmCredentialTheme; private ConfirmCredentialTheme mConfirmCredentialTheme;
private boolean isInternalActivity() {
return (this instanceof ConfirmLockPassword.InternalActivity)
|| (this instanceof ConfirmLockPattern.InternalActivity);
}
@Override @Override
protected void onCreate(Bundle savedState) { protected void onCreate(Bundle savedState) {
int credentialOwnerUserId = Utils.getCredentialOwnerUserId(this, int credentialOwnerUserId = Utils.getCredentialOwnerUserId(this,
Utils.getUserIdFromBundle(this, getIntent().getExtras())); Utils.getUserIdFromBundle(this, getIntent().getExtras(), isInternalActivity()));
if (UserManager.get(this).isManagedProfile(credentialOwnerUserId)) { if (UserManager.get(this).isManagedProfile(credentialOwnerUserId)) {
setTheme(R.style.Theme_ConfirmDeviceCredentialsWork); setTheme(R.style.Theme_ConfirmDeviceCredentialsWork);
mConfirmCredentialTheme = ConfirmCredentialTheme.WORK; mConfirmCredentialTheme = ConfirmCredentialTheme.WORK;

View File

@@ -94,6 +94,11 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedPr
protected boolean mFrp; protected boolean mFrp;
private CharSequence mFrpAlternateButtonText; private CharSequence mFrpAlternateButtonText;
private boolean isInternalActivity() {
return (getActivity() instanceof ConfirmLockPassword.InternalActivity)
|| (getActivity() instanceof ConfirmLockPattern.InternalActivity);
}
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@@ -103,7 +108,8 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedPr
ChooseLockSettingsHelper.EXTRA_KEY_RETURN_CREDENTIALS, false); ChooseLockSettingsHelper.EXTRA_KEY_RETURN_CREDENTIALS, false);
// Only take this argument into account if it belongs to the current profile. // Only take this argument into account if it belongs to the current profile.
Intent intent = getActivity().getIntent(); Intent intent = getActivity().getIntent();
mUserId = Utils.getUserIdFromBundle(getActivity(), intent.getExtras()); mUserId = Utils.getUserIdFromBundle(getActivity(), intent.getExtras(),
isInternalActivity());
mFrp = (mUserId == LockPatternUtils.USER_FRP); mFrp = (mUserId == LockPatternUtils.USER_FRP);
mUserManager = UserManager.get(getActivity()); mUserManager = UserManager.get(getActivity());
mEffectiveUserId = mUserManager.getCredentialOwnerProfile(mUserId); mEffectiveUserId = mUserManager.getCredentialOwnerProfile(mUserId);
@@ -141,7 +147,7 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedPr
getActivity(), getActivity(),
Utils.getUserIdFromBundle( Utils.getUserIdFromBundle(
getActivity(), getActivity(),
getActivity().getIntent().getExtras())); getActivity().getIntent().getExtras(), isInternalActivity()));
if (mUserManager.isManagedProfile(credentialOwnerUserId)) { if (mUserManager.isManagedProfile(credentialOwnerUserId)) {
setWorkChallengeBackground(view, credentialOwnerUserId); setWorkChallengeBackground(view, credentialOwnerUserId);
} }