• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric.shadows;
2 
3 import static android.os.Build.VERSION_CODES.M;
4 import static android.os.Build.VERSION_CODES.N;
5 import static android.os.Build.VERSION_CODES.Q;
6 import static android.os.Build.VERSION_CODES.R;
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.drawable.Drawable;
12 import android.os.Handler;
13 import android.view.FrameMetrics;
14 import android.view.Window;
15 import android.view.Window.OnFrameMetricsAvailableListener;
16 import java.util.HashSet;
17 import java.util.Set;
18 import org.robolectric.annotation.HiddenApi;
19 import org.robolectric.annotation.Implementation;
20 import org.robolectric.annotation.Implements;
21 import org.robolectric.annotation.RealObject;
22 import org.robolectric.util.ReflectionHelpers;
23 import org.robolectric.util.ReflectionHelpers.ClassParameter;
24 import org.robolectric.util.reflector.Direct;
25 import org.robolectric.util.reflector.ForType;
26 
27 @SuppressWarnings({"UnusedDeclaration"})
28 @Implements(Window.class)
29 public class ShadowWindow {
30   @RealObject private Window realWindow;
31 
32   protected CharSequence title = "";
33   protected Drawable backgroundDrawable;
34   private int flags;
35   private int privateFlags;
36   private int softInputMode;
37   private final Set<OnFrameMetricsAvailableListener> onFrameMetricsAvailableListeners =
38       new HashSet<>();
39 
create(Context context)40   public static Window create(Context context) throws ClassNotFoundException {
41     String className = getApiLevel() >= M
42         ? "com.android.internal.policy.PhoneWindow"
43         : "com.android.internal.policy.impl.PhoneWindow";
44     Class<? extends Window> phoneWindowClass =
45         (Class<? extends Window>) Window.class.getClassLoader().loadClass(className);
46     return ReflectionHelpers.callConstructor(phoneWindowClass, ClassParameter.from(Context.class, context));
47   }
48 
49   @Implementation
setFlags(int flags, int mask)50   protected void setFlags(int flags, int mask) {
51     this.flags = (this.flags & ~mask) | (flags & mask);
52     reflector(WindowReflector.class, realWindow).setFlags(flags, mask);
53   }
54 
55   @Implementation(minSdk = Q)
56   @HiddenApi
addSystemFlags(int flags)57   protected void addSystemFlags(int flags) {
58     this.privateFlags |= flags;
59     reflector(WindowReflector.class, realWindow).addSystemFlags(flags);
60   }
61 
62   @Implementation(maxSdk = R)
63   @HiddenApi
addPrivateFlags(int flags)64   protected void addPrivateFlags(int flags) {
65     this.privateFlags |= flags;
66     reflector(WindowReflector.class, realWindow).addPrivateFlags(flags);
67   }
68 
69   @Implementation
setSoftInputMode(int softInputMode)70   protected void setSoftInputMode(int softInputMode) {
71     this.softInputMode = softInputMode;
72     reflector(WindowReflector.class, realWindow).setSoftInputMode(softInputMode);
73   }
74 
getFlag(int flag)75   public boolean getFlag(int flag) {
76     return (flags & flag) == flag;
77   }
78 
79   /**
80    * Return the value from a private flag (a.k.a system flag).
81    *
82    * <p>Private flags can be set via either {@link #addPrivateFlags} (SDK 19-30) or {@link
83    * #addSystemFlags} (SDK 29+) methods.
84    */
getPrivateFlag(int flag)85   public boolean getPrivateFlag(int flag) {
86     return (privateFlags & flag) == flag;
87   }
88 
getTitle()89   public CharSequence getTitle() {
90     return title;
91   }
92 
getSoftInputMode()93   public int getSoftInputMode() {
94     return softInputMode;
95   }
96 
getBackgroundDrawable()97   public Drawable getBackgroundDrawable() {
98     return backgroundDrawable;
99   }
100 
101   @Implementation(minSdk = N)
addOnFrameMetricsAvailableListener( Window.OnFrameMetricsAvailableListener listener, Handler handler)102   protected void addOnFrameMetricsAvailableListener(
103       Window.OnFrameMetricsAvailableListener listener, Handler handler) {
104     onFrameMetricsAvailableListeners.add(listener);
105   }
106 
107   @Implementation(minSdk = N)
removeOnFrameMetricsAvailableListener( Window.OnFrameMetricsAvailableListener listener)108   protected void removeOnFrameMetricsAvailableListener(
109       Window.OnFrameMetricsAvailableListener listener) {
110     if (!onFrameMetricsAvailableListeners.remove(listener)) {
111       // Matches current behavior of android.
112       throw new IllegalArgumentException(
113           "attempt to remove OnFrameMetricsAvailableListener that was never added");
114     }
115   }
116 
117   /**
118    * Calls {@link Window.OnFrameMetrisAvailableListener#onFrameMetricsAvailable()} on each current
119    * listener with 0 as the dropCountSinceLastInvocation.
120    */
reportOnFrameMetricsAvailable(FrameMetrics frameMetrics)121   public void reportOnFrameMetricsAvailable(FrameMetrics frameMetrics) {
122     reportOnFrameMetricsAvailable(frameMetrics, /* dropCountSinceLastInvocation= */ 0);
123   }
124 
125   /**
126    * Calls {@link Window.OnFrameMetrisAvailableListener#onFrameMetricsAvailable()} on each current
127    * listener.
128    *
129    * @param frameMetrics the {@link FrameMetrics} instance passed to the listeners.
130    * @param dropCountSinceLastInvocation the dropCountSinceLastInvocation passed to the listeners.
131    */
reportOnFrameMetricsAvailable( FrameMetrics frameMetrics, int dropCountSinceLastInvocation)132   public void reportOnFrameMetricsAvailable(
133       FrameMetrics frameMetrics, int dropCountSinceLastInvocation) {
134     for (OnFrameMetricsAvailableListener listener : onFrameMetricsAvailableListeners) {
135       listener.onFrameMetricsAvailable(realWindow, frameMetrics, dropCountSinceLastInvocation);
136     }
137   }
138 
139   @ForType(Window.class)
140   interface WindowReflector {
141 
142     @Direct
setFlags(int flags, int mask)143     void setFlags(int flags, int mask);
144 
145     @Direct
addSystemFlags(int flags)146     void addSystemFlags(int flags);
147 
148     @Direct
addPrivateFlags(int flags)149     void addPrivateFlags(int flags);
150 
151     @Direct
setSoftInputMode(int softInputMode)152     void setSoftInputMode(int softInputMode);
153   }
154 }
155