Home | History | Annotate | Download | only in policy
      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 
     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 
     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 
    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      */
    115     private boolean shouldExpandByDefault() {
    116         return (mUserSwitcherController != null) && mUserSwitcherController.isSimpleUserSwitcher();
    117     }
    118 
    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 
    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 
    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 
    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 
    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 
    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 
    226     public void hideIfNotSimple(boolean animate) {
    227         if (mUserSwitcherContainer != null && !mUserSwitcherController.isSimpleUserSwitcher()) {
    228             hide(animate);
    229         }
    230     }
    231 
    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 
    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 
    256         public Adapter(Context context, UserSwitcherController controller,
    257                 KeyguardUserSwitcher kgu) {
    258             super(controller);
    259             mContext = context;
    260             mKeyguardUserSwitcher = kgu;
    261         }
    262 
    263         @Override
    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
    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 
    304         public Container(Context context, AttributeSet attrs) {
    305             super(context, attrs);
    306             setClipChildren(false);
    307         }
    308 
    309         public void setKeyguardUserSwitcher(KeyguardUserSwitcher keyguardUserSwitcher) {
    310             mKeyguardUserSwitcher = keyguardUserSwitcher;
    311         }
    312 
    313         @Override
    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