1 package org.robolectric.shadows; 2 3 import static org.robolectric.shadows.ShadowLooper.shadowMainLooper; 4 import static org.robolectric.util.reflector.Reflector.reflector; 5 6 import android.view.MotionEvent; 7 import android.view.View; 8 import android.view.ViewGroup; 9 import java.io.PrintStream; 10 import org.robolectric.annotation.Implementation; 11 import org.robolectric.annotation.Implements; 12 import org.robolectric.annotation.LooperMode.Mode; 13 import org.robolectric.annotation.RealObject; 14 import org.robolectric.shadow.api.Shadow; 15 import org.robolectric.util.reflector.Direct; 16 import org.robolectric.util.reflector.ForType; 17 18 @SuppressWarnings({"UnusedDeclaration"}) 19 @Implements(ViewGroup.class) 20 public class ShadowViewGroup extends ShadowView { 21 @RealObject protected ViewGroup realViewGroup; 22 23 private boolean disallowInterceptTouchEvent = false; 24 private MotionEvent interceptedTouchEvent; 25 26 @Implementation addView(final View child, final int index, final ViewGroup.LayoutParams params)27 protected void addView(final View child, final int index, final ViewGroup.LayoutParams params) { 28 Runnable addViewRunnable = 29 () -> { 30 reflector(ViewGroupReflector.class, realViewGroup).addView(child, index, params); 31 }; 32 if (ShadowLooper.looperMode() == Mode.LEGACY) { 33 shadowMainLooper().runPaused(addViewRunnable); 34 } else { 35 addViewRunnable.run(); 36 } 37 } 38 39 /** 40 * Returns a string representation of this {@code ViewGroup} by concatenating all of the 41 * strings contained in all of the descendants of this {@code ViewGroup}. 42 */ 43 @Override innerText()44 public String innerText() { 45 StringBuilder innerText = new StringBuilder(); 46 String delimiter = ""; 47 48 for (int i = 0; i < realViewGroup.getChildCount(); i++) { 49 View child = realViewGroup.getChildAt(i); 50 ShadowView shadowView = Shadow.extract(child); 51 String childText = shadowView.innerText(); 52 if (childText.length() > 0) { 53 innerText.append(delimiter); 54 delimiter = " "; 55 } 56 innerText.append(childText); 57 } 58 return innerText.toString(); 59 } 60 61 /** 62 * Dumps the state of this {@code ViewGroup} to {@code System.out}. 63 * @deprecated - Please use {@link androidx.test.espresso.util.HumanReadables#describe(View)} 64 */ 65 @Override 66 @Deprecated dump(PrintStream out, int indent)67 public void dump(PrintStream out, int indent) { 68 dumpFirstPart(out, indent); 69 if (realViewGroup.getChildCount() > 0) { 70 out.println(">"); 71 72 for (int i = 0; i < realViewGroup.getChildCount(); i++) { 73 View child = realViewGroup.getChildAt(i); 74 ShadowView shadowChild = Shadow.extract(child); 75 shadowChild.dump(out, indent + 2); 76 } 77 78 dumpIndent(out, indent); 79 out.println("</" + realView.getClass().getSimpleName() + ">"); 80 } else { 81 out.println("/>"); 82 } 83 } 84 85 @Implementation requestDisallowInterceptTouchEvent(boolean disallowIntercept)86 protected void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { 87 reflector(ViewGroupReflector.class, realViewGroup) 88 .requestDisallowInterceptTouchEvent(disallowIntercept); 89 disallowInterceptTouchEvent = disallowIntercept; 90 } 91 getDisallowInterceptTouchEvent()92 public boolean getDisallowInterceptTouchEvent() { 93 return disallowInterceptTouchEvent; 94 } 95 removedChild(View child)96 protected void removedChild(View child) { 97 if (isAttachedToWindow()) { 98 ShadowView shadowView = Shadow.extract(child); 99 shadowView.callOnDetachedFromWindow(); 100 } 101 } 102 getInterceptedTouchEvent()103 public MotionEvent getInterceptedTouchEvent() { 104 return interceptedTouchEvent; 105 } 106 107 @Implementation onInterceptTouchEvent(MotionEvent ev)108 protected boolean onInterceptTouchEvent(MotionEvent ev) { 109 interceptedTouchEvent = ev; 110 return false; 111 } 112 113 @ForType(ViewGroup.class) 114 interface ViewGroupReflector { 115 116 @Direct addView(View child, int index, ViewGroup.LayoutParams params)117 void addView(View child, int index, ViewGroup.LayoutParams params); 118 119 @Direct requestDisallowInterceptTouchEvent(boolean disallowIntercept)120 void requestDisallowInterceptTouchEvent(boolean disallowIntercept); 121 } 122 } 123