1 package org.robolectric.shadows;
2 
3 import static android.os.Build.VERSION_CODES.Q;
4 import static android.os.Build.VERSION_CODES.R;
5 import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
6 import static org.robolectric.util.reflector.Reflector.reflector;
7 
8 import android.view.InsetsSource;
9 import android.view.InsetsState;
10 import android.view.WindowInsets;
11 import org.robolectric.RuntimeEnvironment;
12 import org.robolectric.annotation.Implements;
13 import org.robolectric.annotation.RealObject;
14 import org.robolectric.annotation.ReflectorObject;
15 import org.robolectric.util.reflector.Accessor;
16 import org.robolectric.util.reflector.ForType;
17 import org.robolectric.util.reflector.Static;
18 
19 /** Shadow of {@link InsetsState}. */
20 @Implements(value = InsetsState.class, minSdk = Q, isInAndroidSdk = false)
21 public class ShadowInsetsState {
22   // These must align with the indexes declared in InsetsState in SDK up to 33
23   static final int STATUS_BARS = 0;
24   static final int NAVIGATION_BARS = 1;
25 
26   @RealObject private InsetsState realInsetsState;
27   @ReflectorObject private InsetsStateReflector insetsStateReflector;
28 
getOrCreateSource(int id)29   InsetsSource getOrCreateSource(int id) {
30     return RuntimeEnvironment.getApiLevel() < UPSIDE_DOWN_CAKE
31         ? insetsStateReflector.getSource(id)
32         : realInsetsState.getOrCreateSource(id, getType(id));
33   }
34 
getSourceSize()35   int getSourceSize() {
36     if (RuntimeEnvironment.getApiLevel() >= UPSIDE_DOWN_CAKE) {
37       return realInsetsState.sourceSize();
38     } else if (RuntimeEnvironment.getApiLevel() >= R) {
39       return reflector(InsetsStateReflector.class).getLastType() + 1;
40     } else {
41       return insetsStateReflector.getSourcesCount();
42     }
43   }
44 
getType(int id)45   private static int getType(int id) {
46     switch (id) {
47       case STATUS_BARS:
48         return RuntimeEnvironment.getApiLevel() < Q
49             ? reflector(WindowInsetsTypeReflector.class).topBar()
50             : WindowInsets.Type.statusBars();
51       case NAVIGATION_BARS:
52         return RuntimeEnvironment.getApiLevel() < Q
53             ? reflector(WindowInsetsTypeReflector.class).sideBars()
54             : WindowInsets.Type.navigationBars();
55       default:
56         throw new IllegalArgumentException();
57     }
58   }
59 
60   @ForType(InsetsState.class)
61   interface InsetsStateReflector {
getSource(int type)62     InsetsSource getSource(int type);
63 
64     @Accessor("ITYPE_IME")
65     @Static
getImeType()66     int getImeType();
67 
68     @Accessor("LAST_TYPE")
69     @Static
getLastType()70     int getLastType();
71 
getSourcesCount()72     int getSourcesCount();
73   }
74 
75   @ForType(WindowInsets.Type.class)
76   interface WindowInsetsTypeReflector {
77     @Static
topBar()78     int topBar();
79 
80     @Static
sideBars()81     int sideBars();
82   }
83 }
84