| /* |
| * Copyright (C) 2017 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.car.settings.accounts; |
| |
| import static android.content.Intent.EXTRA_USER; |
| |
| import android.accounts.AccountManager; |
| import android.accounts.AccountManagerCallback; |
| import android.accounts.AccountManagerFuture; |
| import android.accounts.AuthenticatorException; |
| import android.accounts.OperationCanceledException; |
| import android.app.Activity; |
| import android.app.PendingIntent; |
| import android.content.ComponentName; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.os.Bundle; |
| import android.os.UserHandle; |
| import android.os.UserManager; |
| import android.widget.Toast; |
| |
| import com.android.car.settings.R; |
| import com.android.car.settings.common.Logger; |
| |
| import java.io.IOException; |
| |
| /** |
| * Entry point Activity for account setup. Works as follows |
| * |
| * <ol> |
| * <li> After receiving an account type from ChooseAccountFragment, this Activity launches the |
| * account setup specified by AccountManager. |
| * <li> After the account setup, this Activity finishes without showing anything. |
| * </ol> |
| */ |
| public class AddAccountActivity extends Activity { |
| /** |
| * A boolean to keep the state of whether add account has already been called. |
| */ |
| private static final String KEY_ADD_CALLED = "AddAccountCalled"; |
| /** |
| * Extra parameter to identify the caller. Applications may display a |
| * different UI if the call is made from Settings or from a specific |
| * application. |
| */ |
| private static final String KEY_CALLER_IDENTITY = "pendingIntent"; |
| private static final String SHOULD_NOT_RESOLVE = "SHOULDN'T RESOLVE!"; |
| |
| private static final Logger LOG = new Logger(AddAccountActivity.class); |
| private static final String ALLOW_SKIP = "allowSkip"; |
| |
| /* package */ static final String EXTRA_SELECTED_ACCOUNT = "selected_account"; |
| |
| // Show additional info regarding the use of a device with multiple users |
| static final String EXTRA_HAS_MULTIPLE_USERS = "hasMultipleUsers"; |
| |
| // Need a specific request code for add account activity. |
| private static final int ADD_ACCOUNT_REQUEST = 2001; |
| |
| private UserManager mUserManager; |
| private UserHandle mUserHandle; |
| private PendingIntent mPendingIntent; |
| private boolean mAddAccountCalled; |
| |
| private final AccountManagerCallback<Bundle> mCallback = new AccountManagerCallback<Bundle>() { |
| @Override |
| public void run(AccountManagerFuture<Bundle> future) { |
| if (!future.isDone()) { |
| LOG.v("Account manager future is not done."); |
| finish(); |
| } |
| boolean done = true; |
| try { |
| Bundle result = future.getResult(); |
| Intent intent = result.getParcelable(AccountManager.KEY_INTENT); |
| if (intent != null) { |
| done = false; |
| Bundle addAccountOptions = new Bundle(); |
| addAccountOptions.putBoolean(EXTRA_HAS_MULTIPLE_USERS, |
| hasMultipleUsers(AddAccountActivity.this)); |
| addAccountOptions.putParcelable(EXTRA_USER, mUserHandle); |
| intent.putExtras(addAccountOptions); |
| intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| startActivityForResultAsUser( |
| intent, ADD_ACCOUNT_REQUEST, mUserHandle); |
| } else { |
| setResult(RESULT_OK); |
| if (mPendingIntent != null) { |
| mPendingIntent.cancel(); |
| mPendingIntent = null; |
| } |
| } |
| LOG.v("account added: " + result); |
| } catch (OperationCanceledException | IOException | AuthenticatorException e) { |
| LOG.v("addAccount error: " + e); |
| } finally { |
| if (done) { |
| finish(); |
| } |
| } |
| } |
| }; |
| |
| /** |
| * Creates an intent to start the {@link AddAccountActivity} to add an account of the given |
| * account type. |
| */ |
| public static Intent createAddAccountActivityIntent(Context context, String accountType) { |
| Intent intent = new Intent(context, AddAccountActivity.class); |
| intent.putExtra(EXTRA_SELECTED_ACCOUNT, accountType); |
| return intent; |
| } |
| |
| @Override |
| protected void onSaveInstanceState(Bundle outState) { |
| super.onSaveInstanceState(outState); |
| outState.putBoolean(KEY_ADD_CALLED, mAddAccountCalled); |
| LOG.v("saved"); |
| } |
| |
| @Override |
| public void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| if (savedInstanceState != null) { |
| mAddAccountCalled = savedInstanceState.getBoolean(KEY_ADD_CALLED); |
| LOG.v("Restored from previous add account call: " + mAddAccountCalled); |
| } |
| |
| mUserManager = UserManager.get(getApplicationContext()); |
| mUserHandle = UserHandle.of(UserHandle.myUserId()); |
| |
| if (mUserManager.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) { |
| // We aren't allowed to add an account. |
| Toast.makeText( |
| this, R.string.user_cannot_add_accounts_message, Toast.LENGTH_LONG) |
| .show(); |
| finish(); |
| return; |
| } |
| |
| if (mAddAccountCalled) { |
| // We already called add account - maybe the callback was lost. |
| finish(); |
| return; |
| } |
| addAccount(getIntent().getStringExtra(EXTRA_SELECTED_ACCOUNT)); |
| } |
| |
| @Override |
| public void onActivityResult(int requestCode, int resultCode, Intent data) { |
| setResult(resultCode); |
| if (mPendingIntent != null) { |
| mPendingIntent.cancel(); |
| mPendingIntent = null; |
| } |
| finish(); |
| } |
| |
| private void addAccount(String accountType) { |
| Bundle addAccountOptions = new Bundle(); |
| addAccountOptions.putBoolean(EXTRA_HAS_MULTIPLE_USERS, hasMultipleUsers(this)); |
| addAccountOptions.putBoolean(ALLOW_SKIP, true); |
| |
| /* |
| * The identityIntent is for the purposes of establishing the identity |
| * of the caller and isn't intended for launching activities, services |
| * or broadcasts. |
| */ |
| Intent identityIntent = new Intent(); |
| identityIntent.setComponent(new ComponentName(SHOULD_NOT_RESOLVE, SHOULD_NOT_RESOLVE)); |
| identityIntent.setAction(SHOULD_NOT_RESOLVE); |
| identityIntent.addCategory(SHOULD_NOT_RESOLVE); |
| |
| mPendingIntent = |
| PendingIntent.getBroadcast(this, 0, identityIntent, PendingIntent.FLAG_IMMUTABLE); |
| addAccountOptions.putParcelable(KEY_CALLER_IDENTITY, mPendingIntent); |
| |
| AccountManager.get(this).addAccountAsUser( |
| accountType, |
| /* authTokenType= */ null, |
| /* requiredFeatures= */ null, |
| addAccountOptions, |
| null, |
| mCallback, |
| /* handler= */ null, |
| mUserHandle); |
| mAddAccountCalled = true; |
| } |
| |
| private boolean hasMultipleUsers(Context context) { |
| return ((UserManager) context.getSystemService(Context.USER_SERVICE)) |
| .getUsers().size() > 1; |
| } |
| } |