1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.systemui.statusbar.phone;
18 
19 import android.animation.Animator;
20 import android.animation.AnimatorListenerAdapter;
21 import android.animation.ValueAnimator;
22 import android.content.Context;
23 import android.view.MotionEvent;
24 import android.view.VelocityTracker;
25 import android.view.View;
26 import android.view.ViewConfiguration;
27 
28 import com.android.systemui.Interpolators;
29 import com.android.systemui.R;
30 import com.android.systemui.classifier.FalsingManager;
31 import com.android.systemui.statusbar.FlingAnimationUtils;
32 import com.android.systemui.statusbar.KeyguardAffordanceView;
33 
34 /**
35  * A touch handler of the keyguard which is responsible for launching phone and camera affordances.
36  */
37 public class KeyguardAffordanceHelper {
38 
39     public static final float SWIPE_RESTING_ALPHA_AMOUNT = 0.5f;
40     public static final long HINT_PHASE1_DURATION = 200;
41     private static final long HINT_PHASE2_DURATION = 350;
42     private static final float BACKGROUND_RADIUS_SCALE_FACTOR = 0.25f;
43     private static final int HINT_CIRCLE_OPEN_DURATION = 500;
44 
45     private final Context mContext;
46     private final Callback mCallback;
47 
48     private FlingAnimationUtils mFlingAnimationUtils;
49     private VelocityTracker mVelocityTracker;
50     private boolean mSwipingInProgress;
51     private float mInitialTouchX;
52     private float mInitialTouchY;
53     private float mTranslation;
54     private float mTranslationOnDown;
55     private int mTouchSlop;
56     private int mMinTranslationAmount;
57     private int mMinFlingVelocity;
58     private int mHintGrowAmount;
59     private KeyguardAffordanceView mLeftIcon;
60     private KeyguardAffordanceView mCenterIcon;
61     private KeyguardAffordanceView mRightIcon;
62     private Animator mSwipeAnimator;
63     private FalsingManager mFalsingManager;
64     private int mMinBackgroundRadius;
65     private boolean mMotionCancelled;
66     private int mTouchTargetSize;
67     private View mTargetedView;
68     private boolean mTouchSlopExeeded;
69     private AnimatorListenerAdapter mFlingEndListener = new AnimatorListenerAdapter() {
70         @Override
71         public void onAnimationEnd(Animator animation) {
72             mSwipeAnimator = null;
73             mSwipingInProgress = false;
74             mTargetedView = null;
75         }
76     };
77     private Runnable mAnimationEndRunnable = new Runnable() {
78         @Override
79         public void run() {
80             mCallback.onAnimationToSideEnded();
81         }
82     };
83 
KeyguardAffordanceHelper(Callback callback, Context context)84     KeyguardAffordanceHelper(Callback callback, Context context) {
85         mContext = context;
86         mCallback = callback;
87         initIcons();
88         updateIcon(mLeftIcon, 0.0f, mLeftIcon.getRestingAlpha(), false, false, true, false);
89         updateIcon(mCenterIcon, 0.0f, mCenterIcon.getRestingAlpha(), false, false, true, false);
90         updateIcon(mRightIcon, 0.0f, mRightIcon.getRestingAlpha(), false, false, true, false);
91         initDimens();
92     }
93 
initDimens()94     private void initDimens() {
95         final ViewConfiguration configuration = ViewConfiguration.get(mContext);
96         mTouchSlop = configuration.getScaledPagingTouchSlop();
97         mMinFlingVelocity = configuration.getScaledMinimumFlingVelocity();
98         mMinTranslationAmount = mContext.getResources().getDimensionPixelSize(
99                 R.dimen.keyguard_min_swipe_amount);
100         mMinBackgroundRadius = mContext.getResources().getDimensionPixelSize(
101                 R.dimen.keyguard_affordance_min_background_radius);
102         mTouchTargetSize = mContext.getResources().getDimensionPixelSize(
103                 R.dimen.keyguard_affordance_touch_target_size);
104         mHintGrowAmount =
105                 mContext.getResources().getDimensionPixelSize(R.dimen.hint_grow_amount_sideways);
106         mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.4f);
107         mFalsingManager = FalsingManager.getInstance(mContext);
108     }
109 
initIcons()110     private void initIcons() {
111         mLeftIcon = mCallback.getLeftIcon();
112         mCenterIcon = mCallback.getCenterIcon();
113         mRightIcon = mCallback.getRightIcon();
114         updatePreviews();
115     }
116 
updatePreviews()117     public void updatePreviews() {
118         mLeftIcon.setPreviewView(mCallback.getLeftPreview());
119         mRightIcon.setPreviewView(mCallback.getRightPreview());
120     }
121 
onTouchEvent(MotionEvent event)122     public boolean onTouchEvent(MotionEvent event) {
123         int action = event.getActionMasked();
124         if (mMotionCancelled && action != MotionEvent.ACTION_DOWN) {
125             return false;
126         }
127         final float y = event.getY();
128         final float x = event.getX();
129 
130         boolean isUp = false;
131         switch (action) {
132             case MotionEvent.ACTION_DOWN:
133                 View targetView = getIconAtPosition(x, y);
134                 if (targetView == null || (mTargetedView != null && mTargetedView != targetView)) {
135                     mMotionCancelled = true;
136                     return false;
137                 }
138                 if (mTargetedView != null) {
139                     cancelAnimation();
140                 } else {
141                     mTouchSlopExeeded = false;
142                 }
143                 startSwiping(targetView);
144                 mInitialTouchX = x;
145                 mInitialTouchY = y;
146                 mTranslationOnDown = mTranslation;
147                 initVelocityTracker();
148                 trackMovement(event);
149                 mMotionCancelled = false;
150                 break;
151             case MotionEvent.ACTION_POINTER_DOWN:
152                 mMotionCancelled = true;
153                 endMotion(true /* forceSnapBack */, x, y);
154                 break;
155             case MotionEvent.ACTION_MOVE:
156                 trackMovement(event);
157                 float xDist = x - mInitialTouchX;
158                 float yDist = y - mInitialTouchY;
159                 float distance = (float) Math.hypot(xDist, yDist);
160                 if (!mTouchSlopExeeded && distance > mTouchSlop) {
161                     mTouchSlopExeeded = true;
162                 }
163                 if (mSwipingInProgress) {
164                     if (mTargetedView == mRightIcon) {
165                         distance = mTranslationOnDown - distance;
166                         distance = Math.min(0, distance);
167                     } else {
168                         distance = mTranslationOnDown + distance;
169                         distance = Math.max(0, distance);
170                     }
171                     setTranslation(distance, false /* isReset */, false /* animateReset */);
172                 }
173                 break;
174 
175             case MotionEvent.ACTION_UP:
176                 isUp = true;
177             case MotionEvent.ACTION_CANCEL:
178                 boolean hintOnTheRight = mTargetedView == mRightIcon;
179                 trackMovement(event);
180                 endMotion(!isUp, x, y);
181                 if (!mTouchSlopExeeded && isUp) {
182                     mCallback.onIconClicked(hintOnTheRight);
183                 }
184                 break;
185         }
186         return true;
187     }
188 
startSwiping(View targetView)189     private void startSwiping(View targetView) {
190         mCallback.onSwipingStarted(targetView == mRightIcon);
191         mSwipingInProgress = true;
192         mTargetedView = targetView;
193     }
194 
getIconAtPosition(float x, float y)195     private View getIconAtPosition(float x, float y) {
196         if (leftSwipePossible() && isOnIcon(mLeftIcon, x, y)) {
197             return mLeftIcon;
198         }
199         if (rightSwipePossible() && isOnIcon(mRightIcon, x, y)) {
200             return mRightIcon;
201         }
202         return null;
203     }
204 
isOnAffordanceIcon(float x, float y)205     public boolean isOnAffordanceIcon(float x, float y) {
206         return isOnIcon(mLeftIcon, x, y) || isOnIcon(mRightIcon, x, y);
207     }
208 
isOnIcon(View icon, float x, float y)209     private boolean isOnIcon(View icon, float x, float y) {
210         float iconX = icon.getX() + icon.getWidth() / 2.0f;
211         float iconY = icon.getY() + icon.getHeight() / 2.0f;
212         double distance = Math.hypot(x - iconX, y - iconY);
213         return distance <= mTouchTargetSize / 2;
214     }
215 
endMotion(boolean forceSnapBack, float lastX, float lastY)216     private void endMotion(boolean forceSnapBack, float lastX, float lastY) {
217         if (mSwipingInProgress) {
218             flingWithCurrentVelocity(forceSnapBack, lastX, lastY);
219         } else {
220             mTargetedView = null;
221         }
222         if (mVelocityTracker != null) {
223             mVelocityTracker.recycle();
224             mVelocityTracker = null;
225         }
226     }
227 
rightSwipePossible()228     private boolean rightSwipePossible() {
229         return mRightIcon.getVisibility() == View.VISIBLE;
230     }
231 
leftSwipePossible()232     private boolean leftSwipePossible() {
233         return mLeftIcon.getVisibility() == View.VISIBLE;
234     }
235 
onInterceptTouchEvent(MotionEvent ev)236     public boolean onInterceptTouchEvent(MotionEvent ev) {
237         return false;
238     }
239 
startHintAnimation(boolean right, Runnable onFinishedListener)240     public void startHintAnimation(boolean right,
241             Runnable onFinishedListener) {
242         cancelAnimation();
243         startHintAnimationPhase1(right, onFinishedListener);
244     }
245 
startHintAnimationPhase1(final boolean right, final Runnable onFinishedListener)246     private void startHintAnimationPhase1(final boolean right, final Runnable onFinishedListener) {
247         final KeyguardAffordanceView targetView = right ? mRightIcon : mLeftIcon;
248         ValueAnimator animator = getAnimatorToRadius(right, mHintGrowAmount);
249         animator.addListener(new AnimatorListenerAdapter() {
250             private boolean mCancelled;
251 
252             @Override
253             public void onAnimationCancel(Animator animation) {
254                 mCancelled = true;
255             }
256 
257             @Override
258             public void onAnimationEnd(Animator animation) {
259                 if (mCancelled) {
260                     mSwipeAnimator = null;
261                     mTargetedView = null;
262                     onFinishedListener.run();
263                 } else {
264                     startUnlockHintAnimationPhase2(right, onFinishedListener);
265                 }
266             }
267         });
268         animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
269         animator.setDuration(HINT_PHASE1_DURATION);
270         animator.start();
271         mSwipeAnimator = animator;
272         mTargetedView = targetView;
273     }
274 
275     /**
276      * Phase 2: Move back.
277      */
startUnlockHintAnimationPhase2(boolean right, final Runnable onFinishedListener)278     private void startUnlockHintAnimationPhase2(boolean right, final Runnable onFinishedListener) {
279         ValueAnimator animator = getAnimatorToRadius(right, 0);
280         animator.addListener(new AnimatorListenerAdapter() {
281             @Override
282             public void onAnimationEnd(Animator animation) {
283                 mSwipeAnimator = null;
284                 mTargetedView = null;
285                 onFinishedListener.run();
286             }
287         });
288         animator.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
289         animator.setDuration(HINT_PHASE2_DURATION);
290         animator.setStartDelay(HINT_CIRCLE_OPEN_DURATION);
291         animator.start();
292         mSwipeAnimator = animator;
293     }
294 
getAnimatorToRadius(final boolean right, int radius)295     private ValueAnimator getAnimatorToRadius(final boolean right, int radius) {
296         final KeyguardAffordanceView targetView = right ? mRightIcon : mLeftIcon;
297         ValueAnimator animator = ValueAnimator.ofFloat(targetView.getCircleRadius(), radius);
298         animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
299             @Override
300             public void onAnimationUpdate(ValueAnimator animation) {
301                 float newRadius = (float) animation.getAnimatedValue();
302                 targetView.setCircleRadiusWithoutAnimation(newRadius);
303                 float translation = getTranslationFromRadius(newRadius);
304                 mTranslation = right ? -translation : translation;
305                 updateIconsFromTranslation(targetView);
306             }
307         });
308         return animator;
309     }
310 
cancelAnimation()311     private void cancelAnimation() {
312         if (mSwipeAnimator != null) {
313             mSwipeAnimator.cancel();
314         }
315     }
316 
flingWithCurrentVelocity(boolean forceSnapBack, float lastX, float lastY)317     private void flingWithCurrentVelocity(boolean forceSnapBack, float lastX, float lastY) {
318         float vel = getCurrentVelocity(lastX, lastY);
319 
320         // We snap back if the current translation is not far enough
321         boolean snapBack = false;
322         if (mCallback.needsAntiFalsing()) {
323             snapBack = snapBack || mFalsingManager.isFalseTouch();
324         }
325         snapBack = snapBack || isBelowFalsingThreshold();
326 
327         // or if the velocity is in the opposite direction.
328         boolean velIsInWrongDirection = vel * mTranslation < 0;
329         snapBack |= Math.abs(vel) > mMinFlingVelocity && velIsInWrongDirection;
330         vel = snapBack ^ velIsInWrongDirection ? 0 : vel;
331         fling(vel, snapBack || forceSnapBack, mTranslation < 0);
332     }
333 
isBelowFalsingThreshold()334     private boolean isBelowFalsingThreshold() {
335         return Math.abs(mTranslation) < Math.abs(mTranslationOnDown) + getMinTranslationAmount();
336     }
337 
getMinTranslationAmount()338     private int getMinTranslationAmount() {
339         float factor = mCallback.getAffordanceFalsingFactor();
340         return (int) (mMinTranslationAmount * factor);
341     }
342 
fling(float vel, final boolean snapBack, boolean right)343     private void fling(float vel, final boolean snapBack, boolean right) {
344         float target = right ? -mCallback.getMaxTranslationDistance()
345                 : mCallback.getMaxTranslationDistance();
346         target = snapBack ? 0 : target;
347 
348         ValueAnimator animator = ValueAnimator.ofFloat(mTranslation, target);
349         mFlingAnimationUtils.apply(animator, mTranslation, target, vel);
350         animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
351             @Override
352             public void onAnimationUpdate(ValueAnimator animation) {
353                 mTranslation = (float) animation.getAnimatedValue();
354             }
355         });
356         animator.addListener(mFlingEndListener);
357         if (!snapBack) {
358             startFinishingCircleAnimation(vel * 0.375f, mAnimationEndRunnable, right);
359             mCallback.onAnimationToSideStarted(right, mTranslation, vel);
360         } else {
361             reset(true);
362         }
363         animator.start();
364         mSwipeAnimator = animator;
365         if (snapBack) {
366             mCallback.onSwipingAborted();
367         }
368     }
369 
startFinishingCircleAnimation(float velocity, Runnable mAnimationEndRunnable, boolean right)370     private void startFinishingCircleAnimation(float velocity, Runnable mAnimationEndRunnable,
371             boolean right) {
372         KeyguardAffordanceView targetView = right ? mRightIcon : mLeftIcon;
373         targetView.finishAnimation(velocity, mAnimationEndRunnable);
374     }
375 
setTranslation(float translation, boolean isReset, boolean animateReset)376     private void setTranslation(float translation, boolean isReset, boolean animateReset) {
377         translation = rightSwipePossible() ? translation : Math.max(0, translation);
378         translation = leftSwipePossible() ? translation : Math.min(0, translation);
379         float absTranslation = Math.abs(translation);
380         if (translation != mTranslation || isReset) {
381             KeyguardAffordanceView targetView = translation > 0 ? mLeftIcon : mRightIcon;
382             KeyguardAffordanceView otherView = translation > 0 ? mRightIcon : mLeftIcon;
383             float alpha = absTranslation / getMinTranslationAmount();
384 
385             // We interpolate the alpha of the other icons to 0
386             float fadeOutAlpha = 1.0f - alpha;
387             fadeOutAlpha = Math.max(fadeOutAlpha, 0.0f);
388 
389             boolean animateIcons = isReset && animateReset;
390             boolean forceNoCircleAnimation = isReset && !animateReset;
391             float radius = getRadiusFromTranslation(absTranslation);
392             boolean slowAnimation = isReset && isBelowFalsingThreshold();
393             if (!isReset) {
394                 updateIcon(targetView, radius, alpha + fadeOutAlpha * targetView.getRestingAlpha(),
395                         false, false, false, false);
396             } else {
397                 updateIcon(targetView, 0.0f, fadeOutAlpha * targetView.getRestingAlpha(),
398                         animateIcons, slowAnimation, true /* isReset */, forceNoCircleAnimation);
399             }
400             updateIcon(otherView, 0.0f, fadeOutAlpha * otherView.getRestingAlpha(),
401                     animateIcons, slowAnimation, isReset, forceNoCircleAnimation);
402             updateIcon(mCenterIcon, 0.0f, fadeOutAlpha * mCenterIcon.getRestingAlpha(),
403                     animateIcons, slowAnimation, isReset, forceNoCircleAnimation);
404 
405             mTranslation = translation;
406         }
407     }
408 
updateIconsFromTranslation(KeyguardAffordanceView targetView)409     private void updateIconsFromTranslation(KeyguardAffordanceView targetView) {
410         float absTranslation = Math.abs(mTranslation);
411         float alpha = absTranslation / getMinTranslationAmount();
412 
413         // We interpolate the alpha of the other icons to 0
414         float fadeOutAlpha =  1.0f - alpha;
415         fadeOutAlpha = Math.max(0.0f, fadeOutAlpha);
416 
417         // We interpolate the alpha of the targetView to 1
418         KeyguardAffordanceView otherView = targetView == mRightIcon ? mLeftIcon : mRightIcon;
419         updateIconAlpha(targetView, alpha + fadeOutAlpha * targetView.getRestingAlpha(), false);
420         updateIconAlpha(otherView, fadeOutAlpha * otherView.getRestingAlpha(), false);
421         updateIconAlpha(mCenterIcon, fadeOutAlpha * mCenterIcon.getRestingAlpha(), false);
422     }
423 
getTranslationFromRadius(float circleSize)424     private float getTranslationFromRadius(float circleSize) {
425         float translation = (circleSize - mMinBackgroundRadius)
426                 / BACKGROUND_RADIUS_SCALE_FACTOR;
427         return translation > 0.0f ? translation + mTouchSlop : 0.0f;
428     }
429 
getRadiusFromTranslation(float translation)430     private float getRadiusFromTranslation(float translation) {
431         if (translation <= mTouchSlop) {
432             return 0.0f;
433         }
434         return (translation - mTouchSlop)  * BACKGROUND_RADIUS_SCALE_FACTOR + mMinBackgroundRadius;
435     }
436 
animateHideLeftRightIcon()437     public void animateHideLeftRightIcon() {
438         cancelAnimation();
439         updateIcon(mRightIcon, 0f, 0f, true, false, false, false);
440         updateIcon(mLeftIcon, 0f, 0f, true, false, false, false);
441     }
442 
updateIcon(KeyguardAffordanceView view, float circleRadius, float alpha, boolean animate, boolean slowRadiusAnimation, boolean force, boolean forceNoCircleAnimation)443     private void updateIcon(KeyguardAffordanceView view, float circleRadius, float alpha,
444                             boolean animate, boolean slowRadiusAnimation, boolean force,
445                             boolean forceNoCircleAnimation) {
446         if (view.getVisibility() != View.VISIBLE && !force) {
447             return;
448         }
449         if (forceNoCircleAnimation) {
450             view.setCircleRadiusWithoutAnimation(circleRadius);
451         } else {
452             view.setCircleRadius(circleRadius, slowRadiusAnimation);
453         }
454         updateIconAlpha(view, alpha, animate);
455     }
456 
updateIconAlpha(KeyguardAffordanceView view, float alpha, boolean animate)457     private void updateIconAlpha(KeyguardAffordanceView view, float alpha, boolean animate) {
458         float scale = getScale(alpha, view);
459         alpha = Math.min(1.0f, alpha);
460         view.setImageAlpha(alpha, animate);
461         view.setImageScale(scale, animate);
462     }
463 
getScale(float alpha, KeyguardAffordanceView icon)464     private float getScale(float alpha, KeyguardAffordanceView icon) {
465         float scale = alpha / icon.getRestingAlpha() * 0.2f +
466                 KeyguardAffordanceView.MIN_ICON_SCALE_AMOUNT;
467         return Math.min(scale, KeyguardAffordanceView.MAX_ICON_SCALE_AMOUNT);
468     }
469 
trackMovement(MotionEvent event)470     private void trackMovement(MotionEvent event) {
471         if (mVelocityTracker != null) {
472             mVelocityTracker.addMovement(event);
473         }
474     }
475 
initVelocityTracker()476     private void initVelocityTracker() {
477         if (mVelocityTracker != null) {
478             mVelocityTracker.recycle();
479         }
480         mVelocityTracker = VelocityTracker.obtain();
481     }
482 
getCurrentVelocity(float lastX, float lastY)483     private float getCurrentVelocity(float lastX, float lastY) {
484         if (mVelocityTracker == null) {
485             return 0;
486         }
487         mVelocityTracker.computeCurrentVelocity(1000);
488         float aX = mVelocityTracker.getXVelocity();
489         float aY = mVelocityTracker.getYVelocity();
490         float bX = lastX - mInitialTouchX;
491         float bY = lastY - mInitialTouchY;
492         float bLen = (float) Math.hypot(bX, bY);
493         // Project the velocity onto the distance vector: a * b / |b|
494         float projectedVelocity = (aX * bX + aY * bY) / bLen;
495         if (mTargetedView == mRightIcon) {
496             projectedVelocity = -projectedVelocity;
497         }
498         return projectedVelocity;
499     }
500 
onConfigurationChanged()501     public void onConfigurationChanged() {
502         initDimens();
503         initIcons();
504     }
505 
onRtlPropertiesChanged()506     public void onRtlPropertiesChanged() {
507         initIcons();
508     }
509 
reset(boolean animate)510     public void reset(boolean animate) {
511         cancelAnimation();
512         setTranslation(0.0f, true /* isReset */, animate);
513         mMotionCancelled = true;
514         if (mSwipingInProgress) {
515             mCallback.onSwipingAborted();
516             mSwipingInProgress = false;
517         }
518     }
519 
isSwipingInProgress()520     public boolean isSwipingInProgress() {
521         return mSwipingInProgress;
522     }
523 
launchAffordance(boolean animate, boolean left)524     public void launchAffordance(boolean animate, boolean left) {
525         if (mSwipingInProgress) {
526             // We don't want to mess with the state if the user is actually swiping already.
527             return;
528         }
529         KeyguardAffordanceView targetView = left ? mLeftIcon : mRightIcon;
530         KeyguardAffordanceView otherView = left ? mRightIcon : mLeftIcon;
531         startSwiping(targetView);
532 
533         // Do not animate the circle expanding if the affordance isn't visible,
534         // otherwise the circle will be meaningless.
535         if (targetView.getVisibility() != View.VISIBLE) {
536             animate = false;
537         }
538 
539         if (animate) {
540             fling(0, false, !left);
541             updateIcon(otherView, 0.0f, 0, true, false, true, false);
542             updateIcon(mCenterIcon, 0.0f, 0, true, false, true, false);
543         } else {
544             mCallback.onAnimationToSideStarted(!left, mTranslation, 0);
545             mTranslation = left ? mCallback.getMaxTranslationDistance()
546                     : mCallback.getMaxTranslationDistance();
547             updateIcon(mCenterIcon, 0.0f, 0.0f, false, false, true, false);
548             updateIcon(otherView, 0.0f, 0.0f, false, false, true, false);
549             targetView.instantFinishAnimation();
550             mFlingEndListener.onAnimationEnd(null);
551             mAnimationEndRunnable.run();
552         }
553     }
554 
555     public interface Callback {
556 
557         /**
558          * Notifies the callback when an animation to a side page was started.
559          *
560          * @param rightPage Is the page animated to the right page?
561          */
onAnimationToSideStarted(boolean rightPage, float translation, float vel)562         void onAnimationToSideStarted(boolean rightPage, float translation, float vel);
563 
564         /**
565          * Notifies the callback the animation to a side page has ended.
566          */
onAnimationToSideEnded()567         void onAnimationToSideEnded();
568 
getMaxTranslationDistance()569         float getMaxTranslationDistance();
570 
onSwipingStarted(boolean rightIcon)571         void onSwipingStarted(boolean rightIcon);
572 
onSwipingAborted()573         void onSwipingAborted();
574 
onIconClicked(boolean rightIcon)575         void onIconClicked(boolean rightIcon);
576 
getLeftIcon()577         KeyguardAffordanceView getLeftIcon();
578 
getCenterIcon()579         KeyguardAffordanceView getCenterIcon();
580 
getRightIcon()581         KeyguardAffordanceView getRightIcon();
582 
getLeftPreview()583         View getLeftPreview();
584 
getRightPreview()585         View getRightPreview();
586 
587         /**
588          * @return The factor the minimum swipe amount should be multiplied with.
589          */
getAffordanceFalsingFactor()590         float getAffordanceFalsingFactor();
591 
needsAntiFalsing()592         boolean needsAntiFalsing();
593     }
594 }
595