1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.keyguard;
18
19import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.animation.ValueAnimator.AnimatorUpdateListener;
22import android.animation.ValueAnimator;
23import android.content.Context;
24import android.content.pm.UserInfo;
25import android.content.res.Resources;
26import android.graphics.Bitmap;
27import android.graphics.BitmapFactory;
28import android.graphics.Color;
29import android.os.UserManager;
30import android.util.AttributeSet;
31import android.util.Log;
32import android.view.LayoutInflater;
33import android.view.View;
34import android.widget.FrameLayout;
35import android.widget.ImageView;
36import android.widget.TextView;
37
38class KeyguardMultiUserAvatar extends FrameLayout {
39    private static final String TAG = KeyguardMultiUserAvatar.class.getSimpleName();
40    private static final boolean DEBUG = KeyguardConstants.DEBUG;
41
42    private ImageView mUserImage;
43    private TextView mUserName;
44    private UserInfo mUserInfo;
45    private static final float ACTIVE_ALPHA = 1.0f;
46    private static final float INACTIVE_ALPHA = 1.0f;
47    private static final float ACTIVE_SCALE = 1.5f;
48    private static final float ACTIVE_TEXT_ALPHA = 0f;
49    private static final float INACTIVE_TEXT_ALPHA = 0.5f;
50    private static final int SWITCH_ANIMATION_DURATION = 150;
51
52    private final float mActiveAlpha;
53    private final float mActiveScale;
54    private final float mActiveTextAlpha;
55    private final float mInactiveAlpha;
56    private final float mInactiveTextAlpha;
57    private final float mShadowRadius;
58    private final float mStroke;
59    private final float mIconSize;
60    private final int mFrameColor;
61    private final int mFrameShadowColor;
62    private final int mTextColor;
63    private final int mHighlightColor;
64
65    private boolean mTouched;
66
67    private boolean mActive;
68    private boolean mInit = true;
69    private KeyguardMultiUserSelectorView mUserSelector;
70    private KeyguardCircleFramedDrawable mFramed;
71    private boolean mPressLock;
72    private UserManager mUserManager;
73
74    public static KeyguardMultiUserAvatar fromXml(int resId, Context context,
75            KeyguardMultiUserSelectorView userSelector, UserInfo info) {
76        KeyguardMultiUserAvatar icon = (KeyguardMultiUserAvatar)
77                LayoutInflater.from(context).inflate(resId, userSelector, false);
78
79        icon.init(info, userSelector);
80        return icon;
81    }
82
83    public KeyguardMultiUserAvatar(Context context) {
84        this(context, null, 0);
85    }
86
87    public KeyguardMultiUserAvatar(Context context, AttributeSet attrs) {
88        this(context, attrs, 0);
89    }
90
91    public KeyguardMultiUserAvatar(Context context, AttributeSet attrs, int defStyle) {
92        super(context, attrs, defStyle);
93
94        Resources res = mContext.getResources();
95        mTextColor = res.getColor(R.color.keyguard_avatar_nick_color);
96        mIconSize = res.getDimension(R.dimen.keyguard_avatar_size);
97        mStroke = res.getDimension(R.dimen.keyguard_avatar_frame_stroke_width);
98        mShadowRadius = res.getDimension(R.dimen.keyguard_avatar_frame_shadow_radius);
99        mFrameColor = res.getColor(R.color.keyguard_avatar_frame_color);
100        mFrameShadowColor = res.getColor(R.color.keyguard_avatar_frame_shadow_color);
101        mHighlightColor = res.getColor(R.color.keyguard_avatar_frame_pressed_color);
102        mActiveTextAlpha = ACTIVE_TEXT_ALPHA;
103        mInactiveTextAlpha = INACTIVE_TEXT_ALPHA;
104        mActiveScale = ACTIVE_SCALE;
105        mActiveAlpha = ACTIVE_ALPHA;
106        mInactiveAlpha = INACTIVE_ALPHA;
107        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
108
109        mTouched = false;
110
111        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
112    }
113
114    protected String rewriteIconPath(String path) {
115        return path;
116    }
117
118    public void init(UserInfo user, KeyguardMultiUserSelectorView userSelector) {
119        mUserInfo = user;
120        mUserSelector = userSelector;
121
122        mUserImage = (ImageView) findViewById(R.id.keyguard_user_avatar);
123        mUserName = (TextView) findViewById(R.id.keyguard_user_name);
124
125        mFramed = (KeyguardCircleFramedDrawable)
126                MultiUserAvatarCache.getInstance().get(user.id);
127
128        // If we can't find it or the params don't match, create the drawable again
129        if (mFramed == null
130                || !mFramed.verifyParams(mIconSize, mFrameColor, mStroke, mFrameShadowColor,
131                        mShadowRadius, mHighlightColor)) {
132            Bitmap icon = null;
133            try {
134                icon = mUserManager.getUserIcon(user.id);
135            } catch (Exception e) {
136                if (DEBUG) Log.d(TAG, "failed to get profile icon " + user, e);
137            }
138
139            if (icon == null) {
140                icon = BitmapFactory.decodeResource(mContext.getResources(),
141                        com.android.internal.R.drawable.ic_contact_picture);
142            }
143
144            mFramed = new KeyguardCircleFramedDrawable(icon, (int) mIconSize, mFrameColor, mStroke,
145                    mFrameShadowColor, mShadowRadius, mHighlightColor);
146            MultiUserAvatarCache.getInstance().put(user.id, mFramed);
147        }
148
149        mFramed.reset();
150
151        mUserImage.setImageDrawable(mFramed);
152        mUserName.setText(mUserInfo.name);
153        setOnClickListener(mUserSelector);
154        mInit = false;
155    }
156
157    public void setActive(boolean active, boolean animate, final Runnable onComplete) {
158        if (mActive != active || mInit) {
159            mActive = active;
160
161            if (active) {
162                KeyguardLinearLayout parent = (KeyguardLinearLayout) getParent();
163                parent.setTopChild(this);
164                // TODO: Create an appropriate asset when string changes are possible.
165                setContentDescription(mUserName.getText()
166                        + ". " + mContext.getString(R.string.user_switched, ""));
167            } else {
168                setContentDescription(mUserName.getText());
169            }
170        }
171        updateVisualsForActive(mActive, animate, SWITCH_ANIMATION_DURATION, onComplete);
172    }
173
174    void updateVisualsForActive(boolean active, boolean animate, int duration,
175            final Runnable onComplete) {
176        final float finalAlpha = active ? mActiveAlpha : mInactiveAlpha;
177        final float initAlpha = active ? mInactiveAlpha : mActiveAlpha;
178        final float finalScale = active ? 1f : 1f / mActiveScale;
179        final float initScale = mFramed.getScale();
180        final int finalTextAlpha = active ? (int) (mActiveTextAlpha * 255) :
181                (int) (mInactiveTextAlpha * 255);
182        final int initTextAlpha = active ? (int) (mInactiveTextAlpha * 255) :
183                (int) (mActiveTextAlpha * 255);
184        int textColor = mTextColor;
185        mUserName.setTextColor(textColor);
186
187        if (animate && mTouched) {
188            ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
189            va.addUpdateListener(new AnimatorUpdateListener() {
190                @Override
191                public void onAnimationUpdate(ValueAnimator animation) {
192                    float r = animation.getAnimatedFraction();
193                    float scale = (1 - r) * initScale + r * finalScale;
194                    float alpha = (1 - r) * initAlpha + r * finalAlpha;
195                    int textAlpha = (int) ((1 - r) * initTextAlpha + r * finalTextAlpha);
196                    mFramed.setScale(scale);
197                    mUserImage.setAlpha(alpha);
198                    mUserName.setTextColor(Color.argb(textAlpha, 255, 255, 255));
199                    mUserImage.invalidate();
200                }
201            });
202            va.addListener(new AnimatorListenerAdapter() {
203                @Override
204                public void onAnimationEnd(Animator animation) {
205                    if (onComplete != null) {
206                        onComplete.run();
207                    }
208                }
209            });
210            va.setDuration(duration);
211            va.start();
212        } else {
213            mFramed.setScale(finalScale);
214            mUserImage.setAlpha(finalAlpha);
215            mUserName.setTextColor(Color.argb(finalTextAlpha, 255, 255, 255));
216            if (onComplete != null) {
217                post(onComplete);
218            }
219        }
220
221        mTouched = true;
222    }
223
224    @Override
225    public void setPressed(boolean pressed) {
226        if (mPressLock && !pressed) {
227            return;
228        }
229
230        if (mPressLock || !pressed || isClickable()) {
231            super.setPressed(pressed);
232            mFramed.setPressed(pressed);
233            mUserImage.invalidate();
234        }
235    }
236
237    public void lockPressed(boolean pressed) {
238        mPressLock = pressed;
239        setPressed(pressed);
240    }
241
242    public UserInfo getUserInfo() {
243        return mUserInfo;
244    }
245}
246