1 package com.xtremelabs.robolectric.shadows; 2 3 import android.view.View; 4 import android.view.ViewGroup; 5 import android.view.animation.Animation.AnimationListener; 6 import com.xtremelabs.robolectric.internal.Implementation; 7 import com.xtremelabs.robolectric.internal.Implements; 8 9 import java.io.PrintStream; 10 import java.util.ArrayList; 11 import java.util.List; 12 13 import static com.xtremelabs.robolectric.Robolectric.shadowOf; 14 15 /** 16 * Shadow for {@code ViewGroup} that simulates its implementation 17 */ 18 @SuppressWarnings({"UnusedDeclaration"}) 19 @Implements(ViewGroup.class) 20 public class ShadowViewGroup extends ShadowView { 21 private List<View> children = new ArrayList<View>(); 22 private AnimationListener animListener; 23 private boolean disallowInterceptTouchEvent = false; 24 25 @Implementation 26 @Override findViewById(int id)27 public View findViewById(int id) { 28 if (id == getId()) { 29 return realView; 30 } 31 32 for (View child : children) { 33 View found = child.findViewById(id); 34 if (found != null) { 35 return found; 36 } 37 } 38 return null; 39 } 40 41 @Implementation 42 @Override findViewWithTag(Object obj)43 public View findViewWithTag(Object obj) { 44 if (obj.equals(realView.getTag())) { 45 return realView; 46 } 47 48 for (View child : children) { 49 View found = child.findViewWithTag(obj); 50 if (found != null) { 51 return found; 52 } 53 } 54 55 return null; 56 } 57 58 @Implementation addView(View child)59 public void addView(View child) { 60 ((ViewGroup) realView).addView(child, -1); 61 } 62 63 @Implementation addView(View child, int index)64 public void addView(View child, int index) { 65 if (index == -1) { 66 children.add(child); 67 } else { 68 children.add(index, child); 69 } 70 shadowOf(child).parent = this; 71 } 72 73 @Implementation addView(View child, int width, int height)74 public void addView(View child, int width, int height) { 75 ((ViewGroup) realView).addView(child, -1); 76 } 77 78 @Implementation addView(View child, ViewGroup.LayoutParams params)79 public void addView(View child, ViewGroup.LayoutParams params) { 80 ((ViewGroup) realView).addView(child, -1); 81 } 82 83 @Implementation addView(View child, int index, ViewGroup.LayoutParams params)84 public void addView(View child, int index, ViewGroup.LayoutParams params) { 85 ((ViewGroup) realView).addView(child, index); 86 } 87 88 @Implementation indexOfChild(View child)89 public int indexOfChild(View child) { 90 int count = getChildCount(); 91 for (int i = 0; i < count; i++) { 92 if (children.get(i) == child) { 93 return i; 94 } 95 } 96 return -1; 97 } 98 99 @Implementation getChildCount()100 public int getChildCount() { 101 return children.size(); 102 } 103 104 @Implementation getChildAt(int index)105 public View getChildAt(int index) { 106 if( index >= children.size() ){ return null; } 107 return children.get(index); 108 } 109 110 @Implementation removeAllViews()111 public void removeAllViews() { 112 for (View child : children) { 113 shadowOf(child).parent = null; 114 } 115 children.clear(); 116 } 117 118 @Implementation removeViewAt(int position)119 public void removeViewAt(int position) { 120 shadowOf(children.remove(position)).parent = null; 121 } 122 123 @Implementation removeView(View view)124 public void removeView(View view) { 125 removeViewInLayout(view); 126 } 127 128 @Implementation removeViewInLayout(View view)129 public void removeViewInLayout(View view) { 130 int index = indexOfChild(view); 131 if (index >= 0) { 132 removeViewAt(index); 133 } 134 } 135 136 @Implementation removeViews(int start, int count)137 public void removeViews(int start, int count) { 138 removeViewsInLayout(start, count); 139 } 140 141 @Implementation removeViewsInLayout(int start, int count)142 public void removeViewsInLayout(int start, int count) { 143 int lastIndex = start + count - 1; 144 for (int i = lastIndex; i >= start; i--) { 145 removeViewAt(i); 146 } 147 } 148 149 @Override 150 @Implementation hasFocus()151 public boolean hasFocus() { 152 if (super.hasFocus()) return true; 153 154 for (View child : children) { 155 if (child.hasFocus()) return true; 156 } 157 158 return false; 159 } 160 161 @Implementation 162 @Override clearFocus()163 public void clearFocus() { 164 if (hasFocus()) { 165 super.clearFocus(); 166 167 for (View child : children) { 168 child.clearFocus(); 169 } 170 } 171 } 172 173 @Implementation 174 @Override findFocus()175 public View findFocus() { 176 if (super.hasFocus()) { 177 return this.realView; 178 } 179 180 for (View child : children) { 181 View focusedView = child.findFocus(); 182 if (focusedView != null) { 183 return focusedView; 184 } 185 } 186 187 return null; 188 } 189 190 /** 191 * Returns a string representation of this {@code ViewGroup} by concatenating all of the strings contained in all 192 * of the descendants of this {@code ViewGroup}. 193 * <p/> 194 * Robolectric extension. 195 */ 196 @Override innerText()197 public String innerText() { 198 String innerText = ""; 199 String delimiter = ""; 200 201 for (int i = 0; i < getChildCount(); i++) { 202 View child = getChildAt(i); 203 String childText = shadowOf(child).innerText(); 204 if (childText.length() > 0) { 205 innerText += delimiter; 206 delimiter = " "; 207 } 208 innerText += childText; 209 } 210 return innerText; 211 } 212 213 /** 214 * Non-Android method that dumps the state of this {@code ViewGroup} to {@code System.out} 215 */ 216 @Override dump(PrintStream out, int indent)217 public void dump(PrintStream out, int indent) { 218 dumpFirstPart(out, indent); 219 if (children.size() > 0) { 220 out.println(">"); 221 222 for (View child : children) { 223 shadowOf(child).dump(out, indent + 2); 224 } 225 226 dumpIndent(out, indent); 227 out.println("</" + realView.getClass().getSimpleName() + ">"); 228 } else { 229 out.println("/>"); 230 } 231 } 232 233 @Implementation setLayoutAnimationListener(AnimationListener listener)234 public void setLayoutAnimationListener(AnimationListener listener) { 235 animListener = listener; 236 } 237 238 @Implementation getLayoutAnimationListener()239 public AnimationListener getLayoutAnimationListener() { 240 return animListener; 241 } 242 243 @Implementation requestDisallowInterceptTouchEvent(boolean disallowIntercept)244 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { 245 disallowInterceptTouchEvent = disallowIntercept; 246 } 247 getDisallowInterceptTouchEvent()248 public boolean getDisallowInterceptTouchEvent() { 249 return disallowInterceptTouchEvent; 250 } 251 } 252