• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.settings.users;
18 
19 import static android.os.UserHandle.USER_NULL;
20 
21 import android.app.ActivityManager;
22 import android.app.Dialog;
23 import android.app.settings.SettingsEnums;
24 import android.content.Context;
25 import android.content.pm.UserInfo;
26 import android.os.Bundle;
27 import android.os.RemoteException;
28 import android.os.UserHandle;
29 import android.os.UserManager;
30 import android.util.Log;
31 
32 import androidx.annotation.VisibleForTesting;
33 import androidx.preference.Preference;
34 import androidx.preference.SwitchPreference;
35 
36 import com.android.settings.R;
37 import com.android.settings.SettingsPreferenceFragment;
38 import com.android.settings.Utils;
39 import com.android.settings.core.SubSettingLauncher;
40 import com.android.settingslib.RestrictedLockUtils;
41 import com.android.settingslib.RestrictedLockUtilsInternal;
42 import com.android.settingslib.RestrictedPreference;
43 
44 import java.util.List;
45 
46 /**
47  * Settings screen for configuring, deleting or switching to a specific user.
48  * It is shown when you tap on a user in the user management (UserSettings) screen.
49  *
50  * Arguments to this fragment must include the userId of the user (in EXTRA_USER_ID) for whom
51  * to display controls.
52  */
53 public class UserDetailsSettings extends SettingsPreferenceFragment
54         implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
55 
56     private static final String TAG = UserDetailsSettings.class.getSimpleName();
57 
58     private static final String KEY_SWITCH_USER = "switch_user";
59     private static final String KEY_ENABLE_TELEPHONY = "enable_calling";
60     private static final String KEY_REMOVE_USER = "remove_user";
61     private static final String KEY_APP_AND_CONTENT_ACCESS = "app_and_content_access";
62 
63     /** Integer extra containing the userId to manage */
64     static final String EXTRA_USER_ID = "user_id";
65 
66     private static final int DIALOG_CONFIRM_REMOVE = 1;
67     private static final int DIALOG_CONFIRM_ENABLE_CALLING = 2;
68     private static final int DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS = 3;
69     private static final int DIALOG_SETUP_USER = 4;
70 
71     private UserManager mUserManager;
72     private UserCapabilities mUserCaps;
73 
74     @VisibleForTesting
75     RestrictedPreference mSwitchUserPref;
76     private SwitchPreference mPhonePref;
77     @VisibleForTesting
78     Preference mAppAndContentAccessPref;
79     @VisibleForTesting
80     Preference mRemoveUserPref;
81 
82     @VisibleForTesting
83     UserInfo mUserInfo;
84     private Bundle mDefaultGuestRestrictions;
85 
86     @Override
getMetricsCategory()87     public int getMetricsCategory() {
88         return SettingsEnums.USER_DETAILS;
89     }
90 
91     @Override
onCreate(Bundle icicle)92     public void onCreate(Bundle icicle) {
93         super.onCreate(icicle);
94 
95         final Context context = getActivity();
96         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
97         mUserCaps = UserCapabilities.create(context);
98         addPreferencesFromResource(R.xml.user_details_settings);
99 
100         initialize(context, getArguments());
101     }
102 
103     @Override
onResume()104     public void onResume() {
105         super.onResume();
106         mSwitchUserPref.setEnabled(canSwitchUserNow());
107     }
108 
109     @Override
onPreferenceClick(Preference preference)110     public boolean onPreferenceClick(Preference preference) {
111         if (preference == mRemoveUserPref) {
112             if (canDeleteUser()) {
113                 showDialog(DIALOG_CONFIRM_REMOVE);
114                 return true;
115             }
116         } else if (preference == mSwitchUserPref) {
117             if (canSwitchUserNow()) {
118                 if (shouldShowSetupPromptDialog()) {
119                     showDialog(DIALOG_SETUP_USER);
120                 } else {
121                     switchUser();
122                 }
123                 return true;
124             }
125         } else if (preference == mAppAndContentAccessPref) {
126             openAppAndContentAccessScreen(false);
127             return true;
128         }
129         return false;
130     }
131 
132     @Override
onPreferenceChange(Preference preference, Object newValue)133     public boolean onPreferenceChange(Preference preference, Object newValue) {
134         if (Boolean.TRUE.equals(newValue)) {
135             showDialog(mUserInfo.isGuest() ? DIALOG_CONFIRM_ENABLE_CALLING
136                     : DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS);
137             return false;
138         }
139         enableCallsAndSms(false);
140         return true;
141     }
142 
143     @Override
getDialogMetricsCategory(int dialogId)144     public int getDialogMetricsCategory(int dialogId) {
145         switch (dialogId) {
146             case DIALOG_CONFIRM_REMOVE:
147                 return SettingsEnums.DIALOG_USER_REMOVE;
148             case DIALOG_CONFIRM_ENABLE_CALLING:
149                 return SettingsEnums.DIALOG_USER_ENABLE_CALLING;
150             case DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS:
151                 return SettingsEnums.DIALOG_USER_ENABLE_CALLING_AND_SMS;
152             case DIALOG_SETUP_USER:
153                 return SettingsEnums.DIALOG_USER_SETUP;
154             default:
155                 return 0;
156         }
157     }
158 
159     @Override
onCreateDialog(int dialogId)160     public Dialog onCreateDialog(int dialogId) {
161         Context context = getActivity();
162         if (context == null) {
163             return null;
164         }
165         switch (dialogId) {
166             case DIALOG_CONFIRM_REMOVE:
167                 return UserDialogs.createRemoveDialog(getActivity(), mUserInfo.id,
168                         (dialog, which) -> removeUser());
169             case DIALOG_CONFIRM_ENABLE_CALLING:
170                 return UserDialogs.createEnablePhoneCallsDialog(getActivity(),
171                         (dialog, which) -> enableCallsAndSms(true));
172             case DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS:
173                 return UserDialogs.createEnablePhoneCallsAndSmsDialog(getActivity(),
174                         (dialog, which) -> enableCallsAndSms(true));
175             case DIALOG_SETUP_USER:
176                 return UserDialogs.createSetupUserDialog(getActivity(),
177                         (dialog, which) -> {
178                             if (canSwitchUserNow()) {
179                                 switchUser();
180                             }
181                         });
182         }
183         throw new IllegalArgumentException("Unsupported dialogId " + dialogId);
184     }
185 
186     @VisibleForTesting
187     @Override
188     protected void showDialog(int dialogId) {
189         super.showDialog(dialogId);
190     }
191 
192     @VisibleForTesting
193     void initialize(Context context, Bundle arguments) {
194         int userId = arguments != null ? arguments.getInt(EXTRA_USER_ID, USER_NULL) : USER_NULL;
195         if (userId == USER_NULL) {
196             throw new IllegalStateException("Arguments to this fragment must contain the user id");
197         }
198         boolean isNewUser =
199                 arguments.getBoolean(AppRestrictionsFragment.EXTRA_NEW_USER, false);
200         mUserInfo = mUserManager.getUserInfo(userId);
201 
202         mSwitchUserPref = findPreference(KEY_SWITCH_USER);
203         mPhonePref = findPreference(KEY_ENABLE_TELEPHONY);
204         mRemoveUserPref = findPreference(KEY_REMOVE_USER);
205         mAppAndContentAccessPref = findPreference(KEY_APP_AND_CONTENT_ACCESS);
206 
207         mSwitchUserPref.setTitle(
208                 context.getString(com.android.settingslib.R.string.user_switch_to_user,
209                         mUserInfo.name));
210 
211         if (mUserCaps.mDisallowSwitchUser) {
212             mSwitchUserPref.setDisabledByAdmin(RestrictedLockUtilsInternal.getDeviceOwner(context));
213         } else {
214             mSwitchUserPref.setDisabledByAdmin(null);
215             mSwitchUserPref.setSelectable(true);
216             mSwitchUserPref.setOnPreferenceClickListener(this);
217         }
218 
219         if (!mUserManager.isAdminUser()) { // non admin users can't remove users and allow calls
220             removePreference(KEY_ENABLE_TELEPHONY);
221             removePreference(KEY_REMOVE_USER);
222             removePreference(KEY_APP_AND_CONTENT_ACCESS);
223         } else {
224             if (!Utils.isVoiceCapable(context)) { // no telephony
225                 removePreference(KEY_ENABLE_TELEPHONY);
226             }
227 
228             if (mUserInfo.isRestricted()) {
229                 removePreference(KEY_ENABLE_TELEPHONY);
230                 if (isNewUser) {
231                     // for newly created restricted users we should open the apps and content access
232                     // screen to initialize the default restrictions
233                     openAppAndContentAccessScreen(true);
234                 }
235             } else {
236                 removePreference(KEY_APP_AND_CONTENT_ACCESS);
237             }
238 
239             if (mUserInfo.isGuest()) {
240                 // These are not for an existing user, just general Guest settings.
241                 // Default title is for calling and SMS. Change to calling-only here
242                 mPhonePref.setTitle(R.string.user_enable_calling);
243                 mDefaultGuestRestrictions = mUserManager.getDefaultGuestRestrictions();
244                 mPhonePref.setChecked(
245                         !mDefaultGuestRestrictions.getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
246                 mRemoveUserPref.setTitle(R.string.user_exit_guest_title);
247             } else {
248                 mPhonePref.setChecked(!mUserManager.hasUserRestriction(
249                         UserManager.DISALLOW_OUTGOING_CALLS, new UserHandle(userId)));
250                 mRemoveUserPref.setTitle(R.string.user_remove_user);
251             }
252             if (RestrictedLockUtilsInternal.hasBaseUserRestriction(context,
253                     UserManager.DISALLOW_REMOVE_USER, UserHandle.myUserId())) {
254                 removePreference(KEY_REMOVE_USER);
255             }
256 
257             mRemoveUserPref.setOnPreferenceClickListener(this);
258             mPhonePref.setOnPreferenceChangeListener(this);
259             mAppAndContentAccessPref.setOnPreferenceClickListener(this);
260         }
261     }
262 
263     @VisibleForTesting
264     boolean canDeleteUser() {
265         if (!mUserManager.isAdminUser()) {
266             return false;
267         }
268 
269         Context context = getActivity();
270         if (context == null) {
271             return false;
272         }
273 
274         final RestrictedLockUtils.EnforcedAdmin removeDisallowedAdmin =
275                 RestrictedLockUtilsInternal.checkIfRestrictionEnforced(context,
276                         UserManager.DISALLOW_REMOVE_USER, UserHandle.myUserId());
277         if (removeDisallowedAdmin != null) {
278             RestrictedLockUtils.sendShowAdminSupportDetailsIntent(context,
279                     removeDisallowedAdmin);
280             return false;
281         }
282         return true;
283     }
284 
285     @VisibleForTesting
286     boolean canSwitchUserNow() {
287         return mUserManager.getUserSwitchability() == UserManager.SWITCHABILITY_STATUS_OK;
288     }
289 
290     @VisibleForTesting
291     void switchUser() {
292         try {
293             ActivityManager.getService().switchUser(mUserInfo.id);
294         } catch (RemoteException re) {
295             Log.e(TAG, "Error while switching to other user.");
296         } finally {
297             finishFragment();
298         }
299     }
300 
301     private void enableCallsAndSms(boolean enabled) {
302         mPhonePref.setChecked(enabled);
303         if (mUserInfo.isGuest()) {
304             mDefaultGuestRestrictions.putBoolean(UserManager.DISALLOW_OUTGOING_CALLS, !enabled);
305             // SMS is always disabled for guest
306             mDefaultGuestRestrictions.putBoolean(UserManager.DISALLOW_SMS, true);
307             mUserManager.setDefaultGuestRestrictions(mDefaultGuestRestrictions);
308 
309             // Update the guest's restrictions, if there is a guest
310             // TODO: Maybe setDefaultGuestRestrictions() can internally just set the restrictions
311             // on any existing guest rather than do it here with multiple Binder calls.
312             List<UserInfo> users = mUserManager.getUsers(true);
313             for (UserInfo user : users) {
314                 if (user.isGuest()) {
315                     UserHandle userHandle = UserHandle.of(user.id);
316                     for (String key : mDefaultGuestRestrictions.keySet()) {
317                         mUserManager.setUserRestriction(
318                                 key, mDefaultGuestRestrictions.getBoolean(key), userHandle);
319                     }
320                 }
321             }
322         } else {
323             UserHandle userHandle = UserHandle.of(mUserInfo.id);
324             mUserManager.setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, !enabled,
325                     userHandle);
326             mUserManager.setUserRestriction(UserManager.DISALLOW_SMS, !enabled, userHandle);
327         }
328     }
329 
330     private void removeUser() {
331         mUserManager.removeUser(mUserInfo.id);
332         finishFragment();
333     }
334 
335     /**
336      * @param isNewUser indicates if a user was created recently, for new users
337      *                  AppRestrictionsFragment should set the default restrictions
338      */
339     private void openAppAndContentAccessScreen(boolean isNewUser) {
340         Bundle extras = new Bundle();
341         extras.putInt(AppRestrictionsFragment.EXTRA_USER_ID, mUserInfo.id);
342         extras.putBoolean(AppRestrictionsFragment.EXTRA_NEW_USER, isNewUser);
343         new SubSettingLauncher(getContext())
344                 .setDestination(AppRestrictionsFragment.class.getName())
345                 .setArguments(extras)
346                 .setTitleRes(R.string.user_restrictions_title)
347                 .setSourceMetricsCategory(getMetricsCategory())
348                 .launch();
349     }
350 
351     private boolean isSecondaryUser(UserInfo user) {
352         return UserManager.USER_TYPE_FULL_SECONDARY.equals(user.userType);
353     }
354 
355     private boolean shouldShowSetupPromptDialog() {
356         // TODO: FLAG_INITIALIZED is set when a user is switched to for the first time,
357         //  but what we would really need here is a flag that shows if the setup process was
358         //  completed. After the user cancels the setup process, mUserInfo.isInitialized() will
359         //  return true so there will be no setup prompt dialog shown to the user anymore.
360         return isSecondaryUser(mUserInfo) && !mUserInfo.isInitialized();
361     }
362 }
363