Loading packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java +11 −81 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading @@ -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 Loading Loading @@ -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() { Loading Loading @@ -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; Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/DoubleTapHelper.java 0 → 100644 +174 −0 Original line number Diff line number Diff line /* * 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); } } Loading
packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java +11 −81 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading @@ -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 Loading Loading @@ -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() { Loading Loading @@ -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; Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/DoubleTapHelper.java 0 → 100644 +174 −0 Original line number Diff line number Diff line /* * 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); } }