1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.app; 18 19 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; 20 21 import android.accounts.Account; 22 import android.accounts.AccountManager; 23 import android.content.DialogInterface; 24 import android.content.Intent; 25 import android.content.pm.ApplicationInfo; 26 import android.content.pm.PackageManager.NameNotFoundException; 27 import android.content.pm.UserInfo; 28 import android.os.Bundle; 29 import android.os.PersistableBundle; 30 import android.os.UserManager; 31 import android.util.Log; 32 33 import com.android.internal.R; 34 35 /** 36 * Activity to confirm with the user that it is ok to create a new user, as requested by 37 * an app. It has to do some checks to decide what kind of prompt the user should be shown. 38 * Particularly, it needs to check if the account requested already exists on another user. 39 */ 40 public class ConfirmUserCreationActivity extends AlertActivity 41 implements DialogInterface.OnClickListener { 42 43 private static final String TAG = "CreateUser"; 44 45 private static final String USER_TYPE = UserManager.USER_TYPE_FULL_SECONDARY; 46 47 private String mUserName; 48 private String mAccountName; 49 private String mAccountType; 50 private PersistableBundle mAccountOptions; 51 private boolean mCanProceed; 52 private boolean mIsFirstClick; 53 private UserManager mUserManager; 54 55 @Override onCreate(Bundle icicle)56 public void onCreate(Bundle icicle) { 57 super.onCreate(icicle); 58 59 getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); 60 61 Intent intent = getIntent(); 62 mUserName = intent.getStringExtra(UserManager.EXTRA_USER_NAME); 63 mAccountName = intent.getStringExtra(UserManager.EXTRA_USER_ACCOUNT_NAME); 64 mAccountType = intent.getStringExtra(UserManager.EXTRA_USER_ACCOUNT_TYPE); 65 mAccountOptions = (PersistableBundle) 66 intent.getParcelableExtra(UserManager.EXTRA_USER_ACCOUNT_OPTIONS, android.os.PersistableBundle.class); 67 68 mUserManager = getSystemService(UserManager.class); 69 70 String message = checkUserCreationRequirements(); 71 72 if (message == null) { 73 finish(); 74 return; 75 } 76 final AlertController.AlertParams ap = mAlertParams; 77 ap.mMessage = message; 78 ap.mPositiveButtonText = getString(android.R.string.ok); 79 ap.mPositiveButtonListener = this; 80 81 // Show the negative button if the user actually has a choice 82 if (mCanProceed) { 83 ap.mNegativeButtonText = getString(android.R.string.cancel); 84 ap.mNegativeButtonListener = this; 85 } 86 mIsFirstClick = true; 87 setupAlert(); 88 } 89 checkUserCreationRequirements()90 private String checkUserCreationRequirements() { 91 final String callingPackage = getCallingPackage(); 92 if (callingPackage == null) { 93 throw new SecurityException( 94 "User Creation intent must be launched with startActivityForResult"); 95 } 96 final ApplicationInfo appInfo; 97 try { 98 appInfo = getPackageManager().getApplicationInfo(callingPackage, 0); 99 } catch (NameNotFoundException nnfe) { 100 throw new SecurityException( 101 "Cannot find the calling package"); 102 } 103 final String message; 104 // Check the user restrictions 105 boolean cantCreateUser = mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER) 106 || !mUserManager.isAdminUser(); 107 // Check the system state and user count 108 boolean cantCreateAnyMoreUsers = !mUserManager.canAddMoreUsers(USER_TYPE); 109 // Check the account existence 110 final Account account = new Account(mAccountName, mAccountType); 111 boolean accountExists = mAccountName != null && mAccountType != null 112 && (AccountManager.get(this).someUserHasAccount(account) 113 | mUserManager.someUserHasSeedAccount(mAccountName, mAccountType)); 114 mCanProceed = true; 115 final String appName = appInfo.loadLabel(getPackageManager()).toString(); 116 if (cantCreateUser) { 117 setResult(UserManager.USER_CREATION_FAILED_NOT_PERMITTED); 118 return null; 119 } else if (!(isUserPropertyWithinLimit(mUserName, UserManager.MAX_USER_NAME_LENGTH) 120 && isUserPropertyWithinLimit(mAccountName, UserManager.MAX_ACCOUNT_STRING_LENGTH) 121 && isUserPropertyWithinLimit(mAccountType, UserManager.MAX_ACCOUNT_STRING_LENGTH)) 122 || (mAccountOptions != null && !mAccountOptions.isBundleContentsWithinLengthLimit( 123 UserManager.MAX_ACCOUNT_OPTIONS_LENGTH))) { 124 setResult(UserManager.USER_CREATION_FAILED_NOT_PERMITTED); 125 Log.i(TAG, "User properties must not exceed their character limits"); 126 return null; 127 } else if (cantCreateAnyMoreUsers) { 128 setResult(UserManager.USER_CREATION_FAILED_NO_MORE_USERS); 129 return null; 130 } else if (accountExists) { 131 message = getString(R.string.user_creation_account_exists, appName, mAccountName); 132 } else { 133 message = getString(R.string.user_creation_adding, appName, mAccountName); 134 } 135 return message; 136 } 137 138 @Override onClick(DialogInterface dialog, int which)139 public void onClick(DialogInterface dialog, int which) { 140 setResult(RESULT_CANCELED); 141 if (which == BUTTON_POSITIVE && mCanProceed && mIsFirstClick) { 142 mIsFirstClick = false; 143 Log.i(TAG, "Ok, creating user"); 144 UserInfo user = mUserManager.createUser(mUserName, USER_TYPE, 0); 145 if (user == null) { 146 Log.e(TAG, "Couldn't create user"); 147 finish(); 148 return; 149 } 150 mUserManager.setSeedAccountData(user.id, mAccountName, mAccountType, mAccountOptions); 151 setResult(RESULT_OK); 152 } 153 finish(); 154 } 155 isUserPropertyWithinLimit(String property, int limit)156 private boolean isUserPropertyWithinLimit(String property, int limit) { 157 return property == null || property.length() <= limit; 158 } 159 } 160