1 /* 2 * Copyright (C) 2021 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.profiles; 18 19 import static android.os.UserManager.DISALLOW_ADD_USER; 20 21 import static com.android.car.settings.common.PreferenceController.AVAILABLE; 22 import static com.android.car.settings.common.PreferenceController.AVAILABLE_FOR_VIEWING; 23 import static com.android.car.settings.common.PreferenceController.DISABLED_FOR_PROFILE; 24 import static com.android.car.settings.enterprise.ActionDisabledByAdminDialogFragment.DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG; 25 import static com.android.car.settings.enterprise.EnterpriseUtils.hasUserRestrictionByDpm; 26 import static com.android.car.settings.enterprise.EnterpriseUtils.hasUserRestrictionByUm; 27 28 import android.car.Car; 29 import android.car.user.CarUserManager; 30 import android.content.Context; 31 import android.os.UserManager; 32 import android.widget.Toast; 33 34 import androidx.annotation.VisibleForTesting; 35 import androidx.preference.Preference; 36 37 import com.android.car.settings.R; 38 import com.android.car.settings.common.ConfirmationDialogFragment; 39 import com.android.car.settings.common.ErrorDialog; 40 import com.android.car.settings.common.FragmentController; 41 import com.android.car.settings.common.PreferenceController; 42 import com.android.car.settings.enterprise.EnterpriseUtils; 43 44 /** 45 * Consolidates adding profile logic into one handler so we can have consistent logic across various 46 * parts of the Settings app. 47 */ 48 public class AddProfileHandler implements AddNewProfileTask.AddNewProfileListener { 49 50 @VisibleForTesting 51 static final String CONFIRM_CREATE_NEW_PROFILE_DIALOG_TAG = 52 "com.android.car.settings.profiles.ConfirmCreateNewProfileDialog"; 53 @VisibleForTesting 54 static final String MAX_PROFILES_LIMIT_REACHED_DIALOG_TAG = 55 "com.android.car.settings.profiles.MaxProfilesLimitReachedDialog"; 56 57 @VisibleForTesting 58 AddNewProfileTask mAddNewProfileTask; 59 /** Indicates that a task is running. */ 60 private boolean mIsBusy; 61 62 private final Context mContext; 63 private final FragmentController mFragmentController; 64 private final PreferenceController mPreferenceController; 65 private final Car mCar; 66 private CarUserManager mCarUserManager; 67 68 @VisibleForTesting 69 ConfirmationDialogFragment.ConfirmListener mConfirmCreateNewProfileListener; 70 AddProfileHandler(Context context, FragmentController fragmentController, PreferenceController preferenceController)71 public AddProfileHandler(Context context, FragmentController fragmentController, 72 PreferenceController preferenceController) { 73 mContext = context; 74 mFragmentController = fragmentController; 75 mPreferenceController = preferenceController; 76 mCar = Car.createCar(context); 77 mCarUserManager = (CarUserManager) mCar.getCarManager(Car.CAR_USER_SERVICE); 78 79 mConfirmCreateNewProfileListener = arguments -> { 80 mAddNewProfileTask = new AddNewProfileTask(mContext, 81 mCarUserManager, /* addNewProfileListener= */ this); 82 mAddNewProfileTask.execute(mContext.getString(R.string.user_new_user_name)); 83 84 mIsBusy = true; 85 mPreferenceController.refreshUi(); 86 }; 87 } 88 89 /** 90 * Handles operations that should happen in host's onCreateInternal(). 91 * Resets listeners as they can get unregistered with certain configuration changes. 92 */ onCreateInternal()93 public void onCreateInternal() { 94 ConfirmationDialogFragment.resetListeners( 95 (ConfirmationDialogFragment) mFragmentController.findDialogByTag( 96 CONFIRM_CREATE_NEW_PROFILE_DIALOG_TAG), 97 mConfirmCreateNewProfileListener, 98 /* rejectListener= */ null, 99 /* neutralListener= */ null); 100 } 101 102 /** 103 * Handles operations that should happen in host's onStopInternal(). 104 */ onStopInternal()105 public void onStopInternal() { 106 mFragmentController.showProgressBar(false); 107 } 108 109 /** 110 * Handles events that should happen in host's onDestroyInternal(). 111 */ onDestroyInternal()112 public void onDestroyInternal() { 113 if (mAddNewProfileTask != null) { 114 mAddNewProfileTask.cancel(/* mayInterruptIfRunning= */ false); 115 } 116 if (mCar != null) { 117 mCar.disconnect(); 118 } 119 } 120 121 /** 122 * Handles events that should happen in host's updateState() when there is task running. 123 */ updateState(Preference preference)124 public void updateState(Preference preference) { 125 preference.setEnabled(!mIsBusy); 126 mFragmentController.showProgressBar(mIsBusy); 127 } 128 129 @Override onProfileAddedSuccess()130 public void onProfileAddedSuccess() { 131 mIsBusy = false; 132 mPreferenceController.refreshUi(); 133 } 134 135 @Override onProfileAddedFailure()136 public void onProfileAddedFailure() { 137 mIsBusy = false; 138 mPreferenceController.refreshUi(); 139 // Display failure dialog. 140 mFragmentController.showDialog( 141 ErrorDialog.newInstance(R.string.add_user_error_title), /* tag= */ null); 142 } 143 144 /** 145 * Determines whether the user manager instance has the permission to add profiles 146 * 147 * @param userManager UserManager instance to evaluate 148 * @return whether the user has permissions to add profiles 149 */ canAddProfiles(UserManager userManager)150 public static boolean canAddProfiles(UserManager userManager) { 151 return !userManager.hasUserRestriction(DISALLOW_ADD_USER); 152 } 153 154 /** 155 * Returns {@code PreferenceController.AVAILABLE} when preference should be available, 156 * {@code PreferenceController.DISABLED_FOR_PROFILE} when preference should be unavailable, 157 * {@code PreferenceController.AVAILABLE_FOR_VIEWING} when preference is visible but 158 * disabled. 159 */ getAddProfilePreferenceAvailabilityStatus(Context context)160 public static int getAddProfilePreferenceAvailabilityStatus(Context context) { 161 UserManager um = getUserManager(context); 162 if (um.isDemoUser() || canAddProfiles(um)) { 163 return AVAILABLE; 164 } 165 if (hasUserRestrictionByUm(context, DISALLOW_ADD_USER)) { 166 return DISABLED_FOR_PROFILE; 167 } 168 return AVAILABLE_FOR_VIEWING; 169 } 170 171 /** 172 * Display dialog to add a profile 173 */ showAddProfileDialog()174 public void showAddProfileDialog() { 175 ConfirmationDialogFragment dialogFragment = 176 ProfilesDialogProvider.getConfirmCreateNewProfileDialogFragment( 177 mContext, mConfirmCreateNewProfileListener, null); 178 179 mFragmentController.showDialog(dialogFragment, CONFIRM_CREATE_NEW_PROFILE_DIALOG_TAG); 180 } 181 182 /** 183 * Shows a dialog or toast when the Preference is disabled while still visible. 184 */ runClickableWhileDisabled()185 public void runClickableWhileDisabled() { 186 if (hasUserRestrictionByDpm(mContext, DISALLOW_ADD_USER)) { 187 // Shows a dialog if this PreferenceController is disabled because there is 188 // restriction set from DevicePolicyManager 189 showActionDisabledByAdminDialog(); 190 } else if (!getUserManager(mContext).canAddMoreUsers()) { 191 // Shows a dialog if no more profiles can be added because the maximum allowed number 192 // is reached 193 ConfirmationDialogFragment dialogFragment = 194 ProfilesDialogProvider.getMaxProfilesLimitReachedDialogFragment(mContext, 195 ProfileHelper.getInstance(mContext).getMaxSupportedRealProfiles()); 196 mFragmentController.showDialog(dialogFragment, MAX_PROFILES_LIMIT_REACHED_DIALOG_TAG); 197 } else { 198 Toast.makeText(mContext, mContext.getString(R.string.action_unavailable), 199 Toast.LENGTH_LONG).show(); 200 } 201 } 202 showActionDisabledByAdminDialog()203 private void showActionDisabledByAdminDialog() { 204 mFragmentController.showDialog( 205 EnterpriseUtils.getActionDisabledByAdminDialog(mContext, DISALLOW_ADD_USER), 206 DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG); 207 } 208 getUserManager(Context context)209 private static UserManager getUserManager(Context context) { 210 return context.getSystemService(UserManager.class); 211 } 212 213 @VisibleForTesting setCarUserManager(CarUserManager carUserManager)214 void setCarUserManager(CarUserManager carUserManager) { 215 mCarUserManager = carUserManager; 216 } 217 } 218