• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.systemui.statusbar.policy;
18 
19 import android.animation.Animator;
20 import android.animation.AnimatorListenerAdapter;
21 import android.animation.ObjectAnimator;
22 import android.content.Context;
23 import android.database.DataSetObserver;
24 import android.util.AttributeSet;
25 import android.view.LayoutInflater;
26 import android.view.MotionEvent;
27 import android.view.View;
28 import android.view.ViewGroup;
29 import android.view.ViewStub;
30 import android.widget.FrameLayout;
31 
32 import com.android.settingslib.animation.AppearAnimationUtils;
33 import com.android.systemui.Interpolators;
34 import com.android.systemui.R;
35 import com.android.systemui.qs.tiles.UserDetailItemView;
36 import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
37 import com.android.systemui.statusbar.phone.NotificationPanelView;
38 
39 /**
40  * Manages the user switcher on the Keyguard.
41  */
42 public class KeyguardUserSwitcher {
43 
44     private static final String TAG = "KeyguardUserSwitcher";
45     private static final boolean ALWAYS_ON = false;
46 
47     private final Container mUserSwitcherContainer;
48     private final KeyguardStatusBarView mStatusBarView;
49     private final Adapter mAdapter;
50     private final AppearAnimationUtils mAppearAnimationUtils;
51     private final KeyguardUserSwitcherScrim mBackground;
52 
53     private ViewGroup mUserSwitcher;
54     private ObjectAnimator mBgAnimator;
55     private UserSwitcherController mUserSwitcherController;
56     private boolean mAnimating;
57 
KeyguardUserSwitcher(Context context, ViewStub userSwitcher, KeyguardStatusBarView statusBarView, NotificationPanelView panelView, UserSwitcherController userSwitcherController)58     public KeyguardUserSwitcher(Context context, ViewStub userSwitcher,
59             KeyguardStatusBarView statusBarView, NotificationPanelView panelView,
60             UserSwitcherController userSwitcherController) {
61         boolean keyguardUserSwitcherEnabled =
62                 context.getResources().getBoolean(R.bool.config_keyguardUserSwitcher) || ALWAYS_ON;
63         if (userSwitcherController != null && keyguardUserSwitcherEnabled) {
64             mUserSwitcherContainer = (Container) userSwitcher.inflate();
65             mBackground = new KeyguardUserSwitcherScrim(context);
66             reinflateViews();
67             mStatusBarView = statusBarView;
68             mStatusBarView.setKeyguardUserSwitcher(this);
69             panelView.setKeyguardUserSwitcher(this);
70             mAdapter = new Adapter(context, userSwitcherController, this);
71             mAdapter.registerDataSetObserver(mDataSetObserver);
72             mUserSwitcherController = userSwitcherController;
73             mAppearAnimationUtils = new AppearAnimationUtils(context, 400, -0.5f, 0.5f,
74                     Interpolators.FAST_OUT_SLOW_IN);
75             mUserSwitcherContainer.setKeyguardUserSwitcher(this);
76         } else {
77             mUserSwitcherContainer = null;
78             mStatusBarView = null;
79             mAdapter = null;
80             mAppearAnimationUtils = null;
81             mBackground = null;
82         }
83     }
84 
reinflateViews()85     private void reinflateViews() {
86         if (mUserSwitcher != null) {
87             mUserSwitcher.setBackground(null);
88             mUserSwitcher.removeOnLayoutChangeListener(mBackground);
89         }
90         mUserSwitcherContainer.removeAllViews();
91 
92         LayoutInflater.from(mUserSwitcherContainer.getContext())
93                 .inflate(R.layout.keyguard_user_switcher_inner, mUserSwitcherContainer);
94 
95         mUserSwitcher = (ViewGroup) mUserSwitcherContainer.findViewById(
96                 R.id.keyguard_user_switcher_inner);
97         mUserSwitcher.addOnLayoutChangeListener(mBackground);
98         mUserSwitcher.setBackground(mBackground);
99     }
100 
setKeyguard(boolean keyguard, boolean animate)101     public void setKeyguard(boolean keyguard, boolean animate) {
102         if (mUserSwitcher != null) {
103             if (keyguard && shouldExpandByDefault()) {
104                 show(animate);
105             } else {
106                 hide(animate);
107             }
108         }
109     }
110 
111     /**
112      * @return true if the user switcher should be expanded by default on the lock screen.
113      * @see android.os.UserManager#isUserSwitcherEnabled()
114      */
shouldExpandByDefault()115     private boolean shouldExpandByDefault() {
116         return (mUserSwitcherController != null) && mUserSwitcherController.isSimpleUserSwitcher();
117     }
118 
show(boolean animate)119     public void show(boolean animate) {
120         if (mUserSwitcher != null && mUserSwitcherContainer.getVisibility() != View.VISIBLE) {
121             cancelAnimations();
122             mAdapter.refresh();
123             mUserSwitcherContainer.setVisibility(View.VISIBLE);
124             mStatusBarView.setKeyguardUserSwitcherShowing(true, animate);
125             if (animate) {
126                 startAppearAnimation();
127             }
128         }
129     }
130 
hide(boolean animate)131     private void hide(boolean animate) {
132         if (mUserSwitcher != null && mUserSwitcherContainer.getVisibility() == View.VISIBLE) {
133             cancelAnimations();
134             if (animate) {
135                 startDisappearAnimation();
136             } else {
137                 mUserSwitcherContainer.setVisibility(View.GONE);
138             }
139             mStatusBarView.setKeyguardUserSwitcherShowing(false, animate);
140         }
141     }
142 
cancelAnimations()143     private void cancelAnimations() {
144         int count = mUserSwitcher.getChildCount();
145         for (int i = 0; i < count; i++) {
146             mUserSwitcher.getChildAt(i).animate().cancel();
147         }
148         if (mBgAnimator != null) {
149             mBgAnimator.cancel();
150         }
151         mUserSwitcher.animate().cancel();
152         mAnimating = false;
153     }
154 
startAppearAnimation()155     private void startAppearAnimation() {
156         int count = mUserSwitcher.getChildCount();
157         View[] objects = new View[count];
158         for (int i = 0; i < count; i++) {
159             objects[i] = mUserSwitcher.getChildAt(i);
160         }
161         mUserSwitcher.setClipChildren(false);
162         mUserSwitcher.setClipToPadding(false);
163         mAppearAnimationUtils.startAnimation(objects, new Runnable() {
164             @Override
165             public void run() {
166                 mUserSwitcher.setClipChildren(true);
167                 mUserSwitcher.setClipToPadding(true);
168             }
169         });
170         mAnimating = true;
171         mBgAnimator = ObjectAnimator.ofInt(mBackground, "alpha", 0, 255);
172         mBgAnimator.setDuration(400);
173         mBgAnimator.setInterpolator(Interpolators.ALPHA_IN);
174         mBgAnimator.addListener(new AnimatorListenerAdapter() {
175             @Override
176             public void onAnimationEnd(Animator animation) {
177                 mBgAnimator = null;
178                 mAnimating = false;
179             }
180         });
181         mBgAnimator.start();
182     }
183 
startDisappearAnimation()184     private void startDisappearAnimation() {
185         mAnimating = true;
186         mUserSwitcher.animate()
187                 .alpha(0f)
188                 .setDuration(300)
189                 .setInterpolator(Interpolators.ALPHA_OUT)
190                 .withEndAction(new Runnable() {
191                     @Override
192                     public void run() {
193                         mUserSwitcherContainer.setVisibility(View.GONE);
194                         mUserSwitcher.setAlpha(1f);
195                         mAnimating = false;
196                     }
197                 });
198     }
199 
refresh()200     private void refresh() {
201         final int childCount = mUserSwitcher.getChildCount();
202         final int adapterCount = mAdapter.getCount();
203         final int N = Math.max(childCount, adapterCount);
204         for (int i = 0; i < N; i++) {
205             if (i < adapterCount) {
206                 View oldView = null;
207                 if (i < childCount) {
208                     oldView = mUserSwitcher.getChildAt(i);
209                 }
210                 View newView = mAdapter.getView(i, oldView, mUserSwitcher);
211                 if (oldView == null) {
212                     // We ran out of existing views. Add it at the end.
213                     mUserSwitcher.addView(newView);
214                 } else if (oldView != newView) {
215                     // We couldn't rebind the view. Replace it.
216                     mUserSwitcher.removeViewAt(i);
217                     mUserSwitcher.addView(newView, i);
218                 }
219             } else {
220                 int lastIndex = mUserSwitcher.getChildCount() - 1;
221                 mUserSwitcher.removeViewAt(lastIndex);
222             }
223         }
224     }
225 
hideIfNotSimple(boolean animate)226     public void hideIfNotSimple(boolean animate) {
227         if (mUserSwitcherContainer != null && !mUserSwitcherController.isSimpleUserSwitcher()) {
228             hide(animate);
229         }
230     }
231 
isAnimating()232     boolean isAnimating() {
233         return mAnimating;
234     }
235 
236     public final DataSetObserver mDataSetObserver = new DataSetObserver() {
237         @Override
238         public void onChanged() {
239             refresh();
240         }
241     };
242 
onDensityOrFontScaleChanged()243     public void onDensityOrFontScaleChanged() {
244         if (mUserSwitcherContainer != null) {
245             reinflateViews();
246             refresh();
247         }
248     }
249 
250     public static class Adapter extends UserSwitcherController.BaseUserAdapter implements
251             View.OnClickListener {
252 
253         private Context mContext;
254         private KeyguardUserSwitcher mKeyguardUserSwitcher;
255 
Adapter(Context context, UserSwitcherController controller, KeyguardUserSwitcher kgu)256         public Adapter(Context context, UserSwitcherController controller,
257                 KeyguardUserSwitcher kgu) {
258             super(controller);
259             mContext = context;
260             mKeyguardUserSwitcher = kgu;
261         }
262 
263         @Override
getView(int position, View convertView, ViewGroup parent)264         public View getView(int position, View convertView, ViewGroup parent) {
265             UserSwitcherController.UserRecord item = getItem(position);
266             if (!(convertView instanceof UserDetailItemView)
267                     || !(convertView.getTag() instanceof UserSwitcherController.UserRecord)) {
268                 convertView = LayoutInflater.from(mContext).inflate(
269                         R.layout.keyguard_user_switcher_item, parent, false);
270                 convertView.setOnClickListener(this);
271             }
272             UserDetailItemView v = (UserDetailItemView) convertView;
273 
274             String name = getName(mContext, item);
275             if (item.picture == null) {
276                 v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId());
277             } else {
278                 v.bind(name, item.picture, item.info.id);
279             }
280             // Disable the icon if switching is disabled
281             v.setAvatarEnabled(item.isSwitchToEnabled);
282             convertView.setActivated(item.isCurrent);
283             convertView.setTag(item);
284             return convertView;
285         }
286 
287         @Override
onClick(View v)288         public void onClick(View v) {
289             UserSwitcherController.UserRecord user = (UserSwitcherController.UserRecord) v.getTag();
290             if (user.isCurrent && !user.isGuest) {
291                 // Close the switcher if tapping the current user. Guest is excluded because
292                 // tapping the guest user while it's current clears the session.
293                 mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */);
294             } else if (user.isSwitchToEnabled) {
295                 switchTo(user);
296             }
297         }
298     }
299 
300     public static class Container extends FrameLayout {
301 
302         private KeyguardUserSwitcher mKeyguardUserSwitcher;
303 
Container(Context context, AttributeSet attrs)304         public Container(Context context, AttributeSet attrs) {
305             super(context, attrs);
306             setClipChildren(false);
307         }
308 
setKeyguardUserSwitcher(KeyguardUserSwitcher keyguardUserSwitcher)309         public void setKeyguardUserSwitcher(KeyguardUserSwitcher keyguardUserSwitcher) {
310             mKeyguardUserSwitcher = keyguardUserSwitcher;
311         }
312 
313         @Override
onTouchEvent(MotionEvent ev)314         public boolean onTouchEvent(MotionEvent ev) {
315             // Hide switcher if it didn't handle the touch event (and let the event go through).
316             if (mKeyguardUserSwitcher != null && !mKeyguardUserSwitcher.isAnimating()) {
317                 mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */);
318             }
319             return false;
320         }
321     }
322 }
323