Loading packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java +55 −2 Original line number Diff line number Diff line Loading @@ -26,9 +26,12 @@ import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.SystemProperties; import android.view.DisplayListCanvas; import android.view.RenderNodeAnimator; import android.view.View; import android.view.ViewConfiguration; import android.view.animation.Interpolator; import com.android.systemui.Interpolators; Loading Loading @@ -56,14 +59,17 @@ public class KeyButtonRipple extends Drawable { private float mGlowAlpha = 0f; private float mGlowScale = 1f; private boolean mPressed; private boolean mVisible; private boolean mDrawingHardwareGlow; private int mMaxWidth; private boolean mLastDark; private boolean mDark; private boolean mDelayTouchFeedback; private final Interpolator mInterpolator = new LogInterpolator(); private boolean mSupportHardware; private final View mTargetView; private final Handler mHandler = new Handler(); private final HashSet<Animator> mRunningAnimations = new HashSet<>(); private final ArrayList<Animator> mTmpArray = new ArrayList<>(); Loading @@ -77,6 +83,10 @@ public class KeyButtonRipple extends Drawable { mDark = darkIntensity >= 0.5f; } public void setDelayTouchFeedback(boolean delay) { mDelayTouchFeedback = delay; } private Paint getRipplePaint() { if (mRipplePaint == null) { mRipplePaint = new Paint(); Loading Loading @@ -211,7 +221,16 @@ public class KeyButtonRipple extends Drawable { } } /** * Abort the ripple while it is delayed and before shown used only when setShouldDelayStartTouch * is enabled. */ public void abortDelayedRipple() { mHandler.removeCallbacksAndMessages(null); } private void cancelAnimations() { mVisible = false; mTmpArray.addAll(mRunningAnimations); int size = mTmpArray.size(); for (int i = 0; i < size; i++) { Loading @@ -220,11 +239,21 @@ public class KeyButtonRipple extends Drawable { } mTmpArray.clear(); mRunningAnimations.clear(); mHandler.removeCallbacksAndMessages(null); } private void setPressedSoftware(boolean pressed) { if (pressed) { if (mDelayTouchFeedback) { if (mRunningAnimations.isEmpty()) { mHandler.removeCallbacksAndMessages(null); mHandler.postDelayed(this::enterSoftware, ViewConfiguration.getTapTimeout()); } else if (mVisible) { enterSoftware(); } } else { enterSoftware(); } } else { exitSoftware(); } Loading @@ -232,6 +261,7 @@ public class KeyButtonRipple extends Drawable { private void enterSoftware() { cancelAnimations(); mVisible = true; mGlowAlpha = getMaxGlowAlpha(); ObjectAnimator scaleAnimator = ObjectAnimator.ofFloat(this, "glowScale", 0f, GLOW_MAX_SCALE_FACTOR); Loading @@ -240,6 +270,12 @@ public class KeyButtonRipple extends Drawable { scaleAnimator.addListener(mAnimatorListener); scaleAnimator.start(); mRunningAnimations.add(scaleAnimator); // With the delay, it could eventually animate the enter animation with no pressed state, // then immediately show the exit animation. If this is skipped there will be no ripple. if (mDelayTouchFeedback && !mPressed) { exitSoftware(); } } private void exitSoftware() { Loading @@ -253,7 +289,16 @@ public class KeyButtonRipple extends Drawable { private void setPressedHardware(boolean pressed) { if (pressed) { if (mDelayTouchFeedback) { if (mRunningAnimations.isEmpty()) { mHandler.removeCallbacksAndMessages(null); mHandler.postDelayed(this::enterHardware, ViewConfiguration.getTapTimeout()); } else if (mVisible) { enterHardware(); } } else { enterHardware(); } } else { exitHardware(); } Loading Loading @@ -302,6 +347,7 @@ public class KeyButtonRipple extends Drawable { private void enterHardware() { cancelAnimations(); mVisible = true; mDrawingHardwareGlow = true; setExtendStart(CanvasProperty.createFloat(getExtendSize() / 2)); final RenderNodeAnimator startAnim = new RenderNodeAnimator(getExtendStart(), Loading Loading @@ -343,6 +389,12 @@ public class KeyButtonRipple extends Drawable { mRunningAnimations.add(endAnim); invalidateSelf(); // With the delay, it could eventually animate the enter animation with no pressed state, // then immediately show the exit animation. If this is skipped there will be no ripple. if (mDelayTouchFeedback && !mPressed) { exitHardware(); } } private void exitHardware() { Loading @@ -366,6 +418,7 @@ public class KeyButtonRipple extends Drawable { public void onAnimationEnd(Animator animation) { mRunningAnimations.remove(animation); if (mRunningAnimations.isEmpty() && !mPressed) { mVisible = false; mDrawingHardwareGlow = false; invalidateSelf(); } Loading packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java +8 −27 Original line number Diff line number Diff line Loading @@ -65,7 +65,6 @@ public class KeyButtonView extends ImageView implements ButtonInterface { private int mTouchSlop; private int mTouchDownX; private int mTouchDownY; private boolean mIsPressed; private boolean mSupportsLongpress = true; private AudioManager mAudioManager; private boolean mGestureAborted; Loading @@ -78,7 +77,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface { private final Runnable mCheckLongPress = new Runnable() { public void run() { if (mIsPressed) { if (isPressed()) { // Log.d("KeyButtonView", "longpressed: " + this); if (isLongClickable()) { // Just an old-fashioned ImageView Loading @@ -89,12 +88,6 @@ public class KeyButtonView extends ImageView implements ButtonInterface { sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); mLongClicked = true; } // Only when quick step is enabled, ripple will not be shown on touch down, then // show the ripple on touch up or on long press if (mLongClicked && mOverviewProxyService.getProxy() != null) { setPressed(true); } } } }; Loading Loading @@ -214,9 +207,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface { mGestureAborted = false; } if (mGestureAborted) { if (mIsPressed) { setPressed(false); } return false; } Loading @@ -224,6 +215,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface { case MotionEvent.ACTION_DOWN: mDownTime = SystemClock.uptimeMillis(); mLongClicked = false; setPressed(true); // Use raw X and Y to detect gestures in case a parent changes the x and y values mTouchDownX = (int) ev.getRawX(); Loading @@ -234,10 +226,8 @@ public class KeyButtonView extends ImageView implements ButtonInterface { // Provide the same haptic feedback that the system offers for virtual keys. performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY); } mIsPressed = true; if (!isProxyConnected) { playSoundEffect(SoundEffectConstants.CLICK); setPressed(mIsPressed); } removeCallbacks(mCheckLongPress); postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout()); Loading @@ -250,10 +240,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface { if (exceededTouchSlopX || exceededTouchSlopY) { // When quick step is enabled, prevent animating the ripple triggered by // setPressed and decide to run it on touch up mIsPressed = false; if (!isProxyConnected) { setPressed(mIsPressed); } setPressed(false); removeCallbacks(mCheckLongPress); } break; Loading @@ -265,12 +252,11 @@ public class KeyButtonView extends ImageView implements ButtonInterface { removeCallbacks(mCheckLongPress); break; case MotionEvent.ACTION_UP: final boolean doIt = mIsPressed && !mLongClicked; final boolean doIt = isPressed() && !mLongClicked; setPressed(false); final boolean doHapticFeedback = (SystemClock.uptimeMillis() - mDownTime) > 150; if (isProxyConnected) { if (doIt) { // Animate the ripple in on touch up with setPressed and then out later setPressed(true); if (doHapticFeedback) { mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK); } Loading @@ -281,7 +267,6 @@ public class KeyButtonView extends ImageView implements ButtonInterface { // and it feels weird to sometimes get a release haptic and other times not. performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY_RELEASE); } setPressed(false); if (mCode != 0) { if (doIt) { // If there was a pending remote recents animation, then we need to Loading Loading @@ -311,12 +296,6 @@ public class KeyButtonView extends ImageView implements ButtonInterface { mAudioManager.playSoundEffect(soundConstant, ActivityManager.getCurrentUser()); } @Override public void setPressed(boolean pressed) { mIsPressed = pressed; super.setPressed(pressed); } public void sendEvent(int action, int flags) { sendEvent(action, flags, SystemClock.uptimeMillis()); } Loading @@ -339,6 +318,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface { @Override public void abortCurrentGesture() { setPressed(false); mRipple.abortDelayedRipple(); mGestureAborted = true; } Loading @@ -357,6 +337,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface { @Override public void setDelayTouchFeedback(boolean shouldDelay) { mRipple.setDelayTouchFeedback(shouldDelay); } @Override Loading Loading
packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java +55 −2 Original line number Diff line number Diff line Loading @@ -26,9 +26,12 @@ import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.SystemProperties; import android.view.DisplayListCanvas; import android.view.RenderNodeAnimator; import android.view.View; import android.view.ViewConfiguration; import android.view.animation.Interpolator; import com.android.systemui.Interpolators; Loading Loading @@ -56,14 +59,17 @@ public class KeyButtonRipple extends Drawable { private float mGlowAlpha = 0f; private float mGlowScale = 1f; private boolean mPressed; private boolean mVisible; private boolean mDrawingHardwareGlow; private int mMaxWidth; private boolean mLastDark; private boolean mDark; private boolean mDelayTouchFeedback; private final Interpolator mInterpolator = new LogInterpolator(); private boolean mSupportHardware; private final View mTargetView; private final Handler mHandler = new Handler(); private final HashSet<Animator> mRunningAnimations = new HashSet<>(); private final ArrayList<Animator> mTmpArray = new ArrayList<>(); Loading @@ -77,6 +83,10 @@ public class KeyButtonRipple extends Drawable { mDark = darkIntensity >= 0.5f; } public void setDelayTouchFeedback(boolean delay) { mDelayTouchFeedback = delay; } private Paint getRipplePaint() { if (mRipplePaint == null) { mRipplePaint = new Paint(); Loading Loading @@ -211,7 +221,16 @@ public class KeyButtonRipple extends Drawable { } } /** * Abort the ripple while it is delayed and before shown used only when setShouldDelayStartTouch * is enabled. */ public void abortDelayedRipple() { mHandler.removeCallbacksAndMessages(null); } private void cancelAnimations() { mVisible = false; mTmpArray.addAll(mRunningAnimations); int size = mTmpArray.size(); for (int i = 0; i < size; i++) { Loading @@ -220,11 +239,21 @@ public class KeyButtonRipple extends Drawable { } mTmpArray.clear(); mRunningAnimations.clear(); mHandler.removeCallbacksAndMessages(null); } private void setPressedSoftware(boolean pressed) { if (pressed) { if (mDelayTouchFeedback) { if (mRunningAnimations.isEmpty()) { mHandler.removeCallbacksAndMessages(null); mHandler.postDelayed(this::enterSoftware, ViewConfiguration.getTapTimeout()); } else if (mVisible) { enterSoftware(); } } else { enterSoftware(); } } else { exitSoftware(); } Loading @@ -232,6 +261,7 @@ public class KeyButtonRipple extends Drawable { private void enterSoftware() { cancelAnimations(); mVisible = true; mGlowAlpha = getMaxGlowAlpha(); ObjectAnimator scaleAnimator = ObjectAnimator.ofFloat(this, "glowScale", 0f, GLOW_MAX_SCALE_FACTOR); Loading @@ -240,6 +270,12 @@ public class KeyButtonRipple extends Drawable { scaleAnimator.addListener(mAnimatorListener); scaleAnimator.start(); mRunningAnimations.add(scaleAnimator); // With the delay, it could eventually animate the enter animation with no pressed state, // then immediately show the exit animation. If this is skipped there will be no ripple. if (mDelayTouchFeedback && !mPressed) { exitSoftware(); } } private void exitSoftware() { Loading @@ -253,7 +289,16 @@ public class KeyButtonRipple extends Drawable { private void setPressedHardware(boolean pressed) { if (pressed) { if (mDelayTouchFeedback) { if (mRunningAnimations.isEmpty()) { mHandler.removeCallbacksAndMessages(null); mHandler.postDelayed(this::enterHardware, ViewConfiguration.getTapTimeout()); } else if (mVisible) { enterHardware(); } } else { enterHardware(); } } else { exitHardware(); } Loading Loading @@ -302,6 +347,7 @@ public class KeyButtonRipple extends Drawable { private void enterHardware() { cancelAnimations(); mVisible = true; mDrawingHardwareGlow = true; setExtendStart(CanvasProperty.createFloat(getExtendSize() / 2)); final RenderNodeAnimator startAnim = new RenderNodeAnimator(getExtendStart(), Loading Loading @@ -343,6 +389,12 @@ public class KeyButtonRipple extends Drawable { mRunningAnimations.add(endAnim); invalidateSelf(); // With the delay, it could eventually animate the enter animation with no pressed state, // then immediately show the exit animation. If this is skipped there will be no ripple. if (mDelayTouchFeedback && !mPressed) { exitHardware(); } } private void exitHardware() { Loading @@ -366,6 +418,7 @@ public class KeyButtonRipple extends Drawable { public void onAnimationEnd(Animator animation) { mRunningAnimations.remove(animation); if (mRunningAnimations.isEmpty() && !mPressed) { mVisible = false; mDrawingHardwareGlow = false; invalidateSelf(); } Loading
packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java +8 −27 Original line number Diff line number Diff line Loading @@ -65,7 +65,6 @@ public class KeyButtonView extends ImageView implements ButtonInterface { private int mTouchSlop; private int mTouchDownX; private int mTouchDownY; private boolean mIsPressed; private boolean mSupportsLongpress = true; private AudioManager mAudioManager; private boolean mGestureAborted; Loading @@ -78,7 +77,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface { private final Runnable mCheckLongPress = new Runnable() { public void run() { if (mIsPressed) { if (isPressed()) { // Log.d("KeyButtonView", "longpressed: " + this); if (isLongClickable()) { // Just an old-fashioned ImageView Loading @@ -89,12 +88,6 @@ public class KeyButtonView extends ImageView implements ButtonInterface { sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); mLongClicked = true; } // Only when quick step is enabled, ripple will not be shown on touch down, then // show the ripple on touch up or on long press if (mLongClicked && mOverviewProxyService.getProxy() != null) { setPressed(true); } } } }; Loading Loading @@ -214,9 +207,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface { mGestureAborted = false; } if (mGestureAborted) { if (mIsPressed) { setPressed(false); } return false; } Loading @@ -224,6 +215,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface { case MotionEvent.ACTION_DOWN: mDownTime = SystemClock.uptimeMillis(); mLongClicked = false; setPressed(true); // Use raw X and Y to detect gestures in case a parent changes the x and y values mTouchDownX = (int) ev.getRawX(); Loading @@ -234,10 +226,8 @@ public class KeyButtonView extends ImageView implements ButtonInterface { // Provide the same haptic feedback that the system offers for virtual keys. performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY); } mIsPressed = true; if (!isProxyConnected) { playSoundEffect(SoundEffectConstants.CLICK); setPressed(mIsPressed); } removeCallbacks(mCheckLongPress); postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout()); Loading @@ -250,10 +240,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface { if (exceededTouchSlopX || exceededTouchSlopY) { // When quick step is enabled, prevent animating the ripple triggered by // setPressed and decide to run it on touch up mIsPressed = false; if (!isProxyConnected) { setPressed(mIsPressed); } setPressed(false); removeCallbacks(mCheckLongPress); } break; Loading @@ -265,12 +252,11 @@ public class KeyButtonView extends ImageView implements ButtonInterface { removeCallbacks(mCheckLongPress); break; case MotionEvent.ACTION_UP: final boolean doIt = mIsPressed && !mLongClicked; final boolean doIt = isPressed() && !mLongClicked; setPressed(false); final boolean doHapticFeedback = (SystemClock.uptimeMillis() - mDownTime) > 150; if (isProxyConnected) { if (doIt) { // Animate the ripple in on touch up with setPressed and then out later setPressed(true); if (doHapticFeedback) { mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK); } Loading @@ -281,7 +267,6 @@ public class KeyButtonView extends ImageView implements ButtonInterface { // and it feels weird to sometimes get a release haptic and other times not. performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY_RELEASE); } setPressed(false); if (mCode != 0) { if (doIt) { // If there was a pending remote recents animation, then we need to Loading Loading @@ -311,12 +296,6 @@ public class KeyButtonView extends ImageView implements ButtonInterface { mAudioManager.playSoundEffect(soundConstant, ActivityManager.getCurrentUser()); } @Override public void setPressed(boolean pressed) { mIsPressed = pressed; super.setPressed(pressed); } public void sendEvent(int action, int flags) { sendEvent(action, flags, SystemClock.uptimeMillis()); } Loading @@ -339,6 +318,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface { @Override public void abortCurrentGesture() { setPressed(false); mRipple.abortDelayedRipple(); mGestureAborted = true; } Loading @@ -357,6 +337,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface { @Override public void setDelayTouchFeedback(boolean shouldDelay) { mRipple.setDelayTouchFeedback(shouldDelay); } @Override Loading