--- /dev/null
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="36dp"
+ android:height="36dp"
+ android:viewportWidth="36.0"
+ android:viewportHeight="36.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M18,0C8.06,-0 0,8.06 0,18C0,27.94 8.06,36 18,36C27.94,36 36,27.94 36,18C36,8.06 27.94,0 18,0zM15.5,10.5L20.5,10.5L21.75,11.75L21.75,13L24.66,13C25.57,13 26.34,13.74 26.34,14.66L26.34,18C26.34,18.92 25.57,19.66 24.66,19.66L19.66,19.66L19.66,18.41L16.34,18.41L16.34,19.66L11.34,19.66C10.43,19.66 9.66,18.92 9.66,18L9.66,14.66C9.66,13.74 10.43,13 11.34,13L14.25,13L14.25,11.78L15.5,10.5zM15.5,11.75L15.5,13L20.5,13L20.5,11.75L15.5,11.75zM10.5,20.5L16.34,20.5L16.34,21.75L19.66,21.75L19.66,20.5L25.5,20.5L25.5,23.84C25.5,24.76 24.76,25.5 23.84,25.5L12.16,25.5C11.24,25.5 10.5,24.76 10.5,23.84L10.5,20.5z"/>
+</vector>
<java-symbol type="drawable" name="ic_corp_badge" />
<java-symbol type="drawable" name="ic_corp_badge_off" />
<java-symbol type="drawable" name="ic_corp_icon_badge" />
+ <java-symbol type="drawable" name="ic_corp_user_badge" />
<java-symbol type="drawable" name="ic_corp_badge_no_background" />
<java-symbol type="drawable" name="ic_corp_icon" />
<java-symbol type="drawable" name="ic_corp_statusbar_icon" />
import android.os.BatteryManager;
import android.os.UserManager;
import com.android.internal.util.UserIcons;
-import com.android.settingslib.drawable.CircleFramedDrawable;
+import com.android.settingslib.drawable.UserIconDrawable;
import java.text.NumberFormat;
/**
* Returns a circular icon for a user.
*/
- public static Drawable getUserIcon(Context context, UserManager um, UserInfo user) {
+ public static UserIconDrawable getUserIcon(Context context, UserManager um, UserInfo user) {
+ final int iconSize = UserIconDrawable.getSizeForList(context);
if (user.isManagedProfile()) {
// We use predefined values for managed profiles
Bitmap b = BitmapFactory.decodeResource(context.getResources(),
com.android.internal.R.drawable.ic_corp_icon);
- return CircleFramedDrawable.getInstance(context, b);
+ return new UserIconDrawable(iconSize).setIcon(b).bake();
}
if (user.iconPath != null) {
Bitmap icon = um.getUserIcon(user.id);
if (icon != null) {
- return CircleFramedDrawable.getInstance(context, icon);
+ return new UserIconDrawable(iconSize).setIcon(icon).bake();
}
}
- return CircleFramedDrawable.getInstance(context, UserIcons.convertToBitmap(
- UserIcons.getDefaultUserIcon(user.id, /* light= */ false)));
+ return new UserIconDrawable(iconSize).setIconDrawable(
+ UserIcons.getDefaultUserIcon(user.id, /* light= */ false)).bake();
}
/** Formats the ratio of amount/total as a percentage. */
--- /dev/null
+/*
+ * Copyright (C) 2016 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.settingslib.drawable;
+
+import android.annotation.NonNull;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Shader;
+import android.graphics.drawable.Drawable;
+
+import com.android.settingslib.R;
+
+/**
+ * Converts the user avatar icon to a circularly clipped one with an optional badge and frame
+ */
+public class UserIconDrawable extends Drawable implements Drawable.Callback {
+
+ private Drawable mUserDrawable;
+ private Bitmap mUserIcon;
+ private Bitmap mBitmap; // baked representation. Required for transparent border around badge
+ private final Paint mIconPaint = new Paint();
+ private final Paint mPaint = new Paint();
+ private final Matrix mIconMatrix = new Matrix();
+ private float mIntrinsicRadius;
+ private float mDisplayRadius;
+ private float mPadding = 0;
+ private int mSize = 0; // custom "intrinsic" size for this drawable if non-zero
+ private boolean mInvalidated = true;
+ private ColorStateList mTintColor = null;
+ private PorterDuff.Mode mTintMode = PorterDuff.Mode.SRC_ATOP;
+
+ private float mFrameWidth;
+ private float mFramePadding;
+ private ColorStateList mFrameColor = null;
+ private Paint mFramePaint;
+
+ private Drawable mBadge;
+ private Paint mClearPaint;
+ private float mBadgeRadius;
+ private float mBadgeMargin;
+
+ /**
+ * Gets the system default managed-user badge as a drawable
+ * @param context
+ * @return drawable containing just the badge
+ */
+ public static Drawable getManagedUserBadgeDrawable(Context context) {
+ int displayDensity = context.getResources().getDisplayMetrics().densityDpi;
+ return context.getResources().getDrawableForDensity(
+ com.android.internal.R.drawable.ic_corp_user_badge,
+ displayDensity, context.getTheme());
+ }
+
+ /**
+ * Gets the preferred list-item size of this drawable.
+ * @param context
+ * @return size in pixels
+ */
+ public static int getSizeForList(Context context) {
+ return (int) context.getResources().getDimension(R.dimen.circle_avatar_size);
+ }
+
+ public UserIconDrawable() {
+ this(0);
+ }
+
+ /**
+ * Use this constructor if the drawable is intended to be placed in listviews
+ * @param intrinsicSize if 0, the intrinsic size will come from the icon itself
+ */
+ public UserIconDrawable(int intrinsicSize) {
+ super();
+ mIconPaint.setAntiAlias(true);
+ mIconPaint.setFilterBitmap(true);
+ mPaint.setFilterBitmap(true);
+ mPaint.setAntiAlias(true);
+ if (intrinsicSize > 0) {
+ setBounds(0, 0, intrinsicSize, intrinsicSize);
+ setIntrinsicSize(intrinsicSize);
+ }
+ setIcon(null);
+ }
+
+ public UserIconDrawable setIcon(Bitmap icon) {
+ if (mUserDrawable != null) {
+ mUserDrawable.setCallback(null);
+ mUserDrawable = null;
+ }
+ mUserIcon = icon;
+ if (mUserIcon == null) {
+ mIconPaint.setShader(null);
+ mBitmap = null;
+ } else {
+ mIconPaint.setShader(new BitmapShader(icon, Shader.TileMode.CLAMP,
+ Shader.TileMode.CLAMP));
+ }
+ onBoundsChange(getBounds());
+ return this;
+ }
+
+ public UserIconDrawable setIconDrawable(Drawable icon) {
+ if (mUserDrawable != null) {
+ mUserDrawable.setCallback(null);
+ }
+ mUserIcon = null;
+ mUserDrawable = icon;
+ if (mUserDrawable == null) {
+ mBitmap = null;
+ } else {
+ mUserDrawable.setCallback(this);
+ }
+ onBoundsChange(getBounds());
+ return this;
+ }
+
+ public UserIconDrawable setBadge(Drawable badge) {
+ mBadge = badge;
+ if (mBadge != null) {
+ if (mClearPaint == null) {
+ mClearPaint = new Paint();
+ mClearPaint.setAntiAlias(true);
+ mClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+ mClearPaint.setStyle(Paint.Style.FILL);
+ }
+ // update metrics
+ onBoundsChange(getBounds());
+ } else {
+ invalidateSelf();
+ }
+ return this;
+ }
+
+ public UserIconDrawable setBadgeIfManagedUser(Context context, int userId) {
+ Drawable badge = null;
+ boolean isManaged = context.getSystemService(DevicePolicyManager.class)
+ .getProfileOwnerAsUser(userId) != null;
+ if (isManaged) {
+ badge = getManagedUserBadgeDrawable(context);
+ }
+ return setBadge(badge);
+ }
+
+ public void setBadgeRadius(float radius) {
+ mBadgeRadius = radius;
+ onBoundsChange(getBounds());
+ }
+
+ public void setBadgeMargin(float margin) {
+ mBadgeMargin = margin;
+ onBoundsChange(getBounds());
+ }
+
+ /**
+ * Sets global padding of icon/frame. Doesn't effect the badge.
+ * @param padding
+ */
+ public void setPadding(float padding) {
+ mPadding = padding;
+ onBoundsChange(getBounds());
+ }
+
+ private void initFramePaint() {
+ if (mFramePaint == null) {
+ mFramePaint = new Paint();
+ mFramePaint.setStyle(Paint.Style.STROKE);
+ mFramePaint.setAntiAlias(true);
+ }
+ }
+
+ public void setFrameWidth(float width) {
+ initFramePaint();
+ mFrameWidth = width;
+ mFramePaint.setStrokeWidth(width);
+ onBoundsChange(getBounds());
+ }
+
+ public void setFramePadding(float padding) {
+ initFramePaint();
+ mFramePadding = padding;
+ onBoundsChange(getBounds());
+ }
+
+ public void setFrameColor(int color) {
+ initFramePaint();
+ mFramePaint.setColor(color);
+ invalidateSelf();
+ }
+
+ public void setFrameColor(ColorStateList colorList) {
+ initFramePaint();
+ mFrameColor = colorList;
+ invalidateSelf();
+ }
+
+ /**
+ * This sets the "intrinsic" size of this drawable. Useful for views which use the drawable's
+ * intrinsic size for layout. It is independent of the bounds.
+ * @param size if 0, the intrinsic size will be set to the displayed icon's size
+ */
+ public void setIntrinsicSize(int size) {
+ mSize = size;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (mInvalidated) {
+ rebake();
+ }
+ if (mBitmap != null) {
+ if (mTintColor == null) {
+ mPaint.setColorFilter(null);
+ } else {
+ int color = mTintColor.getColorForState(getState(), mTintColor.getDefaultColor());
+ if (mPaint.getColorFilter() == null) {
+ mPaint.setColorFilter(new PorterDuffColorFilter(color, mTintMode));
+ } else {
+ ((PorterDuffColorFilter) mPaint.getColorFilter()).setMode(mTintMode);
+ ((PorterDuffColorFilter) mPaint.getColorFilter()).setColor(color);
+ }
+ }
+
+ canvas.drawBitmap(mBitmap, 0, 0, mPaint);
+ }
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ mPaint.setAlpha(alpha);
+ super.invalidateSelf();
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ }
+
+ @Override
+ public void setTintList(ColorStateList tintList) {
+ mTintColor = tintList;
+ super.invalidateSelf();
+ }
+
+ @Override
+ public void setTintMode(@NonNull PorterDuff.Mode mode) {
+ mTintMode = mode;
+ super.invalidateSelf();
+ }
+
+ /**
+ * This 'bakes' the current state of this icon into a bitmap and removes/recycles the source
+ * bitmap/drawable. Use this when no more changes will be made and an intrinsic size is set.
+ * This effectively turns this into a static drawable.
+ */
+ public UserIconDrawable bake() {
+ if (mSize <= 0) {
+ throw new IllegalStateException("Baking requires an explicit intrinsic size");
+ }
+ onBoundsChange(new Rect(0, 0, mSize, mSize));
+ rebake();
+ mFrameColor = null;
+ mFramePaint = null;
+ mClearPaint = null;
+ if (mUserDrawable != null) {
+ mUserDrawable.setCallback(null);
+ mUserDrawable = null;
+ } else if (mUserIcon != null) {
+ mUserIcon.recycle();
+ mUserIcon = null;
+ }
+ return this;
+ }
+
+ private void rebake() {
+ mInvalidated = false;
+
+ if (mBitmap == null || (mUserDrawable == null && mUserIcon == null)) {
+ return;
+ }
+
+ final Canvas canvas = new Canvas(mBitmap);
+ canvas.drawColor(0, PorterDuff.Mode.CLEAR);
+
+ if(mUserDrawable != null) {
+ mUserDrawable.draw(canvas);
+ } else if (mUserIcon != null) {
+ int saveId = canvas.save();
+ canvas.concat(mIconMatrix);
+ canvas.drawCircle(mUserIcon.getWidth() * 0.5f, mUserIcon.getHeight() * 0.5f,
+ mIntrinsicRadius, mIconPaint);
+ canvas.restoreToCount(saveId);
+ }
+
+ if (mFrameColor != null) {
+ mFramePaint.setColor(mFrameColor.getColorForState(getState(), Color.TRANSPARENT));
+ }
+ if ((mFrameWidth + mFramePadding) > 0.001f) {
+ float radius = mDisplayRadius - mPadding - mFrameWidth * 0.5f;
+ canvas.drawCircle(getBounds().exactCenterX(), getBounds().exactCenterY(),
+ radius, mFramePaint);
+ }
+
+ if ((mBadge != null) && (mBadgeRadius > 0.001f)) {
+ final float badgeDiameter = mBadgeRadius * 2f;
+ final float badgeTop = mBitmap.getHeight() - badgeDiameter;
+ float badgeLeft = mBitmap.getWidth() - badgeDiameter;
+
+ mBadge.setBounds((int) badgeLeft, (int) badgeTop,
+ (int) (badgeLeft + badgeDiameter), (int) (badgeTop + badgeDiameter));
+
+ final float borderRadius = mBadge.getBounds().width() * 0.5f + mBadgeMargin;
+ canvas.drawCircle(badgeLeft + mBadgeRadius, badgeTop + mBadgeRadius,
+ borderRadius, mClearPaint);
+
+ mBadge.draw(canvas);
+ }
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ if (bounds.isEmpty() || (mUserIcon == null && mUserDrawable == null)) {
+ return;
+ }
+
+ // re-create bitmap if applicable
+ float newDisplayRadius = Math.min(bounds.width(), bounds.height()) * 0.5f;
+ int size = (int) (newDisplayRadius * 2);
+ if (mBitmap == null || size != ((int) (mDisplayRadius * 2))) {
+ mDisplayRadius = newDisplayRadius;
+ if (mBitmap != null) {
+ mBitmap.recycle();
+ }
+ mBitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+ }
+
+ // update metrics
+ mDisplayRadius = Math.min(bounds.width(), bounds.height()) * 0.5f;
+ final float iconRadius = mDisplayRadius - mFrameWidth - mFramePadding - mPadding;
+ RectF dstRect = new RectF(bounds.exactCenterX() - iconRadius,
+ bounds.exactCenterY() - iconRadius,
+ bounds.exactCenterX() + iconRadius,
+ bounds.exactCenterY() + iconRadius);
+ if (mUserDrawable != null) {
+ Rect rounded = new Rect();
+ dstRect.round(rounded);
+ mIntrinsicRadius = Math.min(mUserDrawable.getIntrinsicWidth(),
+ mUserDrawable.getIntrinsicHeight()) * 0.5f;
+ mUserDrawable.setBounds(rounded);
+ } else if (mUserIcon != null) {
+ // Build square-to-square transformation matrix
+ final float iconCX = mUserIcon.getWidth() * 0.5f;
+ final float iconCY = mUserIcon.getHeight() * 0.5f;
+ mIntrinsicRadius = Math.min(iconCX, iconCY);
+ RectF srcRect = new RectF(iconCX - mIntrinsicRadius, iconCY - mIntrinsicRadius,
+ iconCX + mIntrinsicRadius, iconCY + mIntrinsicRadius);
+ mIconMatrix.setRectToRect(srcRect, dstRect, Matrix.ScaleToFit.FILL);
+ }
+
+ invalidateSelf();
+ }
+
+ @Override
+ public void invalidateSelf() {
+ super.invalidateSelf();
+ mInvalidated = true;
+ }
+
+ @Override
+ public boolean isStateful() {
+ return mFrameColor != null && mFrameColor.isStateful();
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return (mSize <= 0 ? (int) mIntrinsicRadius * 2 : mSize);
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return getIntrinsicWidth();
+ }
+
+ @Override
+ public void invalidateDrawable(@NonNull Drawable who) {
+ invalidateSelf();
+ }
+
+ @Override
+ public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
+ scheduleSelf(what, when);
+ }
+
+ @Override
+ public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
+ unscheduleSelf(what);
+ }
+}
import android.widget.SpinnerAdapter;
import android.widget.TextView;
import com.android.internal.util.UserIcons;
-import com.android.settingslib.drawable.CircleFramedDrawable;
+import com.android.settingslib.drawable.UserIconDrawable;
import com.android.settingslib.R;
}
private static Drawable encircle(Context context, Drawable icon) {
- return CircleFramedDrawable.getInstance(context, UserIcons.convertToBitmap(icon));
+ return new UserIconDrawable(UserIconDrawable.getSizeForList(context))
+ .setIconDrawable(icon).bake();
}
}
private ArrayList<UserDetails> data;
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2016 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
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_activated="true" android:color="@color/current_user_border_color" />
+ <item android:color="@android:color/transparent" />
+</selector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2016 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
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:color="@color/qs_tile_disabled_color" />
+ <item android:color="@android:color/transparent" />
+</selector>
\ No newline at end of file
<TextView android:id="@+id/user_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginEnd="16dp"
+ android:layout_marginEnd="13dp"
android:textAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher.UserName"
/>
<com.android.systemui.statusbar.phone.UserAvatarView android:id="@+id/user_picture"
- android:layout_width="@dimen/max_avatar_size"
- android:layout_height="@dimen/max_avatar_size"
+ android:layout_width="@dimen/framed_avatar_size"
+ android:layout_height="@dimen/framed_avatar_size"
android:contentDescription="@null"
+ android:backgroundTint="@color/qs_user_detail_avatar_tint"
+ android:backgroundTintMode="src_atop"
sysui:frameWidth="@dimen/keyguard_user_switcher_border_thickness"
- sysui:framePadding="6dp"
- sysui:activeFrameColor="@color/current_user_border_color" />
+ sysui:framePadding="2.5dp"
+ sysui:badgeDiameter="18dp"
+ sysui:badgeMargin="1dp"
+ sysui:frameColor="@color/qs_user_detail_avatar_frame" />
</com.android.systemui.qs.tiles.UserDetailItemView>
<com.android.systemui.statusbar.phone.UserAvatarView
android:id="@+id/user_picture"
- android:layout_width="@dimen/max_avatar_size"
- android:layout_height="@dimen/max_avatar_size"
- android:layout_marginBottom="10dp"
+ android:layout_width="@dimen/framed_avatar_size"
+ android:layout_height="@dimen/framed_avatar_size"
+ android:layout_marginBottom="7dp"
+ android:backgroundTint="@color/qs_user_detail_avatar_tint"
+ android:backgroundTintMode="src_atop"
systemui:frameWidth="2dp"
- systemui:framePadding="6dp"
- systemui:activeFrameColor="@color/current_user_border_color"/>
+ systemui:framePadding="2.5dp"
+ systemui:badgeDiameter="18dp"
+ systemui:badgeMargin="1dp"
+ systemui:frameColor="@color/qs_user_detail_avatar_frame"/>
<LinearLayout
android:layout_width="wrap_content"
<enum name="vertical" value="1" />
</attr>
<declare-styleable name="UserAvatarView">
+ <attr name="avatarPadding" format="dimension" />
<attr name="frameWidth" format="dimension" />
<attr name="framePadding" format="dimension" />
+ <!-- {@deprecated Use a statelist in frameColor instead.} -->
<attr name="activeFrameColor" format="color" />
- <attr name="frameColor" />
+ <attr name="frameColor" format="color" />
+ <attr name="badgeDiameter" format="dimension" />
+ <attr name="badgeMargin" format="dimension" />
</declare-styleable>
<declare-styleable name="UserDetailItemView">
<attr name="regularFontFamily" format="string" />
quick settings header -->
<dimen name="max_avatar_size">48dp</dimen>
+ <!-- Size of user icon + frame in the qs/keyguard user picker (incl. frame) -->
+ <dimen name="framed_avatar_size">54dp</dimen>
+
<!-- Margin on the left side of the carrier text on Keyguard -->
<dimen name="keyguard_carrier_text_margin">16dp</dimen>
+++ /dev/null
-/*
- * 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 android.graphics.Bitmap;
-import android.graphics.BitmapShader;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.RectF;
-import android.graphics.Shader;
-
-public class BitmapHelper {
- /**
- * Generate a new bitmap (width x height pixels, ARGB_8888) with the input bitmap scaled
- * to fit and clipped to an inscribed circle.
- * @param input Bitmap to resize and clip
- * @param width Width of output bitmap (and diameter of circle)
- * @param height Height of output bitmap
- * @return A shiny new bitmap for you to use
- */
- public static Bitmap createCircularClip(Bitmap input, int width, int height) {
- if (input == null) return null;
-
- final int inWidth = input.getWidth();
- final int inHeight = input.getHeight();
- final Bitmap output = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- final Canvas canvas = new Canvas(output);
- final Paint paint = new Paint();
- paint.setShader(new BitmapShader(input, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
- paint.setAntiAlias(true);
- final RectF srcRect = new RectF(0, 0, inWidth, inHeight);
- final RectF dstRect = new RectF(0, 0, width, height);
- final Matrix m = new Matrix();
- m.setRectToRect(srcRect, dstRect, Matrix.ScaleToFit.CENTER);
- canvas.setMatrix(m);
- canvas.drawCircle(inWidth / 2, inHeight / 2, inWidth / 2, paint);
- return output;
- }
-}
import android.widget.TextView;
import com.android.internal.util.ArrayUtils;
+import com.android.settingslib.drawable.UserIconDrawable;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.UserAvatarView;
return (UserDetailItemView) convertView;
}
- public void bind(String name, Bitmap picture) {
+ public void bind(String name, Bitmap picture, int userId) {
mName.setText(name);
- mAvatar.setBitmap(picture);
+ mAvatar.setAvatarWithBadge(picture, userId);
}
- public void bind(String name, Drawable picture) {
+ public void bind(String name, Drawable picture, int userId) {
mName.setText(name);
- mAvatar.setDrawable(picture);
+ mAvatar.setDrawableWithBadge(picture, userId);
+ }
+
+ public void setAvatarEnabled(boolean enabled) {
+ mAvatar.setEnabled(enabled);
}
public void setDisabledByAdmin(boolean disabled) {
mRestrictedPadlock.setVisibility(disabled ? View.VISIBLE : View.GONE);
mName.setEnabled(!disabled);
- mAvatar.setDisabled(disabled);
+ mAvatar.setEnabled(!disabled);
}
public void setEnabled(boolean enabled) {
mName.setEnabled(enabled);
- mAvatar.setDisabled(!enabled);
+ mAvatar.setEnabled(enabled);
}
@Override
}
String name = getName(mContext, item);
if (item.picture == null) {
- v.bind(name, getDrawable(mContext, item));
+ v.bind(name, getDrawable(mContext, item), item.resolveId());
} else {
- v.bind(name, item.picture);
+ v.bind(name, item.picture, item.info.id);
}
v.setActivated(item.isCurrent);
v.setDisabledByAdmin(item.isDisabledByAdmin);
package com.android.systemui.statusbar.phone;
import android.content.Context;
+import android.content.res.ColorStateList;
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.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
+import com.android.settingslib.drawable.UserIconDrawable;
import com.android.systemui.R;
/**
- * A view that displays a user image cropped to a circle with a frame.
+ * A view that displays a user image cropped to a circle with an optional frame.
*/
public class UserAvatarView extends View {
- private int mActiveFrameColor;
- private int mFrameColor;
- private float mFrameWidth;
- private float mFramePadding;
- private Bitmap mBitmap;
- private Drawable mDrawable;
- private boolean mIsDisabled;
-
- private final Paint mFramePaint = new Paint();
- private final Paint mBitmapPaint = new Paint();
- private final Matrix mDrawMatrix = new Matrix();
-
- private float mScale = 1;
+ private final UserIconDrawable mDrawable = new UserIconDrawable();
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_avatarPadding:
+ setAvatarPadding(a.getDimension(attr, 0));
+ break;
case R.styleable.UserAvatarView_frameWidth:
setFrameWidth(a.getDimension(attr, 0));
break;
case R.styleable.UserAvatarView_framePadding:
setFramePadding(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));
+ setFrameColor(a.getColorStateList(attr));
+ break;
+ case R.styleable.UserAvatarView_badgeDiameter:
+ setBadgeDiameter(a.getDimension(attr, 0));
+ break;
+ case R.styleable.UserAvatarView_badgeMargin:
+ setBadgeMargin(a.getDimension(attr, 0));
break;
}
}
a.recycle();
-
- mFramePaint.setAntiAlias(true);
- mFramePaint.setStyle(Paint.Style.STROKE);
- mBitmapPaint.setAntiAlias(true);
+ setBackground(mDrawable);
}
public UserAvatarView(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, null);
}
+ /**
+ * @deprecated use {@link #setAvatar(Bitmap)} instead.
+ */
+ @Deprecated
public void setBitmap(Bitmap bitmap) {
- setDrawable(null);
- mBitmap = bitmap;
- if (mBitmap != null) {
- mBitmapPaint.setShader(new BitmapShader(
- bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
- } else {
- mBitmapPaint.setShader(null);
- }
- configureBounds();
- invalidate();
+ setAvatar(bitmap);
}
- public void setFrameColor(int frameColor) {
- mFrameColor = frameColor;
- invalidate();
- }
-
- public void setActiveFrameColor(int activeFrameColor) {
- mActiveFrameColor = activeFrameColor;
- invalidate();
+ public void setFrameColor(ColorStateList color) {
+ mDrawable.setFrameColor(color);
}
public void setFrameWidth(float frameWidth) {
- mFrameWidth = frameWidth;
- invalidate();
+ mDrawable.setFrameWidth(frameWidth);
}
public void setFramePadding(float framePadding) {
- mFramePadding = framePadding;
- invalidate();
+ mDrawable.setFramePadding(framePadding);
}
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- configureBounds();
+ public void setAvatarPadding(float avatarPadding) {
+ mDrawable.setPadding(avatarPadding);
}
- 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) {
- vwidth -= 2 * (mFrameWidth - 1);
- vheight -= 2 * (mFrameWidth - 1);
- dwidth = vwidth;
- dheight = vheight;
- mDrawable.setBounds(0, 0, dwidth, dheight);
- } 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;
+ public void setBadgeDiameter(float diameter) {
+ mDrawable.setBadgeRadius(diameter * 0.5f);
}
- @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);
- updateDrawableIfDisabled();
- 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 + (mFramePadding - 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);
- }
+ public void setBadgeMargin(float margin) {
+ mDrawable.setBadgeMargin(margin);
}
- @Override
- protected boolean verifyDrawable(Drawable who) {
- return who == mDrawable || super.verifyDrawable(who);
+ public void setAvatar(Bitmap avatar) {
+ mDrawable.setIcon(avatar);
+ mDrawable.setBadge(null);
}
- @Override
- protected void drawableStateChanged() {
- super.drawableStateChanged();
- if (mDrawable != null && mDrawable.isStateful()) {
- mDrawable.setState(getDrawableState());
- }
+ public void setAvatarWithBadge(Bitmap avatar, int userId) {
+ mDrawable.setIcon(avatar);
+ mDrawable.setBadgeIfManagedUser(getContext(), userId);
}
- public void setDisabled(boolean disabled) {
- if (mIsDisabled == disabled) {
- return;
+ public void setDrawable(Drawable d) {
+ if (d instanceof UserIconDrawable) {
+ throw new RuntimeException("Recursively adding UserIconDrawable");
}
- mIsDisabled = disabled;
- invalidate();
+ mDrawable.setIconDrawable(d);
+ mDrawable.setBadge(null);
}
- private void updateDrawableIfDisabled() {
- int disabledColor = getContext().getColor(R.color.qs_tile_disabled_color);
- PorterDuffColorFilter filter = new PorterDuffColorFilter(disabledColor,
- PorterDuff.Mode.SRC_ATOP);
- if (mBitmap != null) {
- if (mIsDisabled) {
- mBitmapPaint.setColorFilter(filter);
- } else {
- mBitmapPaint.setColorFilter(null);
- }
- } else if (mDrawable != null) {
- if (mIsDisabled) {
- mDrawable.setColorFilter(filter);
- } else {
- mDrawable.setColorFilter(null);
- }
+ public void setDrawableWithBadge(Drawable d, int userId) {
+ if (d instanceof UserIconDrawable) {
+ throw new RuntimeException("Recursively adding UserIconDrawable");
}
+ mDrawable.setIconDrawable(d);
+ mDrawable.setBadgeIfManagedUser(getContext(), userId);
}
}
UserDetailItemView v = (UserDetailItemView) convertView;
String name = getName(mContext, item);
- Drawable drawable;
if (item.picture == null) {
- drawable = getDrawable(mContext, item).mutate();
+ v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId());
} else {
- drawable = new BitmapDrawable(mContext.getResources(), item.picture);
+ v.bind(name, item.picture, item.info.id);
}
// Disable the icon if switching is disabled
- if (!item.isSwitchToEnabled) {
- drawable.setTint(mContext.getColor(R.color.qs_tile_disabled_color));
- }
- v.bind(name, drawable);
+ v.setAvatarEnabled(item.isSwitchToEnabled);
convertView.setActivated(item.isCurrent);
convertView.setTag(item);
return convertView;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.RemoteException;
import android.util.Pair;
import com.android.internal.util.UserIcons;
-import com.android.systemui.BitmapHelper;
+import com.android.settingslib.drawable.UserIconDrawable;
import com.android.systemui.R;
import java.util.ArrayList;
Drawable avatar = null;
Bitmap rawAvatar = um.getUserIcon(userId);
if (rawAvatar != null) {
- avatar = new BitmapDrawable(mContext.getResources(),
- BitmapHelper.createCircularClip(rawAvatar, avatarSize, avatarSize));
+ avatar = new UserIconDrawable(avatarSize)
+ .setIcon(rawAvatar).setBadgeIfManagedUser(mContext, userId).bake();
} else {
avatar = UserIcons.getDefaultUserIcon(isGuest? UserHandle.USER_NULL : userId,
/* light= */ true);
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.internal.util.UserIcons;
import com.android.settingslib.RestrictedLockUtils;
-import com.android.systemui.BitmapHelper;
import com.android.systemui.GuestResumeSessionReceiver;
import com.android.systemui.R;
import com.android.systemui.SystemUISecondaryUserService;
boolean canSwitchUsers = mUserManager.canSwitchUsers();
UserInfo currentUserInfo = null;
UserRecord guestRecord = null;
- int avatarSize = mContext.getResources()
- .getDimensionPixelSize(R.dimen.max_avatar_size);
for (UserInfo info : infos) {
boolean isCurrent = currentId == info.id;
picture = mUserManager.getUserIcon(info.id);
if (picture != null) {
- picture = BitmapHelper.createCircularClip(
- picture, avatarSize, avatarSize);
+ int avatarSize = mContext.getResources()
+ .getDimensionPixelSize(R.dimen.max_avatar_size);
+ picture = Bitmap.createScaledBitmap(
+ picture, avatarSize, avatarSize, true);
}
}
int index = isCurrent ? 0 : records.size();
if (item.isAddUser) {
return context.getDrawable(R.drawable.ic_add_circle_qs);
}
- return UserIcons.getDefaultUserIcon(item.isGuest ? UserHandle.USER_NULL : item.info.id,
- /* light= */ true);
+ return UserIcons.getDefaultUserIcon(item.resolveId(), /* light= */ true);
}
public void refresh() {
isSwitchToEnabled);
}
+ public int resolveId() {
+ if (isGuest || info == null) {
+ return UserHandle.USER_NULL;
+ }
+ return info.id;
+ }
+
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("UserRecord(");