1 /* 2 * Copyright (C) 2021 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.content.Context; 20 import android.util.AttributeSet; 21 import android.util.Log; 22 import android.view.View; 23 24 import com.android.app.animation.Interpolators; 25 import com.android.keyguard.AlphaOptimizedLinearLayout; 26 import com.android.keyguard.KeyguardConstants; 27 import com.android.settingslib.animation.AppearAnimationUtils; 28 import com.android.settingslib.animation.DisappearAnimationUtils; 29 30 /** 31 * The container for the user switcher on Keyguard. 32 */ 33 public class KeyguardUserSwitcherListView extends AlphaOptimizedLinearLayout { 34 35 private static final String TAG = "KeyguardUserSwitcherListView"; 36 private static final boolean DEBUG = KeyguardConstants.DEBUG; 37 38 private boolean mAnimating; 39 private final AppearAnimationUtils mAppearAnimationUtils; 40 private final DisappearAnimationUtils mDisappearAnimationUtils; 41 KeyguardUserSwitcherListView(Context context, AttributeSet attrs)42 public KeyguardUserSwitcherListView(Context context, AttributeSet attrs) { 43 super(context, attrs); 44 mAppearAnimationUtils = new AppearAnimationUtils(context, 45 AppearAnimationUtils.DEFAULT_APPEAR_DURATION, 46 -0.5f /* translationScaleFactor */, 47 0.5f /* delayScaleFactor */, 48 Interpolators.FAST_OUT_SLOW_IN); 49 mDisappearAnimationUtils = new DisappearAnimationUtils(context, 50 AppearAnimationUtils.DEFAULT_APPEAR_DURATION, 51 0.2f /* translationScaleFactor */, 52 0.2f /* delayScaleFactor */, 53 Interpolators.FAST_OUT_SLOW_IN_REVERSE); 54 } 55 56 /** 57 * Set the amount (ratio) that the device has transitioned to doze. 58 * 59 * @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake. 60 */ setDarkAmount(float darkAmount)61 void setDarkAmount(float darkAmount) { 62 int childCount = getChildCount(); 63 for (int i = 0; i < childCount; i++) { 64 View v = getChildAt(i); 65 if (v instanceof KeyguardUserDetailItemView) { 66 ((KeyguardUserDetailItemView) v).setDarkAmount(darkAmount); 67 } 68 } 69 } 70 isAnimating()71 boolean isAnimating() { 72 return mAnimating; 73 } 74 75 /** 76 * Update visibilities of this view and child views for when the user list is open or closed. 77 * If closed, this hides everything but the first item (which is always the current user). 78 */ updateVisibilities(boolean open, boolean animate)79 void updateVisibilities(boolean open, boolean animate) { 80 if (DEBUG) { 81 Log.d(TAG, String.format("updateVisibilities: open=%b animate=%b childCount=%d", 82 open, animate, getChildCount())); 83 } 84 85 mAnimating = false; 86 87 int childCount = getChildCount(); 88 KeyguardUserDetailItemView[] userItemViews = new KeyguardUserDetailItemView[childCount]; 89 for (int i = 0; i < childCount; i++) { 90 userItemViews[i] = (KeyguardUserDetailItemView) getChildAt(i); 91 userItemViews[i].clearAnimation(); 92 if (i == 0) { 93 // The first child is always the current user. 94 userItemViews[i].updateVisibilities(true /* showItem */, open /* showTextName */, 95 animate); 96 userItemViews[i].setClickable(true); 97 } else { 98 // Update clickable state immediately so that the menu feels more responsive 99 userItemViews[i].setClickable(open); 100 // when opening we need to make views visible beforehand so they can be animated 101 if (open) { 102 userItemViews[i].updateVisibilities(true /* showItem */, 103 true /* showTextName */, false /* animate */); 104 } 105 106 } 107 } 108 109 if (animate && userItemViews.length > 1) { 110 // AnimationUtils will immediately hide/show the first item in the array. Since the 111 // first view is the current user, we want to manage its visibility separately. 112 // Set first item to null so AnimationUtils ignores it. 113 userItemViews[0] = null; 114 115 setClipChildren(false); 116 setClipToPadding(false); 117 mAnimating = true; 118 (open ? mAppearAnimationUtils : mDisappearAnimationUtils) 119 .startAnimation(userItemViews, () -> { 120 setClipChildren(true); 121 setClipToPadding(true); 122 mAnimating = false; 123 if (!open) { 124 // after closing we hide children so that height of this view is correct 125 for (int i = 1; i < userItemViews.length; i++) { 126 userItemViews[i].updateVisibilities(false /* showItem */, 127 true /* showTextName */, false /* animate */); 128 } 129 } 130 }); 131 } 132 } 133 134 /** 135 * Replaces the view at the specified position in the group. 136 * 137 * @param index the position in the group of the view to remove 138 */ replaceView(KeyguardUserDetailItemView newView, int index)139 void replaceView(KeyguardUserDetailItemView newView, int index) { 140 removeViewAt(index); 141 addView(newView, index); 142 } 143 144 /** 145 * Removes the last view in the group. 146 */ removeLastView()147 void removeLastView() { 148 int lastIndex = getChildCount() - 1; 149 removeViewAt(lastIndex); 150 } 151 } 152