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