am 22c9518c: Animations for Keyguard user switcher.

* commit '22c9518cee4f8ef7019b4cbf08a3e0d345357035':
  Animations for Keyguard user switcher.
This commit is contained in:
Jorim Jaggi
2014-08-07 22:04:42 +00:00
committed by Android Git Automerger
10 changed files with 281 additions and 49 deletions

View File

@@ -26,38 +26,70 @@ import android.view.animation.Interpolator;
*/
public class AppearAnimationUtils implements AppearAnimationCreator<View> {
public static final long APPEAR_DURATION = 220;
public static final long DEFAULT_APPEAR_DURATION = 220;
private final Interpolator mLinearOutSlowIn;
private final Interpolator mInterpolator;
private final float mStartTranslation;
private final AppearAnimationProperties mProperties = new AppearAnimationProperties();
private final float mDelayScale;
private final long mDuration;
public AppearAnimationUtils(Context ctx) {
this(ctx, 1.0f, 1.0f);
this(ctx, DEFAULT_APPEAR_DURATION,
ctx.getResources().getDimensionPixelSize(R.dimen.appear_y_translation_start),
1.0f,
AnimationUtils.loadInterpolator(ctx, android.R.interpolator.linear_out_slow_in));
}
public AppearAnimationUtils(Context ctx, float delayScaleFactor,
float translationScaleFactor) {
mLinearOutSlowIn = AnimationUtils.loadInterpolator(
ctx, android.R.interpolator.linear_out_slow_in);
public AppearAnimationUtils(Context ctx, long duration, float translationScaleFactor,
float delayScaleFactor, Interpolator interpolator) {
mInterpolator = interpolator;
mStartTranslation = ctx.getResources().getDimensionPixelOffset(
R.dimen.appear_y_translation_start) * translationScaleFactor;
mDelayScale = delayScaleFactor;
mDuration = duration;
}
public void startAppearAnimation(View[][] objects, final Runnable finishListener) {
startAppearAnimation(objects, finishListener, this);
}
public void startAppearAnimation(View[] objects, final Runnable finishListener) {
startAppearAnimation(objects, finishListener, this);
}
public <T> void startAppearAnimation(T[][] objects, final Runnable finishListener,
AppearAnimationCreator<T> creator) {
AppearAnimationProperties properties = getDelays(objects);
startAnimations(properties, objects, finishListener, creator);
}
public <T> void startAppearAnimation(T[] objects, final Runnable finishListener,
AppearAnimationCreator<T> creator) {
AppearAnimationProperties properties = getDelays(objects);
startAnimations(properties, objects, finishListener, creator);
}
private <T> void startAnimations(AppearAnimationProperties properties, T[] objects,
final Runnable finishListener, AppearAnimationCreator<T> creator) {
if (properties.maxDelayRowIndex == -1 || properties.maxDelayColIndex == -1) {
finishListener.run();
return;
}
for (int row = 0; row < properties.delays.length; row++) {
long[] columns = properties.delays[row];
long delay = columns[0];
Runnable endRunnable = null;
if (properties.maxDelayRowIndex == row && properties.maxDelayColIndex == 0) {
endRunnable = finishListener;
}
creator.createAnimation(objects[row], delay, mDuration,
mStartTranslation, mInterpolator, endRunnable);
}
}
private <T> void startAnimations(AppearAnimationProperties properties, T[][] objects,
final Runnable finishListener, AppearAnimationCreator creator) {;
final Runnable finishListener, AppearAnimationCreator<T> creator) {
if (properties.maxDelayRowIndex == -1 || properties.maxDelayColIndex == -1) {
finishListener.run();
return;
@@ -70,15 +102,32 @@ public class AppearAnimationUtils implements AppearAnimationCreator<View> {
if (properties.maxDelayRowIndex == row && properties.maxDelayColIndex == col) {
endRunnable = finishListener;
}
creator.createAnimation(objects[row][col], delay, APPEAR_DURATION,
mStartTranslation, mLinearOutSlowIn, endRunnable);
creator.createAnimation(objects[row][col], delay, mDuration,
mStartTranslation, mInterpolator, endRunnable);
}
}
}
private <T> AppearAnimationProperties getDelays(T[] items) {
long maxDelay = -1;
mProperties.maxDelayColIndex = -1;
mProperties.maxDelayRowIndex = -1;
mProperties.delays = new long[items.length][];
for (int row = 0; row < items.length; row++) {
mProperties.delays[row] = new long[1];
long delay = calculateDelay(row, 0);
mProperties.delays[row][0] = delay;
if (items[row] != null && delay > maxDelay) {
maxDelay = delay;
mProperties.maxDelayColIndex = 0;
mProperties.maxDelayRowIndex = row;
}
}
return mProperties;
}
private <T> AppearAnimationProperties getDelays(T[][] items) {
long maxDelay = 0;
long maxDelay = -1;
mProperties.maxDelayColIndex = -1;
mProperties.maxDelayRowIndex = -1;
mProperties.delays = new long[items.length][];
@@ -103,7 +152,7 @@ public class AppearAnimationUtils implements AppearAnimationCreator<View> {
}
public Interpolator getInterpolator() {
return mLinearOutSlowIn;
return mInterpolator;
}
public float getStartTranslation() {

View File

@@ -37,6 +37,7 @@ import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.Button;
import android.widget.LinearLayout;
@@ -108,8 +109,10 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
public KeyguardPatternView(Context context, AttributeSet attrs) {
super(context, attrs);
mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
mAppearAnimationUtils = new AppearAnimationUtils(context, 1.5f /* delayScale */,
2.0f /* transitionScale */);
mAppearAnimationUtils = new AppearAnimationUtils(context,
AppearAnimationUtils.DEFAULT_APPEAR_DURATION, 1.5f /* delayScale */,
2.0f /* transitionScale */, AnimationUtils.loadInterpolator(
mContext, android.R.interpolator.linear_out_slow_in));
}
public void setKeyguardCallback(KeyguardSecurityCallback callback) {
@@ -420,7 +423,7 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
this);
if (!TextUtils.isEmpty(mHelpMessage.getText())) {
mAppearAnimationUtils.createAnimation(mHelpMessage, 0,
AppearAnimationUtils.APPEAR_DURATION,
AppearAnimationUtils.DEFAULT_APPEAR_DURATION,
mAppearAnimationUtils.getStartTranslation(),
mAppearAnimationUtils.getInterpolator(),
null /* finishRunnable */);

View File

@@ -14,7 +14,8 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<com.android.systemui.statusbar.AlphaOptimizedLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/keyguard_user_switcher"
android:orientation="vertical"
android:layout_height="wrap_content"
@@ -22,4 +23,4 @@
android:gravity="end"
android:visibility="gone"
android:paddingTop="4dp">
</LinearLayout>
</com.android.systemui.statusbar.AlphaOptimizedLinearLayout>

View File

@@ -116,4 +116,9 @@ public class UserDetailItemView extends LinearLayout {
boolean activated = ArrayUtils.contains(getDrawableState(), android.R.attr.state_activated);
mName.setTypeface(activated ? mActivatedTypeface : mRegularTypeface);
}
@Override
public boolean hasOverlappingRendering() {
return false;
}
}

View File

@@ -16,10 +16,14 @@
package com.android.systemui.statusbar.phone;
import android.animation.LayoutTransition;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
@@ -48,6 +52,7 @@ public class KeyguardStatusBarView extends RelativeLayout
private KeyguardUserSwitcher mKeyguardUserSwitcher;
private int mSystemIconsSwitcherHiddenExpandedMargin;
private Interpolator mFastOutSlowInInterpolator;
public KeyguardStatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -61,6 +66,8 @@ public class KeyguardStatusBarView extends RelativeLayout
mMultiUserAvatar = (ImageView) findViewById(R.id.multi_user_avatar);
mBatteryLevel = (TextView) findViewById(R.id.battery_level);
loadDimens();
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
android.R.interpolator.fast_out_slow_in);
updateUserSwitcher();
}
@@ -70,7 +77,14 @@ public class KeyguardStatusBarView extends RelativeLayout
}
private void updateVisibilities() {
mMultiUserSwitch.setVisibility(!mKeyguardUserSwitcherShowing ? VISIBLE : GONE);
if (mMultiUserSwitch.getParent() != this && !mKeyguardUserSwitcherShowing) {
if (mMultiUserSwitch.getParent() != null) {
getOverlay().remove(mMultiUserSwitch);
}
addView(mMultiUserSwitch, 0);
} else if (mMultiUserSwitch.getParent() == this && mKeyguardUserSwitcherShowing) {
removeView(mMultiUserSwitch);
}
mBatteryLevel.setVisibility(mBatteryCharging ? View.VISIBLE : View.GONE);
}
@@ -137,12 +151,71 @@ public class KeyguardStatusBarView extends RelativeLayout
updateUserSwitcher();
}
public void setKeyguardUserSwitcherShowing(boolean showing) {
public void setKeyguardUserSwitcherShowing(boolean showing, boolean animate) {
mKeyguardUserSwitcherShowing = showing;
if (animate) {
animateNextLayoutChange();
}
updateVisibilities();
updateSystemIconsLayoutParams();
}
private void animateNextLayoutChange() {
final int systemIconsCurrentX = mSystemIconsSuperContainer.getLeft();
final boolean userSwitcherVisible = mMultiUserSwitch.getParent() == this;
getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
getViewTreeObserver().removeOnPreDrawListener(this);
boolean userSwitcherHiding = userSwitcherVisible
&& mMultiUserSwitch.getParent() != KeyguardStatusBarView.this;
mSystemIconsSuperContainer.setX(systemIconsCurrentX);
mSystemIconsSuperContainer.animate()
.translationX(0)
.setDuration(400)
.setStartDelay(userSwitcherHiding ? 300 : 0)
.setInterpolator(mFastOutSlowInInterpolator)
.start();
if (userSwitcherHiding) {
getOverlay().add(mMultiUserSwitch);
mMultiUserSwitch.animate()
.alpha(0f)
.setDuration(300)
.setStartDelay(0)
.setInterpolator(PhoneStatusBar.ALPHA_OUT)
.withEndAction(new Runnable() {
@Override
public void run() {
mMultiUserSwitch.setAlpha(1f);
getOverlay().remove(mMultiUserSwitch);
}
})
.start();
} else {
mMultiUserSwitch.setAlpha(0f);
mMultiUserSwitch.animate()
.alpha(1f)
.setDuration(300)
.setStartDelay(200)
.setInterpolator(PhoneStatusBar.ALPHA_IN);
}
return true;
}
});
}
@Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
if (visibility != View.VISIBLE) {
mSystemIconsSuperContainer.animate().cancel();
mMultiUserSwitch.animate().cancel();
mMultiUserSwitch.setAlpha(1f);
}
}
@Override
public boolean hasOverlappingRendering() {
return false;

View File

@@ -65,7 +65,7 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener
if (um.isUserSwitcherEnabled()) {
if (mKeyguardMode) {
if (mKeyguardUserSwitcher != null) {
mKeyguardUserSwitcher.show();
mKeyguardUserSwitcher.show(true /* animate */);
}
} else {
mQsPanel.showDetailAdapter(true,
@@ -78,4 +78,9 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener
getContext().startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
}
}
@Override
public boolean hasOverlappingRendering() {
return false;
}
}

View File

@@ -950,7 +950,7 @@ public class NotificationPanelView extends PanelView implements
? View.VISIBLE
: View.INVISIBLE);
if (mKeyguardUserSwitcher != null && mQsExpanded && !mStackScrollerOverscrolling) {
mKeyguardUserSwitcher.hide();
mKeyguardUserSwitcher.hide(true /* animate */);
}
}

View File

@@ -3341,7 +3341,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
public void showKeyguard() {
setBarState(StatusBarState.KEYGUARD);
updateKeyguardState(false /* goingToFullShade */);
updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
instantExpandNotificationsPanel();
mLeaveOpenOnKeyguardHide = false;
if (mDraggedDownRow != null) {
@@ -3413,7 +3413,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
} else {
instantCollapseNotificationPanel();
}
updateKeyguardState(staying);
updateKeyguardState(staying, false /* fromShadeLocked */);
return staying;
}
@@ -3449,14 +3449,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
&& mStatusBarKeyguardViewManager.isSecure());
}
private void updateKeyguardState(boolean goingToFullShade) {
private void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) {
if (mState == StatusBarState.KEYGUARD) {
mKeyguardIndicationController.setVisible(true);
mNotificationPanel.resetViews();
mKeyguardUserSwitcher.setKeyguard(true);
mKeyguardUserSwitcher.setKeyguard(true, fromShadeLocked);
} else {
mKeyguardIndicationController.setVisible(false);
mKeyguardUserSwitcher.setKeyguard(false);
mKeyguardUserSwitcher.setKeyguard(false,
goingToFullShade || mState == StatusBarState.SHADE_LOCKED || fromShadeLocked);
}
if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
mScrimController.setKeyguardShowing(true);
@@ -3686,7 +3687,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
} else {
mNotificationPanel.animateToFullShade(0 /* delay */);
setBarState(StatusBarState.SHADE_LOCKED);
updateKeyguardState(false /* goingToFullShade */);
updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
if (row != null) {
row.setUserLocked(false);
}
@@ -3699,7 +3700,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
public void goToKeyguard() {
if (mState == StatusBarState.SHADE_LOCKED) {
setBarState(StatusBarState.KEYGUARD);
updateKeyguardState(false /* goingToFullShade */);
updateKeyguardState(false /* goingToFullShade */, true /* fromShadeLocked*/);
}
}

View File

@@ -16,18 +16,25 @@
package com.android.systemui.statusbar.policy;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.database.DataSetObserver;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.view.animation.AnimationUtils;
import android.widget.TextView;
import com.android.keyguard.AppearAnimationUtils;
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;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.phone.StatusBarHeaderView;
import com.android.systemui.statusbar.phone.UserAvatarView;
@@ -43,33 +50,42 @@ public class KeyguardUserSwitcher {
private final KeyguardStatusBarView mStatusBarView;
private final Adapter mAdapter;
private final boolean mSimpleUserSwitcher;
private final AppearAnimationUtils mAppearAnimationUtils;
private final KeyguardUserSwitcherScrim mBackground;
private ObjectAnimator mBgAnimator;
public KeyguardUserSwitcher(Context context, ViewStub userSwitcher,
KeyguardStatusBarView statusBarView, NotificationPanelView panelView,
UserSwitcherController userSwitcherController) {
if (context.getResources().getBoolean(R.bool.config_keyguardUserSwitcher) || ALWAYS_ON) {
mUserSwitcher = (ViewGroup) userSwitcher.inflate();
mUserSwitcher.setBackground(new KeyguardUserSwitcherScrim(mUserSwitcher));
mBackground = new KeyguardUserSwitcherScrim(mUserSwitcher);
mUserSwitcher.setBackground(mBackground);
mStatusBarView = statusBarView;
mStatusBarView.setKeyguardUserSwitcher(this);
panelView.setKeyguardUserSwitcher(this);
mAdapter = new Adapter(context, userSwitcherController);
mAdapter.registerDataSetObserver(mDataSetObserver);
mSimpleUserSwitcher = userSwitcherController.isSimpleUserSwitcher();
mAppearAnimationUtils = new AppearAnimationUtils(context, 400, -0.5f, 0.5f,
AnimationUtils.loadInterpolator(
context, android.R.interpolator.fast_out_slow_in));
} else {
mUserSwitcher = null;
mStatusBarView = null;
mAdapter = null;
mSimpleUserSwitcher = false;
mAppearAnimationUtils = null;
mBackground = null;
}
}
public void setKeyguard(boolean keyguard) {
public void setKeyguard(boolean keyguard, boolean animate) {
if (mUserSwitcher != null) {
if (keyguard && shouldExpandByDefault()) {
show();
show(animate);
} else {
hide();
hide(animate);
}
}
}
@@ -82,22 +98,81 @@ public class KeyguardUserSwitcher {
return mSimpleUserSwitcher;
}
public void show() {
if (mUserSwitcher != null) {
// TODO: animate
public void show(boolean animate) {
if (mUserSwitcher != null && mUserSwitcher.getVisibility() != View.VISIBLE) {
cancelAnimations();
mUserSwitcher.setVisibility(View.VISIBLE);
mStatusBarView.setKeyguardUserSwitcherShowing(true);
mStatusBarView.setKeyguardUserSwitcherShowing(true, animate);
if (animate) {
startAppearAnimation();
}
}
}
public void hide() {
public void hide(boolean animate) {
if (mUserSwitcher != null && mUserSwitcher.getVisibility() == View.VISIBLE) {
// TODO: animate
mUserSwitcher.setVisibility(View.GONE);
mStatusBarView.setKeyguardUserSwitcherShowing(false);
cancelAnimations();
if (animate) {
startDisappearAnimation();
} else {
mUserSwitcher.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();
}
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.startAppearAnimation(objects, new Runnable() {
@Override
public void run() {
mUserSwitcher.setClipChildren(true);
mUserSwitcher.setClipToPadding(true);
}
});
mBgAnimator = ObjectAnimator.ofInt(mBackground, "alpha", 0, 255);
mBgAnimator.setDuration(400);
mBgAnimator.setInterpolator(PhoneStatusBar.ALPHA_IN);
mBgAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mBgAnimator = null;
}
});
mBgAnimator.start();
}
private void startDisappearAnimation() {
mUserSwitcher.animate()
.alpha(0f)
.setDuration(300)
.setInterpolator(PhoneStatusBar.ALPHA_OUT)
.withEndAction(new Runnable() {
@Override
public void run() {
mUserSwitcher.setVisibility(View.GONE);
mUserSwitcher.setAlpha(1f);
}
});
}
private void refresh() {
final int childCount = mUserSwitcher.getChildCount();
final int adapterCount = mAdapter.getCount();

View File

@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.policy;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.LightingColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.RadialGradient;
@@ -41,7 +42,9 @@ public class KeyguardUserSwitcherScrim extends Drawable
private int mDarkColor;
private int mTop;
private int mAlpha;
private Paint mRadialGradientPaint = new Paint();
private int mLayoutWidth;
public KeyguardUserSwitcherScrim(View host) {
host.addOnLayoutChangeListener(this);
@@ -56,13 +59,21 @@ public class KeyguardUserSwitcherScrim extends Drawable
float width = bounds.width() * OUTER_EXTENT;
float height = (mTop + bounds.height()) * OUTER_EXTENT;
canvas.translate(0, -mTop);
canvas.scale(1, height/width);
canvas.scale(1, height / width);
canvas.drawRect(isLtr ? bounds.right - width : 0, 0,
isLtr ? bounds.right : bounds.left + width, width, mRadialGradientPaint);
}
@Override
public void setAlpha(int alpha) {
mAlpha = alpha;
updatePaint();
invalidateSelf();
}
@Override
public int getAlpha() {
return mAlpha;
}
@Override
@@ -78,15 +89,24 @@ public class KeyguardUserSwitcherScrim extends Drawable
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
int oldTop, int oldRight, int oldBottom) {
if (left != oldLeft || top != oldTop || right != oldRight || bottom != oldBottom) {
int width = right - left;
float radius = width * OUTER_EXTENT;
boolean isLtr = getLayoutDirection() == LayoutDirection.LTR;
mRadialGradientPaint.setShader(
new RadialGradient(isLtr ? width : 0, 0, radius,
new int[] { mDarkColor, Color.TRANSPARENT},
new float[] { Math.max(0f, width * INNER_EXTENT / radius), 1f},
Shader.TileMode.CLAMP));
mLayoutWidth = right - left;
mTop = top;
updatePaint();
}
}
private void updatePaint() {
if (mLayoutWidth == 0) {
return;
}
float radius = mLayoutWidth * OUTER_EXTENT;
boolean isLtr = getLayoutDirection() == LayoutDirection.LTR;
mRadialGradientPaint.setShader(
new RadialGradient(isLtr ? mLayoutWidth : 0, 0, radius,
new int[] { Color.argb(
(int) (Color.alpha(mDarkColor) * mAlpha / 255f), 0, 0, 0),
Color.TRANSPARENT },
new float[] { Math.max(0f, mLayoutWidth * INNER_EXTENT / radius), 1f },
Shader.TileMode.CLAMP));
}
}