1 package org.robolectric.shadows; 2 3 import static android.os.Build.VERSION_CODES.JELLY_BEAN; 4 import static org.robolectric.shadow.api.Shadow.directlyOn; 5 6 import android.content.res.Configuration; 7 import android.os.Build.VERSION_CODES; 8 import android.util.DisplayMetrics; 9 import android.view.Display; 10 import android.view.View; 11 import android.view.ViewGroup; 12 import android.view.WindowManagerImpl; 13 import com.google.common.collect.ArrayListMultimap; 14 import com.google.common.collect.ImmutableList; 15 import com.google.common.collect.Multimap; 16 import java.util.HashMap; 17 import java.util.List; 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.shadow.api.Shadow; 24 import org.robolectric.util.ReflectionHelpers; 25 import org.robolectric.util.ReflectionHelpers.ClassParameter; 26 27 @Implements(value = WindowManagerImpl.class, isInAndroidSdk = false) 28 public class ShadowWindowManagerImpl extends ShadowWindowManager { 29 30 private static Display defaultDisplayJB; 31 32 /** internal only */ configureDefaultDisplayForJBOnly( Configuration configuration, DisplayMetrics displayMetrics)33 public static void configureDefaultDisplayForJBOnly( 34 Configuration configuration, DisplayMetrics displayMetrics) { 35 Class<?> arg2Type = ReflectionHelpers.loadClass(ShadowWindowManagerImpl.class.getClassLoader(), 36 "android.view.CompatibilityInfoHolder"); 37 38 defaultDisplayJB = ReflectionHelpers.callConstructor(Display.class, 39 ClassParameter.from(int.class, 0), 40 ClassParameter.from(arg2Type, null)); 41 ShadowDisplay shadowDisplay = Shadow.extract(defaultDisplayJB); 42 shadowDisplay.configureForJBOnly(configuration, displayMetrics); 43 } 44 45 @RealObject 46 WindowManagerImpl realObject; 47 private static final Multimap<Integer, View> views = ArrayListMultimap.create(); 48 49 @Implementation addView(View view, android.view.ViewGroup.LayoutParams layoutParams)50 public void addView(View view, android.view.ViewGroup.LayoutParams layoutParams) { 51 views.put(realObject.getDefaultDisplay().getDisplayId(), view); 52 // views.add(view); 53 directlyOn( 54 realObject, 55 WindowManagerImpl.class, 56 "addView", 57 ClassParameter.from(View.class, view), 58 ClassParameter.from(ViewGroup.LayoutParams.class, layoutParams)); 59 } 60 61 @Implementation removeView(View view)62 public void removeView(View view) { 63 views.remove(realObject.getDefaultDisplay().getDisplayId(), view); 64 directlyOn(realObject, WindowManagerImpl.class, "removeView", 65 ClassParameter.from(View.class, view)); 66 } 67 getViews()68 public List<View> getViews() { 69 return ImmutableList.copyOf(views.get(realObject.getDefaultDisplay().getDisplayId())); 70 } 71 72 @Implementation(maxSdk = JELLY_BEAN) getDefaultDisplay()73 public Display getDefaultDisplay() { 74 if (RuntimeEnvironment.getApiLevel() > JELLY_BEAN) { 75 return directlyOn(realObject, WindowManagerImpl.class).getDefaultDisplay(); 76 } else { 77 return defaultDisplayJB; 78 } 79 } 80 81 @Implements(className = "android.view.WindowManagerImpl$CompatModeWrapper", maxSdk = JELLY_BEAN) 82 public static class ShadowCompatModeWrapper { 83 @Implementation(maxSdk = JELLY_BEAN) getDefaultDisplay()84 protected Display getDefaultDisplay() { 85 return defaultDisplayJB; 86 } 87 88 } 89 90 @Resetter reset()91 public static void reset() { 92 defaultDisplayJB = null; 93 views.clear(); 94 if (RuntimeEnvironment.getApiLevel() <= VERSION_CODES.JELLY_BEAN) { 95 ReflectionHelpers.setStaticField( 96 WindowManagerImpl.class, 97 "sWindowManager", 98 ReflectionHelpers.newInstance(WindowManagerImpl.class)); 99 HashMap windowManagers = 100 ReflectionHelpers.getStaticField(WindowManagerImpl.class, "sCompatWindowManagers"); 101 windowManagers.clear(); 102 } 103 } 104 } 105