diff options
6 files changed, 296 insertions, 7 deletions
diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml index 526aa5e..403860c 100644 --- a/packages/SystemUI/res/layout/qs_user_detail_item.xml +++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml @@ -40,6 +40,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="14sp" - android:textColor="@color/qs_user_detail_name" /> + android:textColor="@color/qs_user_detail_name" + android:gravity="center_horizontal" /> </com.android.systemui.qs.tiles.UserDetailItemView>
\ No newline at end of file diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 46057af..cf2f5d3 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -671,12 +671,34 @@ <string name="keyguard_indication_charging_time">Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string> <!-- Related to user switcher --><skip/> - <!-- Name for the guest user --> + <!-- Name for the guest user [CHAR LIMIT=35] --> <string name="guest_nickname">Guest</string> - <!-- Label for adding a new guest --> + <!-- Label for adding a new guest in the user switcher [CHAR LIMIT=35] --> <string name="guest_new_guest">+ Guest</string> + <!-- Label for exiting guest session in the user switcher [CHAR LIMIT=35] --> + <string name="guest_exit_guest">Exit guest</string> + + <!-- Title of the confirmation dialog when exiting guest session [CHAR LIMIT=NONE] --> + <string name="guest_exit_guest_dialog_title">Exiting guest session?</string> + + <!-- Message of the confirmation dialog when exiting guest session [CHAR LIMIT=NONE] --> + <string name="guest_exit_guest_dialog_message">Exiting the guest session will remove local data.</string> + + <!-- Title of the notification when resuming an existing guest session [CHAR LIMIT=NONE] --> + <string name="guest_wipe_session_title">Welcome back, guest!</string> + + <!-- Message of the notification when resuming an existing guest session [CHAR LIMIT=NONE] --> + <string name="guest_wipe_session_message">Do you want to start a new session?</string> + + <!-- Notification when resuming an existing guest session: Action that starts a new session [CHAR LIMIT=35] --> + <string name="guest_wipe_session_wipe">Yes</string> + + <!-- Notification when resuming an existing guest session: Action that continues with the current session [CHAR LIMIT=35] --> + <string name="guest_wipe_session_dontwipe">No, thanks</string> + + <!-- Zen mode condition: time duration in minutes. [CHAR LIMIT=NONE] --> <plurals name="zen_mode_duration_minutes"> <item quantity="one">For one minute</item> @@ -704,8 +726,6 @@ <!-- Text shown in place of notification contents when the notification is hidden on a secure lockscreen --> <string name="notification_hidden_text">Contents hidden</string> - <string name="guest_exit_guest">Exit guest</string> - <!-- Media projection permission dialog warning text. [CHAR LIMIT=NONE] --> <string name="media_projection_dialog_text"><xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> will start capturing everything that\'s displayed on your screen.</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index abf9337..0b8f876 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -275,4 +275,7 @@ <item name="android:textStyle">italic</item> <item name="android:textColor">#60000000</item> </style> + + <style name="Theme.SystemUI.Dialog" parent="@android:style/Theme.DeviceDefault.Light.Dialog"> + </style> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java new file mode 100644 index 0000000..7f5ed6a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui; + +import com.android.systemui.statusbar.phone.SystemUIDialog; + +import android.app.ActivityManagerNative; +import android.app.Dialog; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.UserInfo; +import android.os.RemoteException; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.Settings; +import android.util.Log; +import android.view.WindowManagerGlobal; + +/** + * Manages notification when a guest session is resumed. + */ +public class GuestResumeSessionReceiver extends BroadcastReceiver { + + private static final String TAG = "GuestResumeSessionReceiver"; + + private static final String SETTING_GUEST_HAS_LOGGED_IN = "systemui.guest_has_logged_in"; + + private Dialog mNewSessionDialog; + + public void register(Context context) { + IntentFilter f = new IntentFilter(Intent.ACTION_USER_SWITCHED); + context.registerReceiverAsUser(this, UserHandle.OWNER, + f, null /* permission */, null /* scheduler */); + } + + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + + if (Intent.ACTION_USER_SWITCHED.equals(action)) { + cancelDialog(); + + int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); + if (userId == UserHandle.USER_NULL) { + Log.e(TAG, intent + " sent to " + TAG + " without EXTRA_USER_HANDLE"); + return; + } + + UserInfo currentUser; + try { + currentUser = ActivityManagerNative.getDefault().getCurrentUser(); + } catch (RemoteException e) { + return; + } + if (!currentUser.isGuest()) { + return; + } + + ContentResolver cr = context.getContentResolver(); + int notFirstLogin = Settings.System.getIntForUser( + cr, SETTING_GUEST_HAS_LOGGED_IN, 0, userId); + if (notFirstLogin != 0) { + mNewSessionDialog = new ResetSessionDialog(context, userId); + mNewSessionDialog.show(); + } else { + Settings.System.putIntForUser( + cr, SETTING_GUEST_HAS_LOGGED_IN, 1, userId); + } + } + } + + /** + * Wipes the guest session. + * + * The guest must be the current user and its id must be {@param userId}. + */ + private static void wipeGuestSession(Context context, int userId) { + UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); + UserInfo currentUser; + try { + currentUser = ActivityManagerNative.getDefault().getCurrentUser(); + } catch (RemoteException e) { + Log.e(TAG, "Couldn't wipe session because ActivityManager is dead"); + return; + } + if (currentUser.id != userId) { + Log.w(TAG, "User requesting to start a new session (" + userId + ")" + + " is not current user (" + currentUser.id + ")"); + return; + } + if (!currentUser.isGuest()) { + Log.w(TAG, "User requesting to start a new session (" + userId + ")" + + " is not a guest"); + return; + } + + userManager.removeUser(currentUser.id); + UserInfo newGuest = userManager.createGuest(context, currentUser.name); + + try { + if (newGuest == null) { + Log.e(TAG, "Could not create new guest, switching back to owner"); + ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER); + WindowManagerGlobal.getWindowManagerService().lockNow(null /* options */); + return; + } + ActivityManagerNative.getDefault().switchUser(newGuest.id); + } catch (RemoteException e) { + Log.e(TAG, "Couldn't wipe session because ActivityManager or WindowManager is dead"); + return; + } + } + + private void cancelDialog() { + if (mNewSessionDialog != null && mNewSessionDialog.isShowing()) { + mNewSessionDialog.cancel(); + mNewSessionDialog = null; + } + } + + private static class ResetSessionDialog extends SystemUIDialog implements + DialogInterface.OnClickListener { + + private static final int BUTTON_WIPE = BUTTON_NEGATIVE; + private static final int BUTTON_DONTWIPE = BUTTON_POSITIVE; + + private final int mUserId; + + public ResetSessionDialog(Context context, int userId) { + super(context); + + setTitle(context.getString(R.string.guest_wipe_session_title)); + setMessage(context.getString(R.string.guest_wipe_session_message)); + setCanceledOnTouchOutside(false); + + setButton(BUTTON_WIPE, + context.getString(R.string.guest_wipe_session_wipe), this); + setButton(BUTTON_DONTWIPE, + context.getString(R.string.guest_wipe_session_dontwipe), this); + + mUserId = userId; + } + + @Override + public void onClick(DialogInterface dialog, int which) { + if (which == BUTTON_WIPE) { + wipeGuestSession(getContext(), mUserId); + dismiss(); + } else if (which == BUTTON_DONTWIPE) { + cancel(); + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java new file mode 100644 index 0000000..7f27a0c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.statusbar.phone; + +import com.android.systemui.R; + +import android.app.AlertDialog; +import android.content.Context; +import android.view.WindowManager; + +/** + * Base class for dialogs that should appear over panels and keyguard. + */ +public class SystemUIDialog extends AlertDialog { + + public SystemUIDialog(Context context) { + super(context, R.style.Theme_SystemUI_Dialog); + + getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM + | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); + WindowManager.LayoutParams attrs = getWindow().getAttributes(); + attrs.setTitle("SystemUIDialog"); + getWindow().setAttributes(attrs); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index 2134042..49e7c67 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -17,14 +17,18 @@ package com.android.systemui.statusbar.policy; import com.android.systemui.BitmapHelper; +import com.android.systemui.GuestResumeSessionReceiver; import com.android.systemui.R; import com.android.systemui.qs.QSTile; import com.android.systemui.qs.tiles.UserDetailView; +import com.android.systemui.statusbar.phone.SystemUIDialog; import android.app.ActivityManager; import android.app.ActivityManagerNative; +import android.app.Dialog; import android.content.BroadcastReceiver; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.UserInfo; @@ -52,15 +56,20 @@ import java.util.List; public class UserSwitcherController { private static final String TAG = "UserSwitcherController"; + private static final boolean DEBUG = false; private final Context mContext; private final UserManager mUserManager; private final ArrayList<WeakReference<BaseUserAdapter>> mAdapters = new ArrayList<>(); + private final GuestResumeSessionReceiver mGuestResumeSessionReceiver + = new GuestResumeSessionReceiver(); private ArrayList<UserRecord> mUsers = new ArrayList<>(); + private Dialog mExitGuestDialog; public UserSwitcherController(Context context) { mContext = context; + mGuestResumeSessionReceiver.register(context); mUserManager = UserManager.get(context); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_USER_ADDED); @@ -169,7 +178,7 @@ public class UserSwitcherController { if (ActivityManager.getCurrentUser() == id) { if (record.isGuest) { - exitGuest(id); + showExitGuestDialog(id); } return; } @@ -186,8 +195,15 @@ public class UserSwitcherController { } } + private void showExitGuestDialog(int id) { + if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) { + mExitGuestDialog.cancel(); + } + mExitGuestDialog = new ExitGuestDialog(mContext, id); + mExitGuestDialog.show(); + } + private void exitGuest(int id) { - // TODO: show confirmation dialog switchToUserId(UserHandle.USER_OWNER); mUserManager.removeUser(id); } @@ -195,7 +211,16 @@ public class UserSwitcherController { private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { + if (DEBUG) { + Log.v(TAG, "Broadcast: a=" + intent.getAction() + + " user=" + intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1)); + } if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) { + if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) { + mExitGuestDialog.cancel(); + mExitGuestDialog = null; + } + final int currentId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); final int N = mUsers.size(); for (int i = 0; i < N; i++) { @@ -341,4 +366,32 @@ public class UserSwitcherController { public void setToggleState(boolean state) { } }; + + private final class ExitGuestDialog extends SystemUIDialog implements + DialogInterface.OnClickListener { + + private final int mGuestId; + + public ExitGuestDialog(Context context, int guestId) { + super(context); + setTitle(R.string.guest_exit_guest_dialog_title); + setMessage(context.getString(R.string.guest_exit_guest_dialog_message)); + setButton(DialogInterface.BUTTON_NEGATIVE, + context.getString(android.R.string.no), this); + setButton(DialogInterface.BUTTON_POSITIVE, + context.getString(android.R.string.yes), this); + setCanceledOnTouchOutside(false); + mGuestId = guestId; + } + + @Override + public void onClick(DialogInterface dialog, int which) { + if (which == BUTTON_NEGATIVE) { + cancel(); + } else { + dismiss(); + exitGuest(mGuestId); + } + } + } } |