blob: 1287ced8594c48d56a6cde8e8a1f0239bc0b18ea [file] [log] [blame]
Eliot Courtney09322282017-11-09 15:31:19 +09001/*
2 * Copyright (C) 2017 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 */
16package com.android.systemui.statusbar;
17
18import android.app.ActivityManager;
19import android.app.Notification;
20import android.app.admin.DevicePolicyManager;
21import android.content.BroadcastReceiver;
22import android.content.Context;
23import android.content.Intent;
24import android.content.IntentFilter;
25import android.content.IntentSender;
26import android.content.pm.UserInfo;
27import android.database.ContentObserver;
28import android.os.RemoteException;
29import android.os.ServiceManager;
30import android.os.UserHandle;
31import android.os.UserManager;
32import android.provider.Settings;
33import android.service.notification.StatusBarNotification;
34import android.util.Log;
35import android.util.SparseArray;
36import android.util.SparseBooleanArray;
37import android.widget.TextView;
38import android.widget.Toast;
39
40import com.android.internal.statusbar.IStatusBarService;
Dieter Hsud39f0d52018-04-14 02:08:30 +080041import com.android.internal.statusbar.NotificationVisibility;
Lucas Dupin16013822018-05-17 18:00:16 -070042import com.android.keyguard.KeyguardUpdateMonitor;
Eliot Courtney09322282017-11-09 15:31:19 +090043import com.android.systemui.Dependency;
44import com.android.systemui.Dumpable;
45import com.android.systemui.OverviewProxyService;
46import com.android.systemui.R;
47import com.android.systemui.statusbar.policy.DeviceProvisionedController;
48
49import java.io.FileDescriptor;
50import java.io.PrintWriter;
Eliot Courtney09322282017-11-09 15:31:19 +090051
52/**
53 * Handles keeping track of the current user, profiles, and various things related to hiding
54 * contents, redacting notifications, and the lockscreen.
55 */
56public class NotificationLockscreenUserManager implements Dumpable {
57 private static final String TAG = "LockscreenUserManager";
58 private static final boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false;
59 public static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
60 public static final String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION
61 = "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
62
63 private final DevicePolicyManager mDevicePolicyManager;
64 private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray();
65 private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
66 private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
67 private final DeviceProvisionedController mDeviceProvisionedController =
68 Dependency.get(DeviceProvisionedController.class);
69 private final UserManager mUserManager;
70 private final IStatusBarService mBarService;
71
72 private boolean mShowLockscreenNotifications;
73 private boolean mAllowLockscreenRemoteInput;
74
75 protected final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
76 @Override
77 public void onReceive(Context context, Intent intent) {
78 final String action = intent.getAction();
79 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
80
81 if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
82 isCurrentProfile(getSendingUserId())) {
83 mUsersAllowingPrivateNotifications.clear();
84 updateLockscreenNotificationSetting();
Eliot Courtney4a96b362017-12-14 19:38:52 +090085 mEntryManager.updateNotifications();
Eliot Courtney09322282017-11-09 15:31:19 +090086 } else if (Intent.ACTION_DEVICE_LOCKED_CHANGED.equals(action)) {
87 if (userId != mCurrentUserId && isCurrentProfile(userId)) {
88 mPresenter.onWorkChallengeChanged();
89 }
90 }
91 }
92 };
93
94 protected final BroadcastReceiver mBaseBroadcastReceiver = new BroadcastReceiver() {
95 @Override
96 public void onReceive(Context context, Intent intent) {
97 String action = intent.getAction();
98 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
99 mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
100 updateCurrentProfilesCache();
101 Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
102
103 updateLockscreenNotificationSetting();
104
105 mPresenter.onUserSwitched(mCurrentUserId);
106 } else if (Intent.ACTION_USER_ADDED.equals(action)) {
107 updateCurrentProfilesCache();
108 } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
109 // Start the overview connection to the launcher service
110 Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser();
111 } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
Eliot Courtney09322282017-11-09 15:31:19 +0900112 try {
Tony Mak90f203c2017-12-27 14:18:49 +0000113 final int lastResumedActivityUserId =
114 ActivityManager.getService().getLastResumedActivityUserId();
115 if (mUserManager.isManagedProfile(lastResumedActivityUserId)) {
116 showForegroundManagedProfileActivityToast();
117 }
Eliot Courtney09322282017-11-09 15:31:19 +0900118 } catch (RemoteException e) {
119 // Abandon hope activity manager not running.
120 }
Eliot Courtney09322282017-11-09 15:31:19 +0900121 } else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) {
122 final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
123 final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
124 if (intentSender != null) {
125 try {
126 mContext.startIntentSender(intentSender, null, 0, 0, 0);
127 } catch (IntentSender.SendIntentException e) {
128 /* ignore */
129 }
130 }
131 if (notificationKey != null) {
Dieter Hsud39f0d52018-04-14 02:08:30 +0800132 final int count =
133 mEntryManager.getNotificationData().getActiveNotifications().size();
134 final int rank = mEntryManager.getNotificationData().getRank(notificationKey);
135 final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
136 rank, count, true);
Eliot Courtney09322282017-11-09 15:31:19 +0900137 try {
Dieter Hsud39f0d52018-04-14 02:08:30 +0800138 mBarService.onNotificationClick(notificationKey, nv);
Eliot Courtney09322282017-11-09 15:31:19 +0900139 } catch (RemoteException e) {
140 /* ignore */
141 }
142 }
143 }
144 }
145 };
146
147 protected final Context mContext;
148 protected final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
149
150 protected int mCurrentUserId = 0;
151 protected NotificationPresenter mPresenter;
Eliot Courtney4a96b362017-12-14 19:38:52 +0900152 protected NotificationEntryManager mEntryManager;
Eliot Courtney09322282017-11-09 15:31:19 +0900153 protected ContentObserver mLockscreenSettingsObserver;
154 protected ContentObserver mSettingsObserver;
155
156 public NotificationLockscreenUserManager(Context context) {
157 mContext = context;
158 mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
159 Context.DEVICE_POLICY_SERVICE);
160 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
161 mCurrentUserId = ActivityManager.getCurrentUser();
162 mBarService = IStatusBarService.Stub.asInterface(
163 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
164 }
165
Eliot Courtney4a96b362017-12-14 19:38:52 +0900166 public void setUpWithPresenter(NotificationPresenter presenter,
167 NotificationEntryManager entryManager) {
Eliot Courtney09322282017-11-09 15:31:19 +0900168 mPresenter = presenter;
Eliot Courtney4a96b362017-12-14 19:38:52 +0900169 mEntryManager = entryManager;
Eliot Courtney09322282017-11-09 15:31:19 +0900170
171 mLockscreenSettingsObserver = new ContentObserver(mPresenter.getHandler()) {
172 @Override
173 public void onChange(boolean selfChange) {
174 // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS or
175 // LOCK_SCREEN_SHOW_NOTIFICATIONS, so we just dump our cache ...
176 mUsersAllowingPrivateNotifications.clear();
177 mUsersAllowingNotifications.clear();
178 // ... and refresh all the notifications
179 updateLockscreenNotificationSetting();
Eliot Courtney4a96b362017-12-14 19:38:52 +0900180 mEntryManager.updateNotifications();
Eliot Courtney09322282017-11-09 15:31:19 +0900181 }
182 };
183
184 mSettingsObserver = new ContentObserver(mPresenter.getHandler()) {
185 @Override
186 public void onChange(boolean selfChange) {
187 updateLockscreenNotificationSetting();
188 if (mDeviceProvisionedController.isDeviceProvisioned()) {
Eliot Courtney4a96b362017-12-14 19:38:52 +0900189 mEntryManager.updateNotifications();
Eliot Courtney09322282017-11-09 15:31:19 +0900190 }
191 }
192 };
193
194 mContext.getContentResolver().registerContentObserver(
195 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
196 mLockscreenSettingsObserver,
197 UserHandle.USER_ALL);
198
199 mContext.getContentResolver().registerContentObserver(
200 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
201 true,
202 mLockscreenSettingsObserver,
203 UserHandle.USER_ALL);
204
205 mContext.getContentResolver().registerContentObserver(
206 Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
207 mSettingsObserver);
208
209 if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
210 mContext.getContentResolver().registerContentObserver(
211 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT),
212 false,
213 mSettingsObserver,
214 UserHandle.USER_ALL);
215 }
216
217 IntentFilter allUsersFilter = new IntentFilter();
218 allUsersFilter.addAction(
219 DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
220 allUsersFilter.addAction(Intent.ACTION_DEVICE_LOCKED_CHANGED);
221 mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter,
222 null, null);
223
224 IntentFilter filter = new IntentFilter();
225 filter.addAction(Intent.ACTION_USER_SWITCHED);
226 filter.addAction(Intent.ACTION_USER_ADDED);
227 filter.addAction(Intent.ACTION_USER_PRESENT);
228 filter.addAction(Intent.ACTION_USER_UNLOCKED);
229 mContext.registerReceiver(mBaseBroadcastReceiver, filter);
230
231 IntentFilter internalFilter = new IntentFilter();
232 internalFilter.addAction(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
233 mContext.registerReceiver(mBaseBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
234
235 updateCurrentProfilesCache();
236
237 mSettingsObserver.onChange(false); // set up
238 }
239
Tony Mak90f203c2017-12-27 14:18:49 +0000240 private void showForegroundManagedProfileActivityToast() {
241 Toast toast = Toast.makeText(mContext,
242 R.string.managed_profile_foreground_toast,
243 Toast.LENGTH_SHORT);
244 TextView text = toast.getView().findViewById(android.R.id.message);
245 text.setCompoundDrawablesRelativeWithIntrinsicBounds(
246 R.drawable.stat_sys_managed_profile_status, 0, 0, 0);
247 int paddingPx = mContext.getResources().getDimensionPixelSize(
248 R.dimen.managed_profile_toast_padding);
249 text.setCompoundDrawablePadding(paddingPx);
250 toast.show();
251 }
252
Eliot Courtney09322282017-11-09 15:31:19 +0900253 public boolean shouldShowLockscreenNotifications() {
254 return mShowLockscreenNotifications;
255 }
256
257 public boolean shouldAllowLockscreenRemoteInput() {
258 return mAllowLockscreenRemoteInput;
259 }
260
261 public boolean isCurrentProfile(int userId) {
262 synchronized (mCurrentProfiles) {
263 return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
264 }
265 }
266
267 /**
Chad Brubakerea8c5ef2018-03-15 16:37:43 -0700268 * Returns true if notifications are temporarily disabled for this user for security reasons,
269 * regardless of the normal settings for that user.
270 */
271 private boolean shouldTemporarilyHideNotifications(int userId) {
272 if (userId == UserHandle.USER_ALL) {
273 userId = mCurrentUserId;
274 }
Lucas Dupin16013822018-05-17 18:00:16 -0700275 return KeyguardUpdateMonitor.getInstance(mContext).isUserInLockdown(userId);
Chad Brubakerea8c5ef2018-03-15 16:37:43 -0700276 }
277
278 /**
Eliot Courtney09322282017-11-09 15:31:19 +0900279 * Returns true if we're on a secure lockscreen and the user wants to hide notification data.
280 * If so, notifications should be hidden.
281 */
282 public boolean shouldHideNotifications(int userId) {
283 return isLockscreenPublicMode(userId) && !userAllowsNotificationsInPublic(userId)
Chad Brubakerea8c5ef2018-03-15 16:37:43 -0700284 || (userId != mCurrentUserId && shouldHideNotifications(mCurrentUserId))
285 || shouldTemporarilyHideNotifications(userId);
Eliot Courtney09322282017-11-09 15:31:19 +0900286 }
287
288 /**
289 * Returns true if we're on a secure lockscreen and the user wants to hide notifications via
290 * package-specific override.
291 */
292 public boolean shouldHideNotifications(String key) {
Jeff Sharkey9447b832018-02-03 16:45:45 -0700293 if (mEntryManager == null) {
294 Log.wtf(TAG, "mEntryManager was null!", new Throwable());
295 return true;
296 }
Eliot Courtney09322282017-11-09 15:31:19 +0900297 return isLockscreenPublicMode(mCurrentUserId)
Eliot Courtney4a96b362017-12-14 19:38:52 +0900298 && mEntryManager.getNotificationData().getVisibilityOverride(key) ==
Eliot Courtney09322282017-11-09 15:31:19 +0900299 Notification.VISIBILITY_SECRET;
300 }
301
302 public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
Jeff Sharkey9447b832018-02-03 16:45:45 -0700303 if (mEntryManager == null) {
304 Log.wtf(TAG, "mEntryManager was null!", new Throwable());
305 return false;
306 }
Eliot Courtney09322282017-11-09 15:31:19 +0900307 return mShowLockscreenNotifications
Eliot Courtney4a96b362017-12-14 19:38:52 +0900308 && !mEntryManager.getNotificationData().isAmbient(sbn.getKey());
Eliot Courtney09322282017-11-09 15:31:19 +0900309 }
310
311 private void setShowLockscreenNotifications(boolean show) {
312 mShowLockscreenNotifications = show;
313 }
314
315 private void setLockscreenAllowRemoteInput(boolean allowLockscreenRemoteInput) {
316 mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
317 }
318
319 protected void updateLockscreenNotificationSetting() {
320 final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
321 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
322 1,
323 mCurrentUserId) != 0;
324 final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(
325 null /* admin */, mCurrentUserId);
326 final boolean allowedByDpm = (dpmFlags
327 & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
328
329 setShowLockscreenNotifications(show && allowedByDpm);
330
331 if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
332 final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(),
333 Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
334 0,
335 mCurrentUserId) != 0;
336 final boolean remoteInputDpm =
337 (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0;
338
339 setLockscreenAllowRemoteInput(remoteInput && remoteInputDpm);
340 } else {
341 setLockscreenAllowRemoteInput(false);
342 }
343 }
344
345 /**
346 * Has the given user chosen to allow their private (full) notifications to be shown even
347 * when the lockscreen is in "public" (secure & locked) mode?
348 */
349 public boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
350 if (userHandle == UserHandle.USER_ALL) {
351 return true;
352 }
353
354 if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
355 final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
356 mContext.getContentResolver(),
357 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
Pavel Grafov65152632018-03-26 15:14:45 +0100358 final boolean allowedByDpm = adminAllowsKeyguardFeature(userHandle,
359 DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
Eliot Courtney09322282017-11-09 15:31:19 +0900360 final boolean allowed = allowedByUser && allowedByDpm;
361 mUsersAllowingPrivateNotifications.append(userHandle, allowed);
362 return allowed;
363 }
364
365 return mUsersAllowingPrivateNotifications.get(userHandle);
366 }
367
Pavel Grafov65152632018-03-26 15:14:45 +0100368 private boolean adminAllowsKeyguardFeature(int userHandle, int feature) {
Eliot Courtney09322282017-11-09 15:31:19 +0900369 if (userHandle == UserHandle.USER_ALL) {
370 return true;
371 }
Pavel Grafov65152632018-03-26 15:14:45 +0100372 final int dpmFlags =
373 mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */, userHandle);
374 return (dpmFlags & feature) == 0;
Eliot Courtney09322282017-11-09 15:31:19 +0900375 }
376
377 /**
378 * Save the current "public" (locked and secure) state of the lockscreen.
379 */
380 public void setLockscreenPublicMode(boolean publicMode, int userId) {
381 mLockscreenPublicMode.put(userId, publicMode);
382 }
383
384 public boolean isLockscreenPublicMode(int userId) {
385 if (userId == UserHandle.USER_ALL) {
386 return mLockscreenPublicMode.get(mCurrentUserId, false);
387 }
388 return mLockscreenPublicMode.get(userId, false);
389 }
390
391 /**
392 * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
393 * "public" (secure & locked) mode?
394 */
395 private boolean userAllowsNotificationsInPublic(int userHandle) {
Pavel Grafov65152632018-03-26 15:14:45 +0100396 if (isCurrentProfile(userHandle) && userHandle != mCurrentUserId) {
Eliot Courtney09322282017-11-09 15:31:19 +0900397 return true;
398 }
399
400 if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) {
Pavel Grafov65152632018-03-26 15:14:45 +0100401 final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
Eliot Courtney09322282017-11-09 15:31:19 +0900402 mContext.getContentResolver(),
403 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
Pavel Grafov65152632018-03-26 15:14:45 +0100404 final boolean allowedByDpm = adminAllowsKeyguardFeature(userHandle,
405 DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
406 final boolean allowed = allowedByUser && allowedByDpm;
Eliot Courtney09322282017-11-09 15:31:19 +0900407 mUsersAllowingNotifications.append(userHandle, allowed);
408 return allowed;
409 }
410
411 return mUsersAllowingNotifications.get(userHandle);
412 }
413
414 /** @return true if the entry needs redaction when on the lockscreen. */
415 public boolean needsRedaction(NotificationData.Entry ent) {
416 int userId = ent.notification.getUserId();
417
418 boolean currentUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(mCurrentUserId);
419 boolean notiUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(userId);
420 boolean redactedLockscreen = currentUserWantsRedaction || notiUserWantsRedaction;
421
422 boolean notificationRequestsRedaction =
423 ent.notification.getNotification().visibility == Notification.VISIBILITY_PRIVATE;
424 boolean userForcesRedaction = packageHasVisibilityOverride(ent.notification.getKey());
425
426 return userForcesRedaction || notificationRequestsRedaction && redactedLockscreen;
427 }
428
429 private boolean packageHasVisibilityOverride(String key) {
Jeff Sharkey9447b832018-02-03 16:45:45 -0700430 if (mEntryManager == null) {
431 Log.wtf(TAG, "mEntryManager was null!", new Throwable());
432 return true;
433 }
Eliot Courtney4a96b362017-12-14 19:38:52 +0900434 return mEntryManager.getNotificationData().getVisibilityOverride(key) ==
Eliot Courtney09322282017-11-09 15:31:19 +0900435 Notification.VISIBILITY_PRIVATE;
436 }
437
Eliot Courtney09322282017-11-09 15:31:19 +0900438 private void updateCurrentProfilesCache() {
439 synchronized (mCurrentProfiles) {
440 mCurrentProfiles.clear();
441 if (mUserManager != null) {
442 for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
443 mCurrentProfiles.put(user.id, user);
444 }
445 }
446 }
447 }
448
449 public boolean isAnyProfilePublicMode() {
450 for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
451 if (isLockscreenPublicMode(mCurrentProfiles.valueAt(i).id)) {
452 return true;
453 }
454 }
455 return false;
456 }
457
458 /**
459 * Returns the current user id. This can change if the user is switched.
460 */
461 public int getCurrentUserId() {
462 return mCurrentUserId;
463 }
464
465 public SparseArray<UserInfo> getCurrentProfiles() {
466 return mCurrentProfiles;
467 }
468
469 public void destroy() {
470 mContext.unregisterReceiver(mBaseBroadcastReceiver);
471 mContext.unregisterReceiver(mAllUsersReceiver);
472 }
473
474 @Override
475 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
476 pw.println("NotificationLockscreenUserManager state:");
477 pw.print(" mCurrentUserId=");
478 pw.println(mCurrentUserId);
479 pw.print(" mShowLockscreenNotifications=");
480 pw.println(mShowLockscreenNotifications);
481 pw.print(" mAllowLockscreenRemoteInput=");
482 pw.println(mAllowLockscreenRemoteInput);
483 pw.print(" mCurrentProfiles=");
484 for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
485 final int userId = mCurrentProfiles.valueAt(i).id;
486 pw.print("" + userId + " ");
487 }
488 pw.println();
489 }
490}