1 package org.robolectric.shadows; 2 3 import android.os.Looper; 4 import android.widget.OverScroller; 5 import org.robolectric.annotation.Implementation; 6 import org.robolectric.annotation.Implements; 7 import org.robolectric.shadow.api.Shadow; 8 import org.robolectric.util.Scheduler; 9 10 @Implements(OverScroller.class) 11 public class ShadowOverScroller { 12 private int startX; 13 private int startY; 14 private int finalX; 15 private int finalY; 16 private long startTime; 17 private long duration; 18 private boolean started; 19 20 @Implementation getStartX()21 protected int getStartX() { 22 return startX; 23 } 24 25 @Implementation getStartY()26 protected int getStartY() { 27 return startY; 28 } 29 30 @Implementation getCurrX()31 protected int getCurrX() { 32 long dt = deltaTime(); 33 return dt >= duration ? finalX : startX + (int) ((deltaX() * dt) / duration); 34 } 35 36 @Implementation getCurrY()37 protected int getCurrY() { 38 long dt = deltaTime(); 39 return dt >= duration ? finalY : startY + (int) ((deltaY() * dt) / duration); 40 } 41 42 @Implementation getFinalX()43 protected int getFinalX() { 44 return finalX; 45 } 46 47 @Implementation getFinalY()48 protected int getFinalY() { 49 return finalY; 50 } 51 52 @Implementation getDuration()53 protected int getDuration() { 54 return (int) duration; 55 } 56 57 @Implementation startScroll(int startX, int startY, int dx, int dy, int duration)58 protected void startScroll(int startX, int startY, int dx, int dy, int duration) { 59 this.startX = startX; 60 this.startY = startY; 61 finalX = startX + dx; 62 finalY = startY + dy; 63 startTime = getScheduler().getCurrentTime(); 64 this.duration = duration; 65 started = true; 66 // post a task so that the scheduler will actually run 67 getScheduler().postDelayed(new Runnable() { 68 @Override 69 public void run() { 70 // do nothing 71 } 72 }, duration); 73 } 74 75 @Implementation abortAnimation()76 protected void abortAnimation() { 77 duration = deltaTime() - 1; 78 } 79 80 @Implementation forceFinished(boolean finished)81 protected void forceFinished(boolean finished) { 82 if (!finished) { 83 throw new RuntimeException("Not implemented."); 84 } 85 86 finalX = getCurrX(); 87 finalY = getCurrY(); 88 duration = deltaTime() - 1; 89 } 90 91 @Implementation computeScrollOffset()92 protected boolean computeScrollOffset() { 93 if (!started) { 94 return false; 95 } 96 started &= deltaTime() < duration; 97 return true; 98 } 99 100 @Implementation 101 protected boolean isFinished() { 102 return deltaTime() > duration; 103 } 104 105 @Implementation timePassed()106 protected int timePassed() { 107 return (int) deltaTime(); 108 } 109 110 @Implementation isScrollingInDirection(float xvel, float yvel)111 protected boolean isScrollingInDirection(float xvel, float yvel) { 112 final int dx = finalX - startX; 113 final int dy = finalY - startY; 114 return !isFinished() 115 && Math.signum(xvel) == Math.signum(dx) 116 && Math.signum(yvel) == Math.signum(dy); 117 } 118 deltaTime()119 private long deltaTime() { 120 return getScheduler().getCurrentTime() - startTime; 121 } 122 getScheduler()123 private Scheduler getScheduler() { 124 ShadowLooper shadowLooper = Shadow.extract(Looper.getMainLooper()); 125 return shadowLooper.getScheduler(); 126 } 127 deltaX()128 private int deltaX() { 129 return (finalX - startX); 130 } 131 deltaY()132 private int deltaY() { 133 return (finalY - startY); 134 } 135 } 136 137