diff options
| author | 2017-02-21 21:38:12 +0100 | |
|---|---|---|
| committer | 2017-02-22 11:15:14 +0100 | |
| commit | 28a0de9c5ee66a90e35f9e2d0e5ab0af8676546b (patch) | |
| tree | eb0cd3658e7baf964c0c232865813491fa2a5c82 | |
| parent | c98c16ded8738054242b2576a74e145f834b6efa (diff) | |
Shade: Factor out DoubleTapHelper
Factors DoubleTapHelper out of ActivatableNotificationView, such that the
same logic can be reused for the StatusBarWindowView.
Bug: 30876804
Test: have a notification, lock phone, interact with notifications on the lockscreen
Change-Id: I4f3a43859d81677d5168424874b106bbfdea0be5
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java | 92 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/phone/DoubleTapHelper.java | 174 |
2 files changed, 185 insertions, 81 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java index 0bd649121321..98787f7c6ec0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java @@ -38,6 +38,7 @@ import com.android.systemui.R; import com.android.systemui.classifier.FalsingManager; import com.android.systemui.statusbar.notification.FakeShadowView; import com.android.systemui.statusbar.notification.NotificationUtils; +import com.android.systemui.statusbar.phone.DoubleTapHelper; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.stack.StackStateAnimator; @@ -47,7 +48,6 @@ import com.android.systemui.statusbar.stack.StackStateAnimator; */ public abstract class ActivatableNotificationView extends ExpandableOutlineView { - private static final long DOUBLETAP_TIMEOUT_MS = 1200; private static final int BACKGROUND_ANIMATION_LENGTH_MS = 220; private static final int ACTIVATE_ANIMATION_LENGTH = 220; private static final int DARK_ANIMATION_LENGTH = 170; @@ -101,6 +101,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView private final int mLowPriorityRippleColor; protected final int mNormalRippleColor; private final AccessibilityManager mAccessibilityManager; + private final DoubleTapHelper mDoubleTapHelper; private boolean mDimmed; private boolean mDark; @@ -114,14 +115,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView */ private boolean mActivated; - private float mDownX; - private float mDownY; - private final float mTouchSlop; - - private float mActivationX; - private float mActivationY; - private final float mDoubleTapSlop; - private OnActivatedListener mOnActivatedListener; private final Interpolator mSlowOutFastInInterpolator; @@ -143,7 +136,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView private final int mLowPriorityColor; private boolean mIsBelowSpeedBump; private FalsingManager mFalsingManager; - private boolean mTrackTouch; private float mNormalBackgroundVisibilityAmount; private ValueAnimator mFadeInFromDarkAnimator; @@ -183,8 +175,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView public ActivatableNotificationView(Context context, AttributeSet attrs) { super(context, attrs); - mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); - mDoubleTapSlop = context.getResources().getDimension(R.dimen.double_tap_slop); mSlowOutFastInInterpolator = new PathInterpolator(0.8f, 0.0f, 0.6f, 1.0f); mSlowOutLinearInInterpolator = new PathInterpolator(0.8f, 0.0f, 1.0f, 1.0f); setClipChildren(false); @@ -200,6 +190,14 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView R.color.notification_ripple_untinted_color); mFalsingManager = FalsingManager.getInstance(context); mAccessibilityManager = AccessibilityManager.getInstance(mContext); + + mDoubleTapHelper = new DoubleTapHelper(this, (active) -> { + if (active) { + makeActive(); + } else { + makeInactive(true /* animate */); + } + }, this::performClick, this::handleSlideBack, mFalsingManager::onNotificationDoubleTap); } @Override @@ -284,60 +282,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView } private boolean handleTouchEventDimmed(MotionEvent event) { - int action = event.getActionMasked(); - switch (action) { - case MotionEvent.ACTION_DOWN: - mDownX = event.getX(); - mDownY = event.getY(); - mTrackTouch = true; - if (mDownY > getActualHeight()) { - mTrackTouch = false; - } - break; - case MotionEvent.ACTION_MOVE: - if (!isWithinTouchSlop(event)) { - makeInactive(true /* animate */); - mTrackTouch = false; - } - break; - case MotionEvent.ACTION_UP: - if (isWithinTouchSlop(event)) { - if (handleSlideBack()) { - return true; - } - if (!mActivated) { - makeActive(); - postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS); - mActivationX = event.getX(); - mActivationY = event.getY(); - } else { - boolean withinDoubleTapSlop = isWithinDoubleTapSlop(event); - mFalsingManager.onNotificationDoubleTap( - withinDoubleTapSlop, - event.getX() - mActivationX, - event.getY() - mActivationY); - if (withinDoubleTapSlop) { - if (!performClick()) { - return false; - } - } else { - makeInactive(true /* animate */); - mTrackTouch = false; - } - } - } else { - makeInactive(true /* animate */); - mTrackTouch = false; - } - break; - case MotionEvent.ACTION_CANCEL: - makeInactive(true /* animate */); - mTrackTouch = false; - break; - default: - break; - } - return mTrackTouch; + return mDoubleTapHelper.onTouchEvent(event, getActualHeight()); } private void makeActive() { @@ -425,21 +370,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView removeCallbacks(mTapTimeoutRunnable); } - private boolean isWithinTouchSlop(MotionEvent event) { - return Math.abs(event.getX() - mDownX) < mTouchSlop - && Math.abs(event.getY() - mDownY) < mTouchSlop; - } - - private boolean isWithinDoubleTapSlop(MotionEvent event) { - if (!mActivated) { - // If we're not activated there's no double tap slop to satisfy. - return true; - } - - return Math.abs(event.getX() - mActivationX) < mDoubleTapSlop - && Math.abs(event.getY() - mActivationY) < mDoubleTapSlop; - } - public void setDimmed(boolean dimmed, boolean fade) { if (mDimmed != dimmed) { mDimmed = dimmed; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DoubleTapHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DoubleTapHelper.java new file mode 100644 index 000000000000..dcb6a3801844 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DoubleTapHelper.java @@ -0,0 +1,174 @@ +/* + * 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.statusbar.phone; + +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; + +import com.android.systemui.R; + +/** + * Detects a double tap. + */ +public class DoubleTapHelper { + + private static final long DOUBLETAP_TIMEOUT_MS = 1200; + + private final View mView; + private final ActivationListener mActivationListener; + private final DoubleTapListener mDoubleTapListener; + private final SlideBackListener mSlideBackListener; + private final DoubleTapLogListener mDoubleTapLogListener; + + private float mTouchSlop; + private float mDoubleTapSlop; + + private boolean mActivated; + + private float mDownX; + private float mDownY; + private boolean mTrackTouch; + + private float mActivationX; + private float mActivationY; + private Runnable mTapTimeoutRunnable = this::makeInactive; + + public DoubleTapHelper(View view, ActivationListener activationListener, + DoubleTapListener doubleTapListener, SlideBackListener slideBackListener, + DoubleTapLogListener doubleTapLogListener) { + mTouchSlop = ViewConfiguration.get(view.getContext()).getScaledTouchSlop(); + mDoubleTapSlop = view.getResources().getDimension(R.dimen.double_tap_slop); + mView = view; + + mActivationListener = activationListener; + mDoubleTapListener = doubleTapListener; + mSlideBackListener = slideBackListener; + mDoubleTapLogListener = doubleTapLogListener; + } + + public boolean onTouchEvent(MotionEvent event) { + return onTouchEvent(event, Integer.MAX_VALUE); + } + + public boolean onTouchEvent(MotionEvent event, int maxTouchableHeight) { + int action = event.getActionMasked(); + switch (action) { + case MotionEvent.ACTION_DOWN: + mDownX = event.getX(); + mDownY = event.getY(); + mTrackTouch = true; + if (mDownY > maxTouchableHeight) { + mTrackTouch = false; + } + break; + case MotionEvent.ACTION_MOVE: + if (!isWithinTouchSlop(event)) { + makeInactive(); + mTrackTouch = false; + } + break; + case MotionEvent.ACTION_UP: + if (isWithinTouchSlop(event)) { + if (mSlideBackListener != null && mSlideBackListener.onSlideBack()) { + return true; + } + if (!mActivated) { + makeActive(); + mView.postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS); + mActivationX = event.getX(); + mActivationY = event.getY(); + } else { + boolean withinDoubleTapSlop = isWithinDoubleTapSlop(event); + if (mDoubleTapLogListener != null) { + mDoubleTapLogListener.onDoubleTapLog(withinDoubleTapSlop, + event.getX() - mActivationX, + event.getY() - mActivationY); + } + if (withinDoubleTapSlop) { + if (!mDoubleTapListener.onDoubleTap()) { + return false; + } + } else { + makeInactive(); + mTrackTouch = false; + } + } + } else { + makeInactive(); + mTrackTouch = false; + } + break; + case MotionEvent.ACTION_CANCEL: + makeInactive(); + mTrackTouch = false; + break; + default: + break; + } + return mTrackTouch; + } + + private void makeActive() { + if (!mActivated) { + mActivated = true; + mActivationListener.onActiveChanged(true); + } + } + + private void makeInactive() { + if (mActivated) { + mActivated = false; + mActivationListener.onActiveChanged(false); + } + } + + private boolean isWithinTouchSlop(MotionEvent event) { + return Math.abs(event.getX() - mDownX) < mTouchSlop + && Math.abs(event.getY() - mDownY) < mTouchSlop; + } + + private boolean isWithinDoubleTapSlop(MotionEvent event) { + if (!mActivated) { + // If we're not activated there's no double tap slop to satisfy. + return true; + } + + return Math.abs(event.getX() - mActivationX) < mDoubleTapSlop + && Math.abs(event.getY() - mActivationY) < mDoubleTapSlop; + } + + @FunctionalInterface + public interface ActivationListener { + void onActiveChanged(boolean active); + } + + @FunctionalInterface + public interface DoubleTapListener { + boolean onDoubleTap(); + } + + @FunctionalInterface + public interface SlideBackListener { + boolean onSlideBack(); + } + + @FunctionalInterface + public interface DoubleTapLogListener { + void onDoubleTapLog(boolean accepted, float dx, float dy); + } +} |