OSDN Git Service

Set the default user restrictions to disallow calling and sms
[android-x86/frameworks-base.git] / packages / SystemUI / src / com / android / systemui / statusbar / policy / UserSwitcherController.java
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.systemui.statusbar.policy;
18
19 import android.app.ActivityManager;
20 import android.app.ActivityManagerNative;
21 import android.app.Dialog;
22 import android.content.BroadcastReceiver;
23 import android.content.Context;
24 import android.content.DialogInterface;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.content.pm.UserInfo;
28 import android.database.ContentObserver;
29 import android.graphics.Bitmap;
30 import android.graphics.drawable.Drawable;
31 import android.os.AsyncTask;
32 import android.os.Handler;
33 import android.os.RemoteException;
34 import android.os.UserHandle;
35 import android.os.UserManager;
36 import android.provider.Settings;
37 import android.util.Log;
38 import android.util.SparseArray;
39 import android.view.View;
40 import android.view.ViewGroup;
41 import android.widget.BaseAdapter;
42
43 import com.android.internal.util.UserIcons;
44 import com.android.systemui.BitmapHelper;
45 import com.android.systemui.GuestResumeSessionReceiver;
46 import com.android.systemui.R;
47 import com.android.systemui.qs.QSTile;
48 import com.android.systemui.qs.tiles.UserDetailView;
49 import com.android.systemui.statusbar.phone.SystemUIDialog;
50
51 import java.io.FileDescriptor;
52 import java.io.PrintWriter;
53 import java.lang.ref.WeakReference;
54 import java.util.ArrayList;
55 import java.util.List;
56
57 /**
58  * Keeps a list of all users on the device for user switching.
59  */
60 public class UserSwitcherController {
61
62     private static final String TAG = "UserSwitcherController";
63     private static final boolean DEBUG = false;
64     private static final String SIMPLE_USER_SWITCHER_GLOBAL_SETTING =
65             "lockscreenSimpleUserSwitcher";
66
67     private final Context mContext;
68     private final UserManager mUserManager;
69     private final ArrayList<WeakReference<BaseUserAdapter>> mAdapters = new ArrayList<>();
70     private final GuestResumeSessionReceiver mGuestResumeSessionReceiver
71             = new GuestResumeSessionReceiver();
72     private final KeyguardMonitor mKeyguardMonitor;
73
74     private ArrayList<UserRecord> mUsers = new ArrayList<>();
75     private Dialog mExitGuestDialog;
76     private Dialog mAddUserDialog;
77     private int mLastNonGuestUser = UserHandle.USER_OWNER;
78     private boolean mSimpleUserSwitcher;
79     private boolean mAddUsersWhenLocked;
80
81     public UserSwitcherController(Context context, KeyguardMonitor keyguardMonitor) {
82         mContext = context;
83         mGuestResumeSessionReceiver.register(context);
84         mKeyguardMonitor = keyguardMonitor;
85         mUserManager = UserManager.get(context);
86         IntentFilter filter = new IntentFilter();
87         filter.addAction(Intent.ACTION_USER_ADDED);
88         filter.addAction(Intent.ACTION_USER_REMOVED);
89         filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
90         filter.addAction(Intent.ACTION_USER_SWITCHED);
91         filter.addAction(Intent.ACTION_USER_STOPPING);
92         mContext.registerReceiverAsUser(mReceiver, UserHandle.OWNER, filter,
93                 null /* permission */, null /* scheduler */);
94
95
96         mContext.getContentResolver().registerContentObserver(
97                 Settings.Global.getUriFor(SIMPLE_USER_SWITCHER_GLOBAL_SETTING), true,
98                 mSettingsObserver);
99         mContext.getContentResolver().registerContentObserver(
100                 Settings.Global.getUriFor(Settings.Global.ADD_USERS_WHEN_LOCKED), true,
101                 mSettingsObserver);
102         // Fetch initial values.
103         mSettingsObserver.onChange(false);
104
105         keyguardMonitor.addCallback(mCallback);
106
107         refreshUsers(UserHandle.USER_NULL);
108     }
109
110     /**
111      * Refreshes users from UserManager.
112      *
113      * The pictures are only loaded if they have not been loaded yet.
114      *
115      * @param forcePictureLoadForId forces the picture of the given user to be reloaded.
116      */
117     @SuppressWarnings("unchecked")
118     private void refreshUsers(int forcePictureLoadForId) {
119
120         SparseArray<Bitmap> bitmaps = new SparseArray<>(mUsers.size());
121         final int N = mUsers.size();
122         for (int i = 0; i < N; i++) {
123             UserRecord r = mUsers.get(i);
124             if (r == null || r.info == null
125                     || r.info.id == forcePictureLoadForId || r.picture == null) {
126                 continue;
127             }
128             bitmaps.put(r.info.id, r.picture);
129         }
130
131         final boolean addUsersWhenLocked = mAddUsersWhenLocked;
132         new AsyncTask<SparseArray<Bitmap>, Void, ArrayList<UserRecord>>() {
133             @SuppressWarnings("unchecked")
134             @Override
135             protected ArrayList<UserRecord> doInBackground(SparseArray<Bitmap>... params) {
136                 final SparseArray<Bitmap> bitmaps = params[0];
137                 List<UserInfo> infos = mUserManager.getUsers(true);
138                 if (infos == null) {
139                     return null;
140                 }
141                 ArrayList<UserRecord> records = new ArrayList<>(infos.size());
142                 int currentId = ActivityManager.getCurrentUser();
143                 UserRecord guestRecord = null;
144                 int avatarSize = mContext.getResources()
145                         .getDimensionPixelSize(R.dimen.max_avatar_size);
146
147                 for (UserInfo info : infos) {
148                     boolean isCurrent = currentId == info.id;
149                     if (info.isGuest()) {
150                         guestRecord = new UserRecord(info, null /* picture */,
151                                 true /* isGuest */, isCurrent, false /* isAddUser */,
152                                 false /* isRestricted */);
153                     } else if (info.supportsSwitchTo()) {
154                         Bitmap picture = bitmaps.get(info.id);
155                         if (picture == null) {
156                             picture = mUserManager.getUserIcon(info.id);
157                         }
158                         if (picture != null) {
159                             picture = BitmapHelper.createCircularClip(
160                                     picture, avatarSize, avatarSize);
161                         }
162                         int index = isCurrent ? 0 : records.size();
163                         records.add(index, new UserRecord(info, picture, false /* isGuest */,
164                                 isCurrent, false /* isAddUser */, false /* isRestricted */));
165                     }
166                 }
167
168                 boolean ownerCanCreateUsers = !mUserManager.hasUserRestriction(
169                         UserManager.DISALLOW_ADD_USER, UserHandle.OWNER);
170                 boolean currentUserCanCreateUsers =
171                         (currentId == UserHandle.USER_OWNER) && ownerCanCreateUsers;
172                 boolean anyoneCanCreateUsers = ownerCanCreateUsers && addUsersWhenLocked;
173                 boolean canCreateGuest = (currentUserCanCreateUsers || anyoneCanCreateUsers)
174                         && guestRecord == null;
175                 boolean canCreateUser = (currentUserCanCreateUsers || anyoneCanCreateUsers)
176                         && mUserManager.canAddMoreUsers();
177                 boolean createIsRestricted = !addUsersWhenLocked;
178
179                 if (!mSimpleUserSwitcher) {
180                     if (guestRecord == null) {
181                         if (canCreateGuest) {
182                             records.add(new UserRecord(null /* info */, null /* picture */,
183                                     true /* isGuest */, false /* isCurrent */,
184                                     false /* isAddUser */, createIsRestricted));
185                         }
186                     } else {
187                         int index = guestRecord.isCurrent ? 0 : records.size();
188                         records.add(index, guestRecord);
189                     }
190                 }
191
192                 if (!mSimpleUserSwitcher && canCreateUser) {
193                     records.add(new UserRecord(null /* info */, null /* picture */,
194                             false /* isGuest */, false /* isCurrent */, true /* isAddUser */,
195                             createIsRestricted));
196                 }
197
198                 return records;
199             }
200
201             @Override
202             protected void onPostExecute(ArrayList<UserRecord> userRecords) {
203                 if (userRecords != null) {
204                     mUsers = userRecords;
205                     notifyAdapters();
206                 }
207             }
208         }.execute((SparseArray) bitmaps);
209     }
210
211     private void notifyAdapters() {
212         for (int i = mAdapters.size() - 1; i >= 0; i--) {
213             BaseUserAdapter adapter = mAdapters.get(i).get();
214             if (adapter != null) {
215                 adapter.notifyDataSetChanged();
216             } else {
217                 mAdapters.remove(i);
218             }
219         }
220     }
221
222     public boolean isSimpleUserSwitcher() {
223         return mSimpleUserSwitcher;
224     }
225
226     public void switchTo(UserRecord record) {
227         int id;
228         if (record.isGuest && record.info == null) {
229             // No guest user. Create one.
230             UserInfo guest = mUserManager.createGuest(
231                     mContext, mContext.getString(R.string.guest_nickname));
232             if (guest == null) {
233                 // Couldn't create guest, most likely because there already exists one, we just
234                 // haven't reloaded the user list yet.
235                 return;
236             }
237             id = guest.id;
238         } else if (record.isAddUser) {
239             showAddUserDialog();
240             return;
241         } else {
242             id = record.info.id;
243         }
244
245         if (ActivityManager.getCurrentUser() == id) {
246             if (record.isGuest) {
247                 showExitGuestDialog(id);
248             }
249             return;
250         }
251
252         switchToUserId(id);
253     }
254
255     private void switchToUserId(int id) {
256         try {
257             ActivityManagerNative.getDefault().switchUser(id);
258         } catch (RemoteException e) {
259             Log.e(TAG, "Couldn't switch user.", e);
260         }
261     }
262
263     private void showExitGuestDialog(int id) {
264         if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) {
265             mExitGuestDialog.cancel();
266         }
267         mExitGuestDialog = new ExitGuestDialog(mContext, id);
268         mExitGuestDialog.show();
269     }
270
271     private void showAddUserDialog() {
272         if (mAddUserDialog != null && mAddUserDialog.isShowing()) {
273             mAddUserDialog.cancel();
274         }
275         mAddUserDialog = new AddUserDialog(mContext);
276         mAddUserDialog.show();
277     }
278
279     private void exitGuest(int id) {
280         int newId = UserHandle.USER_OWNER;
281         if (mLastNonGuestUser != UserHandle.USER_OWNER) {
282             UserInfo info = mUserManager.getUserInfo(mLastNonGuestUser);
283             if (info != null && info.isEnabled() && info.supportsSwitchTo()) {
284                 newId = info.id;
285             }
286         }
287         switchToUserId(newId);
288         mUserManager.removeUser(id);
289     }
290
291     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
292         @Override
293         public void onReceive(Context context, Intent intent) {
294             if (DEBUG) {
295                 Log.v(TAG, "Broadcast: a=" + intent.getAction()
296                        + " user=" + intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
297             }
298             if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
299                 if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) {
300                     mExitGuestDialog.cancel();
301                     mExitGuestDialog = null;
302                 }
303
304                 final int currentId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
305                 final int N = mUsers.size();
306                 for (int i = 0; i < N; i++) {
307                     UserRecord record = mUsers.get(i);
308                     if (record.info == null) continue;
309                     boolean shouldBeCurrent = record.info.id == currentId;
310                     if (record.isCurrent != shouldBeCurrent) {
311                         mUsers.set(i, record.copyWithIsCurrent(shouldBeCurrent));
312                     }
313                     if (shouldBeCurrent && !record.isGuest) {
314                         mLastNonGuestUser = record.info.id;
315                     }
316                     if (currentId != UserHandle.USER_OWNER && record.isRestricted) {
317                         // Immediately remove restricted records in case the AsyncTask is too slow.
318                         mUsers.remove(i);
319                         i--;
320                     }
321                 }
322                 notifyAdapters();
323             }
324             int forcePictureLoadForId = UserHandle.USER_NULL;
325             if (Intent.ACTION_USER_INFO_CHANGED.equals(intent.getAction())) {
326                 forcePictureLoadForId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
327                         UserHandle.USER_NULL);
328             }
329             refreshUsers(forcePictureLoadForId);
330         }
331     };
332
333     private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
334         public void onChange(boolean selfChange) {
335             mSimpleUserSwitcher = Settings.Global.getInt(mContext.getContentResolver(),
336                     SIMPLE_USER_SWITCHER_GLOBAL_SETTING, 0) != 0;
337             mAddUsersWhenLocked = Settings.Global.getInt(mContext.getContentResolver(),
338                     Settings.Global.ADD_USERS_WHEN_LOCKED, 0) != 0;
339             refreshUsers(UserHandle.USER_NULL);
340         };
341     };
342
343     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
344         pw.println("UserSwitcherController state:");
345         pw.println("  mLastNonGuestUser=" + mLastNonGuestUser);
346         pw.print("  mUsers.size="); pw.println(mUsers.size());
347         for (int i = 0; i < mUsers.size(); i++) {
348             final UserRecord u = mUsers.get(i);
349             pw.print("    "); pw.println(u.toString());
350         }
351     }
352
353     public String getCurrentUserName(Context context) {
354         if (mUsers.isEmpty()) return null;
355         UserRecord item = mUsers.get(0);
356         if (item == null || item.info == null) return null;
357         if (item.isGuest) return context.getString(R.string.guest_nickname);
358         return item.info.name;
359     }
360
361     public static abstract class BaseUserAdapter extends BaseAdapter {
362
363         final UserSwitcherController mController;
364
365         protected BaseUserAdapter(UserSwitcherController controller) {
366             mController = controller;
367             controller.mAdapters.add(new WeakReference<>(this));
368         }
369
370         @Override
371         public int getCount() {
372             boolean secureKeyguardShowing = mController.mKeyguardMonitor.isShowing()
373                     && mController.mKeyguardMonitor.isSecure();
374             if (!secureKeyguardShowing) {
375                 return mController.mUsers.size();
376             }
377             // The lock screen is secure and showing. Filter out restricted records.
378             final int N = mController.mUsers.size();
379             int count = 0;
380             for (int i = 0; i < N; i++) {
381                 if (mController.mUsers.get(i).isRestricted) {
382                     break;
383                 } else {
384                     count++;
385                 }
386             }
387             return count;
388         }
389
390         @Override
391         public UserRecord getItem(int position) {
392             return mController.mUsers.get(position);
393         }
394
395         @Override
396         public long getItemId(int position) {
397             return position;
398         }
399
400         public void switchTo(UserRecord record) {
401             mController.switchTo(record);
402         }
403
404         public String getName(Context context, UserRecord item) {
405             if (item.isGuest) {
406                 if (item.isCurrent) {
407                     return context.getString(R.string.guest_exit_guest);
408                 } else {
409                     return context.getString(
410                             item.info == null ? R.string.guest_new_guest : R.string.guest_nickname);
411                 }
412             } else if (item.isAddUser) {
413                 return context.getString(R.string.user_add_user);
414             } else {
415                 return item.info.name;
416             }
417         }
418
419         public int getSwitchableUsers() {
420             int result = 0;
421             ArrayList<UserRecord> users = mController.mUsers;
422             int N = users.size();
423             for (int i = 0; i < N; i++) {
424                 if (users.get(i).info != null) {
425                     result++;
426                 }
427             }
428             return result;
429         }
430
431         public Drawable getDrawable(Context context, UserRecord item) {
432             if (item.isAddUser) {
433                 return context.getDrawable(R.drawable.ic_add_circle_qs);
434             }
435             return UserIcons.getDefaultUserIcon(item.isGuest ? UserHandle.USER_NULL : item.info.id,
436                     /* light= */ true);
437         }
438     }
439
440     public static final class UserRecord {
441         public final UserInfo info;
442         public final Bitmap picture;
443         public final boolean isGuest;
444         public final boolean isCurrent;
445         public final boolean isAddUser;
446         /** If true, the record is only visible to the owner and only when unlocked. */
447         public final boolean isRestricted;
448
449         public UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent,
450                 boolean isAddUser, boolean isRestricted) {
451             this.info = info;
452             this.picture = picture;
453             this.isGuest = isGuest;
454             this.isCurrent = isCurrent;
455             this.isAddUser = isAddUser;
456             this.isRestricted = isRestricted;
457         }
458
459         public UserRecord copyWithIsCurrent(boolean _isCurrent) {
460             return new UserRecord(info, picture, isGuest, _isCurrent, isAddUser, isRestricted);
461         }
462
463         public String toString() {
464             StringBuilder sb = new StringBuilder();
465             sb.append("UserRecord(");
466             if (info != null) {
467                 sb.append("name=\"" + info.name + "\" id=" + info.id);
468             } else {
469                 if (isGuest) {
470                     sb.append("<add guest placeholder>");
471                 } else if (isAddUser) {
472                     sb.append("<add user placeholder>");
473                 }
474             }
475             if (isGuest) sb.append(" <isGuest>");
476             if (isAddUser) sb.append(" <isAddUser>");
477             if (isCurrent) sb.append(" <isCurrent>");
478             if (picture != null) sb.append(" <hasPicture>");
479             if (isRestricted) sb.append(" <isRestricted>");
480             sb.append(')');
481             return sb.toString();
482         }
483     }
484
485     public final QSTile.DetailAdapter userDetailAdapter = new QSTile.DetailAdapter() {
486         private final Intent USER_SETTINGS_INTENT = new Intent("android.settings.USER_SETTINGS");
487
488         @Override
489         public int getTitle() {
490             return R.string.quick_settings_user_title;
491         }
492
493         @Override
494         public View createDetailView(Context context, View convertView, ViewGroup parent) {
495             UserDetailView v;
496             if (!(convertView instanceof UserDetailView)) {
497                 v = UserDetailView.inflate(context, parent, false);
498                 v.createAndSetAdapter(UserSwitcherController.this);
499             } else {
500                 v = (UserDetailView) convertView;
501             }
502             return v;
503         }
504
505         @Override
506         public Intent getSettingsIntent() {
507             return USER_SETTINGS_INTENT;
508         }
509
510         @Override
511         public Boolean getToggleState() {
512             return null;
513         }
514
515         @Override
516         public void setToggleState(boolean state) {
517         }
518     };
519
520     private final KeyguardMonitor.Callback mCallback = new KeyguardMonitor.Callback() {
521         @Override
522         public void onKeyguardChanged() {
523             notifyAdapters();
524         }
525     };
526
527     private final class ExitGuestDialog extends SystemUIDialog implements
528             DialogInterface.OnClickListener {
529
530         private final int mGuestId;
531
532         public ExitGuestDialog(Context context, int guestId) {
533             super(context);
534             setTitle(R.string.guest_exit_guest_dialog_title);
535             setMessage(context.getString(R.string.guest_exit_guest_dialog_message));
536             setButton(DialogInterface.BUTTON_NEGATIVE,
537                     context.getString(android.R.string.cancel), this);
538             setButton(DialogInterface.BUTTON_POSITIVE,
539                     context.getString(R.string.guest_exit_guest_dialog_remove), this);
540             setCanceledOnTouchOutside(false);
541             mGuestId = guestId;
542         }
543
544         @Override
545         public void onClick(DialogInterface dialog, int which) {
546             if (which == BUTTON_NEGATIVE) {
547                 cancel();
548             } else {
549                 dismiss();
550                 exitGuest(mGuestId);
551             }
552         }
553     }
554
555     private final class AddUserDialog extends SystemUIDialog implements
556             DialogInterface.OnClickListener {
557
558         public AddUserDialog(Context context) {
559             super(context);
560             setTitle(R.string.user_add_user_title);
561             setMessage(context.getString(R.string.user_add_user_message_short));
562             setButton(DialogInterface.BUTTON_NEGATIVE,
563                     context.getString(android.R.string.cancel), this);
564             setButton(DialogInterface.BUTTON_POSITIVE,
565                     context.getString(android.R.string.ok), this);
566         }
567
568         @Override
569         public void onClick(DialogInterface dialog, int which) {
570             if (which == BUTTON_NEGATIVE) {
571                 cancel();
572             } else {
573                 dismiss();
574                 UserInfo user = mUserManager.createSecondaryUser(
575                         mContext.getString(R.string.user_new_user_name), 0 /* flags */);
576                 if (user == null) {
577                     // Couldn't create user, most likely because there are too many, but we haven't
578                     // been able to reload the list yet.
579                     return;
580                 }
581                 int id = user.id;
582                 Bitmap icon = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(
583                         id, /* light= */ false));
584                 mUserManager.setUserIcon(id, icon);
585                 switchToUserId(id);
586             }
587         }
588     }
589 }