| /* |
| * 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.statusbar.policy; |
| |
| import android.animation.Animator; |
| import android.animation.AnimatorListenerAdapter; |
| import android.animation.ObjectAnimator; |
| import android.content.Context; |
| import android.database.DataSetObserver; |
| import android.util.AttributeSet; |
| import android.view.LayoutInflater; |
| import android.view.MotionEvent; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.view.ViewStub; |
| import android.widget.FrameLayout; |
| |
| import com.android.settingslib.animation.AppearAnimationUtils; |
| import com.android.systemui.Interpolators; |
| import com.android.systemui.R; |
| import com.android.systemui.qs.tiles.UserDetailItemView; |
| import com.android.systemui.statusbar.phone.KeyguardStatusBarView; |
| import com.android.systemui.statusbar.phone.NotificationPanelView; |
| |
| /** |
| * Manages the user switcher on the Keyguard. |
| */ |
| public class KeyguardUserSwitcher { |
| |
| private static final String TAG = "KeyguardUserSwitcher"; |
| private static final boolean ALWAYS_ON = false; |
| |
| private final Container mUserSwitcherContainer; |
| private final KeyguardStatusBarView mStatusBarView; |
| private final Adapter mAdapter; |
| private final AppearAnimationUtils mAppearAnimationUtils; |
| private final KeyguardUserSwitcherScrim mBackground; |
| |
| private ViewGroup mUserSwitcher; |
| private ObjectAnimator mBgAnimator; |
| private UserSwitcherController mUserSwitcherController; |
| private boolean mAnimating; |
| |
| public KeyguardUserSwitcher(Context context, ViewStub userSwitcher, |
| KeyguardStatusBarView statusBarView, NotificationPanelView panelView, |
| UserSwitcherController userSwitcherController) { |
| boolean keyguardUserSwitcherEnabled = |
| context.getResources().getBoolean(R.bool.config_keyguardUserSwitcher) || ALWAYS_ON; |
| if (userSwitcherController != null && keyguardUserSwitcherEnabled) { |
| mUserSwitcherContainer = (Container) userSwitcher.inflate(); |
| mBackground = new KeyguardUserSwitcherScrim(context); |
| reinflateViews(); |
| mStatusBarView = statusBarView; |
| mStatusBarView.setKeyguardUserSwitcher(this); |
| panelView.setKeyguardUserSwitcher(this); |
| mAdapter = new Adapter(context, userSwitcherController, this); |
| mAdapter.registerDataSetObserver(mDataSetObserver); |
| mUserSwitcherController = userSwitcherController; |
| mAppearAnimationUtils = new AppearAnimationUtils(context, 400, -0.5f, 0.5f, |
| Interpolators.FAST_OUT_SLOW_IN); |
| mUserSwitcherContainer.setKeyguardUserSwitcher(this); |
| } else { |
| mUserSwitcherContainer = null; |
| mStatusBarView = null; |
| mAdapter = null; |
| mAppearAnimationUtils = null; |
| mBackground = null; |
| } |
| } |
| |
| private void reinflateViews() { |
| if (mUserSwitcher != null) { |
| mUserSwitcher.setBackground(null); |
| mUserSwitcher.removeOnLayoutChangeListener(mBackground); |
| } |
| mUserSwitcherContainer.removeAllViews(); |
| |
| LayoutInflater.from(mUserSwitcherContainer.getContext()) |
| .inflate(R.layout.keyguard_user_switcher_inner, mUserSwitcherContainer); |
| |
| mUserSwitcher = (ViewGroup) mUserSwitcherContainer.findViewById( |
| R.id.keyguard_user_switcher_inner); |
| mUserSwitcher.addOnLayoutChangeListener(mBackground); |
| mUserSwitcher.setBackground(mBackground); |
| } |
| |
| public void setKeyguard(boolean keyguard, boolean animate) { |
| if (mUserSwitcher != null) { |
| if (keyguard && shouldExpandByDefault()) { |
| show(animate); |
| } else { |
| hide(animate); |
| } |
| } |
| } |
| |
| /** |
| * @return true if the user switcher should be expanded by default on the lock screen. |
| * @see android.os.UserManager#isUserSwitcherEnabled() |
| */ |
| private boolean shouldExpandByDefault() { |
| return (mUserSwitcherController != null) && mUserSwitcherController.isSimpleUserSwitcher(); |
| } |
| |
| public void show(boolean animate) { |
| if (mUserSwitcher != null && mUserSwitcherContainer.getVisibility() != View.VISIBLE) { |
| cancelAnimations(); |
| mAdapter.refresh(); |
| mUserSwitcherContainer.setVisibility(View.VISIBLE); |
| mStatusBarView.setKeyguardUserSwitcherShowing(true, animate); |
| if (animate) { |
| startAppearAnimation(); |
| } |
| } |
| } |
| |
| private void hide(boolean animate) { |
| if (mUserSwitcher != null && mUserSwitcherContainer.getVisibility() == View.VISIBLE) { |
| cancelAnimations(); |
| if (animate) { |
| startDisappearAnimation(); |
| } else { |
| mUserSwitcherContainer.setVisibility(View.GONE); |
| } |
| mStatusBarView.setKeyguardUserSwitcherShowing(false, animate); |
| } |
| } |
| |
| private void cancelAnimations() { |
| int count = mUserSwitcher.getChildCount(); |
| for (int i = 0; i < count; i++) { |
| mUserSwitcher.getChildAt(i).animate().cancel(); |
| } |
| if (mBgAnimator != null) { |
| mBgAnimator.cancel(); |
| } |
| mUserSwitcher.animate().cancel(); |
| mAnimating = false; |
| } |
| |
| private void startAppearAnimation() { |
| int count = mUserSwitcher.getChildCount(); |
| View[] objects = new View[count]; |
| for (int i = 0; i < count; i++) { |
| objects[i] = mUserSwitcher.getChildAt(i); |
| } |
| mUserSwitcher.setClipChildren(false); |
| mUserSwitcher.setClipToPadding(false); |
| mAppearAnimationUtils.startAnimation(objects, new Runnable() { |
| @Override |
| public void run() { |
| mUserSwitcher.setClipChildren(true); |
| mUserSwitcher.setClipToPadding(true); |
| } |
| }); |
| mAnimating = true; |
| mBgAnimator = ObjectAnimator.ofInt(mBackground, "alpha", 0, 255); |
| mBgAnimator.setDuration(400); |
| mBgAnimator.setInterpolator(Interpolators.ALPHA_IN); |
| mBgAnimator.addListener(new AnimatorListenerAdapter() { |
| @Override |
| public void onAnimationEnd(Animator animation) { |
| mBgAnimator = null; |
| mAnimating = false; |
| } |
| }); |
| mBgAnimator.start(); |
| } |
| |
| private void startDisappearAnimation() { |
| mAnimating = true; |
| mUserSwitcher.animate() |
| .alpha(0f) |
| .setDuration(300) |
| .setInterpolator(Interpolators.ALPHA_OUT) |
| .withEndAction(new Runnable() { |
| @Override |
| public void run() { |
| mUserSwitcherContainer.setVisibility(View.GONE); |
| mUserSwitcher.setAlpha(1f); |
| mAnimating = false; |
| } |
| }); |
| } |
| |
| private void refresh() { |
| final int childCount = mUserSwitcher.getChildCount(); |
| final int adapterCount = mAdapter.getCount(); |
| final int N = Math.max(childCount, adapterCount); |
| for (int i = 0; i < N; i++) { |
| if (i < adapterCount) { |
| View oldView = null; |
| if (i < childCount) { |
| oldView = mUserSwitcher.getChildAt(i); |
| } |
| View newView = mAdapter.getView(i, oldView, mUserSwitcher); |
| if (oldView == null) { |
| // We ran out of existing views. Add it at the end. |
| mUserSwitcher.addView(newView); |
| } else if (oldView != newView) { |
| // We couldn't rebind the view. Replace it. |
| mUserSwitcher.removeViewAt(i); |
| mUserSwitcher.addView(newView, i); |
| } |
| } else { |
| int lastIndex = mUserSwitcher.getChildCount() - 1; |
| mUserSwitcher.removeViewAt(lastIndex); |
| } |
| } |
| } |
| |
| public void hideIfNotSimple(boolean animate) { |
| if (mUserSwitcherContainer != null && !mUserSwitcherController.isSimpleUserSwitcher()) { |
| hide(animate); |
| } |
| } |
| |
| boolean isAnimating() { |
| return mAnimating; |
| } |
| |
| public final DataSetObserver mDataSetObserver = new DataSetObserver() { |
| @Override |
| public void onChanged() { |
| refresh(); |
| } |
| }; |
| |
| public void onDensityOrFontScaleChanged() { |
| if (mUserSwitcherContainer != null) { |
| reinflateViews(); |
| refresh(); |
| } |
| } |
| |
| public static class Adapter extends UserSwitcherController.BaseUserAdapter implements |
| View.OnClickListener { |
| |
| private Context mContext; |
| private KeyguardUserSwitcher mKeyguardUserSwitcher; |
| |
| public Adapter(Context context, UserSwitcherController controller, |
| KeyguardUserSwitcher kgu) { |
| super(controller); |
| mContext = context; |
| mKeyguardUserSwitcher = kgu; |
| } |
| |
| @Override |
| public View getView(int position, View convertView, ViewGroup parent) { |
| UserSwitcherController.UserRecord item = getItem(position); |
| if (!(convertView instanceof UserDetailItemView) |
| || !(convertView.getTag() instanceof UserSwitcherController.UserRecord)) { |
| convertView = LayoutInflater.from(mContext).inflate( |
| R.layout.keyguard_user_switcher_item, parent, false); |
| convertView.setOnClickListener(this); |
| } |
| UserDetailItemView v = (UserDetailItemView) convertView; |
| |
| String name = getName(mContext, item); |
| if (item.picture == null) { |
| v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId()); |
| } else { |
| v.bind(name, item.picture, item.info.id); |
| } |
| // Disable the icon if switching is disabled |
| v.setAvatarEnabled(item.isSwitchToEnabled); |
| convertView.setActivated(item.isCurrent); |
| convertView.setTag(item); |
| return convertView; |
| } |
| |
| @Override |
| public void onClick(View v) { |
| UserSwitcherController.UserRecord user = (UserSwitcherController.UserRecord) v.getTag(); |
| if (user.isCurrent && !user.isGuest) { |
| // Close the switcher if tapping the current user. Guest is excluded because |
| // tapping the guest user while it's current clears the session. |
| mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */); |
| } else if (user.isSwitchToEnabled) { |
| switchTo(user); |
| } |
| } |
| } |
| |
| public static class Container extends FrameLayout { |
| |
| private KeyguardUserSwitcher mKeyguardUserSwitcher; |
| |
| public Container(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| setClipChildren(false); |
| } |
| |
| public void setKeyguardUserSwitcher(KeyguardUserSwitcher keyguardUserSwitcher) { |
| mKeyguardUserSwitcher = keyguardUserSwitcher; |
| } |
| |
| @Override |
| public boolean onTouchEvent(MotionEvent ev) { |
| // Hide switcher if it didn't handle the touch event (and let the event go through). |
| if (mKeyguardUserSwitcher != null && !mKeyguardUserSwitcher.isAnimating()) { |
| mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */); |
| } |
| return false; |
| } |
| } |
| } |