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