1/*
2 * Copyright (C) 2014 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.systemui.statusbar.policy;
18
19import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.animation.ObjectAnimator;
22import android.animation.ValueAnimator;
23import android.content.Context;
24import android.database.DataSetObserver;
25import android.view.LayoutInflater;
26import android.view.View;
27import android.view.ViewGroup;
28import android.view.ViewStub;
29import android.view.animation.AnimationUtils;
30import android.widget.TextView;
31
32import com.android.keyguard.AppearAnimationUtils;
33import com.android.systemui.R;
34import com.android.systemui.qs.tiles.UserDetailItemView;
35import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
36import com.android.systemui.statusbar.phone.NotificationPanelView;
37import com.android.systemui.statusbar.phone.PhoneStatusBar;
38import com.android.systemui.statusbar.phone.StatusBarHeaderView;
39import com.android.systemui.statusbar.phone.UserAvatarView;
40
41/**
42 * Manages the user switcher on the Keyguard.
43 */
44public class KeyguardUserSwitcher {
45
46    private static final String TAG = "KeyguardUserSwitcher";
47    private static final boolean ALWAYS_ON = false;
48
49    private final ViewGroup mUserSwitcher;
50    private final KeyguardStatusBarView mStatusBarView;
51    private final Adapter mAdapter;
52    private final AppearAnimationUtils mAppearAnimationUtils;
53    private final KeyguardUserSwitcherScrim mBackground;
54    private ObjectAnimator mBgAnimator;
55    private UserSwitcherController mUserSwitcherController;
56
57    public KeyguardUserSwitcher(Context context, ViewStub userSwitcher,
58            KeyguardStatusBarView statusBarView, NotificationPanelView panelView,
59            UserSwitcherController userSwitcherController) {
60        if (context.getResources().getBoolean(R.bool.config_keyguardUserSwitcher) || ALWAYS_ON) {
61            mUserSwitcher = (ViewGroup) userSwitcher.inflate();
62            mBackground = new KeyguardUserSwitcherScrim(mUserSwitcher);
63            mUserSwitcher.setBackground(mBackground);
64            mStatusBarView = statusBarView;
65            mStatusBarView.setKeyguardUserSwitcher(this);
66            panelView.setKeyguardUserSwitcher(this);
67            mAdapter = new Adapter(context, userSwitcherController);
68            mAdapter.registerDataSetObserver(mDataSetObserver);
69            mUserSwitcherController = userSwitcherController;
70            mAppearAnimationUtils = new AppearAnimationUtils(context, 400, -0.5f, 0.5f,
71                    AnimationUtils.loadInterpolator(
72                            context, android.R.interpolator.fast_out_slow_in));
73        } else {
74            mUserSwitcher = null;
75            mStatusBarView = null;
76            mAdapter = null;
77            mAppearAnimationUtils = null;
78            mBackground = null;
79        }
80    }
81
82    public void setKeyguard(boolean keyguard, boolean animate) {
83        if (mUserSwitcher != null) {
84            if (keyguard && shouldExpandByDefault()) {
85                show(animate);
86            } else {
87                hide(animate);
88            }
89        }
90    }
91
92    /**
93     * @return true if the user switcher should be expanded by default on the lock screen.
94     * @see android.os.UserManager#isUserSwitcherEnabled()
95     */
96    private boolean shouldExpandByDefault() {
97        return (mUserSwitcherController != null) && mUserSwitcherController.isSimpleUserSwitcher();
98    }
99
100    public void show(boolean animate) {
101        if (mUserSwitcher != null && mUserSwitcher.getVisibility() != View.VISIBLE) {
102            cancelAnimations();
103            mUserSwitcher.setVisibility(View.VISIBLE);
104            mStatusBarView.setKeyguardUserSwitcherShowing(true, animate);
105            if (animate) {
106                startAppearAnimation();
107            }
108        }
109    }
110
111    public void hide(boolean animate) {
112        if (mUserSwitcher != null && mUserSwitcher.getVisibility() == View.VISIBLE) {
113            cancelAnimations();
114            if (animate) {
115                startDisappearAnimation();
116            } else {
117                mUserSwitcher.setVisibility(View.GONE);
118            }
119            mStatusBarView.setKeyguardUserSwitcherShowing(false, animate);
120        }
121    }
122
123    private void cancelAnimations() {
124        int count = mUserSwitcher.getChildCount();
125        for (int i = 0; i < count; i++) {
126            mUserSwitcher.getChildAt(i).animate().cancel();
127        }
128        if (mBgAnimator != null) {
129            mBgAnimator.cancel();
130        }
131        mUserSwitcher.animate().cancel();
132    }
133
134    private void startAppearAnimation() {
135        int count = mUserSwitcher.getChildCount();
136        View[] objects = new View[count];
137        for (int i = 0; i < count; i++) {
138            objects[i] = mUserSwitcher.getChildAt(i);
139        }
140        mUserSwitcher.setClipChildren(false);
141        mUserSwitcher.setClipToPadding(false);
142        mAppearAnimationUtils.startAppearAnimation(objects, new Runnable() {
143            @Override
144            public void run() {
145                mUserSwitcher.setClipChildren(true);
146                mUserSwitcher.setClipToPadding(true);
147            }
148        });
149        mBgAnimator = ObjectAnimator.ofInt(mBackground, "alpha", 0, 255);
150        mBgAnimator.setDuration(400);
151        mBgAnimator.setInterpolator(PhoneStatusBar.ALPHA_IN);
152        mBgAnimator.addListener(new AnimatorListenerAdapter() {
153            @Override
154            public void onAnimationEnd(Animator animation) {
155                mBgAnimator = null;
156            }
157        });
158        mBgAnimator.start();
159    }
160
161    private void startDisappearAnimation() {
162        mUserSwitcher.animate()
163                .alpha(0f)
164                .setDuration(300)
165                .setInterpolator(PhoneStatusBar.ALPHA_OUT)
166                .withEndAction(new Runnable() {
167                    @Override
168                    public void run() {
169                        mUserSwitcher.setVisibility(View.GONE);
170                        mUserSwitcher.setAlpha(1f);
171                    }
172                });
173    }
174
175    private void refresh() {
176        final int childCount = mUserSwitcher.getChildCount();
177        final int adapterCount = mAdapter.getCount();
178        final int N = Math.max(childCount, adapterCount);
179        for (int i = 0; i < N; i++) {
180            if (i < adapterCount) {
181                View oldView = null;
182                if (i < childCount) {
183                    oldView = mUserSwitcher.getChildAt(i);
184                }
185                View newView = mAdapter.getView(i, oldView, mUserSwitcher);
186                if (oldView == null) {
187                    // We ran out of existing views. Add it at the end.
188                    mUserSwitcher.addView(newView);
189                } else if (oldView != newView) {
190                    // We couldn't rebind the view. Replace it.
191                    mUserSwitcher.removeViewAt(i);
192                    mUserSwitcher.addView(newView, i);
193                }
194            } else {
195                int lastIndex = mUserSwitcher.getChildCount() - 1;
196                mUserSwitcher.removeViewAt(lastIndex);
197            }
198        }
199    }
200
201    public final DataSetObserver mDataSetObserver = new DataSetObserver() {
202        @Override
203        public void onChanged() {
204            refresh();
205        }
206    };
207
208    public static class Adapter extends UserSwitcherController.BaseUserAdapter implements
209            View.OnClickListener {
210
211        private Context mContext;
212
213        public Adapter(Context context, UserSwitcherController controller) {
214            super(controller);
215            mContext = context;
216        }
217
218        @Override
219        public View getView(int position, View convertView, ViewGroup parent) {
220            UserSwitcherController.UserRecord item = getItem(position);
221
222            if (!(convertView instanceof UserDetailItemView)
223                    || !(convertView.getTag() instanceof UserSwitcherController.UserRecord)) {
224                convertView = LayoutInflater.from(mContext).inflate(
225                        R.layout.keyguard_user_switcher_item, parent, false);
226                convertView.setOnClickListener(this);
227            }
228            UserDetailItemView v = (UserDetailItemView) convertView;
229
230            String name = getName(mContext, item);
231            if (item.picture == null) {
232                v.bind(name, getDrawable(mContext, item));
233            } else {
234                v.bind(name, item.picture);
235            }
236            convertView.setActivated(item.isCurrent);
237            convertView.setTag(item);
238            return convertView;
239        }
240
241        @Override
242        public void onClick(View v) {
243            switchTo(((UserSwitcherController.UserRecord)v.getTag()));
244        }
245    }
246}
247