1 package org.robolectric.shadows; 2 3 import static android.os.Build.VERSION_CODES.JELLY_BEAN; 4 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; 5 6 import android.content.Context; 7 import android.content.res.Configuration; 8 import android.graphics.Rect; 9 import android.os.Build; 10 import android.os.Looper; 11 import android.util.MergedConfiguration; 12 import android.view.Display; 13 import android.view.IWindowSession; 14 import android.view.ViewRootImpl; 15 import android.view.WindowManager; 16 import android.window.ClientWindowFrames; 17 import java.util.ArrayList; 18 import org.robolectric.RuntimeEnvironment; 19 import org.robolectric.annotation.Implementation; 20 import org.robolectric.annotation.Implements; 21 import org.robolectric.annotation.RealObject; 22 import org.robolectric.annotation.Resetter; 23 import org.robolectric.util.ReflectionHelpers; 24 import org.robolectric.util.ReflectionHelpers.ClassParameter; 25 26 @Implements(value = ViewRootImpl.class, isInAndroidSdk = false) 27 public class ShadowViewRootImpl { 28 29 @RealObject private ViewRootImpl realObject; 30 31 @Implementation(maxSdk = JELLY_BEAN) getWindowSession(Looper mainLooper)32 public static IWindowSession getWindowSession(Looper mainLooper) { 33 return null; 34 } 35 36 @Implementation playSoundEffect(int effectId)37 public void playSoundEffect(int effectId) { 38 } 39 callDispatchResized()40 public void callDispatchResized() { 41 Display display = getDisplay(); 42 Rect frame = new Rect(); 43 display.getRectSize(frame); 44 Rect zeroSizedRect = new Rect(0, 0, 0, 0); 45 ClientWindowFrames clientWindowFrame = new ClientWindowFrames(); 46 47 int apiLevel = RuntimeEnvironment.getApiLevel(); 48 ViewRootImpl component = realObject; 49 if (apiLevel <= Build.VERSION_CODES.JELLY_BEAN) { 50 ReflectionHelpers.callInstanceMethod(ViewRootImpl.class, component, "dispatchResized", 51 ClassParameter.from(int.class, frame.width()), 52 ClassParameter.from(int.class, frame.height()), 53 ClassParameter.from(Rect.class, zeroSizedRect), 54 ClassParameter.from(Rect.class, zeroSizedRect), 55 ClassParameter.from(boolean.class, true), 56 ClassParameter.from(Configuration.class, null)); 57 } else if (apiLevel <= JELLY_BEAN_MR1) { 58 ReflectionHelpers.callInstanceMethod(ViewRootImpl.class, component, "dispatchResized", 59 ClassParameter.from(Rect.class, frame), 60 ClassParameter.from(Rect.class, zeroSizedRect), 61 ClassParameter.from(Rect.class, zeroSizedRect), 62 ClassParameter.from(boolean.class, true), 63 ClassParameter.from(Configuration.class, null)); 64 } else if (apiLevel <= Build.VERSION_CODES.KITKAT) { 65 ReflectionHelpers.callInstanceMethod(ViewRootImpl.class, component, "dispatchResized", 66 ClassParameter.from(Rect.class, frame), 67 ClassParameter.from(Rect.class, zeroSizedRect), 68 ClassParameter.from(Rect.class, zeroSizedRect), 69 ClassParameter.from(Rect.class, zeroSizedRect), 70 ClassParameter.from(boolean.class, true), 71 ClassParameter.from(Configuration.class, null)); 72 } else if (apiLevel <= Build.VERSION_CODES.LOLLIPOP_MR1) { 73 ReflectionHelpers.callInstanceMethod(ViewRootImpl.class, component, "dispatchResized", 74 ClassParameter.from(Rect.class, frame), 75 ClassParameter.from(Rect.class, zeroSizedRect), 76 ClassParameter.from(Rect.class, zeroSizedRect), 77 ClassParameter.from(Rect.class, zeroSizedRect), 78 ClassParameter.from(Rect.class, zeroSizedRect), 79 ClassParameter.from(boolean.class, true), 80 ClassParameter.from(Configuration.class, null)); 81 } else if (apiLevel <= Build.VERSION_CODES.M) { 82 ReflectionHelpers.callInstanceMethod(ViewRootImpl.class, component, "dispatchResized", 83 ClassParameter.from(Rect.class, frame), 84 ClassParameter.from(Rect.class, zeroSizedRect), 85 ClassParameter.from(Rect.class, zeroSizedRect), 86 ClassParameter.from(Rect.class, zeroSizedRect), 87 ClassParameter.from(Rect.class, zeroSizedRect), 88 ClassParameter.from(Rect.class, zeroSizedRect), 89 ClassParameter.from(boolean.class, true), 90 ClassParameter.from(Configuration.class, null)); 91 } else if (apiLevel <= Build.VERSION_CODES.N_MR1) { 92 ReflectionHelpers.callInstanceMethod(ViewRootImpl.class, component, "dispatchResized", 93 ClassParameter.from(Rect.class, frame), 94 ClassParameter.from(Rect.class, zeroSizedRect), 95 ClassParameter.from(Rect.class, zeroSizedRect), 96 ClassParameter.from(Rect.class, zeroSizedRect), 97 ClassParameter.from(Rect.class, zeroSizedRect), 98 ClassParameter.from(Rect.class, zeroSizedRect), 99 ClassParameter.from(boolean.class, true), 100 ClassParameter.from(Configuration.class, null), 101 ClassParameter.from(Rect.class, frame), 102 ClassParameter.from(boolean.class, false), 103 ClassParameter.from(boolean.class, false)); 104 } else if (apiLevel <= Build.VERSION_CODES.O_MR1) { 105 ReflectionHelpers.callInstanceMethod( 106 ViewRootImpl.class, 107 component, 108 "dispatchResized", 109 ClassParameter.from(Rect.class, frame), 110 ClassParameter.from(Rect.class, zeroSizedRect), 111 ClassParameter.from(Rect.class, zeroSizedRect), 112 ClassParameter.from(Rect.class, zeroSizedRect), 113 ClassParameter.from(Rect.class, zeroSizedRect), 114 ClassParameter.from(Rect.class, zeroSizedRect), 115 ClassParameter.from(boolean.class, true), 116 ClassParameter.from(MergedConfiguration.class, new MergedConfiguration()), 117 ClassParameter.from(Rect.class, frame), 118 ClassParameter.from(boolean.class, false), 119 ClassParameter.from(boolean.class, false), 120 ClassParameter.from(int.class, 0)); 121 } else if (apiLevel <= Build.VERSION_CODES.Q) { 122 ReflectionHelpers.callInstanceMethod(ViewRootImpl.class, component, "dispatchResized", 123 ClassParameter.from(Rect.class, frame), 124 ClassParameter.from(Rect.class, zeroSizedRect), 125 ClassParameter.from(Rect.class, zeroSizedRect), 126 ClassParameter.from(Rect.class, zeroSizedRect), 127 ClassParameter.from(Rect.class, zeroSizedRect), 128 ClassParameter.from(Rect.class, zeroSizedRect), 129 ClassParameter.from(boolean.class, true), 130 ClassParameter.from(MergedConfiguration.class, new MergedConfiguration()), 131 ClassParameter.from(Rect.class, frame), 132 ClassParameter.from(boolean.class, false), 133 ClassParameter.from(boolean.class, false), 134 ClassParameter.from(int.class, 0), 135 ClassParameter.from(android.view.DisplayCutout.ParcelableWrapper.class, 136 new android.view.DisplayCutout.ParcelableWrapper())); 137 } else if (apiLevel <= Build.VERSION_CODES.R) { 138 // BEGIN-INTERNAL 139 ReflectionHelpers.callInstanceMethod(ViewRootImpl.class, component, "dispatchResized", 140 ClassParameter.from(Rect.class, frame), 141 ClassParameter.from(Rect.class, zeroSizedRect), 142 ClassParameter.from(Rect.class, zeroSizedRect), 143 ClassParameter.from(Rect.class, zeroSizedRect), 144 ClassParameter.from(boolean.class, true), 145 ClassParameter.from(MergedConfiguration.class, new MergedConfiguration()), 146 ClassParameter.from(Rect.class, frame), 147 ClassParameter.from(boolean.class, false), 148 ClassParameter.from(boolean.class, false), 149 ClassParameter.from(int.class, 0), 150 ClassParameter.from(android.view.DisplayCutout.ParcelableWrapper.class, 151 new android.view.DisplayCutout.ParcelableWrapper())); 152 // END-INTERNAL 153 } else if (apiLevel >= Build.VERSION_CODES.S) { 154 // BEGIN-INTERNAL 155 ReflectionHelpers.callInstanceMethod(ViewRootImpl.class, component, "dispatchResized", 156 ClassParameter.from(ClientWindowFrames.class, clientWindowFrame), 157 ClassParameter.from(boolean.class, true), 158 ClassParameter.from(MergedConfiguration.class, new MergedConfiguration()), 159 ClassParameter.from(boolean.class, false), 160 ClassParameter.from(boolean.class, false), 161 ClassParameter.from(int.class, 0)); 162 // END-INTERNAL 163 } else { 164 throw new RuntimeException("Could not find AndroidRuntimeAdapter for API level: " + apiLevel); 165 } 166 } 167 getDisplay()168 private Display getDisplay() { 169 if (RuntimeEnvironment.getApiLevel() > JELLY_BEAN_MR1) { 170 return realObject.getView().getDisplay(); 171 } else { 172 WindowManager windowManager = (WindowManager) realObject.getView().getContext() 173 .getSystemService(Context.WINDOW_SERVICE); 174 return windowManager.getDefaultDisplay(); 175 } 176 } 177 178 @Resetter reset()179 public static void reset() { 180 ReflectionHelpers.setStaticField(ViewRootImpl.class, "sRunQueues", new ThreadLocal<>()); 181 ReflectionHelpers.setStaticField(ViewRootImpl.class, "sFirstDrawHandlers", new ArrayList<>()); 182 ReflectionHelpers.setStaticField(ViewRootImpl.class, "sFirstDrawComplete", false); 183 ReflectionHelpers.setStaticField(ViewRootImpl.class, "sConfigCallbacks", new ArrayList<>()); 184 } 185 } 186