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 import android.view.animation.AnimationUtils; 28 import android.view.animation.Interpolator; 29 30 import com.android.systemui.R; 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 47 private FlingAnimationUtils mFlingAnimationUtils; 48 private Callback mCallback; 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 Interpolator mAppearInterpolator; 63 private Interpolator mDisappearInterpolator; 64 private Animator mSwipeAnimator; 65 private int mMinBackgroundRadius; 66 private boolean mMotionCancelled; 67 private int mTouchTargetSize; 68 private View mTargetedView; 69 private boolean mTouchSlopExeeded; 70 private AnimatorListenerAdapter mFlingEndListener = new AnimatorListenerAdapter() { 71 @Override 72 public void onAnimationEnd(Animator animation) { 73 mSwipeAnimator = null; 74 mSwipingInProgress = false; 75 mTargetedView = null; 76 } 77 }; 78 private Runnable mAnimationEndRunnable = new Runnable() { 79 @Override 80 public void run() { 81 mCallback.onAnimationToSideEnded(); 82 } 83 }; 84 KeyguardAffordanceHelper(Callback callback, Context context)85 KeyguardAffordanceHelper(Callback callback, Context context) { 86 mContext = context; 87 mCallback = callback; 88 initIcons(); 89 updateIcon(mLeftIcon, 0.0f, mLeftIcon.getRestingAlpha(), false, false, true, false); 90 updateIcon(mCenterIcon, 0.0f, mCenterIcon.getRestingAlpha(), false, false, true, false); 91 updateIcon(mRightIcon, 0.0f, mRightIcon.getRestingAlpha(), false, false, true, false); 92 initDimens(); 93 } 94 initDimens()95 private void initDimens() { 96 final ViewConfiguration configuration = ViewConfiguration.get(mContext); 97 mTouchSlop = configuration.getScaledPagingTouchSlop(); 98 mMinFlingVelocity = configuration.getScaledMinimumFlingVelocity(); 99 mMinTranslationAmount = mContext.getResources().getDimensionPixelSize( 100 R.dimen.keyguard_min_swipe_amount); 101 mMinBackgroundRadius = mContext.getResources().getDimensionPixelSize( 102 R.dimen.keyguard_affordance_min_background_radius); 103 mTouchTargetSize = mContext.getResources().getDimensionPixelSize( 104 R.dimen.keyguard_affordance_touch_target_size); 105 mHintGrowAmount = 106 mContext.getResources().getDimensionPixelSize(R.dimen.hint_grow_amount_sideways); 107 mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.4f); 108 mAppearInterpolator = AnimationUtils.loadInterpolator(mContext, 109 android.R.interpolator.linear_out_slow_in); 110 mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext, 111 android.R.interpolator.fast_out_linear_in); 112 } 113 initIcons()114 private void initIcons() { 115 mLeftIcon = mCallback.getLeftIcon(); 116 mCenterIcon = mCallback.getCenterIcon(); 117 mRightIcon = mCallback.getRightIcon(); 118 updatePreviews(); 119 } 120 updatePreviews()121 public void updatePreviews() { 122 mLeftIcon.setPreviewView(mCallback.getLeftPreview()); 123 mRightIcon.setPreviewView(mCallback.getRightPreview()); 124 } 125 onTouchEvent(MotionEvent event)126 public boolean onTouchEvent(MotionEvent event) { 127 int action = event.getActionMasked(); 128 if (mMotionCancelled && action != MotionEvent.ACTION_DOWN) { 129 return false; 130 } 131 final float y = event.getY(); 132 final float x = event.getX(); 133 134 boolean isUp = false; 135 switch (action) { 136 case MotionEvent.ACTION_DOWN: 137 View targetView = getIconAtPosition(x, y); 138 if (targetView == null || (mTargetedView != null && mTargetedView != targetView)) { 139 mMotionCancelled = true; 140 return false; 141 } 142 if (mTargetedView != null) { 143 cancelAnimation(); 144 } else { 145 mTouchSlopExeeded = false; 146 } 147 startSwiping(targetView); 148 mInitialTouchX = x; 149 mInitialTouchY = y; 150 mTranslationOnDown = mTranslation; 151 initVelocityTracker(); 152 trackMovement(event); 153 mMotionCancelled = false; 154 break; 155 case MotionEvent.ACTION_POINTER_DOWN: 156 mMotionCancelled = true; 157 endMotion(true /* forceSnapBack */, x, y); 158 break; 159 case MotionEvent.ACTION_MOVE: 160 trackMovement(event); 161 float xDist = x - mInitialTouchX; 162 float yDist = y - mInitialTouchY; 163 float distance = (float) Math.hypot(xDist, yDist); 164 if (!mTouchSlopExeeded && distance > mTouchSlop) { 165 mTouchSlopExeeded = true; 166 } 167 if (mSwipingInProgress) { 168 if (mTargetedView == mRightIcon) { 169 distance = mTranslationOnDown - distance; 170 distance = Math.min(0, distance); 171 } else { 172 distance = mTranslationOnDown + distance; 173 distance = Math.max(0, distance); 174 } 175 setTranslation(distance, false /* isReset */, false /* animateReset */); 176 } 177 break; 178 179 case MotionEvent.ACTION_UP: 180 isUp = true; 181 case MotionEvent.ACTION_CANCEL: 182 boolean hintOnTheRight = mTargetedView == mRightIcon; 183 trackMovement(event); 184 endMotion(!isUp, x, y); 185 if (!mTouchSlopExeeded && isUp) { 186 mCallback.onIconClicked(hintOnTheRight); 187 } 188 break; 189 } 190 return true; 191 } 192 startSwiping(View targetView)193 private void startSwiping(View targetView) { 194 mCallback.onSwipingStarted(targetView == mRightIcon); 195 mSwipingInProgress = true; 196 mTargetedView = targetView; 197 } 198 getIconAtPosition(float x, float y)199 private View getIconAtPosition(float x, float y) { 200 if (leftSwipePossible() && isOnIcon(mLeftIcon, x, y)) { 201 return mLeftIcon; 202 } 203 if (rightSwipePossible() && isOnIcon(mRightIcon, x, y)) { 204 return mRightIcon; 205 } 206 return null; 207 } 208 isOnAffordanceIcon(float x, float y)209 public boolean isOnAffordanceIcon(float x, float y) { 210 return isOnIcon(mLeftIcon, x, y) || isOnIcon(mRightIcon, x, y); 211 } 212 isOnIcon(View icon, float x, float y)213 private boolean isOnIcon(View icon, float x, float y) { 214 float iconX = icon.getX() + icon.getWidth() / 2.0f; 215 float iconY = icon.getY() + icon.getHeight() / 2.0f; 216 double distance = Math.hypot(x - iconX, y - iconY); 217 return distance <= mTouchTargetSize / 2; 218 } 219 endMotion(boolean forceSnapBack, float lastX, float lastY)220 private void endMotion(boolean forceSnapBack, float lastX, float lastY) { 221 if (mSwipingInProgress) { 222 flingWithCurrentVelocity(forceSnapBack, lastX, lastY); 223 } else { 224 mTargetedView = null; 225 } 226 if (mVelocityTracker != null) { 227 mVelocityTracker.recycle(); 228 mVelocityTracker = null; 229 } 230 } 231 rightSwipePossible()232 private boolean rightSwipePossible() { 233 return mRightIcon.getVisibility() == View.VISIBLE; 234 } 235 leftSwipePossible()236 private boolean leftSwipePossible() { 237 return mLeftIcon.getVisibility() == View.VISIBLE; 238 } 239 onInterceptTouchEvent(MotionEvent ev)240 public boolean onInterceptTouchEvent(MotionEvent ev) { 241 return false; 242 } 243 startHintAnimation(boolean right, Runnable onFinishedListener)244 public void startHintAnimation(boolean right, 245 Runnable onFinishedListener) { 246 cancelAnimation(); 247 startHintAnimationPhase1(right, onFinishedListener); 248 } 249 startHintAnimationPhase1(final boolean right, final Runnable onFinishedListener)250 private void startHintAnimationPhase1(final boolean right, final Runnable onFinishedListener) { 251 final KeyguardAffordanceView targetView = right ? mRightIcon : mLeftIcon; 252 ValueAnimator animator = getAnimatorToRadius(right, mHintGrowAmount); 253 animator.addListener(new AnimatorListenerAdapter() { 254 private boolean mCancelled; 255 256 @Override 257 public void onAnimationCancel(Animator animation) { 258 mCancelled = true; 259 } 260 261 @Override 262 public void onAnimationEnd(Animator animation) { 263 if (mCancelled) { 264 mSwipeAnimator = null; 265 mTargetedView = null; 266 onFinishedListener.run(); 267 } else { 268 startUnlockHintAnimationPhase2(right, onFinishedListener); 269 } 270 } 271 }); 272 animator.setInterpolator(mAppearInterpolator); 273 animator.setDuration(HINT_PHASE1_DURATION); 274 animator.start(); 275 mSwipeAnimator = animator; 276 mTargetedView = targetView; 277 } 278 279 /** 280 * Phase 2: Move back. 281 */ startUnlockHintAnimationPhase2(boolean right, final Runnable onFinishedListener)282 private void startUnlockHintAnimationPhase2(boolean right, final Runnable onFinishedListener) { 283 ValueAnimator animator = getAnimatorToRadius(right, 0); 284 animator.addListener(new AnimatorListenerAdapter() { 285 @Override 286 public void onAnimationEnd(Animator animation) { 287 mSwipeAnimator = null; 288 mTargetedView = null; 289 onFinishedListener.run(); 290 } 291 }); 292 animator.setInterpolator(mDisappearInterpolator); 293 animator.setDuration(HINT_PHASE2_DURATION); 294 animator.setStartDelay(HINT_CIRCLE_OPEN_DURATION); 295 animator.start(); 296 mSwipeAnimator = animator; 297 } 298 getAnimatorToRadius(final boolean right, int radius)299 private ValueAnimator getAnimatorToRadius(final boolean right, int radius) { 300 final KeyguardAffordanceView targetView = right ? mRightIcon : mLeftIcon; 301 ValueAnimator animator = ValueAnimator.ofFloat(targetView.getCircleRadius(), radius); 302 animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 303 @Override 304 public void onAnimationUpdate(ValueAnimator animation) { 305 float newRadius = (float) animation.getAnimatedValue(); 306 targetView.setCircleRadiusWithoutAnimation(newRadius); 307 float translation = getTranslationFromRadius(newRadius); 308 mTranslation = right ? -translation : translation; 309 updateIconsFromTranslation(targetView); 310 } 311 }); 312 return animator; 313 } 314 cancelAnimation()315 private void cancelAnimation() { 316 if (mSwipeAnimator != null) { 317 mSwipeAnimator.cancel(); 318 } 319 } 320 flingWithCurrentVelocity(boolean forceSnapBack, float lastX, float lastY)321 private void flingWithCurrentVelocity(boolean forceSnapBack, float lastX, float lastY) { 322 float vel = getCurrentVelocity(lastX, lastY); 323 324 // We snap back if the current translation is not far enough 325 boolean 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, false, forceNoCircleAnimation); 399 } 400 updateIcon(otherView, 0.0f, fadeOutAlpha * otherView.getRestingAlpha(), 401 animateIcons, slowAnimation, false, forceNoCircleAnimation); 402 updateIcon(mCenterIcon, 0.0f, fadeOutAlpha * mCenterIcon.getRestingAlpha(), 403 animateIcons, slowAnimation, false, 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, 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 if (animate) { 533 fling(0, false, !left); 534 updateIcon(otherView, 0.0f, 0, true, false, true, false); 535 updateIcon(mCenterIcon, 0.0f, 0, true, false, true, false); 536 } else { 537 mCallback.onAnimationToSideStarted(!left, mTranslation, 0); 538 mTranslation = left ? mCallback.getMaxTranslationDistance() 539 : mCallback.getMaxTranslationDistance(); 540 updateIcon(mCenterIcon, 0.0f, 0.0f, false, false, true, false); 541 updateIcon(otherView, 0.0f, 0.0f, false, false, true, false); 542 targetView.instantFinishAnimation(); 543 mFlingEndListener.onAnimationEnd(null); 544 mAnimationEndRunnable.run(); 545 } 546 } 547 548 public interface Callback { 549 550 /** 551 * Notifies the callback when an animation to a side page was started. 552 * 553 * @param rightPage Is the page animated to the right page? 554 */ onAnimationToSideStarted(boolean rightPage, float translation, float vel)555 void onAnimationToSideStarted(boolean rightPage, float translation, float vel); 556 557 /** 558 * Notifies the callback the animation to a side page has ended. 559 */ onAnimationToSideEnded()560 void onAnimationToSideEnded(); 561 getMaxTranslationDistance()562 float getMaxTranslationDistance(); 563 onSwipingStarted(boolean rightIcon)564 void onSwipingStarted(boolean rightIcon); 565 onSwipingAborted()566 void onSwipingAborted(); 567 onIconClicked(boolean rightIcon)568 void onIconClicked(boolean rightIcon); 569 getLeftIcon()570 KeyguardAffordanceView getLeftIcon(); 571 getCenterIcon()572 KeyguardAffordanceView getCenterIcon(); 573 getRightIcon()574 KeyguardAffordanceView getRightIcon(); 575 getLeftPreview()576 View getLeftPreview(); 577 getRightPreview()578 View getRightPreview(); 579 580 /** 581 * @return The factor the minimum swipe amount should be multiplied with. 582 */ getAffordanceFalsingFactor()583 float getAffordanceFalsingFactor(); 584 } 585 } 586