1 /* 2 * Copyright (C) 2017 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 package com.android.car.settings.accounts; 17 18 import static android.content.Intent.EXTRA_USER; 19 20 import android.accounts.AccountManager; 21 import android.accounts.AccountManagerCallback; 22 import android.accounts.AccountManagerFuture; 23 import android.accounts.AuthenticatorException; 24 import android.accounts.OperationCanceledException; 25 import android.app.Activity; 26 import android.app.PendingIntent; 27 import android.car.userlib.CarUserManagerHelper; 28 import android.content.ComponentName; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.os.Bundle; 32 import android.os.UserHandle; 33 import android.os.UserManager; 34 import android.widget.Toast; 35 36 import com.android.car.settings.R; 37 import com.android.car.settings.common.Logger; 38 39 import java.io.IOException; 40 41 /** 42 * Entry point Activity for account setup. Works as follows 43 * 44 * <ol> 45 * <li> After receiving an account type from ChooseAccountFragment, this Activity launches the 46 * account setup specified by AccountManager. 47 * <li> After the account setup, this Activity finishes without showing anything. 48 * </ol> 49 */ 50 public class AddAccountActivity extends Activity { 51 /** 52 * A boolean to keep the state of whether add account has already been called. 53 */ 54 private static final String KEY_ADD_CALLED = "AddAccountCalled"; 55 /** 56 * Extra parameter to identify the caller. Applications may display a 57 * different UI if the call is made from Settings or from a specific 58 * application. 59 */ 60 private static final String KEY_CALLER_IDENTITY = "pendingIntent"; 61 private static final String SHOULD_NOT_RESOLVE = "SHOULDN'T RESOLVE!"; 62 63 private static final Logger LOG = new Logger(AddAccountActivity.class); 64 private static final String ALLOW_SKIP = "allowSkip"; 65 66 /* package */ static final String EXTRA_SELECTED_ACCOUNT = "selected_account"; 67 68 // Show additional info regarding the use of a device with multiple users 69 static final String EXTRA_HAS_MULTIPLE_USERS = "hasMultipleUsers"; 70 71 // Need a specific request code for add account activity. 72 public static final int ADD_ACCOUNT_REQUEST = 2001; 73 74 private CarUserManagerHelper mCarUserManagerHelper; 75 private UserHandle mUserHandle; 76 private PendingIntent mPendingIntent; 77 private boolean mAddAccountCalled; 78 79 private final AccountManagerCallback<Bundle> mCallback = new AccountManagerCallback<Bundle>() { 80 @Override 81 public void run(AccountManagerFuture<Bundle> future) { 82 if (!future.isDone()) { 83 LOG.v("Account manager future is not done."); 84 finish(); 85 } 86 try { 87 Bundle result = future.getResult(); 88 89 Intent intent = (Intent) result.getParcelable(AccountManager.KEY_INTENT); 90 Bundle addAccountOptions = new Bundle(); 91 addAccountOptions.putBoolean(EXTRA_HAS_MULTIPLE_USERS, 92 hasMultipleUsers(AddAccountActivity.this)); 93 addAccountOptions.putParcelable(EXTRA_USER, mUserHandle); 94 intent.putExtras(addAccountOptions); 95 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 96 startActivityForResultAsUser( 97 intent, ADD_ACCOUNT_REQUEST, mUserHandle); 98 LOG.v("account added: " + result); 99 } catch (OperationCanceledException | IOException | AuthenticatorException e) { 100 LOG.v("addAccount error: " + e); 101 } finally { 102 finish(); 103 } 104 } 105 }; 106 107 @Override onSaveInstanceState(Bundle outState)108 protected void onSaveInstanceState(Bundle outState) { 109 super.onSaveInstanceState(outState); 110 outState.putBoolean(KEY_ADD_CALLED, mAddAccountCalled); 111 LOG.v("saved"); 112 } 113 114 @Override onCreate(Bundle savedInstanceState)115 public void onCreate(Bundle savedInstanceState) { 116 super.onCreate(savedInstanceState); 117 if (savedInstanceState != null) { 118 mAddAccountCalled = savedInstanceState.getBoolean(KEY_ADD_CALLED); 119 LOG.v("Restored from previous add account call: " + mAddAccountCalled); 120 } 121 122 mCarUserManagerHelper = new CarUserManagerHelper(this); 123 mUserHandle = mCarUserManagerHelper.getCurrentProcessUserInfo().getUserHandle(); 124 125 if (mCarUserManagerHelper.isCurrentProcessUserHasRestriction( 126 UserManager.DISALLOW_MODIFY_ACCOUNTS)) { 127 // We aren't allowed to add an account. 128 Toast.makeText( 129 this, R.string.user_cannot_add_accounts_message, Toast.LENGTH_LONG) 130 .show(); 131 finish(); 132 return; 133 } 134 135 if (mAddAccountCalled) { 136 // We already called add account - maybe the callback was lost. 137 finish(); 138 return; 139 } 140 addAccount(getIntent().getStringExtra(EXTRA_SELECTED_ACCOUNT)); 141 } 142 143 @Override onActivityResult(int requestCode, int resultCode, Intent data)144 public void onActivityResult(int requestCode, int resultCode, Intent data) { 145 setResult(resultCode); 146 if (mPendingIntent != null) { 147 mPendingIntent.cancel(); 148 mPendingIntent = null; 149 } 150 finish(); 151 } 152 addAccount(String accountType)153 private void addAccount(String accountType) { 154 Bundle addAccountOptions = new Bundle(); 155 addAccountOptions.putBoolean(EXTRA_HAS_MULTIPLE_USERS, hasMultipleUsers(this)); 156 addAccountOptions.putBoolean(ALLOW_SKIP, true); 157 158 /* 159 * The identityIntent is for the purposes of establishing the identity 160 * of the caller and isn't intended for launching activities, services 161 * or broadcasts. 162 */ 163 Intent identityIntent = new Intent(); 164 identityIntent.setComponent(new ComponentName(SHOULD_NOT_RESOLVE, SHOULD_NOT_RESOLVE)); 165 identityIntent.setAction(SHOULD_NOT_RESOLVE); 166 identityIntent.addCategory(SHOULD_NOT_RESOLVE); 167 168 mPendingIntent = PendingIntent.getBroadcast(this, 0, identityIntent, 0); 169 addAccountOptions.putParcelable(KEY_CALLER_IDENTITY, mPendingIntent); 170 171 AccountManager.get(this).addAccountAsUser( 172 accountType, 173 /* authTokenType= */ null, 174 /* requiredFeatures= */ null, 175 addAccountOptions, 176 null, 177 mCallback, 178 /* handler= */ null, 179 mUserHandle); 180 mAddAccountCalled = true; 181 } 182 hasMultipleUsers(Context context)183 private boolean hasMultipleUsers(Context context) { 184 return ((UserManager) context.getSystemService(Context.USER_SERVICE)) 185 .getUsers().size() > 1; 186 } 187 } 188