From 16fbd9dd1d2d407aa0bc096800af2630c218cde8 Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Thu, 27 Apr 2017 14:28:49 -0400 Subject: [PATCH] Early version of new volume + power menus Still needs a bunch of code cleanup, but this will get a version into the tree for testing. Test: visual Bug: 37013646 Change-Id: I29800b57d80ea120c691663392f368c17325ab54 --- packages/SystemUI/res/drawable/rounded_bg.xml | 11 + .../res/drawable/rounded_bg_bottom.xml | 11 + .../SystemUI/res/drawable/rounded_bg_full.xml | 11 + .../res/drawable/rounded_full_bg_bottom.xml | 11 + .../res/layout/global_actions_item.xml | 57 +++ .../res/layout/global_actions_wrapped.xml | 25 ++ .../SystemUI/res/layout/volume_dialog.xml | 7 +- .../res/layout/volume_dialog_wrapped.xml | 11 + packages/SystemUI/res/values/dimens.xml | 13 +- .../android/systemui/HardwareBgDrawable.java | 114 ++++++ .../android/systemui/HardwareUiLayout.java | 383 ++++++++++++++++++ .../globalactions/GlobalActionsDialog.java | 215 +++++----- .../systemui/volume/VolumeDialogImpl.java | 120 +++--- .../systemui/volume/VolumeDialogMotion.java | 53 +-- 14 files changed, 845 insertions(+), 197 deletions(-) create mode 100644 packages/SystemUI/res/drawable/rounded_bg.xml create mode 100644 packages/SystemUI/res/drawable/rounded_bg_bottom.xml create mode 100644 packages/SystemUI/res/drawable/rounded_bg_full.xml create mode 100644 packages/SystemUI/res/drawable/rounded_full_bg_bottom.xml create mode 100644 packages/SystemUI/res/layout/global_actions_item.xml create mode 100644 packages/SystemUI/res/layout/global_actions_wrapped.xml create mode 100644 packages/SystemUI/res/layout/volume_dialog_wrapped.xml create mode 100644 packages/SystemUI/src/com/android/systemui/HardwareBgDrawable.java create mode 100644 packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java diff --git a/packages/SystemUI/res/drawable/rounded_bg.xml b/packages/SystemUI/res/drawable/rounded_bg.xml new file mode 100644 index 0000000000000..56aa9fe800d9f --- /dev/null +++ b/packages/SystemUI/res/drawable/rounded_bg.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/packages/SystemUI/res/drawable/rounded_bg_bottom.xml b/packages/SystemUI/res/drawable/rounded_bg_bottom.xml new file mode 100644 index 0000000000000..0201f28354524 --- /dev/null +++ b/packages/SystemUI/res/drawable/rounded_bg_bottom.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/packages/SystemUI/res/drawable/rounded_bg_full.xml b/packages/SystemUI/res/drawable/rounded_bg_full.xml new file mode 100644 index 0000000000000..65d00dea73574 --- /dev/null +++ b/packages/SystemUI/res/drawable/rounded_bg_full.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/packages/SystemUI/res/drawable/rounded_full_bg_bottom.xml b/packages/SystemUI/res/drawable/rounded_full_bg_bottom.xml new file mode 100644 index 0000000000000..f6ee558b5064f --- /dev/null +++ b/packages/SystemUI/res/drawable/rounded_full_bg_bottom.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/packages/SystemUI/res/layout/global_actions_item.xml b/packages/SystemUI/res/layout/global_actions_item.xml new file mode 100644 index 0000000000000..358833c1ed414 --- /dev/null +++ b/packages/SystemUI/res/layout/global_actions_item.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + diff --git a/packages/SystemUI/res/layout/global_actions_wrapped.xml b/packages/SystemUI/res/layout/global_actions_wrapped.xml new file mode 100644 index 0000000000000..f409c03833bb5 --- /dev/null +++ b/packages/SystemUI/res/layout/global_actions_wrapped.xml @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml index 18ffd0fac4172..90761994cde6f 100644 --- a/packages/SystemUI/res/layout/volume_dialog.xml +++ b/packages/SystemUI/res/layout/volume_dialog.xml @@ -16,12 +16,12 @@ + android:translationZ="8dp" > + + + + + diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index a98afa9e68303..2f5f7272f24e6 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -208,8 +208,6 @@ @dimen/notification_panel_width - @dimen/standard_notification_panel_width - 0x31 @@ -780,4 +778,15 @@ 17dp + 16dp + + 315dp + 125dp + + 100dp + + 16dp + 0dp + 48dp + 16dp diff --git a/packages/SystemUI/src/com/android/systemui/HardwareBgDrawable.java b/packages/SystemUI/src/com/android/systemui/HardwareBgDrawable.java new file mode 100644 index 0000000000000..6417e292158aa --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/HardwareBgDrawable.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2017 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; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; +import android.util.Log; + +public class HardwareBgDrawable extends LayerDrawable { + + private final Paint mPaint = new Paint(); + private final Drawable[] mLayers; + private final boolean mRoundTop; + private int mPoint; + private boolean mRotatedBackground; + + public HardwareBgDrawable(boolean roundTop, boolean roundEnd, Context context) { + this(roundTop, getLayers(context, roundTop, roundEnd)); + } + + public HardwareBgDrawable(boolean roundTop, Drawable[] layers) { + super(layers); + if (layers.length != 2) { + throw new IllegalArgumentException("Need 2 layers"); + } + mRoundTop = roundTop; + mLayers = layers; + mLayers[1].setTint(0xffeeeeee); + } + + private static Drawable[] getLayers(Context context, boolean roundTop, boolean roundEnd) { + int drawable = roundEnd ? R.drawable.rounded_bg_full : R.drawable.rounded_bg; + if (roundTop) { + return new Drawable[]{ + context.getDrawable(drawable).mutate(), + context.getDrawable(drawable).mutate(), + }; + } + return new Drawable[]{ + context.getDrawable(drawable).mutate(), + context.getDrawable(roundEnd ? R.drawable.rounded_full_bg_bottom + : R.drawable.rounded_bg_bottom).mutate(), + }; + } + + public void setCutPoint(int point) { + mPoint = point; + invalidateSelf(); + } + + public int getCutPoint() { + return mPoint; + } + + @Override + public void draw(Canvas canvas) { + if (mPoint >= 0 && !mRotatedBackground) { + Rect bounds = getBounds(); + int top = bounds.top + mPoint; + if (top > bounds.bottom) top = bounds.bottom; + if (mRoundTop) { + mLayers[0].setBounds(bounds.left, bounds.top, bounds.right, top); + } else { + mLayers[1].setBounds(bounds.left, top, bounds.right, bounds.bottom); + } + if (mRoundTop) { + mLayers[1].draw(canvas); + mLayers[0].draw(canvas); + } else { + mLayers[0].draw(canvas); + mLayers[1].draw(canvas); + } + } else { + mLayers[0].draw(canvas); + } + } + + @Override + public void setAlpha(int alpha) { + mPaint.setAlpha(alpha); + } + + @Override + public void setColorFilter(ColorFilter colorFilter) { + mPaint.setColorFilter(colorFilter); + } + + @Override + public int getOpacity() { + return PixelFormat.OPAQUE; + } + + public void setRotatedBackground(boolean rotatedBackground) { + mRotatedBackground = rotatedBackground; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java new file mode 100644 index 0000000000000..bb0f2f9f3ac00 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java @@ -0,0 +1,383 @@ +/* + * Copyright (C) 2017 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; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.provider.Settings; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewOutlineProvider; +import android.view.ViewTreeObserver; +import android.widget.FrameLayout; +import android.widget.LinearLayout; + +import com.android.systemui.tuner.TunerService; +import com.android.systemui.tuner.TunerService.Tunable; + +public class HardwareUiLayout extends FrameLayout implements Tunable { + + private static final String EDGE_BLEED = "sysui_hwui_edge_bleed"; + private static final String ROUNDED_DIVIDER = "sysui_hwui_rounded_divider"; + private final int[] mTmp2 = new int[2]; + private View mChild; + private int mOldHeight; + private boolean mAnimating; + private AnimatorSet mAnimation; + private View mDivision; + private boolean mHasOutsideTouch; + private HardwareBgDrawable mBackground; + private Animator mAnimator; + private boolean mCollapse; + private int mEndPoint; + private boolean mEdgeBleed; + private boolean mRoundedDivider; + private boolean mLandscape; + private boolean mRotatedBackground; + + public HardwareUiLayout(Context context, AttributeSet attrs) { + super(context, attrs); + updateSettings(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + updateSettings(); + Dependency.get(TunerService.class).addTunable(this, EDGE_BLEED, ROUNDED_DIVIDER); + getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsListener); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsListener); + Dependency.get(TunerService.class).removeTunable(this); + } + + @Override + public void onTuningChanged(String key, String newValue) { + updateSettings(); + } + + private void updateSettings() { + mEdgeBleed = Settings.Secure.getInt(getContext().getContentResolver(), + EDGE_BLEED, 0) != 0; + mRoundedDivider = Settings.Secure.getInt(getContext().getContentResolver(), + ROUNDED_DIVIDER, 1) != 0; + updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding()); + mBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed, getContext()); + if (mChild != null) { + mChild.setBackground(mBackground); + requestLayout(); + } + } + + private void updateEdgeMargin(int edge) { + if (mChild != null) { + MarginLayoutParams params = (MarginLayoutParams) mChild.getLayoutParams(); + if (mLandscape) { + params.topMargin = edge; + } else { + params.rightMargin = edge; + } + mChild.setLayoutParams(params); + } + } + + private int getEdgePadding() { + return getContext().getResources().getDimensionPixelSize(R.dimen.edge_margin); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (mChild == null) { + if (getChildCount() != 0) { + mChild = getChildAt(0); + mChild.setBackground(mBackground); + updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding()); + mOldHeight = mChild.getMeasuredHeight(); + mChild.addOnLayoutChangeListener( + (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> + updatePosition()); + } else { + return; + } + } + int newHeight = mChild.getMeasuredHeight(); + if (newHeight != mOldHeight) { + animateChild(mOldHeight, newHeight); + } + post(() -> updatePosition()); + boolean landscape = getMeasuredWidth() > getMeasuredHeight(); + if (landscape != mLandscape) { + mLandscape = landscape; + if (mLandscape) { + toLandscape(); + if (mChild instanceof LinearLayout) { + mRotatedBackground = true; + mBackground.setRotatedBackground(true); + ((LinearLayout) mChild).setOrientation(LinearLayout.HORIZONTAL); + swapDimens(mChild); + } + } else { + fromLandscape(); + if (mChild instanceof LinearLayout) { + mRotatedBackground = false; + mBackground.setRotatedBackground(false); + ((LinearLayout) mChild).setOrientation(LinearLayout.VERTICAL); + swapDimens(mChild); + } + } + } + } + + private void fromLandscape() { + rotateRight(this); + rotateRight(mChild); + swapDimens(this); + + LayoutParams p = (LayoutParams) mChild.getLayoutParams(); + p.gravity = rotateGravityRight(p.gravity); + mChild.setLayoutParams(p); + } + + private void swapDimens(View v) { + ViewGroup.LayoutParams params = v.getLayoutParams(); + int h = params.width; + params.width = params.height; + params.height = h; + v.setLayoutParams(params); + } + + private int rotateGravityRight(int gravity) { + int retGravity = 0; + int layoutDirection = getLayoutDirection(); + final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection); + final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK; + + switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { + case Gravity.CENTER_HORIZONTAL: + retGravity |= Gravity.CENTER_VERTICAL; + break; + case Gravity.RIGHT: + retGravity |= Gravity.BOTTOM; + break; + case Gravity.LEFT: + default: + retGravity |= Gravity.TOP; + break; + } + + switch (verticalGravity) { + case Gravity.CENTER_VERTICAL: + retGravity |= Gravity.CENTER_HORIZONTAL; + break; + case Gravity.BOTTOM: + retGravity |= Gravity.LEFT; + break; + case Gravity.TOP: + default: + retGravity |= Gravity.RIGHT; + break; + } + return retGravity; + } + + private void toLandscape() { + rotateLeft(this); + rotateLeft(mChild); + swapDimens(this); + + LayoutParams p = (LayoutParams) mChild.getLayoutParams(); + p.gravity = rotateGravityLeft(p.gravity); + mChild.setLayoutParams(p); + } + + private int rotateGravityLeft(int gravity) { + if (gravity == -1) { + gravity = Gravity.TOP | Gravity.START; + } + int retGravity = 0; + int layoutDirection = getLayoutDirection(); + final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection); + final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK; + + switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { + case Gravity.CENTER_HORIZONTAL: + retGravity |= Gravity.CENTER_VERTICAL; + break; + case Gravity.RIGHT: + retGravity |= Gravity.TOP; + break; + case Gravity.LEFT: + default: + retGravity |= Gravity.BOTTOM; + break; + } + + switch (verticalGravity) { + case Gravity.CENTER_VERTICAL: + retGravity |= Gravity.CENTER_HORIZONTAL; + break; + case Gravity.BOTTOM: + retGravity |= Gravity.RIGHT; + break; + case Gravity.TOP: + default: + retGravity |= Gravity.LEFT; + break; + } + return retGravity; + } + + private void rotateLeft(View v) { + v.setPadding(v.getPaddingTop(), v.getPaddingRight(), v.getPaddingBottom(), + v.getPaddingLeft()); + MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams(); + params.setMargins(params.topMargin, params.rightMargin, params.bottomMargin, + params.leftMargin); + v.setLayoutParams(params); + } + + private void rotateRight(View v) { + v.setPadding(v.getPaddingBottom(), v.getPaddingLeft(), v.getPaddingTop(), + v.getPaddingRight()); + MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams(); + params.setMargins(params.bottomMargin, params.leftMargin, params.topMargin, + params.rightMargin); + v.setLayoutParams(params); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + post(() -> updatePosition()); + } + + private void animateChild(int oldHeight, int newHeight) { + if (true) return; + if (mAnimating) { + mAnimation.cancel(); + } + mAnimating = true; + mAnimation = new AnimatorSet(); + mAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mAnimating = false; + } + }); + int fromTop = mChild.getTop(); + int fromBottom = mChild.getBottom(); + int toTop = fromTop - ((newHeight - oldHeight) / 2); + int toBottom = fromBottom + ((newHeight - oldHeight) / 2); + ObjectAnimator top = ObjectAnimator.ofInt(mChild, "top", fromTop, toTop); + top.addUpdateListener(animation -> mBackground.invalidateSelf()); + mAnimation.playTogether(top, + ObjectAnimator.ofInt(mChild, "bottom", fromBottom, toBottom)); + } + + public void setDivisionView(View v) { + mDivision = v; + if (mDivision != null) { + mDivision.addOnLayoutChangeListener( + (v1, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> + updatePosition()); + } + updatePosition(); + } + + private void updatePosition() { + if (mChild == null) return; + if (mDivision != null && mDivision.getVisibility() == VISIBLE) { + int index = mRotatedBackground ? 0 : 1; + mDivision.getLocationOnScreen(mTmp2); + float trans = mRotatedBackground ? mDivision.getTranslationX() + : mDivision.getTranslationY(); + int viewTop = (int) (mTmp2[index] + trans); + mChild.getLocationOnScreen(mTmp2); + viewTop -= mTmp2[index]; + setCutPoint(viewTop); + } else { + setCutPoint(mChild.getMeasuredHeight()); + } + } + + private void setCutPoint(int point) { + int curPoint = mBackground.getCutPoint(); + if (curPoint == point) return; + if (getAlpha() == 0 || curPoint == 0) { + mBackground.setCutPoint(point); + return; + } + if (mAnimator != null) { + if (mEndPoint == point) { + return; + } + mAnimator.cancel(); + } + mEndPoint = point; + mAnimator = ObjectAnimator.ofInt(mBackground, "cutPoint", curPoint, point); + if (mCollapse) { + mAnimator.setStartDelay(300); + mCollapse = false; + } + mAnimator.start(); + } + + @Override + public ViewOutlineProvider getOutlineProvider() { + return super.getOutlineProvider(); + } + + public void setOutsideTouchListener(OnClickListener onClickListener) { + mHasOutsideTouch = true; + requestLayout(); + setOnClickListener(onClickListener); + setClickable(true); + setFocusable(true); + } + + public void setCollapse() { + mCollapse = true; + } + + public static HardwareUiLayout get(View v) { + if (v instanceof HardwareUiLayout) return (HardwareUiLayout) v; + if (v.getParent() instanceof View) { + return get((View) v.getParent()); + } + return null; + } + + private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = inoutInfo -> { + if (mHasOutsideTouch || (mChild == null)) { + inoutInfo.setTouchableInsets( + ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME); + return; + } + inoutInfo.setTouchableInsets( + ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT); + inoutInfo.contentInsets.set(mChild.getLeft(), mChild.getTop(), + 0, getBottom() - mChild.getBottom()); + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index 206342ede6e09..4af21eb387941 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -15,15 +15,16 @@ package com.android.systemui.globalactions; import com.android.internal.R; -import com.android.internal.app.AlertController; -import com.android.internal.app.AlertController.AlertParams; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.EmergencyAffordanceManager; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyProperties; import com.android.internal.widget.LockPatternUtils; +import com.android.systemui.HardwareUiLayout; import com.android.systemui.plugins.GlobalActions.GlobalActionsManager; +import com.android.systemui.volume.VolumeDialogMotion.LogAccelerateInterpolator; +import com.android.systemui.volume.VolumeDialogMotion.LogDecelerateInterpolator; import android.app.ActivityManager; import android.app.Dialog; @@ -34,11 +35,13 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.UserInfo; import android.database.ContentObserver; +import android.database.DataSetObserver; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.net.ConnectivityManager; import android.os.Build; -import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.RemoteException; @@ -56,8 +59,6 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; -import android.util.TypedValue; -import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -65,10 +66,11 @@ import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityEvent; import android.widget.AdapterView; +import android.widget.AdapterView.OnItemLongClickListener; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.ImageView.ScaleType; -import android.widget.ListView; +import android.widget.LinearLayout; import android.widget.TextView; import java.util.ArrayList; @@ -79,7 +81,7 @@ import java.util.List; * may show depending on whether the keyguard is showing, and whether the device * is provisioned. */ -class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener { +class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener { static public final String SYSTEM_DIALOG_REASON_KEY = "reason"; static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions"; @@ -162,6 +164,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn /** * Show the global actions dialog (creating if necessary) + * * @param keyguardShowing True if keyguard is showing */ public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) { @@ -205,12 +208,14 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn mDialog.getWindow().setAttributes(attrs); mDialog.show(); mWindowManagerFuncs.onGlobalActionsShown(); - mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND); + mDialog.getWindow().getDecorView().setSystemUiVisibility( + View.STATUS_BAR_DISABLE_EXPAND); } } /** * Create the global actions dialog. + * * @return A new dialog. */ private ActionsDialog createDialog() { @@ -314,28 +319,19 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn mAdapter = new MyAdapter(); - AlertParams params = new AlertParams(mContext); - params.mAdapter = mAdapter; - params.mOnClickListener = this; - params.mForceInverseBackground = true; - - ActionsDialog dialog = new ActionsDialog(mContext, params); + OnItemLongClickListener onItemLongClickListener = new OnItemLongClickListener() { + @Override + public boolean onItemLongClick(AdapterView parent, View view, int position, + long id) { + final Action action = mAdapter.getItem(position); + if (action instanceof LongPressAction) { + return ((LongPressAction) action).onLongPress(); + } + return false; + } + }; + ActionsDialog dialog = new ActionsDialog(mContext, this, mAdapter, onItemLongClickListener); dialog.setCanceledOnTouchOutside(false); // Handled by the custom class. - - dialog.getListView().setItemsCanFocus(true); - dialog.getListView().setLongClickable(true); - dialog.getListView().setOnItemLongClickListener( - new AdapterView.OnItemLongClickListener() { - @Override - public boolean onItemLongClick(AdapterView parent, View view, int position, - long id) { - final Action action = mAdapter.getItem(position); - if (action instanceof LongPressAction) { - return ((LongPressAction) action).onLongPress(); - } - return false; - } - }); dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); dialog.setOnDismissListener(this); @@ -346,7 +342,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn private final class PowerAction extends SinglePressAction implements LongPressAction { private PowerAction() { super(R.drawable.ic_lock_power_off, - R.string.global_action_power_off); + R.string.global_action_power_off); } @Override @@ -614,7 +610,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn SinglePressAction switchToUser = new SinglePressAction( R.drawable.ic_menu_cc, icon, (user.name != null ? user.name : "Primary") - + (isCurrentUser ? " \u2714" : "")) { + + (isCurrentUser ? " \u2714" : "")) { public void onPress() { try { ActivityManager.getService().switchUser(user.id); @@ -652,7 +648,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn if (!mHasVibrator) { final boolean silentModeOn = mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL; - ((ToggleAction)mSilentModeAction).updateState( + ((ToggleAction) mSilentModeAction).updateState( silentModeOn ? ToggleAction.State.On : ToggleAction.State.Off); } } @@ -681,7 +677,8 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn /** * The adapter used for the list within the global actions dialog, taking * into account whether the keyguard is showing via - * {@link com.android.systemui.globalactions.GlobalActionsDialog#mKeyguardShowing} and whether the device is provisioned + * {@link com.android.systemui.globalactions.GlobalActionsDialog#mKeyguardShowing} and whether + * the device is provisioned * via {@link com.android.systemui.globalactions.GlobalActionsDialog#mDeviceProvisioned}. */ private class MyAdapter extends BaseAdapter { @@ -744,7 +741,11 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn public View getView(int position, View convertView, ViewGroup parent) { Action action = getItem(position); - return action.create(mContext, convertView, parent, LayoutInflater.from(mContext)); + View view = action.create(mContext, convertView, parent, LayoutInflater.from(mContext)); + if (position == 2) { + HardwareUiLayout.get(parent).setDivisionView(view); + } + return view; } } @@ -760,7 +761,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn private interface Action { /** * @return Text that will be announced when dialog is created. null - * for none. + * for none. */ CharSequence getLabelForAccessibility(Context context); @@ -770,13 +771,13 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn /** * @return whether this action should appear in the dialog when the keygaurd - * is showing. + * is showing. */ boolean showDuringKeyguard(); /** * @return whether this action should appear in the dialog before the - * device is provisioned. + * device is provisioned. */ boolean showBeforeProvisioning(); @@ -834,7 +835,8 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn public View create( Context context, View convertView, ViewGroup parent, LayoutInflater inflater) { - View v = inflater.inflate(R.layout.global_actions_item, parent, false); + View v = inflater.inflate(com.android.systemui.R.layout.global_actions_item, parent, + false); ImageView icon = (ImageView) v.findViewById(R.id.icon); TextView messageView = (TextView) v.findViewById(R.id.message); @@ -895,10 +897,10 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn protected int mDisabledStatusMessageResId; /** - * @param enabledIconResId The icon for when this action is on. - * @param disabledIconResid The icon for when this action is off. - * @param message The general information message, e.g 'Silent Mode' - * @param enabledStatusMessageResId The on status message, e.g 'sound disabled' + * @param enabledIconResId The icon for when this action is on. + * @param disabledIconResid The icon for when this action is off. + * @param message The general information message, e.g 'Silent Mode' + * @param enabledStatusMessageResId The on status message, e.g 'sound disabled' * @param disabledStatusMessageResId The off status message, e.g. 'sound enabled' */ public ToggleAction(int enabledIconResId, @@ -931,7 +933,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn willCreate(); View v = inflater.inflate(R - .layout.global_actions_item, parent, false); + .layout.global_actions_item, parent, false); ImageView icon = (ImageView) v.findViewById(R.id.icon); TextView messageView = (TextView) v.findViewById(R.id.message); @@ -979,6 +981,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn * Implementations may override this if their state can be in on of the intermediate * states until some notification is received (e.g airplane mode is 'turning off' until * we know the wireless connections are back online + * * @param buttonOn Whether the button was turned on or off */ protected void changeStateFromPress(boolean buttonOn) { @@ -1020,7 +1023,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn private static class SilentModeTriStateAction implements Action, View.OnClickListener { - private final int[] ITEM_IDS = { R.id.option1, R.id.option2, R.id.option3 }; + private final int[] ITEM_IDS = {R.id.option1, R.id.option2, R.id.option3}; private final AudioManager mAudioManager; private final Handler mHandler; @@ -1145,19 +1148,19 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn private Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { - case MESSAGE_DISMISS: - if (mDialog != null) { - mDialog.dismiss(); - mDialog = null; - } - break; - case MESSAGE_REFRESH: - refreshSilentMode(); - mAdapter.notifyDataSetChanged(); - break; - case MESSAGE_SHOW: - handleShow(); - break; + case MESSAGE_DISMISS: + if (mDialog != null) { + mDialog.dismiss(); + mDialog = null; + } + break; + case MESSAGE_REFRESH: + refreshSilentMode(); + mAdapter.notifyDataSetChanged(); + break; + case MESSAGE_SHOW: + handleShow(); + break; } } }; @@ -1192,39 +1195,81 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn } private static final class ActionsDialog extends Dialog implements DialogInterface { - private final Context mContext; - private final AlertController mAlert; - private final MyAdapter mAdapter; - public ActionsDialog(Context context, AlertParams params) { - super(context, getDialogTheme(context)); + private final Context mContext; + private final MyAdapter mAdapter; + private final LinearLayout mListView; + private final HardwareUiLayout mHardwareLayout; + private final OnClickListener mClickListener; + private final OnItemLongClickListener mLongClickListener; + + public ActionsDialog(Context context, OnClickListener clickListener, MyAdapter adapter, + OnItemLongClickListener longClickListener) { + super(context, android.R.style.Theme_DeviceDefault_Light_NoActionBar_Fullscreen); mContext = getContext(); - mAlert = AlertController.create(mContext, this, getWindow()); - mAdapter = (MyAdapter) params.mAdapter; - params.apply(mAlert); + mAdapter = adapter; + mClickListener = clickListener; + mLongClickListener = longClickListener; + setContentView(com.android.systemui.R.layout.global_actions_wrapped); + getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + mListView = findViewById(android.R.id.list); + mHardwareLayout = HardwareUiLayout.get(mListView); + mHardwareLayout.setOutsideTouchListener(view -> dismiss()); } - private static int getDialogTheme(Context context) { - TypedValue outValue = new TypedValue(); - context.getTheme().resolveAttribute(R.attr.alertDialogTheme, - outValue, true); - return outValue.resourceId; + private void updateList() { + mListView.removeAllViews(); + for (int i = 0; i < mAdapter.getCount(); i++) { + View v = mAdapter.getView(i, null, mListView); + final int pos = i; + v.setOnClickListener(view -> mClickListener.onClick(this, pos)); + v.setOnLongClickListener(view -> + mLongClickListener.onItemLongClick(null, v, pos, 0)); + mListView.addView(v); + } } @Override protected void onStart() { super.setCanceledOnTouchOutside(true); super.onStart(); - } - - public ListView getListView() { - return mAlert.getListView(); + updateList(); } @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mAlert.installContent(); + protected void onStop() { + super.onStop(); + } + + @Override + public void show() { + super.show(); + mHardwareLayout.setTranslationX(getAnimTranslation()); + mHardwareLayout.setAlpha(0); + mHardwareLayout.animate() + .alpha(1) + .translationX(0) + .setDuration(300) + .setInterpolator(new LogDecelerateInterpolator()) + .start(); + } + + @Override + public void dismiss() { + mHardwareLayout.setTranslationX(0); + mHardwareLayout.setAlpha(1); + mHardwareLayout.animate() + .alpha(0) + .translationX(getAnimTranslation()) + .setDuration(300) + .withEndAction(() -> super.dismiss()) + .setInterpolator(new LogAccelerateInterpolator()) + .start(); + } + + private float getAnimTranslation() { + return getContext().getResources().getDimension( + com.android.systemui.R.dimen.global_actions_panel_width) / 2; } @Override @@ -1240,21 +1285,5 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn } return super.dispatchPopulateAccessibilityEvent(event); } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (mAlert.onKeyDown(keyCode, event)) { - return true; - } - return super.onKeyDown(keyCode, event); - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - if (mAlert.onKeyUp(keyCode, event)) { - return true; - } - return super.onKeyUp(keyCode, event); - } } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index b8b046b9990d7..1f674e03b4ca7 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -18,6 +18,7 @@ package com.android.systemui.volume; import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK; import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import android.accessibilityservice.AccessibilityServiceInfo; import android.animation.ObjectAnimator; @@ -59,6 +60,7 @@ import android.view.View.OnAttachStateChangeListener; import android.view.View.OnClickListener; import android.view.View.OnTouchListener; import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; import android.view.ViewGroup.MarginLayoutParams; import android.view.Window; import android.view.WindowManager; @@ -73,6 +75,7 @@ import android.widget.TextView; import com.android.settingslib.Utils; import com.android.systemui.Dependency; +import com.android.systemui.HardwareUiLayout; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.plugins.VolumeDialogController; @@ -199,53 +202,37 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable { | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); mDialog.setCanceledOnTouchOutside(true); final Resources res = mContext.getResources(); - final WindowManager.LayoutParams lp = mWindow.getAttributes(); - lp.type = mWindowType; - lp.format = PixelFormat.TRANSLUCENT; - lp.setTitle(VolumeDialogImpl.class.getSimpleName()); - lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; - lp.y = res.getDimensionPixelSize(R.dimen.volume_offset_top); - lp.gravity = Gravity.TOP; - lp.windowAnimations = -1; - mWindow.setAttributes(lp); mWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING); - mDialog.setContentView(R.layout.volume_dialog); - mDialogView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog); - mDialogView.setOnHoverListener(new View.OnHoverListener() { - @Override - public boolean onHover(View v, MotionEvent event) { - int action = event.getActionMasked(); - mHovering = (action == MotionEvent.ACTION_HOVER_ENTER) - || (action == MotionEvent.ACTION_HOVER_MOVE); - rescheduleTimeoutH(); - return true; - } + mDialog.setContentView(R.layout.volume_dialog_wrapped); + mDialogView = mDialog.findViewById(R.id.volume_dialog); + mDialogView.setOnHoverListener((v, event) -> { + int action = event.getActionMasked(); + mHovering = (action == MotionEvent.ACTION_HOVER_ENTER) + || (action == MotionEvent.ACTION_HOVER_MOVE); + rescheduleTimeoutH(); + return true; }); - mDialogContentView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog_content); - mDialogRowsView = (ViewGroup) mDialogContentView.findViewById(R.id.volume_dialog_rows); + mDialogContentView = mDialog.findViewById(R.id.volume_dialog_content); + mDialogRowsView = mDialogContentView.findViewById(R.id.volume_dialog_rows); mExpanded = false; - mExpandButton = (ImageButton) mDialogView.findViewById(R.id.volume_expand_button); + mExpandButton = mDialogView.findViewById(R.id.volume_expand_button); mExpandButton.setOnClickListener(mClickExpand); mExpandButton.setVisibility( AudioSystem.isSingleVolume(mContext) ? View.GONE : View.VISIBLE); - updateWindowWidthH(); updateExpandButtonH(); - 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; - } + mMotion = new VolumeDialogMotion(mDialog, (View) mDialogView.getParent(), + mDialogContentView, mExpandButton, animating -> { + if (animating) return; + if (mPendingStateChanged) { + mHandler.sendEmptyMessage(H.STATE_CHANGED); + mPendingStateChanged = false; + } + if (mPendingRecheckAll) { + mHandler.sendEmptyMessage(H.RECHECK_ALL); + mPendingRecheckAll = false; } }); @@ -270,11 +257,20 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable { addExistingRows(); } mExpandButtonAnimationDuration = res.getInteger(R.integer.volume_expand_animation_duration); - mZenFooter = (ZenFooter) mDialog.findViewById(R.id.volume_zen_footer); + mZenFooter = mDialog.findViewById(R.id.volume_zen_footer); mZenFooter.init(mZenModeController); - mZenPanel = (TunerZenModePanel) mDialog.findViewById(R.id.tuner_zen_mode_panel); + mZenPanel = mDialog.findViewById(R.id.tuner_zen_mode_panel); mZenPanel.init(mZenModeController); mZenPanel.setCallback(mZenPanelCallback); + + final WindowManager.LayoutParams lp = mWindow.getAttributes(); + lp.width = MATCH_PARENT; + lp.height = MATCH_PARENT; + lp.type = mWindowType; + lp.format = PixelFormat.TRANSLUCENT; + lp.setTitle(VolumeDialogImpl.class.getSimpleName()); + lp.windowAnimations = -1; + mWindow.setAttributes(lp); } @Override @@ -288,20 +284,6 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable { return ColorStateList.valueOf(mContext.getColor(colorResId)); } - private void updateWindowWidthH() { - final ViewGroup.LayoutParams lp = mDialogView.getLayoutParams(); - final DisplayMetrics dm = mContext.getResources().getDisplayMetrics(); - if (D.BUG) Log.d(TAG, "updateWindowWidth dm.w=" + dm.widthPixels); - int w = dm.widthPixels; - final int max = mContext.getResources() - .getDimensionPixelSize(R.dimen.volume_dialog_panel_width); - if (w > max) { - w = max; - } - lp.width = w; - mDialogView.setLayoutParams(lp); - } - public void setStreamImportant(int stream, boolean important) { mHandler.obtainMessage(H.SET_STREAM_IMPORTANT, stream, important ? 1 : 0).sendToTarget(); } @@ -542,10 +524,8 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable { } 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() : + final int bottomMargin = mContext.getResources().getDimensionPixelSize(R.dimen.volume_dialog_margin_bottom); if (bottomMargin != mlp.bottomMargin) { if (D.BUG) Log.d(TAG, "bottomMargin " + mlp.bottomMargin + " -> " + bottomMargin); @@ -575,7 +555,7 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable { TransitionManager.endTransitions(mDialogView); final VolumeRow activeRow = getActiveRow(); if (!dismissing) { - mWindow.setLayout(mWindow.getAttributes().width, ViewGroup.LayoutParams.MATCH_PARENT); + mWindow.setLayout(mWindow.getAttributes().width, MATCH_PARENT); TransitionManager.beginDelayedTransition(mDialogView, getTransistion()); } updateRowsH(activeRow); @@ -637,7 +617,7 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable { final boolean isActive = row == activeRow; final boolean shouldBeVisible = shouldBeVisibleH(row, isActive); Util.setVisOrGone(row.view, shouldBeVisible); - Util.setVisOrGone(row.header, shouldBeVisible); + Util.setVisOrGone(row.header, shouldBeVisible && mExpanded); if (row.view.isShown()) { updateVolumeRowSliderTintH(row, isActive); } @@ -699,6 +679,16 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable { if (wasVisible != visible && !visible) { prepareForCollapse(); } + if (visible != wasVisible) { + if (visible) { + HardwareUiLayout.get(mZenFooter).setDivisionView(mZenFooter); + } else { + mHandler.postDelayed(() -> + HardwareUiLayout.get(mZenFooter).setDivisionView(mZenFooter), + mExpandButtonAnimationDuration); + } + + } Util.setVisOrGone(mZenFooter, visible); mZenFooter.update(); @@ -962,8 +952,7 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable { @Override public void onTransitionEnd(Transition transition) { - mWindow.setLayout( - mWindow.getAttributes().width, ViewGroup.LayoutParams.WRAP_CONTENT); + mWindow.setLayout(MATCH_PARENT, MATCH_PARENT); } @Override @@ -972,8 +961,7 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable { @Override public void onTransitionPause(Transition transition) { - mWindow.setLayout( - mWindow.getAttributes().width, ViewGroup.LayoutParams.WRAP_CONTENT); + mWindow.setLayout(MATCH_PARENT, MATCH_PARENT); } @Override @@ -1025,7 +1013,6 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable { initDialog(); mDensity = density; } - updateWindowWidthH(); mConfigurableTexts.update(); mZenFooter.onConfigurationChanged(); } @@ -1081,6 +1068,9 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable { if (mExpandButtonAnimationRunning) return; final boolean newExpand = !mExpanded; Events.writeEvent(mContext, Events.EVENT_EXPAND, newExpand); + if (!newExpand) { + HardwareUiLayout.get(mDialogContentView).setCollapse(); + } updateExpandedH(newExpand, false /* dismissing */); } }; @@ -1156,8 +1146,8 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable { event.setPackageName(mContext.getPackageName()); ViewGroup.LayoutParams params = getWindow().getAttributes(); - boolean isFullScreen = (params.width == ViewGroup.LayoutParams.MATCH_PARENT) && - (params.height == ViewGroup.LayoutParams.MATCH_PARENT); + boolean isFullScreen = (params.width == MATCH_PARENT) && + (params.height == MATCH_PARENT); event.setFullScreen(isFullScreen); if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java index d6d0f75664195..8afd91d10d546 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.android.systemui.volume; import android.animation.Animator; @@ -67,8 +66,8 @@ public class VolumeDialogMotion { @Override public void onShow(DialogInterface dialog) { if (D.BUG) Log.d(TAG, "mDialog.onShow"); - final int h = mDialogView.getHeight(); - mDialogView.setTranslationY(-h); + final int w = mDialogView.getWidth() / 4; + mDialogView.setTranslationX(w); startShowAnimation(); } }); @@ -117,7 +116,7 @@ public class VolumeDialogMotion { } private int chevronDistance() { - return mChevron.getHeight() / 6; + return 0; } private int chevronPosY() { @@ -128,7 +127,9 @@ public class VolumeDialogMotion { private void startShowAnimation() { if (D.BUG) Log.d(TAG, "startShowAnimation"); mDialogView.animate() + .translationX(0) .translationY(0) + .alpha(1) .setDuration(scaledDuration(300)) .setInterpolator(new LogDecelerateInterpolator()) .setListener(null) @@ -139,7 +140,6 @@ public class VolumeDialogMotion { // reposition chevron final float v = (Float) mChevronPositionAnimator.getAnimatedValue(); final int posY = chevronPosY(); - mChevron.setTranslationY(posY + v + -mDialogView.getTranslationY()); } }) .withEndAction(new Runnable() { @@ -148,7 +148,6 @@ public class VolumeDialogMotion { if (mChevronPositionAnimator == null) return; // reposition chevron final int posY = chevronPosY(); - mChevron.setTranslationY(posY + -mDialogView.getTranslationY()); } }) .start(); @@ -164,19 +163,13 @@ public class VolumeDialogMotion { 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(); @@ -218,34 +211,26 @@ public class VolumeDialogMotion { setShowing(false); } mDialogView.animate() - .translationY(-mDialogView.getHeight()) + .translationX(mDialogView.getWidth() / 4) + .alpha(0) .setDuration(scaledDuration(250)) .setInterpolator(new LogAccelerateInterpolator()) - .setUpdateListener(new AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - mContents.setTranslationY(-mDialogView.getTranslationY()); - final int posY = chevronPosY(); - 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); - } + mHandler.postDelayed(() -> { + 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"); @@ -258,13 +243,13 @@ public class VolumeDialogMotion { return (int) (base * ANIMATION_SCALE); } - private static final class LogDecelerateInterpolator implements TimeInterpolator { + public static final class LogDecelerateInterpolator implements TimeInterpolator { private final float mBase; private final float mDrift; private final float mTimeScale; private final float mOutputScale; - private LogDecelerateInterpolator() { + public LogDecelerateInterpolator() { this(400f, 1.4f, 0); } @@ -286,12 +271,12 @@ public class VolumeDialogMotion { } } - private static final class LogAccelerateInterpolator implements TimeInterpolator { + public static final class LogAccelerateInterpolator implements TimeInterpolator { private final int mBase; private final int mDrift; private final float mLogScale; - private LogAccelerateInterpolator() { + public LogAccelerateInterpolator() { this(100, 0); }