• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.view.View.SYSTEM_UI_FLAG_VISIBLE;
6 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
7 import static org.robolectric.RuntimeEnvironment.getApiLevel;
8 import static org.robolectric.util.reflector.Reflector.reflector;
9 
10 import android.content.Context;
11 import android.graphics.Insets;
12 import android.graphics.Rect;
13 import android.util.SparseIntArray;
14 import android.view.Display;
15 import android.view.DisplayCutout;
16 import android.view.InsetsState;
17 import android.view.View;
18 import android.view.ViewGroup;
19 import android.view.WindowInsets;
20 import android.view.WindowManager;
21 import android.view.WindowManagerImpl;
22 import com.google.common.collect.ArrayListMultimap;
23 import com.google.common.collect.ImmutableList;
24 import com.google.common.collect.Multimap;
25 import java.util.List;
26 import org.robolectric.annotation.Implementation;
27 import org.robolectric.annotation.Implements;
28 import org.robolectric.annotation.RealObject;
29 import org.robolectric.annotation.Resetter;
30 import org.robolectric.shadows.ShadowViewRootImpl.ViewRootImplReflector;
31 import org.robolectric.util.ReflectionHelpers;
32 import org.robolectric.util.ReflectionHelpers.ClassParameter;
33 import org.robolectric.util.reflector.Accessor;
34 import org.robolectric.util.reflector.Direct;
35 import org.robolectric.util.reflector.ForType;
36 
37 @Implements(value = WindowManagerImpl.class, isInAndroidSdk = false)
38 public class ShadowWindowManagerImpl extends ShadowWindowManager {
39 
40   @RealObject WindowManagerImpl realObject;
41   private static final Multimap<Integer, View> views = ArrayListMultimap.create();
42 
43   // removed from WindowManagerImpl in S
44   public static final int NEW_INSETS_MODE_FULL = 2;
45 
46   @Implementation
addView(View view, android.view.ViewGroup.LayoutParams layoutParams)47   public void addView(View view, android.view.ViewGroup.LayoutParams layoutParams) {
48     views.put(realObject.getDefaultDisplay().getDisplayId(), view);
49     // views.add(view);
50     reflector(ReflectorWindowManagerImpl.class, realObject).addView(view, layoutParams);
51   }
52 
53   @Implementation
removeView(View view)54   public void removeView(View view) {
55     views.remove(realObject.getDefaultDisplay().getDisplayId(), view);
56     reflector(ReflectorWindowManagerImpl.class, realObject).removeView(view);
57   }
58 
59   @Implementation
removeViewImmediate(View view)60   protected void removeViewImmediate(View view) {
61     views.remove(realObject.getDefaultDisplay().getDisplayId(), view);
62     reflector(ReflectorWindowManagerImpl.class, realObject).removeViewImmediate(view);
63   }
64 
getViews()65   public List<View> getViews() {
66     return ImmutableList.copyOf(views.get(realObject.getDefaultDisplay().getDisplayId()));
67   }
68 
69   /** Re implement to avoid server call */
70   @Implementation(minSdk = R, maxSdk = S_V2)
getWindowInsetsFromServer(WindowManager.LayoutParams attrs, Rect bounds)71   protected WindowInsets getWindowInsetsFromServer(WindowManager.LayoutParams attrs, Rect bounds) {
72     Context context = reflector(ReflectorWindowManagerImpl.class, realObject).getContext();
73     final Rect systemWindowInsets = new Rect();
74     final Rect stableInsets = new Rect();
75     final DisplayCutout.ParcelableWrapper displayCutout = new DisplayCutout.ParcelableWrapper();
76     final InsetsState insetsState = new InsetsState();
77     final boolean alwaysConsumeSystemBars = true;
78 
79     final boolean isScreenRound = context.getResources().getConfiguration().isScreenRound();
80     if (getApiLevel() <= R
81         && reflector(ViewRootImplReflector.class).getNewInsetsMode() == NEW_INSETS_MODE_FULL) {
82       return ReflectionHelpers.callInstanceMethod(
83           insetsState,
84           "calculateInsets",
85           ClassParameter.from(Rect.class, bounds),
86           ClassParameter.from(InsetsState.class, null),
87           ClassParameter.from(Boolean.TYPE, isScreenRound),
88           ClassParameter.from(Boolean.TYPE, alwaysConsumeSystemBars),
89           ClassParameter.from(DisplayCutout.class, displayCutout.get()),
90           ClassParameter.from(int.class, SOFT_INPUT_ADJUST_NOTHING),
91           ClassParameter.from(int.class, SYSTEM_UI_FLAG_VISIBLE),
92           ClassParameter.from(SparseIntArray.class, null));
93     } else {
94       return new WindowInsets.Builder()
95           .setAlwaysConsumeSystemBars(alwaysConsumeSystemBars)
96           .setRound(isScreenRound)
97           .setSystemWindowInsets(Insets.of(systemWindowInsets))
98           .setStableInsets(Insets.of(stableInsets))
99           .setDisplayCutout(displayCutout.get())
100           .build();
101     }
102   }
103 
104   @ForType(WindowManagerImpl.class)
105   interface ReflectorWindowManagerImpl {
106 
107     @Direct
addView(View view, ViewGroup.LayoutParams layoutParams)108     void addView(View view, ViewGroup.LayoutParams layoutParams);
109 
110     @Direct
removeView(View view)111     void removeView(View view);
112 
113     @Direct
removeViewImmediate(View view)114     void removeViewImmediate(View view);
115 
116     @Direct
getDefaultDisplay()117     Display getDefaultDisplay();
118 
119     @Accessor("mContext")
getContext()120     Context getContext();
121   }
122 
123   @Resetter
reset()124   public static void reset() {
125     views.clear();
126   }
127 }
128