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 android.os.Bundle;
20 import android.os.PersistableBundle;
21 
22 import androidx.annotation.ColorInt;
23 import androidx.annotation.NonNull;
24 import androidx.annotation.Nullable;
25 
26 /**
27  * An immutable data store to control the behavior of {@link MockIme}.
28  */
29 public class ImeSettings {
30 
31     @NonNull
32     private final String mClientPackageName;
33 
34     @NonNull
35     private final String mEventCallbackActionName;
36 
37     private static final String EVENT_CALLBACK_INTENT_ACTION_KEY = "eventCallbackActionName";
38     private static final String DATA_KEY = "data";
39 
40     private static final String BACKGROUND_COLOR_KEY = "BackgroundColor";
41     private static final String NAVIGATION_BAR_COLOR_KEY = "NavigationBarColor";
42     private static final String INPUT_VIEW_HEIGHT =
43             "InputViewHeightWithoutSystemWindowInset";
44     private static final String DRAWS_BEHIND_NAV_BAR = "drawsBehindNavBar";
45     private static final String WINDOW_FLAGS = "WindowFlags";
46     private static final String WINDOW_FLAGS_MASK = "WindowFlagsMask";
47     private static final String FULLSCREEN_MODE_ALLOWED = "FullscreenModeAllowed";
48     private static final String INPUT_VIEW_SYSTEM_UI_VISIBILITY = "InputViewSystemUiVisibility";
49     private static final String WATERMARK_ENABLED = "WatermarkEnabled";
50     private static final String HARD_KEYBOARD_CONFIGURATION_BEHAVIOR_ALLOWED =
51             "HardKeyboardConfigurationBehaviorAllowed";
52     private static final String INLINE_SUGGESTIONS_ENABLED = "InlineSuggestionsEnabled";
53     private static final String INLINE_SUGGESTION_VIEW_CONTENT_DESC =
54             "InlineSuggestionViewContentDesc";
55     private static final String STRICT_MODE_ENABLED = "StrictModeEnabled";
56     private static final String VERIFY_GET_DISPLAY_ON_CREATE = "VerifyGetDisplayOnCreate";
57 
58     @NonNull
59     private final PersistableBundle mBundle;
60 
ImeSettings(@onNull String clientPackageName, @NonNull Bundle bundle)61     ImeSettings(@NonNull String clientPackageName, @NonNull Bundle bundle) {
62         mClientPackageName = clientPackageName;
63         mEventCallbackActionName = bundle.getString(EVENT_CALLBACK_INTENT_ACTION_KEY);
64         mBundle = bundle.getParcelable(DATA_KEY);
65     }
66 
67     @Nullable
getEventCallbackActionName()68     String getEventCallbackActionName() {
69         return mEventCallbackActionName;
70     }
71 
72     @NonNull
getClientPackageName()73     String getClientPackageName() {
74         return mClientPackageName;
75     }
76 
fullscreenModeAllowed(boolean defaultValue)77     public boolean fullscreenModeAllowed(boolean defaultValue) {
78         return mBundle.getBoolean(FULLSCREEN_MODE_ALLOWED, defaultValue);
79     }
80 
81     @ColorInt
getBackgroundColor(@olorInt int defaultColor)82     public int getBackgroundColor(@ColorInt int defaultColor) {
83         return mBundle.getInt(BACKGROUND_COLOR_KEY, defaultColor);
84     }
85 
hasNavigationBarColor()86     public boolean hasNavigationBarColor() {
87         return mBundle.keySet().contains(NAVIGATION_BAR_COLOR_KEY);
88     }
89 
90     @ColorInt
getNavigationBarColor()91     public int getNavigationBarColor() {
92         return mBundle.getInt(NAVIGATION_BAR_COLOR_KEY);
93     }
94 
getInputViewHeight(int defaultHeight)95     public int getInputViewHeight(int defaultHeight) {
96         return mBundle.getInt(INPUT_VIEW_HEIGHT, defaultHeight);
97     }
98 
getDrawsBehindNavBar()99     public boolean getDrawsBehindNavBar() {
100         return mBundle.getBoolean(DRAWS_BEHIND_NAV_BAR, false);
101     }
102 
getWindowFlags(int defaultFlags)103     public int getWindowFlags(int defaultFlags) {
104         return mBundle.getInt(WINDOW_FLAGS, defaultFlags);
105     }
106 
getWindowFlagsMask(int defaultFlags)107     public int getWindowFlagsMask(int defaultFlags) {
108         return mBundle.getInt(WINDOW_FLAGS_MASK, defaultFlags);
109     }
110 
getInputViewSystemUiVisibility(int defaultFlags)111     public int getInputViewSystemUiVisibility(int defaultFlags) {
112         return mBundle.getInt(INPUT_VIEW_SYSTEM_UI_VISIBILITY, defaultFlags);
113     }
114 
isWatermarkEnabled(boolean defaultValue)115     public boolean isWatermarkEnabled(boolean defaultValue) {
116         return mBundle.getBoolean(WATERMARK_ENABLED, defaultValue);
117     }
118 
getHardKeyboardConfigurationBehaviorAllowed(boolean defaultValue)119     public boolean getHardKeyboardConfigurationBehaviorAllowed(boolean defaultValue) {
120         return mBundle.getBoolean(HARD_KEYBOARD_CONFIGURATION_BEHAVIOR_ALLOWED, defaultValue);
121     }
122 
getInlineSuggestionsEnabled()123     public boolean getInlineSuggestionsEnabled() {
124         return mBundle.getBoolean(INLINE_SUGGESTIONS_ENABLED);
125     }
126 
127     @Nullable
getInlineSuggestionViewContentDesc(@ullable String defaultValue)128     public String getInlineSuggestionViewContentDesc(@Nullable String defaultValue) {
129         return mBundle.getString(INLINE_SUGGESTION_VIEW_CONTENT_DESC, defaultValue);
130     }
131 
isStrictModeEnabled()132     public boolean isStrictModeEnabled() {
133         return mBundle.getBoolean(STRICT_MODE_ENABLED, false);
134     }
135 
isVerifyGetDisplayOnCreate()136     public boolean isVerifyGetDisplayOnCreate() {
137         return mBundle.getBoolean(VERIFY_GET_DISPLAY_ON_CREATE, false);
138     }
139 
serializeToBundle(@onNull String eventCallbackActionName, @Nullable Builder builder)140     static Bundle serializeToBundle(@NonNull String eventCallbackActionName,
141             @Nullable Builder builder) {
142         final Bundle result = new Bundle();
143         result.putString(EVENT_CALLBACK_INTENT_ACTION_KEY, eventCallbackActionName);
144         result.putParcelable(DATA_KEY, builder != null ? builder.mBundle : PersistableBundle.EMPTY);
145         return result;
146     }
147 
148     /**
149      * The builder class for {@link ImeSettings}.
150      */
151     public static final class Builder {
152         private final PersistableBundle mBundle = new PersistableBundle();
153 
154         /**
155          * Controls whether fullscreen mode is allowed or not.
156          *
157          * <p>By default, fullscreen mode is not allowed in {@link MockIme}.</p>
158          *
159          * @param allowed {@code true} if fullscreen mode is allowed
160          * @see MockIme#onEvaluateFullscreenMode()
161          */
setFullscreenModeAllowed(boolean allowed)162         public Builder setFullscreenModeAllowed(boolean allowed) {
163             mBundle.putBoolean(FULLSCREEN_MODE_ALLOWED, allowed);
164             return this;
165         }
166 
167         /**
168          * Sets the background color of the {@link MockIme}.
169          * @param color background color to be used
170          */
setBackgroundColor(@olorInt int color)171         public Builder setBackgroundColor(@ColorInt int color) {
172             mBundle.putInt(BACKGROUND_COLOR_KEY, color);
173             return this;
174         }
175 
176         /**
177          * Sets the color to be passed to {@link android.view.Window#setNavigationBarColor(int)}.
178          *
179          * @param color color to be passed to {@link android.view.Window#setNavigationBarColor(int)}
180          * @see android.view.View
181          */
setNavigationBarColor(@olorInt int color)182         public Builder setNavigationBarColor(@ColorInt int color) {
183             mBundle.putInt(NAVIGATION_BAR_COLOR_KEY, color);
184             return this;
185         }
186 
187         /**
188          * Sets the input view height measured from the bottom of the screen.
189          *
190          * @param height height of the soft input view. This includes the system window inset such
191          *               as navigation bar.
192          */
setInputViewHeight(int height)193         public Builder setInputViewHeight(int height) {
194             mBundle.putInt(INPUT_VIEW_HEIGHT, height);
195             return this;
196         }
197 
198         /**
199          * Sets whether IME draws behind navigation bar.
200          */
setDrawsBehindNavBar(boolean drawsBehindNavBar)201         public Builder setDrawsBehindNavBar(boolean drawsBehindNavBar) {
202             mBundle.putBoolean(DRAWS_BEHIND_NAV_BAR, drawsBehindNavBar);
203             return this;
204         }
205 
206         /**
207          * Sets window flags to be specified to {@link android.view.Window#setFlags(int, int)} of
208          * the main {@link MockIme} window.
209          *
210          * <p>When {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_OVERSCAN} is set,
211          * {@link MockIme} tries to render the navigation bar by itself.</p>
212          *
213          * @param flags flags to be specified
214          * @param flagsMask mask bits that specify what bits need to be cleared before setting
215          *                  {@code flags}
216          * @see android.view.WindowManager
217          */
setWindowFlags(int flags, int flagsMask)218         public Builder setWindowFlags(int flags, int flagsMask) {
219             mBundle.putInt(WINDOW_FLAGS, flags);
220             mBundle.putInt(WINDOW_FLAGS_MASK, flagsMask);
221             return this;
222         }
223 
224         /**
225          * Sets flags to be specified to {@link android.view.View#setSystemUiVisibility(int)} of
226          * the main soft input view (the returned view from {@link MockIme#onCreateInputView()}).
227          *
228          * @param visibilityFlags flags to be specified
229          * @see android.view.View
230          */
setInputViewSystemUiVisibility(int visibilityFlags)231         public Builder setInputViewSystemUiVisibility(int visibilityFlags) {
232             mBundle.putInt(INPUT_VIEW_SYSTEM_UI_VISIBILITY, visibilityFlags);
233             return this;
234         }
235 
236         /**
237          * Sets whether a unique watermark image needs to be shown on the software keyboard or not.
238          *
239          * <p>This needs to be enabled to use</p>
240          *
241          * @param enabled {@code true} when such a watermark image is requested.
242          */
setWatermarkEnabled(boolean enabled)243         public Builder setWatermarkEnabled(boolean enabled) {
244             mBundle.putBoolean(WATERMARK_ENABLED, enabled);
245             return this;
246         }
247 
248         /**
249          * Controls whether {@link MockIme} is allowed to change the behavior based on
250          * {@link android.content.res.Configuration#keyboard} and
251          * {@link android.content.res.Configuration#hardKeyboardHidden}.
252          *
253          * <p>Methods in {@link android.inputmethodservice.InputMethodService} such as
254          * {@link android.inputmethodservice.InputMethodService#onEvaluateInputViewShown()} and
255          * {@link android.inputmethodservice.InputMethodService#onShowInputRequested(int, boolean)}
256          * change their behaviors when a hardware keyboard is attached.  This is confusing when
257          * writing tests so by default {@link MockIme} tries to cancel those behaviors.  This
258          * settings re-enables such a behavior.</p>
259          *
260          * @param allowed {@code true} when {@link MockIme} is allowed to change the behavior when
261          *                a hardware keyboard is attached
262          *
263          * @see android.inputmethodservice.InputMethodService#onEvaluateInputViewShown()
264          * @see android.inputmethodservice.InputMethodService#onShowInputRequested(int, boolean)
265          */
setHardKeyboardConfigurationBehaviorAllowed(boolean allowed)266         public Builder setHardKeyboardConfigurationBehaviorAllowed(boolean allowed) {
267             mBundle.putBoolean(HARD_KEYBOARD_CONFIGURATION_BEHAVIOR_ALLOWED, allowed);
268             return this;
269         }
270 
271         /**
272          * Controls whether inline suggestions are enabled for {@link MockIme}. If enabled, a
273          * suggestion strip will be rendered at the top of the keyboard.
274          *
275          * @param enabled {@code true} when {@link MockIme} is enabled to show inline suggestions.
276          */
setInlineSuggestionsEnabled(boolean enabled)277         public Builder setInlineSuggestionsEnabled(boolean enabled) {
278             mBundle.putBoolean(INLINE_SUGGESTIONS_ENABLED, enabled);
279             return this;
280         }
281 
282         /**
283          * Controls whether inline suggestions are enabled for {@link MockIme}. If enabled, a
284          * suggestion strip will be rendered at the top of the keyboard.
285          *
286          * @param contentDesc content description to be set to the inline suggestion View.
287          */
setInlineSuggestionViewContentDesc(@onNull String contentDesc)288         public Builder setInlineSuggestionViewContentDesc(@NonNull String contentDesc) {
289             mBundle.putString(INLINE_SUGGESTION_VIEW_CONTENT_DESC, contentDesc);
290             return this;
291         }
292 
293         /** Sets whether to enable {@link android.os.StrictMode} or not. */
setStrictModeEnabled(boolean enabled)294         public Builder setStrictModeEnabled(boolean enabled) {
295             mBundle.putBoolean(STRICT_MODE_ENABLED, enabled);
296             return this;
297         }
298 
299         /**
300          * Sets whether to verify {@link android.inputmethodservice.InputMethodService#getDisplay()}
301          * or not.
302          */
setVerifyGetDisplayOnCreate(boolean enabled)303         public Builder setVerifyGetDisplayOnCreate(boolean enabled) {
304             mBundle.putBoolean(VERIFY_GET_DISPLAY_ON_CREATE, enabled);
305             return this;
306         }
307     }
308 }
309