diff options
author | John Spurlock <jspurlock@google.com> | 2015-06-24 18:46:51 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-06-24 18:47:08 +0000 |
commit | 6b0f384f0042c21129466c100e20aec1a325a8da (patch) | |
tree | 899b8a71829d9e5f6e611b8b9a3be4ecc36cf552 | |
parent | 67f170993fda3a5b629dc4c55ec52db99176d3df (diff) | |
parent | 22def3d4ebe47d39a03447f46a945228f565a1bf (diff) | |
download | frameworks_base-6b0f384f0042c21129466c100e20aec1a325a8da.zip frameworks_base-6b0f384f0042c21129466c100e20aec1a325a8da.tar.gz frameworks_base-6b0f384f0042c21129466c100e20aec1a325a8da.tar.bz2 |
Merge "Volume Motion: Initial show and expand transition." into mnc-dev
7 files changed, 412 insertions, 25 deletions
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml index 0ed1e2a..7617ed4 100644 --- a/packages/SystemUI/res/layout/volume_dialog.xml +++ b/packages/SystemUI/res/layout/volume_dialog.xml @@ -18,7 +18,7 @@ android:id="@+id/volume_dialog" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="4dp" + android:layout_marginBottom="@dimen/volume_dialog_margin_bottom" android:layout_marginLeft="@dimen/notification_side_padding" android:layout_marginRight="@dimen/notification_side_padding" android:background="@drawable/volume_dialog_background" diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml index c6aa588..1a6d34e 100644 --- a/packages/SystemUI/res/layout/volume_dialog_row.xml +++ b/packages/SystemUI/res/layout/volume_dialog_row.xml @@ -17,6 +17,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:clipChildren="false" + android:id="@+id/volume_dialog_row" android:paddingEnd="8dp" android:paddingStart="8dp" > diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 869b03a..005077f 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -576,6 +576,9 @@ <!-- Standard image button size for volume dialog buttons --> <dimen name="volume_button_size">48dp</dimen> + <!-- Volume dialog root view bottom margin, at rest --> + <dimen name="volume_dialog_margin_bottom">4dp</dimen> + <!-- Padding between icon and text for managed profile toast --> <dimen name="managed_profile_toast_padding">4dp</dimen> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 67d3312..1889862 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -291,11 +291,6 @@ <item name="android:textColor">#ffb0b3c5</item> </style> - <style name="VolumeDialogAnimations"> - <item name="android:windowEnterAnimation">@android:anim/fade_in</item> - <item name="android:windowExitAnimation">@android:anim/fade_out</item> - </style> - <style name="VolumeButtons" parent="@android:style/Widget.Material.Button.Borderless"> <item name="android:background">@drawable/btn_borderless_rect</item> </style> diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java index 065523f..0ab0392 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java @@ -111,6 +111,7 @@ public class VolumeDialog { private final Accessibility mAccessibility = new Accessibility(); private final ColorStateList mActiveSliderTint; private final ColorStateList mInactiveSliderTint; + private final VolumeDialogMotion mMotion; private boolean mShowing; private boolean mExpanded; @@ -120,9 +121,12 @@ public class VolumeDialog { private boolean mSilentMode = VolumePrefs.DEFAULT_ENABLE_SILENT_MODE; private State mState; private int mExpandButtonRes; - private boolean mExpanding; + private boolean mExpandButtonAnimationRunning; private SafetyWarningDialog mSafetyWarning; private Callback mCallback; + private boolean mPendingStateChanged; + private boolean mPendingRecheckAll; + private long mCollapseTime; public VolumeDialog(Context context, int windowType, VolumeDialogController controller, ZenModeController zenModeController, Callback callback) { @@ -151,7 +155,6 @@ public class VolumeDialog { lp.format = PixelFormat.TRANSLUCENT; lp.setTitle(VolumeDialog.class.getSimpleName()); lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; - lp.windowAnimations = R.style.VolumeDialogAnimations; lp.y = res.getDimensionPixelSize(R.dimen.volume_offset_top); lp.gravity = Gravity.TOP; window.setAttributes(lp); @@ -168,9 +171,22 @@ public class VolumeDialog { updateExpandButtonH(); mLayoutTransition = new LayoutTransition(); mLayoutTransition.setDuration(new ValueAnimator().getDuration() / 2); - mLayoutTransition.disableTransitionType(LayoutTransition.DISAPPEARING); - mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING); mDialogContentView.setLayoutTransition(mLayoutTransition); + mMotion = new VolumeDialogMotion(mDialog, mDialogView, mDialogContentView, mExpandButton, + new VolumeDialogMotion.Callback() { + @Override + public void onAnimatingChanged(boolean animating) { + if (animating) return; + if (mPendingStateChanged) { + mHandler.sendEmptyMessage(H.STATE_CHANGED); + mPendingStateChanged = false; + } + if (mPendingRecheckAll) { + mHandler.sendEmptyMessage(H.RECHECK_ALL); + mPendingRecheckAll = false; + } + } + }); addRow(AudioManager.STREAM_RING, R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, true); @@ -242,6 +258,7 @@ public class VolumeDialog { final VolumeRow row = initRow(stream, iconRes, iconMuteRes, important); if (!mRows.isEmpty()) { final View v = new View(mContext); + v.setId(android.R.id.background); final int h = mContext.getResources() .getDimensionPixelSize(R.dimen.volume_slider_interspacing); final LinearLayout.LayoutParams lp = @@ -253,10 +270,11 @@ public class VolumeDialog { @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { - if (D.BUG) Log.d(TAG, "onLayoutChange" + final boolean moved = oldLeft != left || oldTop != top; + if (D.BUG) Log.d(TAG, "onLayoutChange moved=" + moved + " old=" + new Rect(oldLeft, oldTop, oldRight, oldBottom).toShortString() + " new=" + new Rect(left,top,right,bottom).toShortString()); - if (oldLeft != left || oldTop != top) { + if (moved) { for (int i = 0; i < mDialogContentView.getChildCount(); i++) { final View c = mDialogContentView.getChildAt(i); if (!c.isShown()) continue; @@ -302,18 +320,21 @@ public class VolumeDialog { if (D.BUG) Log.d(TAG, "repositionExpandAnim x=" + x + " y=" + y); mExpandButton.setTranslationX(x); mExpandButton.setTranslationY(y); + mExpandButton.setTag((Integer) y); } public void dump(PrintWriter writer) { writer.println(VolumeDialog.class.getSimpleName() + " state:"); writer.print(" mShowing: "); writer.println(mShowing); writer.print(" mExpanded: "); writer.println(mExpanded); - writer.print(" mExpanding: "); writer.println(mExpanding); + writer.print(" mExpandButtonAnimationRunning: "); + writer.println(mExpandButtonAnimationRunning); writer.print(" mActiveStream: "); writer.println(mActiveStream); writer.print(" mDynamic: "); writer.println(mDynamic); writer.print(" mShowHeaders: "); writer.println(mShowHeaders); writer.print(" mAutomute: "); writer.println(mAutomute); writer.print(" mSilentMode: "); writer.println(mSilentMode); + writer.print(" mCollapseTime: "); writer.println(mCollapseTime); writer.print(" mAccessibility.mFeedbackEnabled: "); writer.println(mAccessibility.mFeedbackEnabled); } @@ -412,12 +433,13 @@ public class VolumeDialog { } private void showH(int reason) { + if (D.BUG) Log.d(TAG, "showH r=" + Events.DISMISS_REASONS[reason]); mHandler.removeMessages(H.SHOW); mHandler.removeMessages(H.DISMISS); rescheduleTimeoutH(); if (mShowing) return; mShowing = true; - mDialog.show(); + mMotion.startShow(); Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked()); mController.notifyVisible(true); } @@ -434,7 +456,7 @@ public class VolumeDialog { private int computeTimeoutH() { if (mAccessibility.mFeedbackEnabled) return 20000; if (mSafetyWarning != null) return 5000; - if (mExpanded || mExpanding) return 5000; + if (mExpanded || mExpandButtonAnimationRunning) return 5000; if (mActiveStream == AudioManager.STREAM_MUSIC) return 1500; return 3000; } @@ -444,9 +466,13 @@ public class VolumeDialog { mHandler.removeMessages(H.SHOW); if (!mShowing) return; mShowing = false; - mDialog.dismiss(); + mMotion.startDismiss(new Runnable() { + @Override + public void run() { + setExpandedH(false); + } + }); Events.writeEvent(mContext, Events.EVENT_DISMISS_DIALOG, reason); - setExpandedH(false); mController.notifyVisible(false); synchronized (mSafetyWarningLock) { if (mSafetyWarning != null) { @@ -456,13 +482,40 @@ public class VolumeDialog { } } + private void updateDialogBottomMarginH() { + final long diff = System.currentTimeMillis() - mCollapseTime; + final boolean collapsing = mCollapseTime != 0 && diff < getConservativeCollapseDuration(); + final ViewGroup.MarginLayoutParams mlp = (MarginLayoutParams) mDialogView.getLayoutParams(); + final int bottomMargin = collapsing ? mDialogContentView.getHeight() : + mContext.getResources().getDimensionPixelSize(R.dimen.volume_dialog_margin_bottom); + if (bottomMargin != mlp.bottomMargin) { + if (D.BUG) Log.d(TAG, "bottomMargin " + mlp.bottomMargin + " -> " + bottomMargin); + mlp.bottomMargin = bottomMargin; + mDialogView.setLayoutParams(mlp); + } + } + + private long getConservativeCollapseDuration() { + return mExpandButtonAnimationDuration * 3; + } + + private void prepareForCollapse() { + mHandler.removeMessages(H.UPDATE_BOTTOM_MARGIN); + mCollapseTime = System.currentTimeMillis(); + updateDialogBottomMarginH(); + mHandler.sendEmptyMessageDelayed(H.UPDATE_BOTTOM_MARGIN, getConservativeCollapseDuration()); + } + private void setExpandedH(boolean expanded) { if (mExpanded == expanded) return; mExpanded = expanded; - mExpanding = isAttached(); + mExpandButtonAnimationRunning = isAttached(); if (D.BUG) Log.d(TAG, "setExpandedH " + expanded); + if (!mExpanded && mExpandButtonAnimationRunning) { + prepareForCollapse(); + } updateRowsH(); - if (mExpanding) { + if (mExpandButtonAnimationRunning) { final Drawable d = mExpandButton.getDrawable(); if (d instanceof AnimatedVectorDrawable) { // workaround to reset drawable @@ -473,7 +526,7 @@ public class VolumeDialog { mHandler.postDelayed(new Runnable() { @Override public void run() { - mExpanding = false; + mExpandButtonAnimationRunning = false; updateExpandButtonH(); rescheduleTimeoutH(); } @@ -484,8 +537,9 @@ public class VolumeDialog { } private void updateExpandButtonH() { - mExpandButton.setClickable(!mExpanding); - if (mExpanding && isAttached()) return; + if (D.BUG) Log.d(TAG, "updateExpandButtonH"); + mExpandButton.setClickable(!mExpandButtonAnimationRunning); + if (mExpandButtonAnimationRunning && isAttached()) return; final int res = mExpanded ? R.drawable.ic_volume_collapse_animation : R.drawable.ic_volume_expand_animation; if (res == mExpandButtonRes) return; @@ -502,6 +556,7 @@ public class VolumeDialog { } private void updateRowsH() { + if (D.BUG) Log.d(TAG, "updateRowsH"); final VolumeRow activeRow = getActiveRow(); updateFooterH(); updateExpandButtonH(); @@ -531,6 +586,7 @@ public class VolumeDialog { } private void trimObsoleteH() { + if (D.BUG) Log.d(TAG, "trimObsoleteH"); for (int i = mRows.size() -1; i >= 0; i--) { final VolumeRow row = mRows.get(i); if (row.ss == null || !row.ss.dynamic) continue; @@ -543,7 +599,13 @@ public class VolumeDialog { } private void onStateChangedH(State state) { + final boolean animating = mMotion.isAnimating(); + if (D.BUG) Log.d(TAG, "onStateChangedH animating=" + animating); mState = state; + if (animating) { + mPendingStateChanged = true; + return; + } mDynamic.clear(); // add any new dynamic rows for (int i = 0; i < state.states.size(); i++) { @@ -568,11 +630,18 @@ public class VolumeDialog { } private void updateFooterH() { - Util.setVisOrGone(mZenFooter, mState.zenMode != Global.ZEN_MODE_OFF); + if (D.BUG) Log.d(TAG, "updateFooterH"); + final boolean wasVisible = mZenFooter.getVisibility() == View.VISIBLE; + final boolean visible = mState.zenMode != Global.ZEN_MODE_OFF; + if (wasVisible != visible && !visible) { + prepareForCollapse(); + } + Util.setVisOrGone(mZenFooter, visible); mZenFooter.update(); } private void updateVolumeRowH(VolumeRow row) { + if (D.BUG) Log.d(TAG, "updateVolumeRowH s=" + row.stream); if (mState == null) return; final StreamState ss = mState.states.get(row.stream); if (ss == null) return; @@ -841,7 +910,7 @@ public class VolumeDialog { private final OnClickListener mClickExpand = new OnClickListener() { @Override public void onClick(View v) { - if (mExpanding) return; + if (mExpandButtonAnimationRunning) return; final boolean newExpand = !mExpanded; Events.writeEvent(mContext, Events.EVENT_EXPAND, newExpand); setExpandedH(newExpand); @@ -870,6 +939,8 @@ public class VolumeDialog { private static final int RECHECK_ALL = 4; private static final int SET_STREAM_IMPORTANT = 5; private static final int RESCHEDULE_TIMEOUT = 6; + private static final int STATE_CHANGED = 7; + private static final int UPDATE_BOTTOM_MARGIN = 8; public H() { super(Looper.getMainLooper()); @@ -884,6 +955,8 @@ public class VolumeDialog { case RECHECK_ALL: recheckH(null); break; case SET_STREAM_IMPORTANT: setStreamImportantH(msg.arg1, msg.arg2 != 0); break; case RESCHEDULE_TIMEOUT: rescheduleTimeoutH(); break; + case STATE_CHANGED: onStateChangedH(mState); break; + case UPDATE_BOTTOM_MARGIN: updateDialogBottomMarginH(); break; } } } @@ -902,6 +975,12 @@ public class VolumeDialog { @Override protected void onStop() { super.onStop(); + final boolean animating = mMotion.isAnimating(); + if (D.BUG) Log.d(TAG, "onStop animating=" + animating); + if (animating) { + mPendingRecheckAll = true; + return; + } mHandler.sendEmptyMessage(H.RECHECK_ALL); } @@ -978,11 +1057,13 @@ public class VolumeDialog { mDialogView.addOnAttachStateChangeListener(new OnAttachStateChangeListener() { @Override public void onViewDetachedFromWindow(View v) { + if (D.BUG) Log.d(TAG, "onViewDetachedFromWindow"); // noop } @Override public void onViewAttachedToWindow(View v) { + if (D.BUG) Log.d(TAG, "onViewAttachedToWindow"); updateFeedbackEnabled(); } }); diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java new file mode 100644 index 0000000..fdf1840 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2015 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.volume; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.TimeInterpolator; +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.DialogInterface.OnDismissListener; +import android.content.DialogInterface.OnShowListener; +import android.os.Handler; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.PathInterpolator; + +public class VolumeDialogMotion { + private static final String TAG = Util.logTag(VolumeDialogMotion.class); + + private static final float ANIMATION_SCALE = 1.0f; + private static final int PRE_DISMISS_DELAY = 50; + private static final int POST_SHOW_DELAY = 200; + + private final Dialog mDialog; + private final View mDialogView; + private final ViewGroup mContents; // volume rows + zen footer + private final View mChevron; + private final Handler mHandler = new Handler(); + private final Callback mCallback; + + private boolean mAnimating; // show or dismiss animation is running + private boolean mShowing; // show animation is running + private boolean mDismissing; // dismiss animation is running + private ValueAnimator mChevronPositionAnimator; + private ValueAnimator mContentsPositionAnimator; + + public VolumeDialogMotion(Dialog dialog, View dialogView, ViewGroup contents, View chevron, + Callback callback) { + mDialog = dialog; + mDialogView = dialogView; + mContents = contents; + mChevron = chevron; + mCallback = callback; + mDialog.setOnDismissListener(new OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + if (D.BUG) Log.d(TAG, "mDialog.onDismiss"); + } + }); + mDialog.setOnShowListener(new OnShowListener() { + @Override + public void onShow(DialogInterface dialog) { + if (D.BUG) Log.d(TAG, "mDialog.onShow"); + final int h = mDialogView.getHeight(); + mDialogView.setTranslationY(-h); + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + startShowAnimation(); + } + }, POST_SHOW_DELAY); + } + }); + } + + public boolean isAnimating() { + return mAnimating; + } + + private void setShowing(boolean showing) { + if (showing == mShowing) return; + mShowing = showing; + if (D.BUG) Log.d(TAG, "mShowing = " + mShowing); + updateAnimating(); + } + + private void setDismissing(boolean dismissing) { + if (dismissing == mDismissing) return; + mDismissing = dismissing; + if (D.BUG) Log.d(TAG, "mDismissing = " + mDismissing); + updateAnimating(); + } + + private void updateAnimating() { + final boolean animating = mShowing || mDismissing; + if (animating == mAnimating) return; + mAnimating = animating; + if (D.BUG) Log.d(TAG, "mAnimating = " + mAnimating); + if (mCallback != null) { + mCallback.onAnimatingChanged(mAnimating); + } + } + + public void startShow() { + if (D.BUG) Log.d(TAG, "startShow"); + if (mShowing) return; + setShowing(true); + if (mDismissing) { + mDialogView.animate().cancel(); + setDismissing(false); + startShowAnimation(); + return; + } + if (D.BUG) Log.d(TAG, "mDialog.show()"); + mDialog.show(); + } + + private int chevronDistance() { + return mChevron.getHeight() / 6; + } + + private void startShowAnimation() { + if (D.BUG) Log.d(TAG, "startShowAnimation"); + mDialogView.animate() + .translationY(0) + .setDuration(scaledDuration(300)) + .setInterpolator(new LogDecelerateInterpolator()) + .setListener(null) + .setUpdateListener(new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + if (mChevronPositionAnimator == null) return; + // reposition chevron + final float v = (Float) mChevronPositionAnimator.getAnimatedValue(); + final int posY = (Integer) mChevron.getTag(); + mChevron.setTranslationY(posY + v + -mDialogView.getTranslationY()); + }}) + .start(); + + mContentsPositionAnimator = ValueAnimator.ofFloat(-chevronDistance(), 0) + .setDuration(scaledDuration(400)); + mContentsPositionAnimator.addListener(new AnimatorListenerAdapter() { + private boolean mCancelled; + + @Override + public void onAnimationEnd(Animator animation) { + if (mCancelled) return; + if (D.BUG) Log.d(TAG, "show.onAnimationEnd"); + setShowing(false); + } + @Override + public void onAnimationCancel(Animator animation) { + if (D.BUG) Log.d(TAG, "show.onAnimationCancel"); + mCancelled = true; + } + }); + mContentsPositionAnimator.addUpdateListener(new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float v = (Float) animation.getAnimatedValue(); + mContents.setTranslationY(v + -mDialogView.getTranslationY()); + } + }); + mContentsPositionAnimator.setInterpolator(new LogDecelerateInterpolator()); + mContentsPositionAnimator.start(); + + mContents.setAlpha(0); + mContents.animate() + .alpha(1) + .setDuration(scaledDuration(150)) + .setInterpolator(new PathInterpolator(0f, 0f, .2f, 1f)) + .start(); + + mChevronPositionAnimator = ValueAnimator.ofFloat(-chevronDistance(), 0) + .setDuration(scaledDuration(250)); + mChevronPositionAnimator.setInterpolator(new PathInterpolator(.4f, 0f, .2f, 1f)); + mChevronPositionAnimator.start(); + + mChevron.setAlpha(0); + mChevron.animate() + .alpha(1) + .setStartDelay(scaledDuration(50)) + .setDuration(scaledDuration(150)) + .setInterpolator(new PathInterpolator(.4f, 0f, 1f, 1f)) + .start(); + } + + public void startDismiss(final Runnable onComplete) { + if (D.BUG) Log.d(TAG, "startDismiss"); + if (mDismissing) return; + setDismissing(true); + if (mShowing) { + mDialogView.animate().cancel(); + mContentsPositionAnimator.cancel(); + mContents.animate().cancel(); + mChevronPositionAnimator.cancel(); + mChevron.animate().cancel(); + setShowing(false); + } + mDialogView.animate() + .translationY(-mDialogView.getHeight()) + .setDuration(scaledDuration(250)) + .setInterpolator(new LogAccelerateInterpolator()) + .setUpdateListener(new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mContents.setTranslationY(-mDialogView.getTranslationY()); + int posY = (Integer) mChevron.getTag(); + mChevron.setTranslationY(posY + -mDialogView.getTranslationY()); + } + }) + .setListener(new AnimatorListenerAdapter() { + private boolean mCancelled; + @Override + public void onAnimationEnd(Animator animation) { + if (mCancelled) return; + if (D.BUG) Log.d(TAG, "dismiss.onAnimationEnd"); + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + if (D.BUG) Log.d(TAG, "mDialog.dismiss()"); + mDialog.dismiss(); + onComplete.run(); + setDismissing(false); + } + }, PRE_DISMISS_DELAY); + + } + @Override + public void onAnimationCancel(Animator animation) { + if (D.BUG) Log.d(TAG, "dismiss.onAnimationCancel"); + mCancelled = true; + } + }).start(); + } + + private static int scaledDuration(int base) { + return (int) (base * ANIMATION_SCALE); + } + + private static final class LogDecelerateInterpolator implements TimeInterpolator { + private final float mBase; + private final float mDrift; + private final float mTimeScale; + private final float mOutputScale; + + private LogDecelerateInterpolator() { + this(400f, 1.4f, 0); + } + + private LogDecelerateInterpolator(float base, float timeScale, float drift) { + mBase = base; + mDrift = drift; + mTimeScale = 1f / timeScale; + + mOutputScale = 1f / computeLog(1f); + } + + private float computeLog(float t) { + return 1f - (float) Math.pow(mBase, -t * mTimeScale) + (mDrift * t); + } + + @Override + public float getInterpolation(float t) { + return computeLog(t) * mOutputScale; + } + } + + private static final class LogAccelerateInterpolator implements TimeInterpolator { + private final int mBase; + private final int mDrift; + private final float mLogScale; + + private LogAccelerateInterpolator() { + this(100, 0); + } + + private LogAccelerateInterpolator(int base, int drift) { + mBase = base; + mDrift = drift; + mLogScale = 1f / computeLog(1, mBase, mDrift); + } + + private static float computeLog(float t, int base, int drift) { + return (float) -Math.pow(base, -t) + 1 + (drift * t); + } + + @Override + public float getInterpolation(float t) { + return 1 - computeLog(1 - t, mBase, mDrift) * mLogScale; + } + } + + public interface Callback { + void onAnimatingChanged(boolean animating); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java index 3f6294d..af7ee08 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java +++ b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java @@ -16,6 +16,7 @@ package com.android.systemui.volume; import android.animation.LayoutTransition; +import android.animation.ValueAnimator; import android.content.Context; import android.provider.Settings.Global; import android.service.notification.ZenModeConfig; @@ -51,7 +52,9 @@ public class ZenFooter extends LinearLayout { super(context, attrs); mContext = context; mSpTexts = new SpTexts(mContext); - setLayoutTransition(new LayoutTransition()); + final LayoutTransition layoutTransition = new LayoutTransition(); + layoutTransition.setDuration(new ValueAnimator().getDuration() / 2); + setLayoutTransition(layoutTransition); } @Override |