Merge "Implement keyguard user switcher"
This commit is contained in:
@@ -22,7 +22,13 @@ Copyright (C) 2014 The Android Open Source Project
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0"/>
|
||||
|
||||
<group
|
||||
android:scaleX="1.2"
|
||||
android:scaleY="1.2"
|
||||
android:pivotX="12.0"
|
||||
android:pivotY="12.0">
|
||||
<path
|
||||
android:fill="#FFFFFFFF"
|
||||
android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,5.0c1.7,0.0 3.0,1.3 3.0,3.0c0.0,1.7 -1.3,3.0 -3.0,3.0c-1.7,0.0 -3.0,-1.3 -3.0,-3.0C9.0,6.3 10.3,5.0 12.0,5.0zM12.0,19.2c-2.5,0.0 -4.7,-1.3 -6.0,-3.2c0.0,-2.0 4.0,-3.1 6.0,-3.1c2.0,0.0 6.0,1.1 6.0,3.1C16.7,17.9 14.5,19.2 12.0,19.2z"/>
|
||||
</group>
|
||||
</vector>
|
||||
|
||||
25
packages/SystemUI/res/layout/keyguard_user_switcher.xml
Normal file
25
packages/SystemUI/res/layout/keyguard_user_switcher.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ 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
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/keyguard_user_switcher"
|
||||
android:orientation="vertical"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:gravity="end"
|
||||
android:visibility="gone"
|
||||
android:paddingTop="4dp">
|
||||
</LinearLayout>
|
||||
40
packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
Normal file
40
packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
~ 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
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:sysui="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:clickable="true"
|
||||
android:background="@drawable/ripple_drawable">
|
||||
<TextView android:id="@+id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:textAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher.UserName"
|
||||
/>
|
||||
<com.android.systemui.statusbar.phone.UserAvatarView android:id="@+id/picture"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:contentDescription="@null"
|
||||
sysui:frameWidth="@dimen/keyguard_user_switcher_border_thickness"
|
||||
sysui:activeFrameColor="@color/current_user_border_color" />
|
||||
</LinearLayout>
|
||||
@@ -24,6 +24,7 @@
|
||||
android:id="@+id/notification_panel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/transparent"
|
||||
>
|
||||
|
||||
<include
|
||||
@@ -91,6 +92,14 @@
|
||||
|
||||
<include layout="@layout/status_bar_expanded_header" />
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/keyguard_user_switcher"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginTop="@dimen/status_bar_header_height_keyguard"
|
||||
android:layout_gravity="end"
|
||||
android:layout="@layout/keyguard_user_switcher" />
|
||||
|
||||
<include
|
||||
layout="@layout/keyguard_bottom_area"
|
||||
android:visibility="gone" />
|
||||
|
||||
@@ -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" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/header_charging_info"
|
||||
|
||||
@@ -32,4 +32,7 @@
|
||||
<!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
|
||||
card. -->
|
||||
<integer name="keyguard_max_notification_count">5</integer>
|
||||
|
||||
<!-- Set to true to enable the user switcher on the keyguard. -->
|
||||
<bool name="config_keyguardUserSwitcher">true</bool>
|
||||
</resources>
|
||||
|
||||
@@ -54,5 +54,10 @@
|
||||
<enum name="horizontal" value="0" />
|
||||
<enum name="vertical" value="1" />
|
||||
</attr>
|
||||
<declare-styleable name="UserAvatarView">
|
||||
<attr name="frameWidth" format="dimension" />
|
||||
<attr name="activeFrameColor" format="color" />
|
||||
<attr name="frameColor" />
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
|
||||
|
||||
@@ -60,6 +60,9 @@
|
||||
|
||||
<color name="keyguard_affordance">#ffffffff</color>
|
||||
|
||||
<!-- The color of the circle around the primary user in the user switcher -->
|
||||
<color name="current_user_border_color">@color/primary_color</color>
|
||||
|
||||
<!-- Our material color palette (deep teal) -->
|
||||
<color name="primary_color">#ff7fcac3</color>
|
||||
<color name="background_color_1">#ff384248</color>
|
||||
|
||||
@@ -154,5 +154,8 @@
|
||||
Notification.tickerText across the status bar for what seems like an
|
||||
eternity. -->
|
||||
<bool name="enable_ticker">false</bool>
|
||||
|
||||
<!-- Set to true to enable the user switcher on the keyguard. -->
|
||||
<bool name="config_keyguardUserSwitcher">false</bool>
|
||||
</resources>
|
||||
|
||||
|
||||
@@ -332,4 +332,11 @@
|
||||
|
||||
<!-- end margin for multi user switch in expanded quick settings -->
|
||||
<dimen name="multi_user_switch_expanded_margin">8dp</dimen>
|
||||
|
||||
<!-- end margin for system icons if multi user switch is hidden -->
|
||||
<dimen name="system_icons_switcher_hidden_expanded_margin">16dp</dimen>
|
||||
|
||||
<!-- The thickness of the colored border around the current user. -->
|
||||
<dimen name="keyguard_user_switcher_border_thickness">2dp</dimen>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -100,6 +100,13 @@
|
||||
<style name="TextAppearance.StatusBar.Expanded.Network.EmergencyOnly">
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.StatusBar.Expanded.UserSwitcher">
|
||||
<item name="android:textSize">16sp</item>
|
||||
<item name="android:textStyle">normal</item>
|
||||
<item name="android:textColor">#ffffff</item>
|
||||
</style>
|
||||
<style name="TextAppearance.StatusBar.Expanded.UserSwitcher.UserName" />
|
||||
|
||||
<style name="TextAppearance" />
|
||||
<style name="TextAppearance.QuickSettings" />
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<UserInfo> 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<Void, Void, ArrayList<UserData>>() {
|
||||
@Override
|
||||
protected ArrayList<UserData> doInBackground(Void... params) {
|
||||
return loadUsers();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(ArrayList<UserData> userInfos) {
|
||||
bind(userInfos);
|
||||
}
|
||||
}.execute((Void[]) null);
|
||||
}
|
||||
}
|
||||
|
||||
private void bind(ArrayList<UserData> 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<UserData> loadUsers() {
|
||||
ArrayList<UserInfo> users = (ArrayList<UserInfo>) mUserManager
|
||||
.getUsers(true /* excludeDying */);
|
||||
int N = users.size();
|
||||
ArrayList<UserData> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user