am 6b0f384f: Merge "Volume Motion: Initial show and expand transition." into mnc-dev
* commit '6b0f384f0042c21129466c100e20aec1a325a8da': Volume Motion: Initial show and expand transition.
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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" >
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user