1/* 2 * Copyright (C) 2011 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 */ 16package android.support.v4.widget; 17 18import android.content.Context; 19import android.graphics.Canvas; 20import android.os.Build; 21 22/** 23 * Helper for accessing {@link android.widget.EdgeEffect} introduced after 24 * API level 4 in a backwards compatible fashion. 25 * 26 * This class is used to access {@link android.widget.EdgeEffect} on platform versions 27 * that support it. When running on older platforms it will result in no-ops. It should 28 * be used by views that wish to use the standard Android visual effects at the edges 29 * of scrolling containers. 30 */ 31public final class EdgeEffectCompat { 32 private Object mEdgeEffect; 33 34 private static final EdgeEffectImpl IMPL; 35 36 static { 37 if (Build.VERSION.SDK_INT >= 21) { 38 IMPL = new EdgeEffectLollipopImpl(); // Lollipop 39 } else if (Build.VERSION.SDK_INT >= 14) { // ICS 40 IMPL = new EdgeEffectIcsImpl(); 41 } else { 42 IMPL = new BaseEdgeEffectImpl(); 43 } 44 } 45 46 interface EdgeEffectImpl { 47 public Object newEdgeEffect(Context context); 48 public void setSize(Object edgeEffect, int width, int height); 49 public boolean isFinished(Object edgeEffect); 50 public void finish(Object edgeEffect); 51 public boolean onPull(Object edgeEffect, float deltaDistance); 52 public boolean onRelease(Object edgeEffect); 53 public boolean onAbsorb(Object edgeEffect, int velocity); 54 public boolean draw(Object edgeEffect, Canvas canvas); 55 public boolean onPull(Object edgeEffect, float deltaDistance, float displacement); 56 } 57 58 /** 59 * Null implementation to use pre-ICS 60 */ 61 static class BaseEdgeEffectImpl implements EdgeEffectImpl { 62 public Object newEdgeEffect(Context context) { 63 return null; 64 } 65 66 public void setSize(Object edgeEffect, int width, int height) { 67 } 68 69 public boolean isFinished(Object edgeEffect) { 70 return true; 71 } 72 73 public void finish(Object edgeEffect) { 74 } 75 76 public boolean onPull(Object edgeEffect, float deltaDistance) { 77 return false; 78 } 79 80 public boolean onRelease(Object edgeEffect) { 81 return false; 82 } 83 84 public boolean onAbsorb(Object edgeEffect, int velocity) { 85 return false; 86 } 87 88 public boolean draw(Object edgeEffect, Canvas canvas) { 89 return false; 90 } 91 92 public boolean onPull(Object edgeEffect, float deltaDistance, float displacement) { 93 return false; 94 } 95 } 96 97 static class EdgeEffectIcsImpl implements EdgeEffectImpl { 98 public Object newEdgeEffect(Context context) { 99 return EdgeEffectCompatIcs.newEdgeEffect(context); 100 } 101 102 public void setSize(Object edgeEffect, int width, int height) { 103 EdgeEffectCompatIcs.setSize(edgeEffect, width, height); 104 } 105 106 public boolean isFinished(Object edgeEffect) { 107 return EdgeEffectCompatIcs.isFinished(edgeEffect); 108 } 109 110 public void finish(Object edgeEffect) { 111 EdgeEffectCompatIcs.finish(edgeEffect); 112 } 113 114 public boolean onPull(Object edgeEffect, float deltaDistance) { 115 return EdgeEffectCompatIcs.onPull(edgeEffect, deltaDistance); 116 } 117 118 public boolean onRelease(Object edgeEffect) { 119 return EdgeEffectCompatIcs.onRelease(edgeEffect); 120 } 121 122 public boolean onAbsorb(Object edgeEffect, int velocity) { 123 return EdgeEffectCompatIcs.onAbsorb(edgeEffect, velocity); 124 } 125 126 public boolean draw(Object edgeEffect, Canvas canvas) { 127 return EdgeEffectCompatIcs.draw(edgeEffect, canvas); 128 } 129 130 public boolean onPull(Object edgeEffect, float deltaDistance, float displacement) { 131 return EdgeEffectCompatIcs.onPull(edgeEffect, deltaDistance); 132 } 133 } 134 135 static class EdgeEffectLollipopImpl extends EdgeEffectIcsImpl { 136 public boolean onPull(Object edgeEffect, float deltaDistance, float displacement) { 137 return EdgeEffectCompatLollipop.onPull(edgeEffect, deltaDistance, displacement); 138 } 139 } 140 141 /** 142 * Construct a new EdgeEffect themed using the given context. 143 * 144 * <p>Note: On platform versions that do not support EdgeEffect, all operations 145 * on the newly constructed object will be mocked/no-ops.</p> 146 * 147 * @param context Context to use for theming the effect 148 */ 149 public EdgeEffectCompat(Context context) { 150 mEdgeEffect = IMPL.newEdgeEffect(context); 151 } 152 153 /** 154 * Set the size of this edge effect in pixels. 155 * 156 * @param width Effect width in pixels 157 * @param height Effect height in pixels 158 */ 159 public void setSize(int width, int height) { 160 IMPL.setSize(mEdgeEffect, width, height); 161 } 162 163 /** 164 * Reports if this EdgeEffectCompat's animation is finished. If this method returns false 165 * after a call to {@link #draw(Canvas)} the host widget should schedule another 166 * drawing pass to continue the animation. 167 * 168 * @return true if animation is finished, false if drawing should continue on the next frame. 169 */ 170 public boolean isFinished() { 171 return IMPL.isFinished(mEdgeEffect); 172 } 173 174 /** 175 * Immediately finish the current animation. 176 * After this call {@link #isFinished()} will return true. 177 */ 178 public void finish() { 179 IMPL.finish(mEdgeEffect); 180 } 181 182 /** 183 * A view should call this when content is pulled away from an edge by the user. 184 * This will update the state of the current visual effect and its associated animation. 185 * The host view should always {@link android.view.View#invalidate()} if this method 186 * returns true and draw the results accordingly. 187 * 188 * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to 189 * 1.f (full length of the view) or negative values to express change 190 * back toward the edge reached to initiate the effect. 191 * @return true if the host view should call invalidate, false if it should not. 192 * @deprecated use {@link #onPull(float, float)} 193 */ 194 @Deprecated 195 public boolean onPull(float deltaDistance) { 196 return IMPL.onPull(mEdgeEffect, deltaDistance); 197 } 198 199 /** 200 * A view should call this when content is pulled away from an edge by the user. 201 * This will update the state of the current visual effect and its associated animation. 202 * The host view should always {@link android.view.View#invalidate()} if this method 203 * returns true and draw the results accordingly. 204 * 205 * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to 206 * 1.f (full length of the view) or negative values to express change 207 * back toward the edge reached to initiate the effect. 208 * @param displacement The displacement from the starting side of the effect of the point 209 * initiating the pull. In the case of touch this is the finger position. 210 * Values may be from 0-1. 211 * @return true if the host view should call invalidate, false if it should not. 212 */ 213 public boolean onPull(float deltaDistance, float displacement) { 214 return IMPL.onPull(mEdgeEffect, deltaDistance, displacement); 215 } 216 217 /** 218 * Call when the object is released after being pulled. 219 * This will begin the "decay" phase of the effect. After calling this method 220 * the host view should {@link android.view.View#invalidate()} if this method 221 * returns true and thereby draw the results accordingly. 222 * 223 * @return true if the host view should invalidate, false if it should not. 224 */ 225 public boolean onRelease() { 226 return IMPL.onRelease(mEdgeEffect); 227 } 228 229 /** 230 * Call when the effect absorbs an impact at the given velocity. 231 * Used when a fling reaches the scroll boundary. 232 * 233 * <p>When using a {@link android.widget.Scroller} or {@link android.widget.OverScroller}, 234 * the method <code>getCurrVelocity</code> will provide a reasonable approximation 235 * to use here.</p> 236 * 237 * @param velocity Velocity at impact in pixels per second. 238 * @return true if the host view should invalidate, false if it should not. 239 */ 240 public boolean onAbsorb(int velocity) { 241 return IMPL.onAbsorb(mEdgeEffect, velocity); 242 } 243 244 /** 245 * Draw into the provided canvas. Assumes that the canvas has been rotated 246 * accordingly and the size has been set. The effect will be drawn the full 247 * width of X=0 to X=width, beginning from Y=0 and extending to some factor < 248 * 1.f of height. 249 * 250 * @param canvas Canvas to draw into 251 * @return true if drawing should continue beyond this frame to continue the 252 * animation 253 */ 254 public boolean draw(Canvas canvas) { 255 return IMPL.draw(mEdgeEffect, canvas); 256 } 257} 258