• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.cts.mockime;
18 
19 import static java.lang.annotation.RetentionPolicy.SOURCE;
20 
21 import android.os.Bundle;
22 import android.os.PersistableBundle;
23 import android.view.inputmethod.InputMethodSubtype;
24 
25 import androidx.annotation.ColorInt;
26 import androidx.annotation.IntDef;
27 import androidx.annotation.NonNull;
28 import androidx.annotation.Nullable;
29 import androidx.window.extensions.layout.WindowLayoutInfo;
30 
31 import java.lang.annotation.Retention;
32 
33 /**
34  * An immutable data store to control the behavior of {@link MockIme}.
35  */
36 public class ImeSettings {
37 
38     @NonNull
39     private final String mClientPackageName;
40 
41     @NonNull
42     private final String mEventCallbackActionName;
43 
44     private static final String EVENT_CALLBACK_INTENT_ACTION_KEY = "eventCallbackActionName";
45     private static final String DATA_KEY = "data";
46 
47     private static final String BACKGROUND_COLOR_KEY = "BackgroundColor";
48     private static final String NAVIGATION_BAR_COLOR_KEY = "NavigationBarColor";
49     private static final String INPUT_VIEW_HEIGHT =
50             "InputViewHeightWithoutSystemWindowInset";
51     private static final String DRAWS_BEHIND_NAV_BAR = "drawsBehindNavBar";
52     private static final String WINDOW_FLAGS = "WindowFlags";
53     private static final String WINDOW_FLAGS_MASK = "WindowFlagsMask";
54     private static final String FULLSCREEN_MODE_POLICY = "FullscreenModePolicy";
55     private static final String INPUT_VIEW_SYSTEM_UI_VISIBILITY = "InputViewSystemUiVisibility";
56     private static final String WATERMARK_ENABLED = "WatermarkEnabled";
57     private static final String WATERMARK_GRAVITY = "WatermarkGravity";
58     private static final String HARD_KEYBOARD_CONFIGURATION_BEHAVIOR_ALLOWED =
59             "HardKeyboardConfigurationBehaviorAllowed";
60     private static final String INLINE_SUGGESTIONS_ENABLED = "InlineSuggestionsEnabled";
61     private static final String INLINE_SUGGESTION_VIEW_CONTENT_DESC =
62             "InlineSuggestionViewContentDesc";
63     private static final String STRICT_MODE_ENABLED = "StrictModeEnabled";
64     private static final String VERIFY_CONTEXT_APIS_IN_ON_CREATE = "VerifyContextApisInOnCreate";
65     private static final String WINDOW_LAYOUT_INFO_CALLBACK_ENABLED =
66             "WindowLayoutInfoCallbackEnabled";
67 
68     /**
69      * Simulate the manifest flag enableOnBackInvokedCallback being true for the IME.
70      */
71     private static final String ON_BACK_CALLBACK_ENABLED = "onBackCallbackEnabled";
72 
73     @NonNull
74     private final PersistableBundle mBundle;
75 
76 
77     @Retention(SOURCE)
78     @IntDef(value = {
79             FullscreenModePolicy.NO_FULLSCREEN,
80             FullscreenModePolicy.FORCE_FULLSCREEN,
81             FullscreenModePolicy.OS_DEFAULT,
82     })
83     public @interface FullscreenModePolicy {
84         /**
85          * Let {@link MockIme} always return {@code false} from
86          * {@link android.inputmethodservice.InputMethodService#onEvaluateFullscreenMode()}.
87          *
88          * <p>This is chosen to be the default behavior of {@link MockIme} to make CTS tests most
89          * deterministic.</p>
90          */
91         int NO_FULLSCREEN = 0;
92 
93         /**
94          * Let {@link MockIme} always return {@code true} from
95          * {@link android.inputmethodservice.InputMethodService#onEvaluateFullscreenMode()}.
96          *
97          * <p>This can be used to test the behaviors when a full-screen IME is running.</p>
98          */
99         int FORCE_FULLSCREEN = 1;
100 
101         /**
102          * Let {@link MockIme} always return the default behavior of
103          * {@link android.inputmethodservice.InputMethodService#onEvaluateFullscreenMode()}.
104          *
105          * <p>This can be used to test the default behavior of that public API.</p>
106          */
107         int OS_DEFAULT = 2;
108     }
109 
ImeSettings(@onNull String clientPackageName, @NonNull Bundle bundle)110     ImeSettings(@NonNull String clientPackageName, @NonNull Bundle bundle) {
111         mClientPackageName = clientPackageName;
112         mEventCallbackActionName = bundle.getString(EVENT_CALLBACK_INTENT_ACTION_KEY);
113         mBundle = bundle.getParcelable(DATA_KEY);
114     }
115 
116     @Nullable
getEventCallbackActionName()117     String getEventCallbackActionName() {
118         return mEventCallbackActionName;
119     }
120 
121     @NonNull
getClientPackageName()122     String getClientPackageName() {
123         return mClientPackageName;
124     }
125 
126     @FullscreenModePolicy
fullscreenModePolicy()127     public int fullscreenModePolicy() {
128         return mBundle.getInt(FULLSCREEN_MODE_POLICY);
129     }
130 
131     @ColorInt
getBackgroundColor(@olorInt int defaultColor)132     public int getBackgroundColor(@ColorInt int defaultColor) {
133         return mBundle.getInt(BACKGROUND_COLOR_KEY, defaultColor);
134     }
135 
hasNavigationBarColor()136     public boolean hasNavigationBarColor() {
137         return mBundle.keySet().contains(NAVIGATION_BAR_COLOR_KEY);
138     }
139 
140     @ColorInt
getNavigationBarColor()141     public int getNavigationBarColor() {
142         return mBundle.getInt(NAVIGATION_BAR_COLOR_KEY);
143     }
144 
getInputViewHeight(int defaultHeight)145     public int getInputViewHeight(int defaultHeight) {
146         return mBundle.getInt(INPUT_VIEW_HEIGHT, defaultHeight);
147     }
148 
getDrawsBehindNavBar()149     public boolean getDrawsBehindNavBar() {
150         return mBundle.getBoolean(DRAWS_BEHIND_NAV_BAR, false);
151     }
152 
getWindowFlags(int defaultFlags)153     public int getWindowFlags(int defaultFlags) {
154         return mBundle.getInt(WINDOW_FLAGS, defaultFlags);
155     }
156 
getWindowFlagsMask(int defaultFlags)157     public int getWindowFlagsMask(int defaultFlags) {
158         return mBundle.getInt(WINDOW_FLAGS_MASK, defaultFlags);
159     }
160 
getInputViewSystemUiVisibility(int defaultFlags)161     public int getInputViewSystemUiVisibility(int defaultFlags) {
162         return mBundle.getInt(INPUT_VIEW_SYSTEM_UI_VISIBILITY, defaultFlags);
163     }
164 
isWatermarkEnabled(boolean defaultValue)165     public boolean isWatermarkEnabled(boolean defaultValue) {
166         return mBundle.getBoolean(WATERMARK_ENABLED, defaultValue);
167     }
168 
getWatermarkGravity(int defaultValue)169     public int getWatermarkGravity(int defaultValue) {
170         return mBundle.getInt(WATERMARK_GRAVITY, defaultValue);
171     }
172 
getHardKeyboardConfigurationBehaviorAllowed(boolean defaultValue)173     public boolean getHardKeyboardConfigurationBehaviorAllowed(boolean defaultValue) {
174         return mBundle.getBoolean(HARD_KEYBOARD_CONFIGURATION_BEHAVIOR_ALLOWED, defaultValue);
175     }
176 
getInlineSuggestionsEnabled()177     public boolean getInlineSuggestionsEnabled() {
178         return mBundle.getBoolean(INLINE_SUGGESTIONS_ENABLED);
179     }
180 
181     @Nullable
getInlineSuggestionViewContentDesc(@ullable String defaultValue)182     public String getInlineSuggestionViewContentDesc(@Nullable String defaultValue) {
183         return mBundle.getString(INLINE_SUGGESTION_VIEW_CONTENT_DESC, defaultValue);
184     }
185 
isStrictModeEnabled()186     public boolean isStrictModeEnabled() {
187         return mBundle.getBoolean(STRICT_MODE_ENABLED, false);
188     }
189 
isVerifyContextApisInOnCreate()190     public boolean isVerifyContextApisInOnCreate() {
191         return mBundle.getBoolean(VERIFY_CONTEXT_APIS_IN_ON_CREATE, false);
192     }
193 
isWindowLayoutInfoCallbackEnabled()194     public boolean isWindowLayoutInfoCallbackEnabled() {
195         return mBundle.getBoolean(WINDOW_LAYOUT_INFO_CALLBACK_ENABLED, false);
196     }
197 
isOnBackCallbackEnabled()198     public boolean isOnBackCallbackEnabled() {
199         return mBundle.getBoolean(ON_BACK_CALLBACK_ENABLED, false);
200     }
201 
serializeToBundle(@onNull String eventCallbackActionName, @Nullable Builder builder)202     static Bundle serializeToBundle(@NonNull String eventCallbackActionName,
203             @Nullable Builder builder) {
204         final Bundle result = new Bundle();
205         result.putString(EVENT_CALLBACK_INTENT_ACTION_KEY, eventCallbackActionName);
206         result.putParcelable(DATA_KEY, builder != null ? builder.mBundle : PersistableBundle.EMPTY);
207         return result;
208     }
209 
210     /**
211      * The builder class for {@link ImeSettings}.
212      */
213     public static final class Builder {
214         private final PersistableBundle mBundle = new PersistableBundle();
215 
216         @Nullable
217         InputMethodSubtype[] mAdditionalSubtypes;
218 
219         /**
220          * Specifies additional {@link InputMethodSubtype}s to be set before launching
221          * {@link MockIme} by using
222          * {@link android.view.inputmethod.InputMethodManager#setAdditionalInputMethodSubtypes(
223          * String, InputMethodSubtype[])}.
224          *
225          * @param subtypes An array of {@link InputMethodSubtype}.
226          * @return this {@link Builder} object
227          */
setAdditionalSubtypes(InputMethodSubtype... subtypes)228         public Builder setAdditionalSubtypes(InputMethodSubtype... subtypes) {
229             mAdditionalSubtypes = subtypes;
230             return this;
231         }
232 
233         /**
234          * Controls how MockIme reacts to
235          * {@link android.inputmethodservice.InputMethodService#onEvaluateFullscreenMode()}.
236          *
237          * @param policy one of {@link FullscreenModePolicy}
238          * @see MockIme#onEvaluateFullscreenMode()
239          */
setFullscreenModePolicy(@ullscreenModePolicy int policy)240         public Builder setFullscreenModePolicy(@FullscreenModePolicy int policy) {
241             mBundle.putInt(FULLSCREEN_MODE_POLICY, policy);
242             return this;
243         }
244 
245         /**
246          * Sets the background color of the {@link MockIme}.
247          * @param color background color to be used
248          */
setBackgroundColor(@olorInt int color)249         public Builder setBackgroundColor(@ColorInt int color) {
250             mBundle.putInt(BACKGROUND_COLOR_KEY, color);
251             return this;
252         }
253 
254         /**
255          * Sets the color to be passed to {@link android.view.Window#setNavigationBarColor(int)}.
256          *
257          * @param color color to be passed to {@link android.view.Window#setNavigationBarColor(int)}
258          * @see android.view.View
259          */
setNavigationBarColor(@olorInt int color)260         public Builder setNavigationBarColor(@ColorInt int color) {
261             mBundle.putInt(NAVIGATION_BAR_COLOR_KEY, color);
262             return this;
263         }
264 
265         /**
266          * Sets the input view height measured from the bottom of the screen.
267          *
268          * @param height height of the soft input view. This includes the system window inset such
269          *               as navigation bar.
270          */
setInputViewHeight(int height)271         public Builder setInputViewHeight(int height) {
272             mBundle.putInt(INPUT_VIEW_HEIGHT, height);
273             return this;
274         }
275 
276         /**
277          * Sets whether IME draws behind navigation bar.
278          */
setDrawsBehindNavBar(boolean drawsBehindNavBar)279         public Builder setDrawsBehindNavBar(boolean drawsBehindNavBar) {
280             mBundle.putBoolean(DRAWS_BEHIND_NAV_BAR, drawsBehindNavBar);
281             return this;
282         }
283 
284         /**
285          * Sets window flags to be specified to {@link android.view.Window#setFlags(int, int)} of
286          * the main {@link MockIme} window.
287          *
288          * <p>When {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_OVERSCAN} is set,
289          * {@link MockIme} tries to render the navigation bar by itself.</p>
290          *
291          * @param flags flags to be specified
292          * @param flagsMask mask bits that specify what bits need to be cleared before setting
293          *                  {@code flags}
294          * @see android.view.WindowManager
295          */
setWindowFlags(int flags, int flagsMask)296         public Builder setWindowFlags(int flags, int flagsMask) {
297             mBundle.putInt(WINDOW_FLAGS, flags);
298             mBundle.putInt(WINDOW_FLAGS_MASK, flagsMask);
299             return this;
300         }
301 
302         /**
303          * Sets flags to be specified to {@link android.view.View#setSystemUiVisibility(int)} of
304          * the main soft input view (the returned view from {@link MockIme#onCreateInputView()}).
305          *
306          * @param visibilityFlags flags to be specified
307          * @see android.view.View
308          */
setInputViewSystemUiVisibility(int visibilityFlags)309         public Builder setInputViewSystemUiVisibility(int visibilityFlags) {
310             mBundle.putInt(INPUT_VIEW_SYSTEM_UI_VISIBILITY, visibilityFlags);
311             return this;
312         }
313 
314         /**
315          * Sets whether a unique watermark image needs to be shown on the software keyboard or not.
316          *
317          * <p>This needs to be enabled to use</p>
318          *
319          * @param enabled {@code true} when such a watermark image is requested.
320          */
setWatermarkEnabled(boolean enabled)321         public Builder setWatermarkEnabled(boolean enabled) {
322             mBundle.putBoolean(WATERMARK_ENABLED, enabled);
323             return this;
324         }
325 
326         /**
327          * Sets the {@link android.view.Gravity} flags for the watermark image.
328          *
329          * <p>{@link android.view.Gravity#CENTER} will be used if not set.</p>
330          *
331          * @param gravity {@code true} {@link android.view.Gravity} flags to be set.
332          */
setWatermarkGravity(int gravity)333         public Builder setWatermarkGravity(int gravity) {
334             mBundle.putInt(WATERMARK_GRAVITY, gravity);
335             return this;
336         }
337 
338         /**
339          * Controls whether {@link MockIme} is allowed to change the behavior based on
340          * {@link android.content.res.Configuration#keyboard} and
341          * {@link android.content.res.Configuration#hardKeyboardHidden}.
342          *
343          * <p>Methods in {@link android.inputmethodservice.InputMethodService} such as
344          * {@link android.inputmethodservice.InputMethodService#onEvaluateInputViewShown()} and
345          * {@link android.inputmethodservice.InputMethodService#onShowInputRequested(int, boolean)}
346          * change their behaviors when a hardware keyboard is attached.  This is confusing when
347          * writing tests so by default {@link MockIme} tries to cancel those behaviors.  This
348          * settings re-enables such a behavior.</p>
349          *
350          * @param allowed {@code true} when {@link MockIme} is allowed to change the behavior when
351          *                a hardware keyboard is attached
352          *
353          * @see android.inputmethodservice.InputMethodService#onEvaluateInputViewShown()
354          * @see android.inputmethodservice.InputMethodService#onShowInputRequested(int, boolean)
355          */
setHardKeyboardConfigurationBehaviorAllowed(boolean allowed)356         public Builder setHardKeyboardConfigurationBehaviorAllowed(boolean allowed) {
357             mBundle.putBoolean(HARD_KEYBOARD_CONFIGURATION_BEHAVIOR_ALLOWED, allowed);
358             return this;
359         }
360 
361         /**
362          * Controls whether inline suggestions are enabled for {@link MockIme}. If enabled, a
363          * suggestion strip will be rendered at the top of the keyboard.
364          *
365          * @param enabled {@code true} when {@link MockIme} is enabled to show inline suggestions.
366          */
setInlineSuggestionsEnabled(boolean enabled)367         public Builder setInlineSuggestionsEnabled(boolean enabled) {
368             mBundle.putBoolean(INLINE_SUGGESTIONS_ENABLED, enabled);
369             return this;
370         }
371 
372         /**
373          * Controls whether inline suggestions are enabled for {@link MockIme}. If enabled, a
374          * suggestion strip will be rendered at the top of the keyboard.
375          *
376          * @param contentDesc content description to be set to the inline suggestion View.
377          */
setInlineSuggestionViewContentDesc(@onNull String contentDesc)378         public Builder setInlineSuggestionViewContentDesc(@NonNull String contentDesc) {
379             mBundle.putString(INLINE_SUGGESTION_VIEW_CONTENT_DESC, contentDesc);
380             return this;
381         }
382 
383         /** Sets whether to enable {@link android.os.StrictMode} or not. */
setStrictModeEnabled(boolean enabled)384         public Builder setStrictModeEnabled(boolean enabled) {
385             mBundle.putBoolean(STRICT_MODE_ENABLED, enabled);
386             return this;
387         }
388 
389         /**
390          * Sets whether to verify below {@link android.content.Context} APIs or not:
391          * <ul>
392          *     <li>{@link android.inputmethodservice.InputMethodService#getDisplay}</li>
393          *     <li>{@link android.inputmethodservice.InputMethodService#isUiContext}</li>
394          * </ul>
395          */
setVerifyUiContextApisInOnCreate(boolean enabled)396         public Builder setVerifyUiContextApisInOnCreate(boolean enabled) {
397             mBundle.putBoolean(VERIFY_CONTEXT_APIS_IN_ON_CREATE, enabled);
398             return this;
399         }
400 
401         /**
402          * Sets whether to enable {@link WindowLayoutInfo} callbacks for {@link MockIme}.
403          */
setWindowLayoutInfoCallbackEnabled(boolean enabled)404         public Builder setWindowLayoutInfoCallbackEnabled(boolean enabled) {
405             mBundle.putBoolean(WINDOW_LAYOUT_INFO_CALLBACK_ENABLED, enabled);
406             return this;
407         }
408 
409         /**
410          * Sets whether the IME's
411          * {@link android.content.pm.ApplicationInfo#isOnBackInvokedCallbackEnabled()}
412          * should be set to {@code true}.
413          */
setOnBackCallbackEnabled(boolean enabled)414         public Builder setOnBackCallbackEnabled(boolean enabled) {
415             mBundle.putBoolean(ON_BACK_CALLBACK_ENABLED, enabled);
416             return this;
417         }
418     }
419 }
420