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