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