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