1 package org.robolectric.shadows; 2 3 import static android.os.Build.VERSION_CODES.R; 4 import static android.os.Build.VERSION_CODES.S_V2; 5 import static android.os.Build.VERSION_CODES.TIRAMISU; 6 import static org.robolectric.util.reflector.Reflector.reflector; 7 8 import android.graphics.Rect; 9 import android.view.Display; 10 import android.view.HandlerActionQueue; 11 import android.view.IWindow; 12 import android.view.Surface; 13 import android.view.SurfaceControl; 14 import android.view.View; 15 import android.view.ViewRootImpl; 16 import android.view.WindowInsets; 17 import android.view.WindowManager; 18 import java.util.ArrayList; 19 import org.robolectric.RuntimeEnvironment; 20 import org.robolectric.annotation.Implementation; 21 import org.robolectric.annotation.Implements; 22 import org.robolectric.annotation.RealObject; 23 import org.robolectric.annotation.Resetter; 24 import org.robolectric.util.ReflectionHelpers; 25 import org.robolectric.util.reflector.Accessor; 26 import org.robolectric.util.reflector.Direct; 27 import org.robolectric.util.reflector.ForType; 28 import org.robolectric.util.reflector.Static; 29 30 @Implements(value = ViewRootImpl.class, isInAndroidSdk = false) 31 public class ShadowViewRootImpl { 32 33 static { 34 if (RuntimeEnvironment.getApiLevel() == R) { ReflectionHelpers.setStaticField(ViewRootImpl.class, "sNewInsetsMode", 2)35 ReflectionHelpers.setStaticField(ViewRootImpl.class, "sNewInsetsMode", 2); 36 } 37 } 38 39 @RealObject protected ViewRootImpl realObject; 40 41 @Implementation playSoundEffect(int effectId)42 public void playSoundEffect(int effectId) {} 43 44 // TODO: Deprecate and remove this method, resize should get dispatched automatically to all 45 // windows added in the window session when a display changes its size. callDispatchResized()46 public void callDispatchResized() { 47 ShadowWindowManagerGlobal.notifyResize( 48 reflector(ViewRootImplReflector.class, realObject).getWindow()); 49 } 50 getDisplay()51 protected Display getDisplay() { 52 return reflector(ViewRootImplReflector.class, realObject).getDisplay(); 53 } 54 55 @Implementation(minSdk = TIRAMISU) updateBlastSurfaceIfNeeded()56 protected void updateBlastSurfaceIfNeeded() {} 57 58 @Resetter reset()59 public static void reset() { 60 ViewRootImplReflector viewRootImplStatic = reflector(ViewRootImplReflector.class); 61 viewRootImplStatic.setRunQueues(new ThreadLocal<>()); 62 viewRootImplStatic.setFirstDrawHandlers(new ArrayList<>()); 63 viewRootImplStatic.setFirstDrawComplete(false); 64 viewRootImplStatic.setConfigCallbacks(new ArrayList<>()); 65 } 66 callWindowFocusChanged(boolean hasFocus)67 public void callWindowFocusChanged(boolean hasFocus) { 68 if (RuntimeEnvironment.getApiLevel() <= S_V2) { 69 reflector(ViewRootImplReflector.class, realObject) 70 .windowFocusChanged(hasFocus, ShadowWindowManagerGlobal.getInTouchMode()); 71 } else { 72 reflector(ViewRootImplReflector.class, realObject).windowFocusChanged(hasFocus); 73 } 74 } 75 getSurface()76 Surface getSurface() { 77 return reflector(ViewRootImplReflector.class, realObject).getSurface(); 78 } 79 80 /** Reflector interface for {@link ViewRootImpl}'s internals. */ 81 @ForType(ViewRootImpl.class) 82 protected interface ViewRootImplReflector { 83 @Accessor("mWindow") getWindow()84 IWindow getWindow(); 85 86 @Direct setView(View view, WindowManager.LayoutParams attrs, View panelParentView)87 void setView(View view, WindowManager.LayoutParams attrs, View panelParentView); 88 89 @Direct setView(View view, WindowManager.LayoutParams attrs, View panelParentView, int userId)90 void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, int userId); 91 92 @Static 93 @Accessor("sRunQueues") setRunQueues(ThreadLocal<HandlerActionQueue> threadLocal)94 void setRunQueues(ThreadLocal<HandlerActionQueue> threadLocal); 95 96 @Static 97 @Accessor("sFirstDrawHandlers") setFirstDrawHandlers(ArrayList<Runnable> handlers)98 void setFirstDrawHandlers(ArrayList<Runnable> handlers); 99 100 @Static 101 @Accessor("sFirstDrawComplete") setFirstDrawComplete(boolean isComplete)102 void setFirstDrawComplete(boolean isComplete); 103 104 @Static 105 @Accessor("sConfigCallbacks") setConfigCallbacks(ArrayList<ViewRootImpl.ConfigChangedCallback> callbacks)106 void setConfigCallbacks(ArrayList<ViewRootImpl.ConfigChangedCallback> callbacks); 107 108 @Accessor("sNewInsetsMode") 109 @Static getNewInsetsMode()110 int getNewInsetsMode(); 111 112 @Accessor("mWinFrame") setWinFrame(Rect winFrame)113 void setWinFrame(Rect winFrame); 114 115 @Accessor("mDisplay") getDisplay()116 Display getDisplay(); 117 118 @Accessor("mSurfaceControl") getSurfaceControl()119 SurfaceControl getSurfaceControl(); 120 121 @Accessor("mSurface") getSurface()122 Surface getSurface(); 123 124 @Accessor("mWindowAttributes") getWindowAttributes()125 WindowManager.LayoutParams getWindowAttributes(); 126 127 // SDK <= S_V2 windowFocusChanged(boolean hasFocus, boolean inTouchMode)128 void windowFocusChanged(boolean hasFocus, boolean inTouchMode); 129 130 // SDK >= T windowFocusChanged(boolean hasFocus)131 void windowFocusChanged(boolean hasFocus); 132 133 // SDK >= M 134 @Direct getWindowInsets(boolean forceConstruct)135 WindowInsets getWindowInsets(boolean forceConstruct); 136 } 137 } 138