diff --git a/packages/SystemUI/res/drawable/ic_account_circle.xml b/packages/SystemUI/res/drawable/ic_account_circle.xml
index a7e8514ae7e26..4a4c1c1e2afc3 100644
--- a/packages/SystemUI/res/drawable/ic_account_circle.xml
+++ b/packages/SystemUI/res/drawable/ic_account_circle.xml
@@ -22,7 +22,13 @@ Copyright (C) 2014 The Android Open Source Project
android:viewportWidth="24.0"
android:viewportHeight="24.0"/>
+
+
diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher.xml b/packages/SystemUI/res/layout/keyguard_user_switcher.xml
new file mode 100644
index 0000000000000..5648065b3b0e2
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyguard_user_switcher.xml
@@ -0,0 +1,25 @@
+
+
+
+
diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
new file mode 100644
index 0000000000000..691a80eb08215
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index cde83bfc32aaa..b54ba1a7254fe 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -24,6 +24,7 @@
android:id="@+id/notification_panel"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:background="@android:color/transparent"
>
+
+
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 353368b0a8c7e..2e4c0efefb9a2 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -73,9 +73,9 @@
android:layout_width="wrap_content"
android:layout_height="@dimen/status_bar_header_height"
android:layout_toStartOf="@id/multi_user_switch"
- android:layout_marginEnd="2dp"
+ android:layout_alignWithParentIfMissing="true"
android:layout_marginStart="16dp"
- />
+ android:paddingEnd="2dp" />
5
+
+
+ true
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index c45361874f1cd..8473d9609a8c1 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -54,5 +54,10 @@
+
+
+
+
+
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 3bd86891e5e1a..4e38da6123d90 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -60,6 +60,9 @@
#ffffffff
+
+ @color/primary_color
+
#ff7fcac3
#ff384248
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index c64a182c788f0..48b327d0e5fdb 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -154,5 +154,8 @@
Notification.tickerText across the status bar for what seems like an
eternity. -->
false
+
+
+ false
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index bbcc9c13c9ea9..fe6321140ec1d 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -332,4 +332,11 @@
8dp
+
+
+ 16dp
+
+
+ 2dp
+
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index c117eba8aefe3..e5d5b03c34f10 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -100,6 +100,13 @@
+
+
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 1da7dabb55be0..154d554a19520 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -123,6 +123,7 @@ import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
import com.android.systemui.statusbar.policy.CastControllerImpl;
import com.android.systemui.statusbar.policy.DateView;
import com.android.systemui.statusbar.policy.HeadsUpNotificationView;
+import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.LocationControllerImpl;
import com.android.systemui.statusbar.policy.NetworkControllerImpl;
@@ -211,6 +212,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
ZenModeController mZenModeController;
CastControllerImpl mCastController;
VolumeComponent mVolumeComponent;
+ KeyguardUserSwitcher mKeyguardUserSwitcher;
int mNaturalBarHeight = -1;
int mIconSize = -1;
@@ -713,6 +715,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
final SignalClusterView signalCluster =
(SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster);
+ mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
+ (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), mHeader);
mNetworkController.addSignalCluster(signalCluster);
signalCluster.setNetworkController(mNetworkController);
@@ -2913,9 +2917,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mKeyguardStatusView.setVisibility(View.VISIBLE);
mKeyguardIndicationController.setVisible(true);
mNotificationPanel.resetViews();
+ mKeyguardUserSwitcher.setKeyguard(true);
} else {
mKeyguardStatusView.setVisibility(View.GONE);
mKeyguardIndicationController.setVisible(false);
+ mKeyguardUserSwitcher.setKeyguard(false);
}
if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
mKeyguardBottomArea.setVisibility(View.VISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index 1712124e18d86..fc10a081e3840 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -63,6 +63,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
private boolean mShowEmergencyCallsOnly;
private boolean mShowChargingInfo;
+ private boolean mKeyguardUserSwitcherShowing;
private int mCollapsedHeight;
private int mExpandedHeight;
@@ -72,6 +73,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
private int mNormalWidth;
private int mPadding;
private int mMultiUserExpandedMargin;
+ private int mSystemIconsSwitcherHiddenExpandedMargin;
private ActivityStarter mActivityStarter;
private BrightnessController mBrightnessController;
@@ -125,7 +127,8 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
mPadding = getResources().getDimensionPixelSize(R.dimen.notification_side_padding);
mMultiUserExpandedMargin =
getResources().getDimensionPixelSize(R.dimen.multi_user_switch_expanded_margin);
-
+ mSystemIconsSwitcherHiddenExpandedMargin = getResources().getDimensionPixelSize(
+ R.dimen.system_icons_switcher_hidden_expanded_margin);
}
public void setActivityStarter(ActivityStarter activityStarter) {
@@ -216,12 +219,15 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
? VISIBLE : GONE);
mChargingInfo.setVisibility(mExpanded && !mOverscrolled && mShowChargingInfo
&& !mShowEmergencyCallsOnly ? VISIBLE : GONE);
+ mMultiUserSwitch.setVisibility(mExpanded || !mKeyguardUserSwitcherShowing
+ ? VISIBLE : GONE);
}
private void updateSystemIconsLayoutParams() {
RelativeLayout.LayoutParams lp = (LayoutParams) mSystemIconsContainer.getLayoutParams();
boolean systemIconsAboveClock = mExpanded && !mOverscrolled
&& mShowChargingInfo && !mShowEmergencyCallsOnly;
+ lp.setMarginEnd(0);
if (systemIconsAboveClock) {
lp.addRule(ALIGN_PARENT_START);
lp.removeRule(START_OF);
@@ -230,7 +236,11 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
? mSettingsButton.getId()
: mMultiUserSwitch.getId());
lp.removeRule(ALIGN_PARENT_START);
+ if (mMultiUserSwitch.getVisibility() == GONE) {
+ lp.setMarginEnd(mSystemIconsSwitcherHiddenExpandedMargin);
+ }
}
+ mSystemIconsContainer.setLayoutParams(lp);
RelativeLayout.LayoutParams clockLp = (LayoutParams) mDateTime.getLayoutParams();
if (systemIconsAboveClock) {
@@ -238,6 +248,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
} else {
clockLp.addRule(BELOW, mEmergencyCallsOnly.getId());
}
+ mDateTime.setLayoutParams(clockLp);
}
private void updateBrightnessControllerState() {
@@ -385,4 +396,11 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL
public void setChargingInfo(CharSequence chargingInfo) {
mChargingInfo.setText(chargingInfo);
}
+
+ public void setKeyguardUserSwitcherShowing(boolean showing) {
+ // STOPSHIP: NOT CALLED PROPERLY WHEN GOING TO FULL SHADE AND RETURNING!?!
+ mKeyguardUserSwitcherShowing = showing;
+ updateVisibilities();
+ updateSystemIconsLayoutParams();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
new file mode 100644
index 0000000000000..6c9dc85e45d45
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
@@ -0,0 +1,215 @@
+/*
+ * 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.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Shader;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * A view that displays a user image cropped to a circle with a frame.
+ */
+public class UserAvatarView extends View {
+
+ private int mActiveFrameColor;
+ private int mFrameColor;
+ private float mFrameWidth;
+ private Bitmap mBitmap;
+ private Drawable mDrawable;
+
+ private final Paint mFramePaint = new Paint();
+ private final Paint mBitmapPaint = new Paint();
+ private final Matrix mDrawMatrix = new Matrix();
+
+ private float mScale = 1;
+
+ public UserAvatarView(Context context, AttributeSet attrs,
+ int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.UserAvatarView, defStyleAttr, defStyleRes);
+ final int N = a.getIndexCount();
+ for (int i = 0; i < N; i++) {
+ int attr = a.getIndex(i);
+ switch (attr) {
+ case R.styleable.UserAvatarView_frameWidth:
+ setFrameWidth(a.getDimension(attr, 0));
+ break;
+ case R.styleable.UserAvatarView_activeFrameColor:
+ setActiveFrameColor(a.getColor(attr, 0));
+ break;
+ case R.styleable.UserAvatarView_frameColor:
+ setFrameColor(a.getColor(attr, 0));
+ break;
+ }
+ }
+ a.recycle();
+
+ mFramePaint.setAntiAlias(true);
+ mFramePaint.setStyle(Paint.Style.STROKE);
+ mBitmapPaint.setAntiAlias(true);
+ }
+
+ public UserAvatarView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public UserAvatarView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public UserAvatarView(Context context) {
+ this(context, null);
+ }
+
+ public void setBitmap(Bitmap bitmap) {
+ setDrawable(null);
+ mBitmap = bitmap;
+ mBitmapPaint.setShader(new BitmapShader(
+ bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
+ configureBounds();
+ invalidate();
+ }
+
+ public void setFrameColor(int frameColor) {
+ mFrameColor = frameColor;
+ invalidate();
+ }
+
+ public void setActiveFrameColor(int activeFrameColor) {
+ mActiveFrameColor = activeFrameColor;
+ invalidate();
+ }
+
+ public void setFrameWidth(float frameWidth) {
+ mFrameWidth = frameWidth;
+ invalidate();
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ configureBounds();
+ }
+
+ public void configureBounds() {
+ int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
+ int vheight = getHeight() - mPaddingTop - mPaddingBottom;
+
+ int dwidth;
+ int dheight;
+ if (mBitmap != null) {
+ dwidth = mBitmap.getWidth();
+ dheight = mBitmap.getHeight();
+ } else if (mDrawable != null) {
+ dwidth = mDrawable.getIntrinsicWidth();
+ dheight = mDrawable.getIntrinsicHeight();
+ mDrawable.setBounds(0, 0, dwidth, dheight);
+ vwidth -= 2 * (mFrameWidth - 1);
+ vheight -= 2 * (mFrameWidth - 1);
+ } else {
+ return;
+ }
+
+ float scale;
+ float dx;
+ float dy;
+
+ scale = Math.min((float) vwidth / (float) dwidth,
+ (float) vheight / (float) dheight);
+
+ dx = (int) ((vwidth - dwidth * scale) * 0.5f + 0.5f);
+ dy = (int) ((vheight - dheight * scale) * 0.5f + 0.5f);
+
+ mDrawMatrix.setScale(scale, scale);
+ mDrawMatrix.postTranslate(dx, dy);
+ mScale = scale;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ int frameColor = isActivated() ? mActiveFrameColor : mFrameColor;
+ float halfW = getWidth() / 2f;
+ float halfH = getHeight() / 2f;
+ float halfSW = Math.min(halfH, halfW);
+ if (mBitmap != null && mScale > 0) {
+ int saveCount = canvas.getSaveCount();
+ canvas.save();
+ canvas.translate(mPaddingLeft, mPaddingTop);
+ canvas.concat(mDrawMatrix);
+ float halfBW = mBitmap.getWidth() / 2f;
+ float halfBH = mBitmap.getHeight() / 2f;
+ float halfBSW = Math.min(halfBH, halfBW);
+ canvas.drawCircle(halfBW, halfBH, halfBSW - mFrameWidth / mScale + 1, mBitmapPaint);
+ canvas.restoreToCount(saveCount);
+ } else if (mDrawable != null && mScale > 0) {
+ int saveCount = canvas.getSaveCount();
+ canvas.save();
+ canvas.translate(mPaddingLeft, mPaddingTop);
+ canvas.translate(mFrameWidth - 1, mFrameWidth - 1);
+ canvas.concat(mDrawMatrix);
+ mDrawable.draw(canvas);
+ canvas.restoreToCount(saveCount);
+ }
+ if (frameColor != 0) {
+ mFramePaint.setColor(frameColor);
+ mFramePaint.setStrokeWidth(mFrameWidth);
+ canvas.drawCircle(halfW, halfH, halfSW - mFrameWidth / 2f, mFramePaint);
+ }
+ }
+
+ public void setDrawable(Drawable d) {
+ if (mDrawable != null) {
+ mDrawable.setCallback(null);
+ unscheduleDrawable(mDrawable);
+ }
+ mDrawable = d;
+ if (d != null) {
+ d.setCallback(this);
+ if (d.isStateful()) {
+ d.setState(getDrawableState());
+ }
+ d.setLayoutDirection(getLayoutDirection());
+ configureBounds();
+ }
+ if (d != null) {
+ mBitmap = null;
+ }
+ configureBounds();
+ invalidate();
+ }
+
+ @Override
+ public void invalidateDrawable(Drawable dr) {
+ if (dr == mDrawable) {
+ invalidate();
+ } else {
+ super.invalidateDrawable(dr);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
new file mode 100644
index 0000000000000..c90750c082e61
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -0,0 +1,209 @@
+/*
+ * 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.policy;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.StatusBarHeaderView;
+import com.android.systemui.statusbar.phone.UserAvatarView;
+
+import android.app.ActivityManagerNative;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.graphics.Bitmap;
+import android.os.AsyncTask;
+import android.os.RemoteException;
+import android.os.UserManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewStub;
+import android.view.WindowManagerGlobal;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Manages the user switcher on the Keyguard.
+ */
+public class KeyguardUserSwitcher implements View.OnClickListener {
+
+ private static final String TAG = "KeyguardUserSwitcher";
+
+ private final Context mContext;
+ private final ViewGroup mUserSwitcher;
+ private final UserManager mUserManager;
+ private final StatusBarHeaderView mHeader;
+
+ public KeyguardUserSwitcher(Context context, ViewStub userSwitcher,
+ StatusBarHeaderView header) {
+ mContext = context;
+ if (context.getResources().getBoolean(R.bool.config_keyguardUserSwitcher)) {
+ mUserSwitcher = (ViewGroup) userSwitcher.inflate();
+ mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ mHeader = header;
+ refresh();
+ } else {
+ mUserSwitcher = null;
+ mUserManager = null;
+ mHeader = null;
+ }
+ }
+
+ public void setKeyguard(boolean keyguard) {
+ if (mUserSwitcher != null) {
+ // TODO: Cache showUserSwitcherOnKeyguard().
+ if (keyguard && showUserSwitcherOnKeyguard()) {
+ show();
+ refresh();
+ } else {
+ hide();
+ }
+ }
+ }
+
+ /**
+ * @return true if the user switcher should be shown on the lock screen.
+ * @see android.os.UserManager#isUserSwitcherEnabled()
+ */
+ private boolean showUserSwitcherOnKeyguard() {
+ // TODO: Set isEdu. The edu provisioning process can add settings to Settings.Global.
+ boolean isEdu = false;
+ if (isEdu) {
+ return true;
+ }
+ List users = mUserManager.getUsers(true /* excludeDying */);
+ int N = users.size();
+ int switchableUsers = 0;
+ for (int i = 0; i < N; i++) {
+ if (users.get(i).supportsSwitchTo()) {
+ switchableUsers++;
+ }
+ }
+ return switchableUsers > 1;
+ }
+
+ public void show() {
+ if (mUserSwitcher != null) {
+ // TODO: animate
+ mUserSwitcher.setVisibility(View.VISIBLE);
+ mHeader.setKeyguardUserSwitcherShowing(true);
+ }
+ }
+
+ private void hide() {
+ if (mUserSwitcher != null) {
+ // TODO: animate
+ mUserSwitcher.setVisibility(View.GONE);
+ mHeader.setKeyguardUserSwitcherShowing(false);
+ }
+ }
+
+ private void refresh() {
+ if (mUserSwitcher != null) {
+ new AsyncTask>() {
+ @Override
+ protected ArrayList doInBackground(Void... params) {
+ return loadUsers();
+ }
+
+ @Override
+ protected void onPostExecute(ArrayList userInfos) {
+ bind(userInfos);
+ }
+ }.execute((Void[]) null);
+ }
+ }
+
+ private void bind(ArrayList userList) {
+ mUserSwitcher.removeAllViews();
+ int N = userList.size();
+ for (int i = 0; i < N; i++) {
+ mUserSwitcher.addView(inflateUser(userList.get(i)));
+ }
+ // TODO: add Guest
+ // TODO: add (+) button
+ }
+
+ private View inflateUser(UserData user) {
+ View v = LayoutInflater.from(mUserSwitcher.getContext()).inflate(
+ R.layout.keyguard_user_switcher_item, mUserSwitcher, false);
+ TextView name = (TextView) v.findViewById(R.id.name);
+ UserAvatarView picture = (UserAvatarView) v.findViewById(R.id.picture);
+ name.setText(user.userInfo.name);
+ picture.setActivated(user.isCurrent);
+ if (user.userInfo.isGuest()) {
+ picture.setDrawable(mContext.getResources().getDrawable(R.drawable.ic_account_circle));
+ } else {
+ picture.setBitmap(user.userIcon);
+ }
+ v.setOnClickListener(this);
+ v.setTag(user.userInfo);
+ // TODO: mark which user is current for accessibility.
+ return v;
+ }
+
+ @Override
+ public void onClick(View v) {
+ switchUser(((UserInfo)v.getTag()).id);
+ }
+
+ // TODO: Factor out logic below and share with QS implementation.
+
+ private ArrayList loadUsers() {
+ ArrayList users = (ArrayList) mUserManager
+ .getUsers(true /* excludeDying */);
+ int N = users.size();
+ ArrayList result = new ArrayList<>(N);
+ int currentUser = -1;
+ try {
+ currentUser = ActivityManagerNative.getDefault().getCurrentUser().id;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Couln't get current user.", e);
+ }
+ for (int i = 0; i < N; i++) {
+ UserInfo user = users.get(i);
+ if (user.supportsSwitchTo()) {
+ boolean isCurrent = user.id == currentUser;
+ result.add(new UserData(user, mUserManager.getUserIcon(user.id), isCurrent));
+ }
+ }
+ return result;
+ }
+
+ private void switchUser(int userId) {
+ try {
+ WindowManagerGlobal.getWindowManagerService().lockNow(null);
+ ActivityManagerNative.getDefault().switchUser(userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Couldn't switch user.", e);
+ }
+ }
+
+ private static class UserData {
+ final UserInfo userInfo;
+ final Bitmap userIcon;
+ final boolean isCurrent;
+
+ UserData(UserInfo userInfo, Bitmap userIcon, boolean isCurrent) {
+ this.userInfo = userInfo;
+ this.userIcon = userIcon;
+ this.isCurrent = isCurrent;
+ }
+ }
+}