1 /*
2  * Copyright (C) 2020 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.car.settings.accounts;
18 
19 import static android.app.Activity.RESULT_OK;
20 import static android.os.UserManager.DISALLOW_MODIFY_ACCOUNTS;
21 
22 import static com.android.car.settings.enterprise.EnterpriseUtils.hasUserRestrictionByUm;
23 import static com.android.car.settings.enterprise.EnterpriseUtils.isDeviceManaged;
24 
25 import android.car.drivingstate.CarUxRestrictions;
26 import android.content.Context;
27 import android.content.Intent;
28 
29 import androidx.annotation.Nullable;
30 import androidx.annotation.VisibleForTesting;
31 import androidx.preference.Preference;
32 
33 import com.android.car.settings.admin.NewUserDisclaimerActivity;
34 import com.android.car.settings.common.ActivityResultCallback;
35 import com.android.car.settings.common.FragmentController;
36 import com.android.car.settings.common.Logger;
37 import com.android.car.settings.common.PreferenceController;
38 import com.android.car.settings.profiles.ProfileHelper;
39 
40 import java.util.Arrays;
41 import java.util.HashSet;
42 import java.util.Set;
43 
44 /**
45  * Business Logic for preference starts the add account flow.
46  */
47 public class AddAccountPreferenceController extends PreferenceController<Preference>
48         implements ActivityResultCallback {
49     public static final int NEW_USER_DISCLAIMER_REQUEST = 1;
50     private static final Logger LOG = new Logger(AddAccountPreferenceController.class);
51 
52     private String[] mAuthorities;
53     private String[] mAccountTypes;
54 
AddAccountPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)55     public AddAccountPreferenceController(Context context, String preferenceKey,
56             FragmentController fragmentController,
57             CarUxRestrictions uxRestrictions) {
58         super(context, preferenceKey, fragmentController, uxRestrictions);
59     }
60 
61     /** Sets the account authorities that are available. */
setAuthorities(String[] authorities)62     public AddAccountPreferenceController setAuthorities(String[] authorities) {
63         mAuthorities = authorities;
64         return this;
65     }
66 
67     /** Sets the account authorities that are available. */
setAccountTypes(String[] accountTypes)68     public AddAccountPreferenceController setAccountTypes(String[] accountTypes) {
69         mAccountTypes = accountTypes;
70         return this;
71     }
72 
73     @Override
getPreferenceType()74     protected Class<Preference> getPreferenceType() {
75         return Preference.class;
76     }
77 
78     @Override
onCreateInternal()79     protected void onCreateInternal() {
80         super.onCreateInternal();
81         setClickableWhileDisabled(getPreference(), /* clickable= */ true, p -> {
82             if (!getProfileHelper().isNewUserDisclaimerAcknolwedged(getContext())) {
83                 LOG.d("isNewUserDisclaimerAcknolwedged returns false, start activity");
84                 startNewUserDisclaimerActivityForResult();
85                 return;
86             }
87             getProfileHelper()
88                     .runClickableWhileDisabled(getContext(), getFragmentController());
89         });
90     }
91 
92     @Override
handlePreferenceClicked(Preference preference)93     protected boolean handlePreferenceClicked(Preference preference) {
94         AccountTypesHelper helper = getAccountTypesHelper();
95 
96         if (mAuthorities != null) {
97             helper.setAuthorities(Arrays.asList(mAuthorities));
98         }
99         if (mAccountTypes != null) {
100             helper.setAccountTypesFilter(
101                     new HashSet<>(Arrays.asList(mAccountTypes)));
102         }
103         launchAddAccount();
104         return true;
105     }
106 
107     @Override
processActivityResult(int requestCode, int resultCode, @Nullable Intent data)108     public void processActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
109         if (requestCode == NEW_USER_DISCLAIMER_REQUEST && resultCode == RESULT_OK) {
110             LOG.d("New user disclaimer acknowledged, launching add account.");
111             launchAddAccount();
112         }  else {
113             LOG.e("New user disclaimer failed with result " + resultCode);
114         }
115     }
116 
launchAddAccount()117     private void launchAddAccount() {
118         Set<String> authorizedAccountTypes = getAccountTypesHelper().getAuthorizedAccountTypes();
119 
120         // Skip the choose account screen if there is only one account type and the device is not
121         // managed by a device owner.
122         // TODO (b/213894991) add check for profile owner when work profile is supported
123         if (authorizedAccountTypes.size() == 1 && !isDeviceManaged(getContext())) {
124             String accountType = authorizedAccountTypes.iterator().next();
125             getContext().startActivity(
126                     AddAccountActivity.createAddAccountActivityIntent(getContext(), accountType));
127         } else {
128             getFragmentController().launchFragment(new ChooseAccountFragment());
129         }
130     }
131 
132     @Override
getDefaultAvailabilityStatus()133     protected int getDefaultAvailabilityStatus() {
134         if (isDeviceManaged(getContext())
135                 && !getProfileHelper().isNewUserDisclaimerAcknolwedged(getContext())) {
136             return AVAILABLE_FOR_VIEWING;
137         }
138         if (getProfileHelper().canCurrentProcessModifyAccounts()) {
139             return AVAILABLE;
140         }
141         if (getProfileHelper().isDemoOrGuest()
142                 || hasUserRestrictionByUm(getContext(), DISALLOW_MODIFY_ACCOUNTS)) {
143             return DISABLED_FOR_PROFILE;
144         }
145         return AVAILABLE_FOR_VIEWING;
146     }
147 
startNewUserDisclaimerActivityForResult()148     private void startNewUserDisclaimerActivityForResult() {
149         getFragmentController().startActivityForResult(
150                 new Intent(getContext(), NewUserDisclaimerActivity.class),
151                         NEW_USER_DISCLAIMER_REQUEST, /* callback= */ this);
152     }
153 
154     @VisibleForTesting
getProfileHelper()155     ProfileHelper getProfileHelper() {
156         return ProfileHelper.getInstance(getContext());
157     }
158 
159     @VisibleForTesting
getAccountTypesHelper()160     AccountTypesHelper getAccountTypesHelper() {
161         return new AccountTypesHelper(getContext());
162     }
163 }
164