blob: 905a94f5726230a8d9d4c7fe2ff064c2d9984d9b [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 * use this file except in compliance with the License. You may obtain a copy of
5 * the License at
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007 * http://www.apache.org/licenses/LICENSE-2.0
Doug Zongkerab5c49c2009-12-04 10:31:43 -08008 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 * License for the specific language governing permissions and limitations under
13 * the License.
14 */
15
Yohei Yukawa603f4d02018-09-11 15:04:58 -070016package com.android.server.inputmethod;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080017
lumarkef1965b2018-09-12 17:42:53 +080018import static android.view.Display.DEFAULT_DISPLAY;
lumark90120a82018-08-15 00:33:03 +080019import static android.view.Display.INVALID_DISPLAY;
Yohei Yukawa0569a182018-08-28 16:09:28 -070020
Yohei Yukawafa0e47e2016-04-05 09:55:56 -070021import static java.lang.annotation.RetentionPolicy.SOURCE;
22
Yohei Yukawa926488d2017-12-11 17:24:55 -080023import android.Manifest;
Phil Weaver03a65b02018-07-19 16:07:57 -070024import android.accessibilityservice.AccessibilityService;
Tarandeep Singh75a92392018-01-12 14:58:59 -080025import android.annotation.AnyThread;
Yohei Yukawad6475a62017-04-17 10:35:27 -070026import android.annotation.BinderThread;
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +090027import android.annotation.ColorInt;
Yohei Yukawa41b094f2018-09-09 23:58:45 -070028import android.annotation.DrawableRes;
Yohei Yukawafa0e47e2016-04-05 09:55:56 -070029import android.annotation.IntDef;
Yohei Yukawa930328c2017-10-18 20:19:53 -070030import android.annotation.MainThread;
Yohei Yukawa6ab1a822015-08-25 14:01:28 -070031import android.annotation.NonNull;
Yohei Yukawae13a20fa2015-09-30 19:11:32 -070032import android.annotation.Nullable;
Yohei Yukawa926488d2017-12-11 17:24:55 -080033import android.annotation.RequiresPermission;
Yohei Yukawa7b18aec2016-03-07 13:04:32 -080034import android.annotation.UserIdInt;
Sudheer Shankadc589ac2016-11-10 15:30:17 -080035import android.app.ActivityManager;
Sudheer Shankafc46e9b2016-10-21 17:55:27 -070036import android.app.ActivityManagerInternal;
Andrew Sapperstein8a3b4cb2017-04-28 14:35:31 -070037import android.app.ActivityThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.app.AlertDialog;
Yohei Yukawa6ab1a822015-08-25 14:01:28 -070039import android.app.AppGlobals;
Yohei Yukawae63b5fa2014-09-19 13:14:55 +090040import android.app.AppOpsManager;
satokf90a33e2011-07-19 11:55:52 +090041import android.app.KeyguardManager;
satok7cfc0ed2011-06-20 21:29:36 +090042import android.app.Notification;
43import android.app.NotificationManager;
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070044import android.app.PendingIntent;
satok5b927c432012-05-01 20:09:34 +090045import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.content.ComponentName;
Yohei Yukawa3933a6e2016-11-10 00:47:48 -080047import android.content.ContentProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.content.ContentResolver;
49import android.content.Context;
50import android.content.DialogInterface;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.content.DialogInterface.OnCancelListener;
Tadashi G. Takaokad130b802014-08-01 14:05:47 +090052import android.content.DialogInterface.OnClickListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.content.Intent;
satoke7c6998e2011-06-03 17:57:59 +090054import android.content.IntentFilter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.content.ServiceConnection;
Brandon Ballinger6da35a02009-10-21 00:38:13 -070056import android.content.pm.ApplicationInfo;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +090057import android.content.pm.IPackageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.content.pm.PackageManager;
59import android.content.pm.ResolveInfo;
60import android.content.pm.ServiceInfo;
Amith Yamasanie861ec12010-03-24 21:39:27 -070061import android.content.res.Configuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.content.res.Resources;
63import android.content.res.TypedArray;
64import android.database.ContentObserver;
Yohei Yukawab4f328a2019-05-02 08:41:27 -070065import android.graphics.Matrix;
Alan Viverette505e3ab2014-11-24 15:22:11 -080066import android.graphics.drawable.Drawable;
Yohei Yukawab4f328a2019-05-02 08:41:27 -070067import android.hardware.display.DisplayManagerInternal;
Joe Onorato857fd9b2011-01-27 15:08:35 -080068import android.inputmethodservice.InputMethodService;
Michael Wright7b5a96b2014-08-09 19:28:42 -070069import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070import android.os.Binder;
Chris Wren1ce4b6d2015-06-11 10:19:43 -040071import android.os.Bundle;
Seigo Nonakae27dc2b2015-08-14 18:21:27 -070072import android.os.Debug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.os.Handler;
74import android.os.IBinder;
75import android.os.IInterface;
Yohei Yukawa23cbe852016-05-17 16:42:58 -070076import android.os.LocaleList;
Yohei Yukawa0569a182018-08-28 16:09:28 -070077import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078import android.os.Parcel;
Yohei Yukawa6ab1a822015-08-25 14:01:28 -070079import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080import android.os.RemoteException;
The Android Open Source Project4df24232009-03-05 14:34:35 -080081import android.os.ResultReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082import android.os.ServiceManager;
Yohei Yukawa926488d2017-12-11 17:24:55 -080083import android.os.ShellCallback;
84import android.os.ShellCommand;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.os.SystemClock;
Tarandeep Singh75a92392018-01-12 14:58:59 -080086import android.os.SystemProperties;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +090087import android.os.UserHandle;
Amith Yamasani734983f2014-03-04 16:48:05 -080088import android.os.UserManager;
Yohei Yukawa42081402019-01-15 09:57:50 -080089import android.os.UserManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090import android.provider.Settings;
91import android.text.TextUtils;
satokf9f01002011-05-19 21:31:50 +090092import android.text.style.SuggestionSpan;
Yohei Yukawaac9311e2018-11-20 19:25:23 -080093import android.util.ArrayMap;
Christopher Tate7b9a28c2015-03-18 13:06:16 -070094import android.util.ArraySet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095import android.util.EventLog;
satokf9f01002011-05-19 21:31:50 +090096import android.util.LruCache;
satokab751aa2010-09-14 19:17:36 +090097import android.util.Pair;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098import android.util.PrintWriterPrinter;
99import android.util.Printer;
satoke7c6998e2011-06-03 17:57:59 +0900100import android.util.Slog;
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700101import android.util.SparseArray;
Tadashi G. Takaokad130b802014-08-01 14:05:47 +0900102import android.view.ContextThemeWrapper;
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700103import android.view.DisplayInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104import android.view.IWindowManager;
Jeff Brownc28867a2013-03-26 15:42:39 -0700105import android.view.InputChannel;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900106import android.view.LayoutInflater;
107import android.view.View;
108import android.view.ViewGroup;
Wale Ogunwale3a931692016-11-02 16:49:48 -0700109import android.view.Window;
Yohei Yukawa6e875592019-01-28 00:49:30 -0800110import android.view.WindowManager.LayoutParams;
Yohei Yukawab0c26452018-10-21 10:42:52 -0700111import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
Adam Hebc67f2e2019-11-13 14:34:56 -0800112import android.view.autofill.AutofillId;
satokab751aa2010-09-14 19:17:36 +0900113import android.view.inputmethod.EditorInfo;
Feng Cao16b2de52020-01-09 17:27:27 -0800114import android.view.inputmethod.InlineSuggestionsRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115import android.view.inputmethod.InputBinding;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800116import android.view.inputmethod.InputConnection;
Yohei Yukawa19a80a12016-03-14 22:57:37 -0700117import android.view.inputmethod.InputConnectionInspector;
Yohei Yukawa432cf602018-10-21 10:41:37 -0700118import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119import android.view.inputmethod.InputMethod;
120import android.view.inputmethod.InputMethodInfo;
121import android.view.inputmethod.InputMethodManager;
satokab751aa2010-09-14 19:17:36 +0900122import android.view.inputmethod.InputMethodSubtype;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900123import android.widget.ArrayAdapter;
satok01038492012-04-09 21:08:27 +0900124import android.widget.CompoundButton;
125import android.widget.CompoundButton.OnCheckedChangeListener;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900126import android.widget.RadioButton;
satok01038492012-04-09 21:08:27 +0900127import android.widget.Switch;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900128import android.widget.TextView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129
Yohei Yukawa0569a182018-08-28 16:09:28 -0700130import com.android.internal.annotations.GuardedBy;
131import com.android.internal.content.PackageMonitor;
132import com.android.internal.inputmethod.IInputContentUriToken;
Yohei Yukawac54c1172018-09-06 11:39:50 -0700133import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
Yohei Yukawaa468d702018-10-21 11:42:34 -0700134import com.android.internal.inputmethod.InputMethodDebug;
Yohei Yukawa35fa6d52018-10-31 11:33:32 -0700135import com.android.internal.inputmethod.StartInputFlags;
Yohei Yukawac6632df2018-10-21 11:47:16 -0700136import com.android.internal.inputmethod.StartInputReason;
Yohei Yukawa499e3f72018-10-21 20:15:11 -0700137import com.android.internal.inputmethod.UnbindReason;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700138import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
139import com.android.internal.notification.SystemNotificationChannels;
140import com.android.internal.os.HandlerCaller;
141import com.android.internal.os.SomeArgs;
142import com.android.internal.os.TransferPipe;
143import com.android.internal.util.DumpUtils;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700144import com.android.internal.util.IndentingPrintWriter;
Adam Hebc67f2e2019-11-13 14:34:56 -0800145import com.android.internal.view.IInlineSuggestionsRequestCallback;
Feng Cao16b2de52020-01-09 17:27:27 -0800146import com.android.internal.view.IInlineSuggestionsResponseCallback;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700147import com.android.internal.view.IInputContext;
148import com.android.internal.view.IInputMethod;
149import com.android.internal.view.IInputMethodClient;
150import com.android.internal.view.IInputMethodManager;
151import com.android.internal.view.IInputMethodSession;
152import com.android.internal.view.IInputSessionCallback;
153import com.android.internal.view.InputBindResult;
Yohei Yukawa603f4d02018-09-11 15:04:58 -0700154import com.android.server.EventLogTags;
155import com.android.server.LocalServices;
156import com.android.server.SystemService;
Yohei Yukawae6b6e0e2018-09-12 16:42:48 -0700157import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
158import com.android.server.inputmethod.InputMethodUtils.InputMethodSettings;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700159import com.android.server.statusbar.StatusBarManagerService;
Adrian Roose99bc052017-11-20 17:55:31 +0100160import com.android.server.wm.WindowManagerInternal;
161
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162import java.io.FileDescriptor;
163import java.io.IOException;
164import java.io.PrintWriter;
Yohei Yukawafa0e47e2016-04-05 09:55:56 -0700165import java.lang.annotation.Retention;
Yohei Yukawa25e08132016-06-22 16:31:41 -0700166import java.security.InvalidParameterException;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800167import java.text.SimpleDateFormat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168import java.util.ArrayList;
Yohei Yukawab8d240f2018-12-26 10:03:11 -0800169import java.util.Arrays;
satok688bd472012-02-09 20:09:17 +0900170import java.util.Collections;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800171import java.util.Date;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172import java.util.List;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800173import java.util.Locale;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800174import java.util.WeakHashMap;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800175import java.util.concurrent.atomic.AtomicInteger;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176
177/**
178 * This class provides a system service that manages input methods.
179 */
180public class InputMethodManagerService extends IInputMethodManager.Stub
181 implements ServiceConnection, Handler.Callback {
182 static final boolean DEBUG = false;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700183 static final String TAG = "InputMethodManagerService";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184
Yohei Yukawa926488d2017-12-11 17:24:55 -0800185 @Retention(SOURCE)
186 @IntDef({ShellCommandResult.SUCCESS, ShellCommandResult.FAILURE})
187 private @interface ShellCommandResult {
188 int SUCCESS = 0;
189 int FAILURE = -1;
190 }
191
Seigo Nonakad4474cb2015-05-04 16:53:24 -0700192 static final int MSG_SHOW_IM_SUBTYPE_PICKER = 1;
193 static final int MSG_SHOW_IM_SUBTYPE_ENABLER = 2;
194 static final int MSG_SHOW_IM_CONFIG = 3;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 static final int MSG_UNBIND_INPUT = 1000;
197 static final int MSG_BIND_INPUT = 1010;
198 static final int MSG_SHOW_SOFT_INPUT = 1020;
199 static final int MSG_HIDE_SOFT_INPUT = 1030;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700200 static final int MSG_HIDE_CURRENT_INPUT_METHOD = 1035;
Yohei Yukawac54c1172018-09-06 11:39:50 -0700201 static final int MSG_INITIALIZE_IME = 1040;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 static final int MSG_CREATE_SESSION = 1050;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800203
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 static final int MSG_START_INPUT = 2000;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800205
Yohei Yukawa33e81792015-11-17 21:14:42 -0800206 static final int MSG_UNBIND_CLIENT = 3000;
207 static final int MSG_BIND_CLIENT = 3010;
Dianne Hackborna6e41342012-05-22 16:30:34 -0700208 static final int MSG_SET_ACTIVE = 3020;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700209 static final int MSG_SET_INTERACTIVE = 3030;
Yohei Yukawa2bc66172017-02-08 11:13:25 -0800210 static final int MSG_REPORT_FULLSCREEN_MODE = 3045;
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -0800211 static final int MSG_REPORT_PRE_RENDERED = 3060;
212 static final int MSG_APPLY_IME_VISIBILITY = 3070;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800213
satok01038492012-04-09 21:08:27 +0900214 static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000;
215
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -0700216 static final int MSG_SYSTEM_UNLOCK_USER = 5000;
217
Adam Hebc67f2e2019-11-13 14:34:56 -0800218 static final int MSG_INLINE_SUGGESTIONS_REQUEST = 6000;
219
Satoshi Kataokabcacc322013-10-21 17:57:27 -0700220 static final long TIME_TO_RECONNECT = 3 * 1000;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800221
satokf9f01002011-05-19 21:31:50 +0900222 static final int SECURE_SUGGESTION_SPANS_MAX_SIZE = 20;
223
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +0900224 private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID;
satokb6359412011-06-28 17:47:41 +0900225 private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +0900226
Yohei Yukawaa67a4592017-03-30 15:57:02 -0700227 /**
228 * Binding flags for establishing connection to the {@link InputMethodService}.
229 */
230 private static final int IME_CONNECTION_BIND_FLAGS =
231 Context.BIND_AUTO_CREATE
232 | Context.BIND_NOT_VISIBLE
233 | Context.BIND_NOT_FOREGROUND
Yohei Yukawaad78a612017-08-04 01:57:27 -0700234 | Context.BIND_IMPORTANT_BACKGROUND;
Yohei Yukawaa67a4592017-03-30 15:57:02 -0700235
236 /**
237 * Binding flags used only while the {@link InputMethodService} is showing window.
238 */
239 private static final int IME_VISIBLE_BIND_FLAGS =
240 Context.BIND_AUTO_CREATE
241 | Context.BIND_TREAT_LIKE_ACTIVITY
Yohei Yukawaad78a612017-08-04 01:57:27 -0700242 | Context.BIND_FOREGROUND_SERVICE
Amith Yamasanic45a9902019-04-05 16:29:30 -0700243 | Context.BIND_INCLUDE_CAPABILITIES
Yohei Yukawa59730962019-03-18 10:47:22 -0700244 | Context.BIND_SHOWING_UI
245 | Context.BIND_SCHEDULE_LIKE_TOP_APP;
Yohei Yukawaa67a4592017-03-30 15:57:02 -0700246
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +0900247 /**
248 * A protected broadcast intent action for internal use for {@link PendingIntent} in
249 * the notification.
250 */
251 private static final String ACTION_SHOW_INPUT_METHOD_PICKER =
Yohei Yukawa603f4d02018-09-11 15:04:58 -0700252 "com.android.server.inputmethod.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER";
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +0900253
Tarandeep Singh75a92392018-01-12 14:58:59 -0800254 /**
255 * Debug flag for overriding runtime {@link SystemProperties}.
256 */
257 @AnyThread
258 private static final class DebugFlag {
259 private static final Object LOCK = new Object();
260 private final String mKey;
Tarandeep Singh9df4ad12018-04-03 13:35:50 -0700261 private final boolean mDefaultValue;
Tarandeep Singh75a92392018-01-12 14:58:59 -0800262 @GuardedBy("LOCK")
263 private boolean mValue;
264
Tarandeep Singh1c042c52018-03-29 17:04:44 -0700265 public DebugFlag(String key, boolean defaultValue) {
Tarandeep Singh75a92392018-01-12 14:58:59 -0800266 mKey = key;
Tarandeep Singh9df4ad12018-04-03 13:35:50 -0700267 mDefaultValue = defaultValue;
Tarandeep Singh1c042c52018-03-29 17:04:44 -0700268 mValue = SystemProperties.getBoolean(key, defaultValue);
Tarandeep Singh75a92392018-01-12 14:58:59 -0800269 }
270
271 void refresh() {
272 synchronized (LOCK) {
Tarandeep Singh9df4ad12018-04-03 13:35:50 -0700273 mValue = SystemProperties.getBoolean(mKey, mDefaultValue);
Tarandeep Singh75a92392018-01-12 14:58:59 -0800274 }
275 }
276
277 boolean value() {
278 synchronized (LOCK) {
279 return mValue;
280 }
281 }
282 }
283
284 /**
285 * Debug flags that can be overridden using "adb shell setprop <key>"
286 * Note: These flags are cached. To refresh, run "adb shell ime refresh_debug_properties".
287 */
288 private static final class DebugFlags {
289 static final DebugFlag FLAG_OPTIMIZE_START_INPUT =
Tarandeep Singh1c042c52018-03-29 17:04:44 -0700290 new DebugFlag("debug.optimize_startinput", false);
Tarandeep Singheadb1392018-11-09 18:15:57 +0100291 static final DebugFlag FLAG_PRE_RENDER_IME_VIEWS =
292 new DebugFlag("persist.pre_render_ime_views", false);
Tarandeep Singh75a92392018-01-12 14:58:59 -0800293 }
294
Yohei Yukawaa7babbb2019-01-08 16:45:34 -0800295 @UserIdInt
296 private int mLastSwitchUserId;
Tarandeep Singh75a92392018-01-12 14:58:59 -0800297
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298 final Context mContext;
Dianne Hackborn7d3a5bc2010-11-29 22:52:12 -0800299 final Resources mRes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 final Handler mHandler;
satokd87c2592010-09-29 11:52:06 +0900301 final InputMethodSettings mSettings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 final SettingsObserver mSettingsObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303 final IWindowManager mIWindowManager;
Seigo Nonaka7309b122015-08-17 18:34:13 -0700304 final WindowManagerInternal mWindowManagerInternal;
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700305 private final DisplayManagerInternal mDisplayManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 final HandlerCaller mCaller;
Dianne Hackborn119bbc32013-03-22 17:27:25 -0700307 final boolean mHasFeature;
Yohei Yukawab557d572018-12-29 21:26:26 -0800308 private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypeMap =
309 new ArrayMap<>();
Tarandeep Singheadb1392018-11-09 18:15:57 +0100310 private final boolean mIsLowRam;
satok01038492012-04-09 21:08:27 +0900311 private final HardKeyboardListener mHardKeyboardListener;
Yohei Yukawae63b5fa2014-09-19 13:14:55 +0900312 private final AppOpsManager mAppOpsManager;
Yohei Yukawaed4952a2016-02-17 07:57:25 -0800313 private final UserManager mUserManager;
Yohei Yukawa42081402019-01-15 09:57:50 -0800314 private final UserManagerInternal mUserManagerInternal;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 // All known input methods. mMethodMap also serves as the global
317 // lock for this class.
Yohei Yukawab0377bb2015-08-10 21:06:30 -0700318 final ArrayList<InputMethodInfo> mMethodList = new ArrayList<>();
Yohei Yukawa1dd7de62018-11-20 19:25:29 -0800319 final ArrayMap<String, InputMethodInfo> mMethodMap = new ArrayMap<>();
satokf9f01002011-05-19 21:31:50 +0900320 private final LruCache<SuggestionSpan, InputMethodInfo> mSecureSuggestionSpans =
Yohei Yukawab0377bb2015-08-10 21:06:30 -0700321 new LruCache<>(SECURE_SUGGESTION_SPANS_MAX_SIZE);
Satoshi Kataokad787f692013-10-26 04:44:21 +0900322 private final InputMethodSubtypeSwitchingController mSwitchingController;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800323
Yohei Yukawae0733062017-02-09 22:49:35 -0800324 /**
325 * Tracks how many times {@link #mMethodMap} was updated.
326 */
327 @GuardedBy("mMethodMap")
328 private int mMethodMapUpdateCount = 0;
329
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -0700330 // Used to bring IME service up to visible adjustment while it is being shown.
331 final ServiceConnection mVisibleConnection = new ServiceConnection() {
Yohei Yukawad3ef8422018-06-07 16:28:07 -0700332 @Override public void onBindingDied(ComponentName name) {
333 synchronized (mMethodMap) {
334 if (mVisibleBound) {
335 mContext.unbindService(mVisibleConnection);
336 mVisibleBound = false;
337 }
338 }
339 }
340
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -0700341 @Override public void onServiceConnected(ComponentName name, IBinder service) {
342 }
343
344 @Override public void onServiceDisconnected(ComponentName name) {
345 }
346 };
347 boolean mVisibleBound = false;
348
satok7cfc0ed2011-06-20 21:29:36 +0900349 // Ongoing notification
Dianne Hackborn661cd522011-08-22 00:26:20 -0700350 private NotificationManager mNotificationManager;
351 private KeyguardManager mKeyguardManager;
Griff Hazen6090c262016-03-25 08:11:24 -0700352 private @Nullable StatusBarManagerService mStatusBar;
Chris Wren1ce4b6d2015-06-11 10:19:43 -0400353 private Notification.Builder mImeSwitcherNotification;
Dianne Hackborn661cd522011-08-22 00:26:20 -0700354 private PendingIntent mImeSwitchPendingIntent;
satokb858c732011-07-22 19:54:34 +0900355 private boolean mShowOngoingImeSwitcherForPhones;
satok7cfc0ed2011-06-20 21:29:36 +0900356 private boolean mNotificationShown;
357
Tadashi G. Takaoka8c6d4772014-08-05 15:29:17 +0900358 static class SessionState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 final ClientState client;
360 final IInputMethod method;
Jeff Brownc28867a2013-03-26 15:42:39 -0700361
362 IInputMethodSession session;
363 InputChannel channel;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 @Override
366 public String toString() {
367 return "SessionState{uid " + client.uid + " pid " + client.pid
368 + " method " + Integer.toHexString(
369 System.identityHashCode(method))
370 + " session " + Integer.toHexString(
371 System.identityHashCode(session))
Jeff Brownc28867a2013-03-26 15:42:39 -0700372 + " channel " + channel
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 + "}";
374 }
375
376 SessionState(ClientState _client, IInputMethod _method,
Jeff Brownc28867a2013-03-26 15:42:39 -0700377 IInputMethodSession _session, InputChannel _channel) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 client = _client;
379 method = _method;
380 session = _session;
Jeff Brownc28867a2013-03-26 15:42:39 -0700381 channel = _channel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 }
383 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800384
Yohei Yukawaa71bb252018-09-19 19:21:24 -0700385 private static final class ClientDeathRecipient implements IBinder.DeathRecipient {
386 private final InputMethodManagerService mImms;
387 private final IInputMethodClient mClient;
388
389 ClientDeathRecipient(InputMethodManagerService imms, IInputMethodClient client) {
390 mImms = imms;
391 mClient = client;
392 }
393
394 @Override
395 public void binderDied() {
396 mImms.removeClient(mClient);
397 }
398 }
399
Jeff Brownc28867a2013-03-26 15:42:39 -0700400 static final class ClientState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 final IInputMethodClient client;
402 final IInputContext inputContext;
403 final int uid;
404 final int pid;
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800405 final int selfReportedDisplayId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 final InputBinding binding;
Yohei Yukawaa71bb252018-09-19 19:21:24 -0700407 final ClientDeathRecipient clientDeathRecipient;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800408
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 boolean sessionRequested;
Tarandeep Singheadb1392018-11-09 18:15:57 +0100410 // Determines if IMEs should be pre-rendered.
411 // DebugFlag can be flipped anytime. This flag is kept per-client to maintain behavior
412 // through the life of the current client.
413 boolean shouldPreRenderIme;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 SessionState curSession;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 @Override
417 public String toString() {
418 return "ClientState{" + Integer.toHexString(
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800419 System.identityHashCode(this)) + " uid=" + uid
420 + " pid=" + pid + " displayId=" + selfReportedDisplayId + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 }
422
423 ClientState(IInputMethodClient _client, IInputContext _inputContext,
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800424 int _uid, int _pid, int _selfReportedDisplayId,
425 ClientDeathRecipient _clientDeathRecipient) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 client = _client;
427 inputContext = _inputContext;
428 uid = _uid;
429 pid = _pid;
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800430 selfReportedDisplayId = _selfReportedDisplayId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 binding = new InputBinding(null, inputContext.asBinder(), uid, pid);
Yohei Yukawaa71bb252018-09-19 19:21:24 -0700432 clientDeathRecipient = _clientDeathRecipient;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 }
434 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800435
Yohei Yukawaac9311e2018-11-20 19:25:23 -0800436 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800437
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700438 private static final class ActivityViewInfo {
439 /**
440 * {@link ClientState} where {@link android.app.ActivityView} is running.
441 */
442 private final ClientState mParentClient;
443 /**
444 * {@link Matrix} to convert screen coordinates in the embedded virtual display to
445 * screen coordinates where {@link #mParentClient} exists.
446 */
447 private final Matrix mMatrix;
448
449 ActivityViewInfo(ClientState parentClient, Matrix matrix) {
450 mParentClient = parentClient;
451 mMatrix = matrix;
452 }
453 }
454
455 /**
456 * A mapping table from virtual display IDs created for {@link android.app.ActivityView}
457 * to its parent IME client where {@link android.app.ActivityView} is running.
458 *
459 * <p>Note: this can be used only for virtual display IDs created by
460 * {@link android.app.ActivityView}.</p>
461 */
462 private SparseArray<ActivityViewInfo> mActivityViewDisplayIdToParentMap = new SparseArray<>();
463
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 /**
Dianne Hackborna34f1ad2009-09-02 13:26:28 -0700465 * Set once the system is ready to run third party code.
466 */
467 boolean mSystemReady;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800468
Dianne Hackborna34f1ad2009-09-02 13:26:28 -0700469 /**
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700470 * Id obtained with {@link InputMethodInfo#getId()} for the currently selected input method.
471 * method. This is to be synchronized with the secure settings keyed with
472 * {@link Settings.Secure#DEFAULT_INPUT_METHOD}.
473 *
474 * <p>This can be transiently {@code null} when the system is re-initializing input method
475 * settings, e.g., the system locale is just changed.</p>
476 *
477 * <p>Note that {@link #mCurId} is used to track which IME is being connected to
478 * {@link InputMethodManagerService}.</p>
479 *
480 * @see #mCurId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800481 */
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700482 @Nullable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483 String mCurMethodId;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800484
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 /**
486 * The current binding sequence number, incremented every time there is
487 * a new bind performed.
488 */
489 int mCurSeq;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800490
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800491 /**
492 * The client that is currently bound to an input method.
493 */
494 ClientState mCurClient;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800495
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 /**
Yohei Yukawae39d4ed2015-11-19 03:38:49 -0800497 * The last window token that we confirmed to be focused. This is always updated upon reports
498 * from the input method client. If the window state is already changed before the report is
499 * handled, this field just keeps the last value.
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700500 */
501 IBinder mCurFocusedWindow;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800502
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700503 /**
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -0700504 * The last window token that we confirmed that IME started talking to. This is always updated
505 * upon reports from the input method. If the window state is already changed before the report
506 * is handled, this field just keeps the last value.
507 */
508 IBinder mLastImeTargetWindow;
509
510 /**
Yohei Yukawa6e875592019-01-28 00:49:30 -0800511 * {@link LayoutParams#softInputMode} of {@link #mCurFocusedWindow}.
Yohei Yukawa22a89232017-02-12 16:38:59 -0800512 *
513 * @see #mCurFocusedWindow
514 */
Yohei Yukawab0c26452018-10-21 10:42:52 -0700515 @SoftInputModeFlags
Yohei Yukawa22a89232017-02-12 16:38:59 -0800516 int mCurFocusedWindowSoftInputMode;
517
518 /**
Tarandeep Singheb570612018-01-29 16:20:32 -0800519 * The client by which {@link #mCurFocusedWindow} was reported.
Yohei Yukawae39d4ed2015-11-19 03:38:49 -0800520 */
521 ClientState mCurFocusedWindowClient;
522
523 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 * The input context last provided by the current client.
525 */
526 IInputContext mCurInputContext;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800527
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 /**
Yohei Yukawa19a80a12016-03-14 22:57:37 -0700529 * The missing method flags for the input context last provided by the current client.
530 *
531 * @see android.view.inputmethod.InputConnectionInspector.MissingMethodFlags
532 */
Yohei Yukawa432cf602018-10-21 10:41:37 -0700533 @MissingMethodFlags
Yohei Yukawa19a80a12016-03-14 22:57:37 -0700534 int mCurInputContextMissingMethods;
535
536 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 * The attributes last provided by the current client.
538 */
539 EditorInfo mCurAttribute;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800540
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 /**
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700542 * A special {@link Matrix} to convert virtual screen coordinates to the IME target display
543 * coordinates.
544 *
545 * <p>Used only while the IME client is running in a virtual display inside
546 * {@link android.app.ActivityView}. {@code null} otherwise.</p>
547 */
548 @Nullable
549 private Matrix mCurActivityViewToScreenMatrix = null;
550
551 /**
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700552 * Id obtained with {@link InputMethodInfo#getId()} for the input method that we are currently
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 * connected to or in the process of connecting to.
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700554 *
555 * <p>This can be {@code null} when no input method is connected.</p>
556 *
557 * @see #mCurMethodId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 */
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700559 @Nullable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 String mCurId;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800561
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 /**
satokab751aa2010-09-14 19:17:36 +0900563 * The current subtype of the current input method.
564 */
565 private InputMethodSubtype mCurrentSubtype;
566
John Spurlocke0980502013-10-25 11:59:29 -0400567 // Was the keyguard locked when this client became current?
568 private boolean mCurClientInKeyguard;
569
satokab751aa2010-09-14 19:17:36 +0900570 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571 * Set to true if our ServiceConnection is currently actively bound to
572 * a service (whether or not we have gotten its IBinder back yet).
573 */
574 boolean mHaveConnection;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800575
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576 /**
577 * Set if the client has asked for the input method to be shown.
578 */
579 boolean mShowRequested;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800580
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 /**
582 * Set if we were explicitly told to show the input method.
583 */
584 boolean mShowExplicitlyRequested;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800585
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 /**
587 * Set if we were forced to be shown.
588 */
589 boolean mShowForced;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800590
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 /**
592 * Set if we last told the input method to show itself.
593 */
594 boolean mInputShown;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800595
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 /**
Yohei Yukawa2bc66172017-02-08 11:13:25 -0800597 * {@code true} if the current input method is in fullscreen mode.
598 */
599 boolean mInFullscreenMode;
600
601 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602 * The Intent used to connect to the current input method.
603 */
604 Intent mCurIntent;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800605
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606 /**
607 * The token we have made for the currently active input method, to
608 * identify it in the future.
609 */
610 IBinder mCurToken;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 /**
lumark90120a82018-08-15 00:33:03 +0800613 * The displayId of current active input method.
614 */
615 int mCurTokenDisplayId = INVALID_DISPLAY;
616
lumark7570cac2019-03-07 22:14:38 +0800617 /**
618 * The display ID of the input method indicates the fallback display which returned by
619 * {@link #computeImeDisplayIdForTarget}.
620 */
621 private static final int FALLBACK_DISPLAY_ID = DEFAULT_DISPLAY;
622
lumarkef1965b2018-09-12 17:42:53 +0800623 final ImeDisplayValidator mImeDisplayValidator;
624
lumark90120a82018-08-15 00:33:03 +0800625 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800626 * If non-null, this is the input method service we are currently connected
627 * to.
628 */
629 IInputMethod mCurMethod;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800630
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631 /**
632 * Time that we last initiated a bind to the input method, to determine
633 * if we should try to disconnect and reconnect to it.
634 */
635 long mLastBindTime;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800636
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 /**
638 * Have we called mCurMethod.bindInput()?
639 */
640 boolean mBoundToMethod;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800641
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642 /**
643 * Currently enabled session. Only touched by service thread, not
644 * protected by a lock.
645 */
646 SessionState mEnabledSession;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800647
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 /**
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700649 * True if the device is currently interactive with user. The value is true initially.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 */
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700651 boolean mIsInteractive = true;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800652
Joe Onorato857fd9b2011-01-27 15:08:35 -0800653 int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
Seigo Nonakad9eb9112015-05-26 20:54:43 +0900654
655 /**
656 * A set of status bits regarding the active IME.
657 *
658 * <p>This value is a combination of following two bits:</p>
659 * <dl>
660 * <dt>{@link InputMethodService#IME_ACTIVE}</dt>
661 * <dd>
662 * If this bit is ON, connected IME is ready to accept touch/key events.
663 * </dd>
664 * <dt>{@link InputMethodService#IME_VISIBLE}</dt>
665 * <dd>
666 * If this bit is ON, some of IME view, e.g. software input, candidate view, is visible.
667 * </dd>
Tarandeep Singheadb1392018-11-09 18:15:57 +0100668 * dt>{@link InputMethodService#IME_INVISIBLE}</dt>
669 * <dd> If this bit is ON, IME is ready with views from last EditorInfo but is
670 * currently invisible.
671 * </dd>
Seigo Nonakad9eb9112015-05-26 20:54:43 +0900672 * </dl>
lumark7570cac2019-03-07 22:14:38 +0800673 * <em>Do not update this value outside of {@link #setImeWindowStatus(IBinder, int, int)} and
674 * {@link #unbindCurrentMethodLocked()}.</em>
Seigo Nonakad9eb9112015-05-26 20:54:43 +0900675 */
Joe Onorato857fd9b2011-01-27 15:08:35 -0800676 int mImeWindowVis;
677
Ken Wakasa05dbb652011-08-22 15:22:43 +0900678 private AlertDialog.Builder mDialogBuilder;
679 private AlertDialog mSwitchingDialog;
Wale Ogunwale3a931692016-11-02 16:49:48 -0700680 private IBinder mSwitchingDialogToken = new Binder();
satok01038492012-04-09 21:08:27 +0900681 private View mSwitchingDialogTitleView;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900682 private InputMethodInfo[] mIms;
683 private int[] mSubtypeIds;
Yohei Yukawae985c242016-02-24 18:27:04 -0800684 private LocaleList mLastSystemLocales;
Michael Wright7b5a96b2014-08-09 19:28:42 -0700685 private boolean mShowImeWithHardKeyboard;
Anna Galusza9b278112016-01-04 11:37:37 -0800686 private boolean mAccessibilityRequestingNoSoftKeyboard;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +0900687 private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
688 private final IPackageManager mIPackageManager;
Jason Monk3e189872016-01-12 09:10:34 -0500689 private final String mSlotIme;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800690
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800691 /**
692 * Internal state snapshot when {@link #MSG_START_INPUT} message is about to be posted to the
693 * internal message queue. Any subsequent state change inside {@link InputMethodManagerService}
694 * will not affect those tasks that are already posted.
695 *
696 * <p>Posting {@link #MSG_START_INPUT} message basically means that
697 * {@link InputMethodService#doStartInput(InputConnection, EditorInfo, boolean)} will be called
698 * back in the current IME process shortly, which will also affect what the current IME starts
699 * receiving from {@link InputMethodService#getCurrentInputConnection()}. In other words, this
700 * snapshot will be taken every time when {@link InputMethodManagerService} is initiating a new
701 * logical input session between the client application and the current IME.</p>
702 *
703 * <p>Be careful to not keep strong references to this object forever, which can prevent
704 * {@link StartInputInfo#mImeToken} and {@link StartInputInfo#mTargetWindow} from being GC-ed.
705 * </p>
706 */
707 private static class StartInputInfo {
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800708 private static final AtomicInteger sSequenceNumber = new AtomicInteger(0);
709
710 final int mSequenceNumber;
711 final long mTimestamp;
712 final long mWallTime;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800713 @UserIdInt
714 final int mImeUserId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800715 @NonNull
716 final IBinder mImeToken;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800717 final int mImeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800718 @NonNull
719 final String mImeId;
Yohei Yukawadc66e522018-10-21 10:43:14 -0700720 @StartInputReason
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800721 final int mStartInputReason;
722 final boolean mRestarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800723 @UserIdInt
724 final int mTargetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800725 final int mTargetDisplayId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800726 @Nullable
727 final IBinder mTargetWindow;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800728 @NonNull
729 final EditorInfo mEditorInfo;
Yohei Yukawab0c26452018-10-21 10:42:52 -0700730 @SoftInputModeFlags
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800731 final int mTargetWindowSoftInputMode;
732 final int mClientBindSequenceNumber;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800733
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800734 StartInputInfo(@UserIdInt int imeUserId, @NonNull IBinder imeToken, int imeDisplayId,
735 @NonNull String imeId, @StartInputReason int startInputReason, boolean restarting,
736 @UserIdInt int targetUserId, int targetDisplayId, @Nullable IBinder targetWindow,
737 @NonNull EditorInfo editorInfo, @SoftInputModeFlags int targetWindowSoftInputMode,
738 int clientBindSequenceNumber) {
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800739 mSequenceNumber = sSequenceNumber.getAndIncrement();
740 mTimestamp = SystemClock.uptimeMillis();
741 mWallTime = System.currentTimeMillis();
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800742 mImeUserId = imeUserId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800743 mImeToken = imeToken;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800744 mImeDisplayId = imeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800745 mImeId = imeId;
746 mStartInputReason = startInputReason;
747 mRestarting = restarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800748 mTargetUserId = targetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800749 mTargetDisplayId = targetDisplayId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800750 mTargetWindow = targetWindow;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800751 mEditorInfo = editorInfo;
752 mTargetWindowSoftInputMode = targetWindowSoftInputMode;
753 mClientBindSequenceNumber = clientBindSequenceNumber;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800754 }
755 }
756
Yohei Yukawab37d8bd2017-02-13 18:29:05 -0800757 @GuardedBy("mMethodMap")
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -0700758 private final WeakHashMap<IBinder, IBinder> mImeTargetWindowMap = new WeakHashMap<>();
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800759
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800760 /**
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -0800761 * Map of generated token to windowToken that is requesting
762 * {@link InputMethodManager#showSoftInput(View, int)}.
763 * This map tracks origin of showSoftInput requests.
764 */
765 @GuardedBy("mMethodMap")
766 private final WeakHashMap<IBinder, IBinder> mShowRequestWindowMap = new WeakHashMap<>();
767
768 /**
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800769 * A ring buffer to store the history of {@link StartInputInfo}.
770 */
771 private static final class StartInputHistory {
772 /**
773 * Entry size for non low-RAM devices.
774 *
775 * <p>TODO: Consider to follow what other system services have been doing to manage
776 * constants (e.g. {@link android.provider.Settings.Global#ACTIVITY_MANAGER_CONSTANTS}).</p>
777 */
778 private final static int ENTRY_SIZE_FOR_HIGH_RAM_DEVICE = 16;
779
780 /**
781 * Entry size for non low-RAM devices.
782 *
783 * <p>TODO: Consider to follow what other system services have been doing to manage
784 * constants (e.g. {@link android.provider.Settings.Global#ACTIVITY_MANAGER_CONSTANTS}).</p>
785 */
786 private final static int ENTRY_SIZE_FOR_LOW_RAM_DEVICE = 5;
787
788 private static int getEntrySize() {
789 if (ActivityManager.isLowRamDeviceStatic()) {
790 return ENTRY_SIZE_FOR_LOW_RAM_DEVICE;
791 } else {
792 return ENTRY_SIZE_FOR_HIGH_RAM_DEVICE;
793 }
794 }
795
796 /**
797 * Backing store for the ring bugger.
798 */
799 private final Entry[] mEntries = new Entry[getEntrySize()];
800
801 /**
802 * An index of {@link #mEntries}, to which next {@link #addEntry(StartInputInfo)} should
803 * write.
804 */
805 private int mNextIndex = 0;
806
807 /**
808 * Recyclable entry to store the information in {@link StartInputInfo}.
809 */
810 private static final class Entry {
811 int mSequenceNumber;
812 long mTimestamp;
813 long mWallTime;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800814 @UserIdInt
815 int mImeUserId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800816 @NonNull
817 String mImeTokenString;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800818 int mImeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800819 @NonNull
820 String mImeId;
Yohei Yukawadc66e522018-10-21 10:43:14 -0700821 @StartInputReason
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800822 int mStartInputReason;
823 boolean mRestarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800824 @UserIdInt
825 int mTargetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800826 int mTargetDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800827 @NonNull
828 String mTargetWindowString;
829 @NonNull
830 EditorInfo mEditorInfo;
Yohei Yukawab0c26452018-10-21 10:42:52 -0700831 @SoftInputModeFlags
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800832 int mTargetWindowSoftInputMode;
833 int mClientBindSequenceNumber;
834
835 Entry(@NonNull StartInputInfo original) {
836 set(original);
837 }
838
839 void set(@NonNull StartInputInfo original) {
840 mSequenceNumber = original.mSequenceNumber;
841 mTimestamp = original.mTimestamp;
842 mWallTime = original.mWallTime;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800843 mImeUserId = original.mImeUserId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800844 // Intentionally convert to String so as not to keep a strong reference to a Binder
845 // object.
846 mImeTokenString = String.valueOf(original.mImeToken);
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800847 mImeDisplayId = original.mImeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800848 mImeId = original.mImeId;
849 mStartInputReason = original.mStartInputReason;
850 mRestarting = original.mRestarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800851 mTargetUserId = original.mTargetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800852 mTargetDisplayId = original.mTargetDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800853 // Intentionally convert to String so as not to keep a strong reference to a Binder
854 // object.
855 mTargetWindowString = String.valueOf(original.mTargetWindow);
856 mEditorInfo = original.mEditorInfo;
857 mTargetWindowSoftInputMode = original.mTargetWindowSoftInputMode;
858 mClientBindSequenceNumber = original.mClientBindSequenceNumber;
859 }
860 }
861
862 /**
863 * Add a new entry and discard the oldest entry as needed.
864 * @param info {@lin StartInputInfo} to be added.
865 */
866 void addEntry(@NonNull StartInputInfo info) {
867 final int index = mNextIndex;
868 if (mEntries[index] == null) {
869 mEntries[index] = new Entry(info);
870 } else {
871 mEntries[index].set(info);
872 }
873 mNextIndex = (mNextIndex + 1) % mEntries.length;
874 }
875
876 void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
877 final SimpleDateFormat dataFormat =
878 new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
879
880 for (int i = 0; i < mEntries.length; ++i) {
881 final Entry entry = mEntries[(i + mNextIndex) % mEntries.length];
882 if (entry == null) {
883 continue;
884 }
885 pw.print(prefix);
886 pw.println("StartInput #" + entry.mSequenceNumber + ":");
887
888 pw.print(prefix);
889 pw.println(" time=" + dataFormat.format(new Date(entry.mWallTime))
890 + " (timestamp=" + entry.mTimestamp + ")"
891 + " reason="
Yohei Yukawaa468d702018-10-21 11:42:34 -0700892 + InputMethodDebug.startInputReasonToString(entry.mStartInputReason)
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800893 + " restarting=" + entry.mRestarting);
894
895 pw.print(prefix);
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800896 pw.print(" imeToken=" + entry.mImeTokenString + " [" + entry.mImeId + "]");
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800897 pw.print(" imeUserId=" + entry.mImeUserId);
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800898 pw.println(" imeDisplayId=" + entry.mImeDisplayId);
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800899
900 pw.print(prefix);
901 pw.println(" targetWin=" + entry.mTargetWindowString
902 + " [" + entry.mEditorInfo.packageName + "]"
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800903 + " targetUserId=" + entry.mTargetUserId
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800904 + " targetDisplayId=" + entry.mTargetDisplayId
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800905 + " clientBindSeq=" + entry.mClientBindSequenceNumber);
906
907 pw.print(prefix);
Yohei Yukawaa468d702018-10-21 11:42:34 -0700908 pw.println(" softInputMode=" + InputMethodDebug.softInputModeToString(
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800909 entry.mTargetWindowSoftInputMode));
910
911 pw.print(prefix);
912 pw.println(" inputType=0x" + Integer.toHexString(entry.mEditorInfo.inputType)
913 + " imeOptions=0x" + Integer.toHexString(entry.mEditorInfo.imeOptions)
914 + " fieldId=0x" + Integer.toHexString(entry.mEditorInfo.fieldId)
915 + " fieldName=" + entry.mEditorInfo.fieldName
916 + " actionId=" + entry.mEditorInfo.actionId
917 + " actionLabel=" + entry.mEditorInfo.actionLabel);
918 }
919 }
920 }
921
922 @GuardedBy("mMethodMap")
923 @NonNull
924 private final StartInputHistory mStartInputHistory = new StartInputHistory();
925
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800926 class SettingsObserver extends ContentObserver {
Yohei Yukawa81482972015-06-04 00:58:59 -0700927 int mUserId;
928 boolean mRegistered = false;
Yohei Yukawa7b574cb2016-03-16 17:22:22 -0700929 @NonNull
Dianne Hackbornfd7aded2013-01-22 17:10:23 -0800930 String mLastEnabled = "";
931
Yohei Yukawa81482972015-06-04 00:58:59 -0700932 /**
933 * <em>This constructor must be called within the lock.</em>
934 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935 SettingsObserver(Handler handler) {
936 super(handler);
Yohei Yukawa81482972015-06-04 00:58:59 -0700937 }
938
Yohei Yukawa7b18aec2016-03-07 13:04:32 -0800939 public void registerContentObserverLocked(@UserIdInt int userId) {
Yohei Yukawa81482972015-06-04 00:58:59 -0700940 if (mRegistered && mUserId == userId) {
941 return;
942 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800943 ContentResolver resolver = mContext.getContentResolver();
Yohei Yukawa81482972015-06-04 00:58:59 -0700944 if (mRegistered) {
945 mContext.getContentResolver().unregisterContentObserver(this);
946 mRegistered = false;
947 }
948 if (mUserId != userId) {
949 mLastEnabled = "";
950 mUserId = userId;
951 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -0700953 Settings.Secure.DEFAULT_INPUT_METHOD), false, this, userId);
satokab751aa2010-09-14 19:17:36 +0900954 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -0700955 Settings.Secure.ENABLED_INPUT_METHODS), false, this, userId);
satokb6109bb2011-02-03 22:24:54 +0900956 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -0700957 Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this, userId);
Michael Wright7b5a96b2014-08-09 19:28:42 -0700958 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -0700959 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, this, userId);
Anna Galusza9b278112016-01-04 11:37:37 -0800960 resolver.registerContentObserver(Settings.Secure.getUriFor(
961 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE), false, this, userId);
Yohei Yukawa81482972015-06-04 00:58:59 -0700962 mRegistered = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800964
Michael Wright7b5a96b2014-08-09 19:28:42 -0700965 @Override public void onChange(boolean selfChange, Uri uri) {
Anna Galusza9b278112016-01-04 11:37:37 -0800966 final Uri showImeUri = Settings.Secure.getUriFor(
967 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
968 final Uri accessibilityRequestingNoImeUri = Settings.Secure.getUriFor(
969 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 synchronized (mMethodMap) {
Michael Wright7b5a96b2014-08-09 19:28:42 -0700971 if (showImeUri.equals(uri)) {
972 updateKeyboardFromSettingsLocked();
Anna Galusza9b278112016-01-04 11:37:37 -0800973 } else if (accessibilityRequestingNoImeUri.equals(uri)) {
Phil Weaver03a65b02018-07-19 16:07:57 -0700974 final int accessibilitySoftKeyboardSetting = Settings.Secure.getIntForUser(
Anna Galusza9b278112016-01-04 11:37:37 -0800975 mContext.getContentResolver(),
Phil Weaver03a65b02018-07-19 16:07:57 -0700976 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0, mUserId);
977 mAccessibilityRequestingNoSoftKeyboard =
978 (accessibilitySoftKeyboardSetting & AccessibilityService.SHOW_MODE_MASK)
979 == AccessibilityService.SHOW_MODE_HIDDEN;
Anna Galusza9b278112016-01-04 11:37:37 -0800980 if (mAccessibilityRequestingNoSoftKeyboard) {
981 final boolean showRequested = mShowRequested;
982 hideCurrentInputLocked(0, null);
983 mShowRequested = showRequested;
984 } else if (mShowRequested) {
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -0800985 showCurrentInputLocked(
986 mCurFocusedWindow, InputMethodManager.SHOW_IMPLICIT, null);
Anna Galusza9b278112016-01-04 11:37:37 -0800987 }
Michael Wright7b5a96b2014-08-09 19:28:42 -0700988 } else {
989 boolean enabledChanged = false;
990 String newEnabled = mSettings.getEnabledInputMethodsStr();
991 if (!mLastEnabled.equals(newEnabled)) {
992 mLastEnabled = newEnabled;
993 enabledChanged = true;
994 }
995 updateInputMethodsFromSettingsLocked(enabledChanged);
Dianne Hackbornfd7aded2013-01-22 17:10:23 -0800996 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 }
998 }
Yohei Yukawa81482972015-06-04 00:58:59 -0700999
1000 @Override
1001 public String toString() {
1002 return "SettingsObserver{mUserId=" + mUserId + " mRegistered=" + mRegistered
1003 + " mLastEnabled=" + mLastEnabled + "}";
1004 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001006
Yohei Yukawa0ec08002019-03-08 10:48:26 -08001007 /**
1008 * {@link BroadcastReceiver} that is intended to listen to broadcasts sent to the system user
1009 * only.
1010 */
1011 private final class ImmsBroadcastReceiverForSystemUser extends BroadcastReceiver {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001012 @Override
1013 public void onReceive(Context context, Intent intent) {
1014 final String action = intent.getAction();
Yohei Yukawa4225c7d2019-03-08 00:06:11 -08001015 if (Intent.ACTION_USER_ADDED.equals(action)
Amith Yamasani734983f2014-03-04 16:48:05 -08001016 || Intent.ACTION_USER_REMOVED.equals(action)) {
Kenny Guy2a764942014-04-02 13:29:20 +01001017 updateCurrentProfileIds();
Amith Yamasani734983f2014-03-04 16:48:05 -08001018 return;
Yohei Yukawa79247822017-01-23 15:26:15 -08001019 } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001020 onActionLocaleChanged();
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001021 } else if (ACTION_SHOW_INPUT_METHOD_PICKER.equals(action)) {
1022 // ACTION_SHOW_INPUT_METHOD_PICKER action is a protected-broadcast and it is
1023 // guaranteed to be send only from the system, so that there is no need for extra
1024 // security check such as
1025 // {@link #canShowInputMethodPickerLocked(IInputMethodClient)}.
1026 mHandler.obtainMessage(
1027 MSG_SHOW_IM_SUBTYPE_PICKER,
lumark0b05f9e2018-11-26 15:09:06 +08001028 // TODO(b/120076400): Design and implement IME switcher for heterogeneous
1029 // navbar configuration.
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001030 InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES,
lumark0b05f9e2018-11-26 15:09:06 +08001031 DEFAULT_DISPLAY).sendToTarget();
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001032 } else {
1033 Slog.w(TAG, "Unexpected intent " + intent);
1034 }
1035 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001037
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001038 /**
Yohei Yukawa0ec08002019-03-08 10:48:26 -08001039 * {@link BroadcastReceiver} that is intended to listen to broadcasts sent to all the users.
1040 */
1041 private final class ImmsBroadcastReceiverForAllUsers extends BroadcastReceiver {
1042 @Override
1043 public void onReceive(Context context, Intent intent) {
1044 final String action = intent.getAction();
1045 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
1046 final PendingResult pendingResult = getPendingResult();
1047 if (pendingResult == null) {
1048 return;
1049 }
1050 // sender userId can be a real user ID or USER_ALL.
1051 final int senderUserId = pendingResult.getSendingUserId();
1052 if (senderUserId != UserHandle.USER_ALL) {
Tarandeep Singhcf5ff822019-07-08 14:06:27 -07001053 if (senderUserId != mSettings.getCurrentUserId()) {
Yohei Yukawa0ec08002019-03-08 10:48:26 -08001054 // A background user is trying to hide the dialog. Ignore.
1055 return;
1056 }
1057 }
1058 hideInputMethodMenu();
1059 } else {
1060 Slog.w(TAG, "Unexpected intent " + intent);
1061 }
1062 }
1063 }
1064
1065 /**
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001066 * Handles {@link Intent#ACTION_LOCALE_CHANGED}.
1067 *
1068 * <p>Note: For historical reasons, {@link Intent#ACTION_LOCALE_CHANGED} has been sent to all
1069 * the users. We should ignore this event if this is about any background user's locale.</p>
1070 *
1071 * <p>Caution: This method must not be called when system is not ready.</p>
1072 */
1073 void onActionLocaleChanged() {
1074 synchronized (mMethodMap) {
1075 final LocaleList possibleNewLocale = mRes.getConfiguration().getLocales();
1076 if (possibleNewLocale != null && possibleNewLocale.equals(mLastSystemLocales)) {
1077 return;
1078 }
1079 buildInputMethodListLocked(true);
1080 // If the locale is changed, needs to reset the default ime
1081 resetDefaultImeLocked(mContext);
1082 updateFromSettingsLocked(true);
1083 mLastSystemLocales = possibleNewLocale;
1084 }
1085 }
1086
Yohei Yukawac4e44912017-02-09 19:30:22 -08001087 final class MyPackageMonitor extends PackageMonitor {
1088 /**
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001089 * Package names that are known to contain {@link InputMethodService}.
Yohei Yukawac4e44912017-02-09 19:30:22 -08001090 *
1091 * <p>No need to include packages because of direct-boot unaware IMEs since we always rescan
1092 * all the packages when the user is unlocked, and direct-boot awareness will not be changed
1093 * dynamically unless the entire package is updated, which also always triggers package
1094 * rescanning.</p>
1095 */
1096 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001097 final private ArraySet<String> mKnownImePackageNames = new ArraySet<>();
1098
1099 /**
1100 * Packages that are appeared, disappeared, or modified for whatever reason.
1101 *
1102 * <p>Note: For now we intentionally use {@link ArrayList} instead of {@link ArraySet}
1103 * because 1) the number of elements is almost always 1 or so, and 2) we do not care
1104 * duplicate elements for our use case.</p>
1105 *
1106 * <p>This object must be accessed only from callback methods in {@link PackageMonitor},
1107 * which should be bound to {@link #getRegisteredHandler()}.</p>
1108 */
1109 private final ArrayList<String> mChangedPackages = new ArrayList<>();
1110
1111 /**
1112 * {@code true} if one or more packages that contain {@link InputMethodService} appeared.
1113 *
1114 * <p>This field must be accessed only from callback methods in {@link PackageMonitor},
1115 * which should be bound to {@link #getRegisteredHandler()}.</p>
1116 */
1117 private boolean mImePackageAppeared = false;
Yohei Yukawac4e44912017-02-09 19:30:22 -08001118
1119 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001120 void clearKnownImePackageNamesLocked() {
1121 mKnownImePackageNames.clear();
Yohei Yukawac4e44912017-02-09 19:30:22 -08001122 }
1123
1124 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001125 final void addKnownImePackageNameLocked(@NonNull String packageName) {
1126 mKnownImePackageNames.add(packageName);
Yohei Yukawac4e44912017-02-09 19:30:22 -08001127 }
1128
Yohei Yukawa278f2ab2017-02-14 19:51:33 -08001129 @GuardedBy("mMethodMap")
1130 private boolean isChangingPackagesOfCurrentUserLocked() {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001131 final int userId = getChangingUserId();
1132 final boolean retval = userId == mSettings.getCurrentUserId();
1133 if (DEBUG) {
satok81f8b7c2012-12-04 20:42:56 +09001134 if (!retval) {
1135 Slog.d(TAG, "--- ignore this call back from a background user: " + userId);
1136 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001137 }
1138 return retval;
1139 }
1140
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001142 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001143 synchronized (mMethodMap) {
Yohei Yukawa278f2ab2017-02-14 19:51:33 -08001144 if (!isChangingPackagesOfCurrentUserLocked()) {
1145 return false;
1146 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001147 String curInputMethodId = mSettings.getSelectedInputMethod();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148 final int N = mMethodList.size();
1149 if (curInputMethodId != null) {
1150 for (int i=0; i<N; i++) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001151 InputMethodInfo imi = mMethodList.get(i);
1152 if (imi.getId().equals(curInputMethodId)) {
1153 for (String pkg : packages) {
1154 if (imi.getPackageName().equals(pkg)) {
1155 if (!doit) {
1156 return true;
1157 }
satok723a27e2010-11-11 14:58:11 +09001158 resetSelectedInputMethodAndSubtypeLocked("");
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001159 chooseNewDefaultIMELocked();
1160 return true;
1161 }
1162 }
1163 }
1164 }
1165 }
1166 }
1167 return false;
1168 }
1169
1170 @Override
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001171 public void onBeginPackageChanges() {
1172 clearPackageChangeState();
1173 }
1174
1175 @Override
1176 public void onPackageAppeared(String packageName, int reason) {
1177 if (!mImePackageAppeared) {
1178 final PackageManager pm = mContext.getPackageManager();
1179 final List<ResolveInfo> services = pm.queryIntentServicesAsUser(
1180 new Intent(InputMethod.SERVICE_INTERFACE).setPackage(packageName),
Yohei Yukawa5ec1fce2018-12-17 07:56:14 -08001181 PackageManager.MATCH_DISABLED_COMPONENTS, getChangingUserId());
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001182 // No need to lock this because we access it only on getRegisteredHandler().
1183 if (!services.isEmpty()) {
1184 mImePackageAppeared = true;
1185 }
1186 }
1187 // No need to lock this because we access it only on getRegisteredHandler().
1188 mChangedPackages.add(packageName);
1189 }
1190
1191 @Override
1192 public void onPackageDisappeared(String packageName, int reason) {
1193 // No need to lock this because we access it only on getRegisteredHandler().
1194 mChangedPackages.add(packageName);
1195 }
1196
1197 @Override
1198 public void onPackageModified(String packageName) {
1199 // No need to lock this because we access it only on getRegisteredHandler().
1200 mChangedPackages.add(packageName);
1201 }
1202
1203 @Override
1204 public void onPackagesSuspended(String[] packages) {
1205 // No need to lock this because we access it only on getRegisteredHandler().
1206 for (String packageName : packages) {
1207 mChangedPackages.add(packageName);
Yohei Yukawac4e44912017-02-09 19:30:22 -08001208 }
1209 }
1210
1211 @Override
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001212 public void onPackagesUnsuspended(String[] packages) {
1213 // No need to lock this because we access it only on getRegisteredHandler().
1214 for (String packageName : packages) {
1215 mChangedPackages.add(packageName);
1216 }
1217 }
1218
1219 @Override
1220 public void onFinishPackageChanges() {
1221 onFinishPackageChangesInternal();
1222 clearPackageChangeState();
1223 }
1224
1225 private void clearPackageChangeState() {
1226 // No need to lock them because we access these fields only on getRegisteredHandler().
1227 mChangedPackages.clear();
1228 mImePackageAppeared = false;
1229 }
1230
Andreas Gampea36dc622018-02-05 17:19:22 -08001231 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001232 private boolean shouldRebuildInputMethodListLocked() {
1233 // This method is guaranteed to be called only by getRegisteredHandler().
1234
1235 // If there is any new package that contains at least one IME, then rebuilt the list
1236 // of IMEs.
1237 if (mImePackageAppeared) {
1238 return true;
1239 }
1240
1241 // Otherwise, check if mKnownImePackageNames and mChangedPackages have any intersection.
1242 // TODO: Consider to create a utility method to do the following test. List.retainAll()
1243 // is an option, but it may still do some extra operations that we do not need here.
1244 final int N = mChangedPackages.size();
1245 for (int i = 0; i < N; ++i) {
1246 final String packageName = mChangedPackages.get(i);
1247 if (mKnownImePackageNames.contains(packageName)) {
1248 return true;
1249 }
1250 }
1251 return false;
1252 }
1253
1254 private void onFinishPackageChangesInternal() {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001255 synchronized (mMethodMap) {
Yohei Yukawa278f2ab2017-02-14 19:51:33 -08001256 if (!isChangingPackagesOfCurrentUserLocked()) {
1257 return;
1258 }
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001259 if (!shouldRebuildInputMethodListLocked()) {
1260 return;
1261 }
1262
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001263 InputMethodInfo curIm = null;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001264 String curInputMethodId = mSettings.getSelectedInputMethod();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001265 final int N = mMethodList.size();
1266 if (curInputMethodId != null) {
1267 for (int i=0; i<N; i++) {
1268 InputMethodInfo imi = mMethodList.get(i);
satoke7c6998e2011-06-03 17:57:59 +09001269 final String imiId = imi.getId();
1270 if (imiId.equals(curInputMethodId)) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001271 curIm = imi;
1272 }
satoke7c6998e2011-06-03 17:57:59 +09001273
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001274 int change = isPackageDisappearing(imi.getPackageName());
satoke7c6998e2011-06-03 17:57:59 +09001275 if (isPackageModified(imi.getPackageName())) {
Yohei Yukawab557d572018-12-29 21:26:26 -08001276 mAdditionalSubtypeMap.remove(imi.getId());
1277 AdditionalSubtypeUtils.save(mAdditionalSubtypeMap, mMethodMap,
1278 mSettings.getCurrentUserId());
satoke7c6998e2011-06-03 17:57:59 +09001279 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001280 if (change == PACKAGE_TEMPORARY_CHANGE
1281 || change == PACKAGE_PERMANENT_CHANGE) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001282 Slog.i(TAG, "Input method uninstalled, disabling: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001283 + imi.getComponent());
1284 setInputMethodEnabledLocked(imi.getId(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 }
1286 }
1287 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001288
Yohei Yukawa94e33302016-02-12 19:37:03 -08001289 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001290
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 boolean changed = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001292
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001293 if (curIm != null) {
Anna Galusza9b278112016-01-04 11:37:37 -08001294 int change = isPackageDisappearing(curIm.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001295 if (change == PACKAGE_TEMPORARY_CHANGE
1296 || change == PACKAGE_PERMANENT_CHANGE) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001297 ServiceInfo si = null;
1298 try {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001299 si = mIPackageManager.getServiceInfo(
1300 curIm.getComponent(), 0, mSettings.getCurrentUserId());
1301 } catch (RemoteException ex) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001302 }
1303 if (si == null) {
1304 // Uh oh, current input method is no longer around!
1305 // Pick another one...
Joe Onorato8a9b2202010-02-26 18:56:32 -08001306 Slog.i(TAG, "Current input method removed: " + curInputMethodId);
Yohei Yukawa849443c2019-01-21 09:02:25 -08001307 updateSystemUiLocked(0 /* vis */, mBackDisposition);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001308 if (!chooseNewDefaultIMELocked()) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001309 changed = true;
1310 curIm = null;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001311 Slog.i(TAG, "Unsetting current input method");
satok723a27e2010-11-11 14:58:11 +09001312 resetSelectedInputMethodAndSubtypeLocked("");
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001313 }
1314 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001315 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001316 }
satokab751aa2010-09-14 19:17:36 +09001317
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001318 if (curIm == null) {
1319 // We currently don't have a default input method... is
1320 // one now available?
1321 changed = chooseNewDefaultIMELocked();
Yohei Yukawa54d512c2015-05-19 22:15:02 -07001322 } else if (!changed && isPackageModified(curIm.getPackageName())) {
1323 // Even if the current input method is still available, mCurrentSubtype could
1324 // be obsolete when the package is modified in practice.
1325 changed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001326 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001327
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001328 if (changed) {
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08001329 updateFromSettingsLocked(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001330 }
1331 }
1332 }
1333 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001334
Jeff Brownc28867a2013-03-26 15:42:39 -07001335 private static final class MethodCallback extends IInputSessionCallback.Stub {
Jean Chalarde0d32a62011-10-20 20:36:07 +09001336 private final InputMethodManagerService mParentIMMS;
Jeff Brownc28867a2013-03-26 15:42:39 -07001337 private final IInputMethod mMethod;
1338 private final InputChannel mChannel;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001339
Jeff Brownc28867a2013-03-26 15:42:39 -07001340 MethodCallback(InputMethodManagerService imms, IInputMethod method,
1341 InputChannel channel) {
Jean Chalarde0d32a62011-10-20 20:36:07 +09001342 mParentIMMS = imms;
Jeff Brownc28867a2013-03-26 15:42:39 -07001343 mMethod = method;
1344 mChannel = channel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001345 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001346
satoke7c6998e2011-06-03 17:57:59 +09001347 @Override
Jeff Brownc28867a2013-03-26 15:42:39 -07001348 public void sessionCreated(IInputMethodSession session) {
Dianne Hackborn6b6b3fd2014-03-24 11:27:18 -07001349 long ident = Binder.clearCallingIdentity();
1350 try {
1351 mParentIMMS.onSessionCreated(mMethod, session, mChannel);
1352 } finally {
1353 Binder.restoreCallingIdentity(ident);
1354 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001355 }
1356 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001357
satok01038492012-04-09 21:08:27 +09001358 private class HardKeyboardListener
Seigo Nonaka7309b122015-08-17 18:34:13 -07001359 implements WindowManagerInternal.OnHardKeyboardStatusChangeListener {
satok01038492012-04-09 21:08:27 +09001360 @Override
Michael Wright7b5a96b2014-08-09 19:28:42 -07001361 public void onHardKeyboardStatusChange(boolean available) {
1362 mHandler.sendMessage(mHandler.obtainMessage(MSG_HARD_KEYBOARD_SWITCH_CHANGED,
1363 available ? 1 : 0));
satok01038492012-04-09 21:08:27 +09001364 }
1365
Michael Wright7b5a96b2014-08-09 19:28:42 -07001366 public void handleHardKeyboardStatusChange(boolean available) {
satok01038492012-04-09 21:08:27 +09001367 if (DEBUG) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07001368 Slog.w(TAG, "HardKeyboardStatusChanged: available=" + available);
satok01038492012-04-09 21:08:27 +09001369 }
1370 synchronized(mMethodMap) {
1371 if (mSwitchingDialog != null && mSwitchingDialogTitleView != null
1372 && mSwitchingDialog.isShowing()) {
1373 mSwitchingDialogTitleView.findViewById(
1374 com.android.internal.R.id.hard_keyboard_section).setVisibility(
1375 available ? View.VISIBLE : View.GONE);
1376 }
1377 }
1378 }
1379 }
1380
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001381 public static final class Lifecycle extends SystemService {
1382 private InputMethodManagerService mService;
1383
1384 public Lifecycle(Context context) {
1385 super(context);
1386 mService = new InputMethodManagerService(context);
1387 }
1388
1389 @Override
1390 public void onStart() {
1391 LocalServices.addService(InputMethodManagerInternal.class,
Yohei Yukawafffc0e52018-09-04 13:24:00 -07001392 new LocalServiceImpl(mService));
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001393 publishBinderService(Context.INPUT_METHOD_SERVICE, mService);
1394 }
1395
1396 @Override
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001397 public void onSwitchUser(@UserIdInt int userHandle) {
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07001398 // Called on ActivityManager thread.
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001399 // TODO: Dispatch this to a worker thread as needed.
1400 mService.onSwitchUser(userHandle);
1401 }
1402
1403 @Override
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001404 public void onBootPhase(int phase) {
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07001405 // Called on ActivityManager thread.
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001406 // TODO: Dispatch this to a worker thread as needed.
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001407 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
1408 StatusBarManagerService statusBarService = (StatusBarManagerService) ServiceManager
1409 .getService(Context.STATUS_BAR_SERVICE);
1410 mService.systemRunning(statusBarService);
1411 }
1412 }
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001413
1414 @Override
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07001415 public void onUnlockUser(final @UserIdInt int userHandle) {
1416 // Called on ActivityManager thread.
1417 mService.mHandler.sendMessage(mService.mHandler.obtainMessage(MSG_SYSTEM_UNLOCK_USER,
Fyodor Kupolov0f57cce2016-09-09 10:36:30 -07001418 userHandle /* arg1 */, 0 /* arg2 */));
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001419 }
1420 }
1421
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001422 void onUnlockUser(@UserIdInt int userId) {
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001423 synchronized(mMethodMap) {
1424 final int currentUserId = mSettings.getCurrentUserId();
1425 if (DEBUG) {
1426 Slog.d(TAG, "onUnlockUser: userId=" + userId + " curUserId=" + currentUserId);
1427 }
1428 if (userId != currentUserId) {
1429 return;
1430 }
1431 mSettings.switchCurrentUser(currentUserId, !mSystemReady);
Yohei Yukawa79247822017-01-23 15:26:15 -08001432 if (mSystemReady) {
1433 // We need to rebuild IMEs.
1434 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
1435 updateInputMethodsFromSettingsLocked(true /* enabledChanged */);
1436 }
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001437 }
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001438 }
1439
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001440 void onSwitchUser(@UserIdInt int userId) {
1441 synchronized (mMethodMap) {
1442 switchUserLocked(userId);
1443 }
1444 }
1445
Seigo Nonaka7309b122015-08-17 18:34:13 -07001446 public InputMethodManagerService(Context context) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001447 mIPackageManager = AppGlobals.getPackageManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 mContext = context;
Dianne Hackborn7d3a5bc2010-11-29 22:52:12 -08001449 mRes = context.getResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001450 mHandler = new Handler(this);
Yohei Yukawa81482972015-06-04 00:58:59 -07001451 // Note: SettingsObserver doesn't register observers in its constructor.
1452 mSettingsObserver = new SettingsObserver(mHandler);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001453 mIWindowManager = IWindowManager.Stub.asInterface(
1454 ServiceManager.getService(Context.WINDOW_SERVICE));
Seigo Nonaka7309b122015-08-17 18:34:13 -07001455 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
Yohei Yukawab4f328a2019-05-02 08:41:27 -07001456 mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
lumark9a72d222019-03-30 18:31:45 +08001457 mImeDisplayValidator = displayId -> mWindowManagerInternal.shouldShowIme(displayId);
Mita Yuned218c72012-12-06 17:18:25 -08001458 mCaller = new HandlerCaller(context, null, new HandlerCaller.Callback() {
satoke7c6998e2011-06-03 17:57:59 +09001459 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 public void executeMessage(Message msg) {
1461 handleMessage(msg);
1462 }
Mita Yuned218c72012-12-06 17:18:25 -08001463 }, true /*asyncHandler*/);
Yohei Yukawad34e1482016-02-11 08:03:52 -08001464 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001465 mUserManager = mContext.getSystemService(UserManager.class);
Yohei Yukawa42081402019-01-15 09:57:50 -08001466 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
satok01038492012-04-09 21:08:27 +09001467 mHardKeyboardListener = new HardKeyboardListener();
Dianne Hackborn119bbc32013-03-22 17:27:25 -07001468 mHasFeature = context.getPackageManager().hasSystemFeature(
1469 PackageManager.FEATURE_INPUT_METHODS);
Jason Monk3e189872016-01-12 09:10:34 -05001470 mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
Tarandeep Singheadb1392018-11-09 18:15:57 +01001471 mIsLowRam = ActivityManager.isLowRamDeviceStatic();
satok7cfc0ed2011-06-20 21:29:36 +09001472
Chris Wren1ce4b6d2015-06-11 10:19:43 -04001473 Bundle extras = new Bundle();
1474 extras.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, true);
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001475 @ColorInt final int accentColor = mContext.getColor(
1476 com.android.internal.R.color.system_notification_accent_color);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05001477 mImeSwitcherNotification =
1478 new Notification.Builder(mContext, SystemNotificationChannels.VIRTUAL_KEYBOARD)
1479 .setSmallIcon(com.android.internal.R.drawable.ic_notification_ime_default)
1480 .setWhen(0)
1481 .setOngoing(true)
1482 .addExtras(extras)
1483 .setCategory(Notification.CATEGORY_SYSTEM)
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001484 .setColor(accentColor);
Daniel Sandler590d5152012-06-14 16:10:13 -04001485
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001486 Intent intent = new Intent(ACTION_SHOW_INPUT_METHOD_PICKER)
1487 .setPackage(mContext.getPackageName());
satok683e2382011-07-12 08:28:52 +09001488 mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
satokb858c732011-07-22 19:54:34 +09001489
1490 mShowOngoingImeSwitcherForPhones = false;
satok7cfc0ed2011-06-20 21:29:36 +09001491
satok7cfc0ed2011-06-20 21:29:36 +09001492 mNotificationShown = false;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001493 int userId = 0;
1494 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001495 userId = ActivityManager.getService().getCurrentUser().id;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001496 } catch (RemoteException e) {
1497 Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
1498 }
satok913a8922010-08-26 21:53:41 +09001499
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08001500 mLastSwitchUserId = userId;
1501
satokd87c2592010-09-29 11:52:06 +09001502 // mSettings should be created before buildInputMethodListLocked
satokdf31ae62011-01-15 06:19:44 +09001503 mSettings = new InputMethodSettings(
Yohei Yukawaf9277532019-01-25 02:47:32 -08001504 mRes, context.getContentResolver(), mMethodMap, userId, !mSystemReady);
Svet Ganovadc1cf42015-06-15 16:36:24 -07001505
Kenny Guy2a764942014-04-02 13:29:20 +01001506 updateCurrentProfileIds();
Yohei Yukawab557d572018-12-29 21:26:26 -08001507 AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, userId);
Yohei Yukawa79247822017-01-23 15:26:15 -08001508 mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
1509 mSettings, context);
satok5b927c432012-05-01 20:09:34 +09001510 }
1511
satok5b927c432012-05-01 20:09:34 +09001512 private void resetDefaultImeLocked(Context context) {
1513 // Do not reset the default (current) IME when it is a 3rd-party IME
Yohei Yukawafd70fe82018-04-08 12:19:56 -07001514 if (mCurMethodId != null && !mMethodMap.get(mCurMethodId).isSystem()) {
satok5b927c432012-05-01 20:09:34 +09001515 return;
1516 }
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001517 final List<InputMethodInfo> suitableImes = InputMethodUtils.getDefaultEnabledImes(
Yohei Yukawaaf5cee82017-01-23 16:17:11 -08001518 context, mSettings.getEnabledInputMethodListLocked());
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001519 if (suitableImes.isEmpty()) {
1520 Slog.i(TAG, "No default found");
1521 return;
satok5b927c432012-05-01 20:09:34 +09001522 }
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001523 final InputMethodInfo defIm = suitableImes.get(0);
Yohei Yukawad0332832017-02-01 13:59:43 -08001524 if (DEBUG) {
1525 Slog.i(TAG, "Default found, using " + defIm.getId());
1526 }
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001527 setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
satok5b927c432012-05-01 20:09:34 +09001528 }
1529
Andreas Gampea36dc622018-02-05 17:19:22 -08001530 @GuardedBy("mMethodMap")
Satoshi Kataoka5ade83b2012-09-26 22:59:41 +09001531 private void switchUserLocked(int newUserId) {
Yohei Yukawa90bf7082015-06-03 23:50:27 -07001532 if (DEBUG) Slog.d(TAG, "Switching user stage 1/3. newUserId=" + newUserId
1533 + " currentUserId=" + mSettings.getCurrentUserId());
1534
Yohei Yukawa81482972015-06-04 00:58:59 -07001535 // ContentObserver should be registered again when the user is changed
1536 mSettingsObserver.registerContentObserverLocked(newUserId);
Yohei Yukawa68645a62016-02-17 07:54:20 -08001537
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001538 // If the system is not ready or the device is not yed unlocked by the user, then we use
1539 // copy-on-write settings.
1540 final boolean useCopyOnWriteSettings =
Yohei Yukawa42081402019-01-15 09:57:50 -08001541 !mSystemReady || !mUserManagerInternal.isUserUnlockingOrUnlocked(newUserId);
Yohei Yukawa68645a62016-02-17 07:54:20 -08001542 mSettings.switchCurrentUser(newUserId, useCopyOnWriteSettings);
Kenny Guy2a764942014-04-02 13:29:20 +01001543 updateCurrentProfileIds();
Yohei Yukawab557d572018-12-29 21:26:26 -08001544 // Additional subtypes should be reset when the user is changed
1545 AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, newUserId);
Satoshi Kataoka7f7535f2013-02-18 12:54:16 +09001546 final String defaultImiId = mSettings.getSelectedInputMethod();
Yohei Yukawa90bf7082015-06-03 23:50:27 -07001547
1548 if (DEBUG) Slog.d(TAG, "Switching user stage 2/3. newUserId=" + newUserId
1549 + " defaultImiId=" + defaultImiId);
1550
Satoshi Kataoka7c4a2a12013-02-25 15:25:43 +09001551 // For secondary users, the list of enabled IMEs may not have been updated since the
1552 // callbacks to PackageMonitor are ignored for the secondary user. Here, defaultImiId may
1553 // not be empty even if the IME has been uninstalled by the primary user.
1554 // Even in such cases, IMMS works fine because it will find the most applicable
1555 // IME for that user.
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09001556 final boolean initialUserSwitch = TextUtils.isEmpty(defaultImiId);
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001557 mLastSystemLocales = mRes.getConfiguration().getLocales();
1558
1559 // TODO: Is it really possible that switchUserLocked() happens before system ready?
1560 if (mSystemReady) {
1561 hideCurrentInputLocked(0, null);
Yohei Yukawab7526452018-10-21 20:15:17 -07001562 resetCurrentMethodAndClient(UnbindReason.SWITCH_USER);
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001563 buildInputMethodListLocked(initialUserSwitch);
1564 if (TextUtils.isEmpty(mSettings.getSelectedInputMethod())) {
1565 // This is the first time of the user switch and
1566 // set the current ime to the proper one.
1567 resetDefaultImeLocked(mContext);
1568 }
1569 updateFromSettingsLocked(true);
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001570 }
1571
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09001572 if (initialUserSwitch) {
Yohei Yukawa094c71f2015-06-20 00:41:31 -07001573 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
1574 mSettings.getEnabledInputMethodListLocked(), newUserId,
1575 mContext.getBasePackageName());
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09001576 }
Yohei Yukawa90bf7082015-06-03 23:50:27 -07001577
1578 if (DEBUG) Slog.d(TAG, "Switching user stage 3/3. newUserId=" + newUserId
1579 + " selectedIme=" + mSettings.getSelectedInputMethod());
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08001580
1581 mLastSwitchUserId = newUserId;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001582 }
1583
Kenny Guy2a764942014-04-02 13:29:20 +01001584 void updateCurrentProfileIds() {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -07001585 mSettings.setCurrentProfileIds(
1586 mUserManager.getProfileIdsWithDisabled(mSettings.getCurrentUserId()));
Amith Yamasani734983f2014-03-04 16:48:05 -08001587 }
1588
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001589 @Override
1590 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1591 throws RemoteException {
1592 try {
1593 return super.onTransact(code, data, reply, flags);
1594 } catch (RuntimeException e) {
1595 // The input method manager only throws security exceptions, so let's
1596 // log all others.
1597 if (!(e instanceof SecurityException)) {
Dianne Hackborn164371f2013-10-01 19:10:13 -07001598 Slog.wtf(TAG, "Input Method Manager Crash", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001599 }
1600 throw e;
1601 }
1602 }
1603
Svetoslav Ganova0027152013-06-25 14:59:53 -07001604 public void systemRunning(StatusBarManagerService statusBar) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07001605 synchronized (mMethodMap) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001606 if (DEBUG) {
1607 Slog.d(TAG, "--- systemReady");
1608 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07001609 if (!mSystemReady) {
1610 mSystemReady = true;
Yohei Yukawa79247822017-01-23 15:26:15 -08001611 mLastSystemLocales = mRes.getConfiguration().getLocales();
Yohei Yukawa68645a62016-02-17 07:54:20 -08001612 final int currentUserId = mSettings.getCurrentUserId();
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001613 mSettings.switchCurrentUser(currentUserId,
Yohei Yukawa42081402019-01-15 09:57:50 -08001614 !mUserManagerInternal.isUserUnlockingOrUnlocked(currentUserId));
Yohei Yukawad34e1482016-02-11 08:03:52 -08001615 mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
1616 mNotificationManager = mContext.getSystemService(NotificationManager.class);
Dianne Hackborn661cd522011-08-22 00:26:20 -07001617 mStatusBar = statusBar;
Griff Hazen6090c262016-03-25 08:11:24 -07001618 if (mStatusBar != null) {
1619 mStatusBar.setIconVisibility(mSlotIme, false);
1620 }
Yohei Yukawa849443c2019-01-21 09:02:25 -08001621 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
satokb858c732011-07-22 19:54:34 +09001622 mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
1623 com.android.internal.R.bool.show_ongoing_ime_switcher);
satok01038492012-04-09 21:08:27 +09001624 if (mShowOngoingImeSwitcherForPhones) {
Seigo Nonaka7309b122015-08-17 18:34:13 -07001625 mWindowManagerInternal.setOnHardKeyboardStatusChangeListener(
satok01038492012-04-09 21:08:27 +09001626 mHardKeyboardListener);
1627 }
Yohei Yukawa79247822017-01-23 15:26:15 -08001628
1629 mMyPackageMonitor.register(mContext, null, UserHandle.ALL, true);
1630 mSettingsObserver.registerContentObserverLocked(currentUserId);
1631
Yohei Yukawa0ec08002019-03-08 10:48:26 -08001632 final IntentFilter broadcastFilterForSystemUser = new IntentFilter();
1633 broadcastFilterForSystemUser.addAction(Intent.ACTION_USER_ADDED);
1634 broadcastFilterForSystemUser.addAction(Intent.ACTION_USER_REMOVED);
1635 broadcastFilterForSystemUser.addAction(Intent.ACTION_LOCALE_CHANGED);
1636 broadcastFilterForSystemUser.addAction(ACTION_SHOW_INPUT_METHOD_PICKER);
1637 mContext.registerReceiver(new ImmsBroadcastReceiverForSystemUser(),
1638 broadcastFilterForSystemUser);
1639
1640 final IntentFilter broadcastFilterForAllUsers = new IntentFilter();
1641 broadcastFilterForAllUsers.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
1642 mContext.registerReceiverAsUser(new ImmsBroadcastReceiverForAllUsers(),
1643 UserHandle.ALL, broadcastFilterForAllUsers, null, null);
Yohei Yukawa79247822017-01-23 15:26:15 -08001644
Yohei Yukawa1f9a3cb2017-10-26 15:00:59 -07001645 final String defaultImiId = mSettings.getSelectedInputMethod();
1646 final boolean imeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId);
1647 buildInputMethodListLocked(!imeSelectedOnBoot /* resetDefaultEnabledIme */);
Yohei Yukawa79247822017-01-23 15:26:15 -08001648 updateFromSettingsLocked(true);
1649 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
1650 mSettings.getEnabledInputMethodListLocked(), currentUserId,
1651 mContext.getBasePackageName());
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07001652 }
1653 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001654 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001655
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001656 // ---------------------------------------------------------------------------------------
1657 // Check whether or not this is a valid IPC. Assumes an IPC is valid when either
1658 // 1) it comes from the system process
1659 // 2) the calling process' user id is identical to the current user id IMMS thinks.
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08001660 @GuardedBy("mMethodMap")
Yohei Yukawa46d74762019-01-22 10:17:22 -08001661 private boolean calledFromValidUserLocked() {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001662 final int uid = Binder.getCallingUid();
1663 final int userId = UserHandle.getUserId(uid);
1664 if (DEBUG) {
1665 Slog.d(TAG, "--- calledFromForegroundUserOrSystemProcess ? "
1666 + "calling uid = " + uid + " system uid = " + Process.SYSTEM_UID
1667 + " calling userId = " + userId + ", foreground user id = "
Satoshi Kataoka87c29142013-07-31 23:11:54 +09001668 + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid()
1669 + InputMethodUtils.getApiCallStack());
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001670 }
Yohei Yukawaa878b952019-01-10 19:36:24 -08001671 if (uid == Process.SYSTEM_UID) {
1672 return true;
1673 }
1674 if (userId == mSettings.getCurrentUserId()) {
1675 return true;
1676 }
Satoshi Kataoka135e5fb2012-09-28 18:25:06 +09001677
1678 // Caveat: A process which has INTERACT_ACROSS_USERS_FULL gets results for the
1679 // foreground user, not for the user of that process. Accordingly InputMethodManagerService
1680 // must not manage background users' states in any functions.
1681 // Note that privacy-sensitive IPCs, such as setInputMethod, are still securely guarded
1682 // by a token.
1683 if (mContext.checkCallingOrSelfPermission(
1684 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1685 == PackageManager.PERMISSION_GRANTED) {
1686 if (DEBUG) {
1687 Slog.d(TAG, "--- Access granted because the calling process has "
1688 + "the INTERACT_ACROSS_USERS_FULL permission");
1689 }
1690 return true;
1691 }
Yohei Yukawad0332832017-02-01 13:59:43 -08001692 // TODO(b/34886274): The semantics of this verification is actually not well-defined.
Seigo Nonakae27dc2b2015-08-14 18:21:27 -07001693 Slog.w(TAG, "--- IPC called from background users. Ignore. callers="
1694 + Debug.getCallers(10));
Satoshi Kataoka135e5fb2012-09-28 18:25:06 +09001695 return false;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001696 }
1697
Yohei Yukawa22c97be2014-06-04 19:43:36 +09001698
1699 /**
1700 * Returns true iff the caller is identified to be the current input method with the token.
1701 * @param token The window token given to the input method when it was started.
1702 * @return true if and only if non-null valid token is specified.
1703 */
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08001704 @GuardedBy("mMethodMap")
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08001705 private boolean calledWithValidTokenLocked(@NonNull IBinder token) {
1706 if (token == null) {
1707 throw new InvalidParameterException("token must not be null.");
Yohei Yukawad0332832017-02-01 13:59:43 -08001708 }
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08001709 if (token != mCurToken) {
Yohei Yukawad0332832017-02-01 13:59:43 -08001710 Slog.e(TAG, "Ignoring " + Debug.getCaller() + " due to an invalid token."
1711 + " uid:" + Binder.getCallingUid() + " token:" + token);
Yohei Yukawa22c97be2014-06-04 19:43:36 +09001712 return false;
1713 }
1714 return true;
1715 }
1716
Yohei Yukawaf80087c2018-05-21 09:47:53 -07001717 @GuardedBy("mMethodMap")
1718 private boolean bindCurrentInputMethodServiceLocked(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001719 Intent service, ServiceConnection conn, int flags) {
1720 if (service == null || conn == null) {
1721 Slog.e(TAG, "--- bind failed: service = " + service + ", conn = " + conn);
1722 return false;
1723 }
Amith Yamasani27b89e62013-01-16 12:30:11 -08001724 return mContext.bindServiceAsUser(service, conn, flags,
1725 new UserHandle(mSettings.getCurrentUserId()));
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001726 }
1727
satoke7c6998e2011-06-03 17:57:59 +09001728 @Override
Yohei Yukawad20eef82019-02-05 10:45:32 -08001729 public List<InputMethodInfo> getInputMethodList(@UserIdInt int userId) {
1730 if (UserHandle.getCallingUserId() != userId) {
1731 mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
1732 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001733 synchronized (mMethodMap) {
Yohei Yukawad20eef82019-02-05 10:45:32 -08001734 final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001735 mSettings.getCurrentUserId(), null);
1736 if (resolvedUserIds.length != 1) {
1737 return Collections.emptyList();
1738 }
1739 final long ident = Binder.clearCallingIdentity();
1740 try {
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08001741 return getInputMethodListLocked(resolvedUserIds[0]);
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001742 } finally {
1743 Binder.restoreCallingIdentity(ident);
Tarandeep Singh89a6c482017-11-21 14:26:11 -08001744 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001745 }
1746 }
1747
satoke7c6998e2011-06-03 17:57:59 +09001748 @Override
Yohei Yukawa1fb13c52019-02-05 07:55:28 -08001749 public List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) {
1750 if (UserHandle.getCallingUserId() != userId) {
1751 mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
1752 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001753 synchronized (mMethodMap) {
Yohei Yukawa1fb13c52019-02-05 07:55:28 -08001754 final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001755 mSettings.getCurrentUserId(), null);
1756 if (resolvedUserIds.length != 1) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08001757 return Collections.emptyList();
1758 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001759 final long ident = Binder.clearCallingIdentity();
1760 try {
1761 return getEnabledInputMethodListLocked(resolvedUserIds[0]);
1762 } finally {
1763 Binder.restoreCallingIdentity(ident);
1764 }
1765 }
1766 }
1767
1768 @GuardedBy("mMethodMap")
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08001769 private List<InputMethodInfo> getInputMethodListLocked(@UserIdInt int userId) {
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001770 final ArrayList<InputMethodInfo> methodList;
1771 if (userId == mSettings.getCurrentUserId()) {
1772 // Create a copy.
1773 methodList = new ArrayList<>(mMethodList);
1774 } else {
1775 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
1776 methodList = new ArrayList<>();
1777 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
1778 new ArrayMap<>();
1779 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
1780 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
1781 methodList);
1782 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001783 return methodList;
1784 }
1785
1786 @GuardedBy("mMethodMap")
1787 private List<InputMethodInfo> getEnabledInputMethodListLocked(@UserIdInt int userId) {
1788 if (userId == mSettings.getCurrentUserId()) {
satokd87c2592010-09-29 11:52:06 +09001789 return mSettings.getEnabledInputMethodListLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001790 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001791 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
1792 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
1793 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
1794 new ArrayMap<>();
1795 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
1796 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
1797 methodList);
1798 final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
Yohei Yukawaf9277532019-01-25 02:47:32 -08001799 mContext.getContentResolver(), methodMap, userId, true);
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001800 return settings.getEnabledInputMethodListLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001801 }
1802
Adam Hebc67f2e2019-11-13 14:34:56 -08001803 @GuardedBy("mMethodMap")
Feng Cao16b2de52020-01-09 17:27:27 -08001804 private void onCreateInlineSuggestionsRequestLocked(@UserIdInt int userId,
1805 ComponentName componentName, AutofillId autofillId,
1806 IInlineSuggestionsRequestCallback callback) {
Adam He7bc8f602019-12-12 17:00:34 -08001807 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
1808 try {
Feng Cao16b2de52020-01-09 17:27:27 -08001809 if (userId == mSettings.getCurrentUserId() && imi != null
1810 && imi.isInlineSuggestionsEnabled() && mCurMethod != null) {
Adam He7bc8f602019-12-12 17:00:34 -08001811 executeOrSendMessage(mCurMethod,
1812 mCaller.obtainMessageOOOO(MSG_INLINE_SUGGESTIONS_REQUEST, mCurMethod,
Feng Cao16b2de52020-01-09 17:27:27 -08001813 componentName, autofillId,
1814 new InlineSuggestionsRequestCallbackDecorator(callback,
1815 imi.getPackageName())));
Adam He7bc8f602019-12-12 17:00:34 -08001816 } else {
1817 callback.onInlineSuggestionsUnsupported();
1818 }
1819 } catch (RemoteException e) {
1820 Slog.w(TAG, "RemoteException calling onCreateInlineSuggestionsRequest(): " + e);
Adam Hebc67f2e2019-11-13 14:34:56 -08001821 }
1822 }
1823
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09001824 /**
Feng Cao16b2de52020-01-09 17:27:27 -08001825 * The decorator which validates the host package name in the
1826 * {@link InlineSuggestionsRequest} argument to make sure it matches the IME package name.
1827 */
1828 private static final class InlineSuggestionsRequestCallbackDecorator
1829 extends IInlineSuggestionsRequestCallback.Stub {
1830 @NonNull
1831 private final IInlineSuggestionsRequestCallback mCallback;
1832 @NonNull
1833 private final String mImePackageName;
1834
1835 InlineSuggestionsRequestCallbackDecorator(
1836 @NonNull IInlineSuggestionsRequestCallback callback,
1837 @NonNull String imePackageName) {
1838 mCallback = callback;
1839 mImePackageName = imePackageName;
1840 }
1841
1842 @Override
1843 public void onInlineSuggestionsUnsupported() throws RemoteException {
1844 mCallback.onInlineSuggestionsUnsupported();
1845 }
1846
1847 @Override
1848 public void onInlineSuggestionsRequest(InlineSuggestionsRequest request,
1849 IInlineSuggestionsResponseCallback callback) throws RemoteException {
1850 if (!mImePackageName.equals(request.getHostPackageName())) {
1851 throw new SecurityException(
1852 "Host package name in the provide request=[" + request.getHostPackageName()
1853 + "] doesn't match the IME package name=[" + mImePackageName
1854 + "].");
1855 }
1856 mCallback.onInlineSuggestionsRequest(request, callback);
1857 }
1858 }
1859
1860 /**
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09001861 * @param imiId if null, returns enabled subtypes for the current imi
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09001862 * @return enabled subtypes of the specified imi
1863 */
satoke7c6998e2011-06-03 17:57:59 +09001864 @Override
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09001865 public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
satok16331c82010-12-20 23:48:46 +09001866 boolean allowsImplicitlySelectedSubtypes) {
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001867 final int callingUserId = UserHandle.getCallingUserId();
satok67ddf9c2010-11-17 09:45:54 +09001868 synchronized (mMethodMap) {
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001869 final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
1870 mSettings.getCurrentUserId(), null);
1871 if (resolvedUserIds.length != 1) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08001872 return Collections.emptyList();
1873 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001874 final long ident = Binder.clearCallingIdentity();
1875 try {
1876 return getEnabledInputMethodSubtypeListLocked(imiId,
1877 allowsImplicitlySelectedSubtypes, resolvedUserIds[0]);
1878 } finally {
1879 Binder.restoreCallingIdentity(ident);
1880 }
1881 }
1882 }
1883
1884 @GuardedBy("mMethodMap")
1885 private List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(String imiId,
1886 boolean allowsImplicitlySelectedSubtypes, @UserIdInt int userId) {
1887 if (userId == mSettings.getCurrentUserId()) {
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09001888 final InputMethodInfo imi;
1889 if (imiId == null && mCurMethodId != null) {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09001890 imi = mMethodMap.get(mCurMethodId);
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09001891 } else {
1892 imi = mMethodMap.get(imiId);
1893 }
1894 if (imi == null) {
Yohei Yukawab0377bb2015-08-10 21:06:30 -07001895 return Collections.emptyList();
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09001896 }
1897 return mSettings.getEnabledInputMethodSubtypeListLocked(
1898 mContext, imi, allowsImplicitlySelectedSubtypes);
satok67ddf9c2010-11-17 09:45:54 +09001899 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001900 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
1901 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
1902 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
1903 new ArrayMap<>();
1904 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
1905 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
1906 methodList);
1907 final InputMethodInfo imi = methodMap.get(imiId);
1908 if (imi == null) {
1909 return Collections.emptyList();
1910 }
1911 final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
Yohei Yukawaf9277532019-01-25 02:47:32 -08001912 mContext.getContentResolver(), methodMap, userId, true);
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001913 return settings.getEnabledInputMethodSubtypeListLocked(
1914 mContext, imi, allowsImplicitlySelectedSubtypes);
satok67ddf9c2010-11-17 09:45:54 +09001915 }
1916
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001917 /**
1918 * Called by each application process as a preparation to start interacting with
1919 * {@link InputMethodManagerService}.
1920 *
1921 * <p>As a general principle, IPCs from the application process that take
Yohei Yukawa499e3f72018-10-21 20:15:11 -07001922 * {@link IInputMethodClient} will be rejected without this step.</p>
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001923 *
1924 * @param client {@link android.os.Binder} proxy that is associated with the singleton instance
1925 * of {@link android.view.inputmethod.InputMethodManager} that runs on the client
1926 * process
1927 * @param inputContext communication channel for the dummy
1928 * {@link android.view.inputmethod.InputConnection}
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08001929 * @param selfReportedDisplayId self-reported display ID to which the client is associated.
1930 * Whether the client is still allowed to access to this display
1931 * or not needs to be evaluated every time the client interacts
1932 * with the display
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001933 */
1934 @Override
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08001935 public void addClient(IInputMethodClient client, IInputContext inputContext,
1936 int selfReportedDisplayId) {
Yohei Yukawacb768bc2018-10-24 16:05:09 -07001937 // Here there are two scenarios where this method is called:
1938 // A. IMM is being instantiated in a different process and this is an IPC from that process
1939 // B. IMM is being instantiated in the same process but Binder.clearCallingIdentity() is
1940 // called in the caller side if necessary.
1941 // In either case the following UID/PID should be the ones where InputMethodManager is
1942 // actually running.
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001943 final int callerUid = Binder.getCallingUid();
1944 final int callerPid = Binder.getCallingPid();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001945 synchronized (mMethodMap) {
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001946 // TODO: Optimize this linear search.
Yohei Yukawaac9311e2018-11-20 19:25:23 -08001947 final int numClients = mClients.size();
1948 for (int i = 0; i < numClients; ++i) {
1949 final ClientState state = mClients.valueAt(i);
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08001950 if (state.uid == callerUid && state.pid == callerPid
1951 && state.selfReportedDisplayId == selfReportedDisplayId) {
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001952 throw new SecurityException("uid=" + callerUid + "/pid=" + callerPid
Yohei Yukawacb768bc2018-10-24 16:05:09 -07001953 + "/displayId=" + selfReportedDisplayId + " is already registered.");
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001954 }
1955 }
1956 final ClientDeathRecipient deathRecipient = new ClientDeathRecipient(this, client);
1957 try {
1958 client.asBinder().linkToDeath(deathRecipient, 0);
1959 } catch (RemoteException e) {
1960 throw new IllegalStateException(e);
1961 }
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08001962 // We cannot fully avoid race conditions where the client UID already lost the access to
1963 // the given self-reported display ID, even if the client is not maliciously reporting
1964 // a fake display ID. Unconditionally returning SecurityException just because the
1965 // client doesn't pass display ID verification can cause many test failures hence not an
1966 // option right now. At the same time
1967 // context.getSystemService(InputMethodManager.class)
1968 // is expected to return a valid non-null instance at any time if we do not choose to
1969 // have the client crash. Thus we do not verify the display ID at all here. Instead we
1970 // later check the display ID every time the client needs to interact with the specified
1971 // display.
1972 mClients.put(client.asBinder(), new ClientState(client, inputContext, callerUid,
1973 callerPid, selfReportedDisplayId, deathRecipient));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001974 }
1975 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001976
Yohei Yukawae24ed792018-08-28 19:10:32 -07001977 void removeClient(IInputMethodClient client) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001978 synchronized (mMethodMap) {
Jeff Brownc28867a2013-03-26 15:42:39 -07001979 ClientState cs = mClients.remove(client.asBinder());
1980 if (cs != null) {
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001981 client.asBinder().unlinkToDeath(cs.clientDeathRecipient, 0);
Jeff Brownc28867a2013-03-26 15:42:39 -07001982 clearClientSessionLocked(cs);
Yohei Yukawab4f328a2019-05-02 08:41:27 -07001983
1984 final int numItems = mActivityViewDisplayIdToParentMap.size();
1985 for (int i = numItems - 1; i >= 0; --i) {
1986 final ActivityViewInfo info = mActivityViewDisplayIdToParentMap.valueAt(i);
1987 if (info.mParentClient == cs) {
1988 mActivityViewDisplayIdToParentMap.removeAt(i);
1989 }
1990 }
1991
Yohei Yukawa072b1b52015-11-18 15:54:34 -08001992 if (mCurClient == cs) {
Tarandeep Singh93c00cea2018-02-16 14:31:17 -08001993 if (mBoundToMethod) {
1994 mBoundToMethod = false;
1995 if (mCurMethod != null) {
1996 executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
1997 MSG_UNBIND_INPUT, mCurMethod));
1998 }
1999 }
Yohei Yukawa072b1b52015-11-18 15:54:34 -08002000 mCurClient = null;
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002001 mCurActivityViewToScreenMatrix = null;
Yohei Yukawa072b1b52015-11-18 15:54:34 -08002002 }
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08002003 if (mCurFocusedWindowClient == cs) {
2004 mCurFocusedWindowClient = null;
2005 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002006 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002007 }
2008 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002009
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002010 void executeOrSendMessage(IInterface target, Message msg) {
2011 if (target.asBinder() instanceof Binder) {
2012 mCaller.sendMessage(msg);
2013 } else {
2014 handleMessage(msg);
2015 msg.recycle();
2016 }
2017 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002018
Yohei Yukawa4afd9332018-10-21 10:43:53 -07002019 void unbindCurrentClientLocked(@UnbindReason int unbindClientReason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002020 if (mCurClient != null) {
Yohei Yukawa35d3f372015-11-25 11:07:19 -08002021 if (DEBUG) Slog.v(TAG, "unbindCurrentInputLocked: client="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002022 + mCurClient.client.asBinder());
2023 if (mBoundToMethod) {
2024 mBoundToMethod = false;
2025 if (mCurMethod != null) {
2026 executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
2027 MSG_UNBIND_INPUT, mCurMethod));
2028 }
2029 }
Dianne Hackborna6e41342012-05-22 16:30:34 -07002030
Yohei Yukawa2bc66172017-02-08 11:13:25 -08002031 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
2032 MSG_SET_ACTIVE, 0, 0, mCurClient));
Yohei Yukawa33e81792015-11-17 21:14:42 -08002033 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
2034 MSG_UNBIND_CLIENT, mCurSeq, unbindClientReason, mCurClient.client));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002035 mCurClient.sessionRequested = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002036 mCurClient = null;
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002037 mCurActivityViewToScreenMatrix = null;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002038
The Android Open Source Project10592532009-03-18 17:39:46 -07002039 hideInputMethodMenuLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002040 }
2041 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002042
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002043 private int getImeShowFlags() {
2044 int flags = 0;
2045 if (mShowForced) {
2046 flags |= InputMethod.SHOW_FORCED
2047 | InputMethod.SHOW_EXPLICIT;
2048 } else if (mShowExplicitlyRequested) {
2049 flags |= InputMethod.SHOW_EXPLICIT;
2050 }
2051 return flags;
2052 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002053
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 private int getAppShowFlags() {
2055 int flags = 0;
2056 if (mShowForced) {
2057 flags |= InputMethodManager.SHOW_FORCED;
2058 } else if (!mShowExplicitlyRequested) {
2059 flags |= InputMethodManager.SHOW_IMPLICIT;
2060 }
2061 return flags;
2062 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002063
Andreas Gampea36dc622018-02-05 17:19:22 -08002064 @GuardedBy("mMethodMap")
Yohei Yukawa2553e482017-12-15 15:47:33 -08002065 @NonNull
Yohei Yukawadc66e522018-10-21 10:43:14 -07002066 InputBindResult attachNewInputLocked(@StartInputReason int startInputReason, boolean initial) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002067 if (!mBoundToMethod) {
2068 executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
2069 MSG_BIND_INPUT, mCurMethod, mCurClient.binding));
2070 mBoundToMethod = true;
2071 }
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08002072
2073 final Binder startInputToken = new Binder();
Yohei Yukawa7979e1a2019-02-12 02:01:10 -08002074 final StartInputInfo info = new StartInputInfo(mSettings.getCurrentUserId(), mCurToken,
2075 mCurTokenDisplayId, mCurId, startInputReason, !initial,
2076 UserHandle.getUserId(mCurClient.uid), mCurClient.selfReportedDisplayId,
2077 mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode, mCurSeq);
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002078 mImeTargetWindowMap.put(startInputToken, mCurFocusedWindow);
Yohei Yukawa357b2f62017-02-14 09:40:03 -08002079 mStartInputHistory.addEntry(info);
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08002080
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002081 final SessionState session = mCurClient.curSession;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08002082 executeOrSendMessage(session.method, mCaller.obtainMessageIIOOOO(
Yohei Yukawaf7526b52017-02-11 20:57:10 -08002083 MSG_START_INPUT, mCurInputContextMissingMethods, initial ? 0 : 1 /* restarting */,
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08002084 startInputToken, session, mCurInputContext, mCurAttribute));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002085 if (mShowRequested) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002086 if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08002087 showCurrentInputLocked(mCurFocusedWindow, getAppShowFlags(), null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002088 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002089 return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
2090 session.session, (session.channel != null ? session.channel.dup() : null),
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002091 mCurId, mCurSeq, mCurActivityViewToScreenMatrix);
2092 }
2093
2094 @Nullable
2095 private Matrix getActivityViewToScreenMatrixLocked(int clientDisplayId, int imeDisplayId) {
2096 if (clientDisplayId == imeDisplayId) {
2097 return null;
2098 }
2099 int displayId = clientDisplayId;
2100 Matrix matrix = null;
2101 while (true) {
2102 final ActivityViewInfo info = mActivityViewDisplayIdToParentMap.get(displayId);
2103 if (info == null) {
2104 return null;
2105 }
2106 if (matrix == null) {
2107 matrix = new Matrix(info.mMatrix);
2108 } else {
2109 matrix.postConcat(info.mMatrix);
2110 }
2111 if (info.mParentClient.selfReportedDisplayId == imeDisplayId) {
2112 return matrix;
2113 }
2114 displayId = info.mParentClient.selfReportedDisplayId;
2115 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002116 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002117
Andreas Gampea36dc622018-02-05 17:19:22 -08002118 @GuardedBy("mMethodMap")
Yohei Yukawa2553e482017-12-15 15:47:33 -08002119 @NonNull
Yohei Yukawa35d3f372015-11-25 11:07:19 -08002120 InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07002121 @MissingMethodFlags int missingMethods, @NonNull EditorInfo attribute,
2122 @StartInputFlags int startInputFlags, @StartInputReason int startInputReason) {
Dianne Hackborn7663d802012-02-24 13:08:49 -08002123 // If no method is currently selected, do nothing.
2124 if (mCurMethodId == null) {
Yohei Yukawa2553e482017-12-15 15:47:33 -08002125 return InputBindResult.NO_IME;
Dianne Hackborn7663d802012-02-24 13:08:49 -08002126 }
2127
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002128 if (!mSystemReady) {
2129 // If the system is not yet ready, we shouldn't be running third
2130 // party code.
2131 return new InputBindResult(
2132 InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002133 null, null, mCurMethodId, mCurSeq, null);
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002134 }
2135
Yohei Yukawad57ba672015-06-08 16:39:46 -07002136 if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid,
2137 attribute.packageName)) {
2138 Slog.e(TAG, "Rejecting this client as it reported an invalid package name."
2139 + " uid=" + cs.uid + " package=" + attribute.packageName);
Yohei Yukawa2553e482017-12-15 15:47:33 -08002140 return InputBindResult.INVALID_PACKAGE_NAME;
Yohei Yukawa0f3ad12015-04-06 16:48:24 -07002141 }
2142
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002143 if (!mWindowManagerInternal.isUidAllowedOnDisplay(cs.selfReportedDisplayId, cs.uid)) {
2144 // Wait, the client no longer has access to the display.
2145 return InputBindResult.INVALID_DISPLAY_ID;
2146 }
lumarkef1965b2018-09-12 17:42:53 +08002147 // Compute the final shown display ID with validated cs.selfReportedDisplayId for this
2148 // session & other conditions.
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08002149 final int displayIdToShowIme = computeImeDisplayIdForTarget(cs.selfReportedDisplayId,
2150 mImeDisplayValidator);
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002151
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002152 if (mCurClient != cs) {
John Spurlocke0980502013-10-25 11:59:29 -04002153 // Was the keyguard locked when switching over to the new client?
2154 mCurClientInKeyguard = isKeyguardLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002155 // If the client is changing, we need to switch over to the new
2156 // one.
Yohei Yukawab7526452018-10-21 20:15:17 -07002157 unbindCurrentClientLocked(UnbindReason.SWITCH_CLIENT);
Yohei Yukawa35d3f372015-11-25 11:07:19 -08002158 if (DEBUG) Slog.v(TAG, "switching to client: client="
John Spurlocke0980502013-10-25 11:59:29 -04002159 + cs.client.asBinder() + " keyguard=" + mCurClientInKeyguard);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002160
2161 // If the screen is on, inform the new client it is active
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07002162 if (mIsInteractive) {
tiansiming [田思明]e102c972018-04-17 18:15:33 +08002163 executeOrSendMessage(cs.client, mCaller.obtainMessageIO(MSG_SET_ACTIVE, 1, cs));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002164 }
2165 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002167 // Bump up the sequence for this client and attach it.
2168 mCurSeq++;
2169 if (mCurSeq <= 0) mCurSeq = 1;
2170 mCurClient = cs;
2171 mCurInputContext = inputContext;
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002172 mCurActivityViewToScreenMatrix =
2173 getActivityViewToScreenMatrixLocked(cs.selfReportedDisplayId, displayIdToShowIme);
2174 if (cs.selfReportedDisplayId != displayIdToShowIme
2175 && mCurActivityViewToScreenMatrix == null) {
Yohei Yukawa3d2cc0f2019-04-25 18:32:15 -07002176 // CursorAnchorInfo API does not work as-is for cross-display scenario. Pretend that
2177 // InputConnection#requestCursorUpdates() is not implemented in the application so that
2178 // IMEs will always receive false from this API.
2179 missingMethods |= MissingMethodFlags.REQUEST_CURSOR_UPDATES;
2180 }
Yohei Yukawa19a80a12016-03-14 22:57:37 -07002181 mCurInputContextMissingMethods = missingMethods;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002182 mCurAttribute = attribute;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002184 // Check if the input method is changing.
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002185 // We expect the caller has already verified that the client is allowed to access this
2186 // display ID.
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002187 if (mCurId != null && mCurId.equals(mCurMethodId)
2188 && displayIdToShowIme == mCurTokenDisplayId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002189 if (cs.curSession != null) {
2190 // Fast case: if we are already connected to the input method,
2191 // then just return it.
Yohei Yukawa87ca8402017-02-07 00:13:14 -08002192 return attachNewInputLocked(startInputReason,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07002193 (startInputFlags & StartInputFlags.INITIAL_CONNECTION) != 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002194 }
2195 if (mHaveConnection) {
2196 if (mCurMethod != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002197 // Return to client, and we will get back with it when
2198 // we have had a session made for it.
Jeff Brownc28867a2013-03-26 15:42:39 -07002199 requestClientSessionLocked(cs);
Yohei Yukawa2553e482017-12-15 15:47:33 -08002200 return new InputBindResult(
2201 InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002202 null, null, mCurId, mCurSeq, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002203 } else if (SystemClock.uptimeMillis()
2204 < (mLastBindTime+TIME_TO_RECONNECT)) {
2205 // In this case we have connected to the service, but
2206 // don't yet have its interface. If it hasn't been too
2207 // long since we did the connection, we'll return to
2208 // the client and wait to get the service interface so
2209 // we can report back. If it has been too long, we want
2210 // to fall through so we can try a disconnect/reconnect
2211 // to see if we can get back in touch with the service.
Yohei Yukawa2553e482017-12-15 15:47:33 -08002212 return new InputBindResult(
2213 InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002214 null, null, mCurId, mCurSeq, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002215 } else {
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002216 EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
2217 mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002218 }
2219 }
2220 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002222 InputMethodInfo info = mMethodMap.get(mCurMethodId);
2223 if (info == null) {
2224 throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
2225 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002226
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002227 unbindCurrentMethodLocked();
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002228
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002229 mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE);
2230 mCurIntent.setComponent(info.getComponent());
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07002231 mCurIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
2232 com.android.internal.R.string.input_method_binding_label);
2233 mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
2234 mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002235
Yohei Yukawaf80087c2018-05-21 09:47:53 -07002236 if (bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002237 mLastBindTime = SystemClock.uptimeMillis();
2238 mHaveConnection = true;
2239 mCurId = info.getId();
2240 mCurToken = new Binder();
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002241 mCurTokenDisplayId = displayIdToShowIme;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002242 try {
lumark90120a82018-08-15 00:33:03 +08002243 if (DEBUG) {
2244 Slog.v(TAG, "Adding window token: " + mCurToken + " for display: "
2245 + mCurTokenDisplayId);
2246 }
Yohei Yukawa6e875592019-01-28 00:49:30 -08002247 mIWindowManager.addWindowToken(mCurToken, LayoutParams.TYPE_INPUT_METHOD,
2248 mCurTokenDisplayId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002249 } catch (RemoteException e) {
2250 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002251 return new InputBindResult(
2252 InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002253 null, null, mCurId, mCurSeq, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002254 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002255 mCurIntent = null;
2256 Slog.w(TAG, "Failure connecting to input method service: " + mCurIntent);
2257 return InputBindResult.IME_NOT_CONNECTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002258 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002259
lumarkef1965b2018-09-12 17:42:53 +08002260 @FunctionalInterface
2261 interface ImeDisplayValidator {
2262 boolean displayCanShowIme(int displayId);
2263 }
2264
2265 /**
2266 * Find the display where the IME should be shown.
2267 *
2268 * @param displayId the ID of the display where the IME client target is.
lumarkef1965b2018-09-12 17:42:53 +08002269 * @param checker instance of {@link ImeDisplayValidator} which is used for
2270 * checking display config to adjust the final target display.
2271 * @return The ID of the display where the IME should be shown.
2272 */
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08002273 static int computeImeDisplayIdForTarget(int displayId, @NonNull ImeDisplayValidator checker) {
lumarkef1965b2018-09-12 17:42:53 +08002274 if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) {
lumark7570cac2019-03-07 22:14:38 +08002275 return FALLBACK_DISPLAY_ID;
lumarkef1965b2018-09-12 17:42:53 +08002276 }
lumark9a72d222019-03-30 18:31:45 +08002277
2278 // Show IME window on fallback display when the display doesn't support system decorations
2279 // or the display is virtual and isn't owned by system for security concern.
lumark7570cac2019-03-07 22:14:38 +08002280 return checker.displayCanShowIme(displayId) ? displayId : FALLBACK_DISPLAY_ID;
lumarkef1965b2018-09-12 17:42:53 +08002281 }
2282
satoke7c6998e2011-06-03 17:57:59 +09002283 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002284 public void onServiceConnected(ComponentName name, IBinder service) {
2285 synchronized (mMethodMap) {
2286 if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
2287 mCurMethod = IInputMethod.Stub.asInterface(service);
Dianne Hackborncc278702009-09-02 23:07:23 -07002288 if (mCurToken == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002289 Slog.w(TAG, "Service connected without a token!");
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002290 unbindCurrentMethodLocked();
Dianne Hackborncc278702009-09-02 23:07:23 -07002291 return;
2292 }
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002293 if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
lumark90120a82018-08-15 00:33:03 +08002294 // Dispatch display id for InputMethodService to update context display.
2295 executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
2296 MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002297 if (mCurClient != null) {
Jeff Brownc28867a2013-03-26 15:42:39 -07002298 clearClientSessionLocked(mCurClient);
2299 requestClientSessionLocked(mCurClient);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002300 }
2301 }
2302 }
2303 }
2304
Jeff Brownc28867a2013-03-26 15:42:39 -07002305 void onSessionCreated(IInputMethod method, IInputMethodSession session,
2306 InputChannel channel) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002307 synchronized (mMethodMap) {
2308 if (mCurMethod != null && method != null
2309 && mCurMethod.asBinder() == method.asBinder()) {
2310 if (mCurClient != null) {
Jeff Brownc28867a2013-03-26 15:42:39 -07002311 clearClientSessionLocked(mCurClient);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002312 mCurClient.curSession = new SessionState(mCurClient,
Jeff Brownc28867a2013-03-26 15:42:39 -07002313 method, session, channel);
Yohei Yukawa87ca8402017-02-07 00:13:14 -08002314 InputBindResult res = attachNewInputLocked(
Yohei Yukawa42194222018-10-21 20:14:40 -07002315 StartInputReason.SESSION_CREATED_BY_IME, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002316 if (res.method != null) {
2317 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
Yohei Yukawa33e81792015-11-17 21:14:42 -08002318 MSG_BIND_CLIENT, mCurClient.client, res));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002319 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002320 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002321 }
2322 }
2323 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002324
2325 // Session abandoned. Close its associated input channel.
2326 channel.dispose();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002327 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002328
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002329 void unbindCurrentMethodLocked() {
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002330 if (mVisibleBound) {
2331 mContext.unbindService(mVisibleConnection);
2332 mVisibleBound = false;
2333 }
2334
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002335 if (mHaveConnection) {
2336 mContext.unbindService(this);
2337 mHaveConnection = false;
2338 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002339
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002340 if (mCurToken != null) {
2341 try {
lumark90120a82018-08-15 00:33:03 +08002342 if (DEBUG) {
2343 Slog.v(TAG, "Removing window token: " + mCurToken + " for display: "
2344 + mCurTokenDisplayId);
2345 }
lumark90120a82018-08-15 00:33:03 +08002346 mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId);
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002347 } catch (RemoteException e) {
2348 }
lumark7570cac2019-03-07 22:14:38 +08002349 // Set IME window status as invisible when unbind current method.
2350 mImeWindowVis = 0;
2351 mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
2352 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002353 mCurToken = null;
lumark90120a82018-08-15 00:33:03 +08002354 mCurTokenDisplayId = INVALID_DISPLAY;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002355 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002356
The Android Open Source Project10592532009-03-18 17:39:46 -07002357 mCurId = null;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002358 clearCurMethodLocked();
Yohei Yukawabc7b5262015-11-17 17:38:41 -08002359 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002360
Yohei Yukawa4afd9332018-10-21 10:43:53 -07002361 void resetCurrentMethodAndClient(@UnbindReason int unbindClientReason) {
Yohei Yukawabc7b5262015-11-17 17:38:41 -08002362 mCurMethodId = null;
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002363 unbindCurrentMethodLocked();
Yohei Yukawa33e81792015-11-17 21:14:42 -08002364 unbindCurrentClientLocked(unbindClientReason);
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002365 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002366
2367 void requestClientSessionLocked(ClientState cs) {
2368 if (!cs.sessionRequested) {
2369 if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs);
2370 InputChannel[] channels = InputChannel.openInputChannelPair(cs.toString());
2371 cs.sessionRequested = true;
2372 executeOrSendMessage(mCurMethod, mCaller.obtainMessageOOO(
2373 MSG_CREATE_SESSION, mCurMethod, channels[1],
2374 new MethodCallback(this, mCurMethod, channels[0])));
2375 }
2376 }
2377
2378 void clearClientSessionLocked(ClientState cs) {
2379 finishSessionLocked(cs.curSession);
2380 cs.curSession = null;
2381 cs.sessionRequested = false;
2382 }
2383
2384 private void finishSessionLocked(SessionState sessionState) {
2385 if (sessionState != null) {
2386 if (sessionState.session != null) {
2387 try {
2388 sessionState.session.finishSession();
2389 } catch (RemoteException e) {
2390 Slog.w(TAG, "Session failed to close due to remote exception", e);
Yohei Yukawa849443c2019-01-21 09:02:25 -08002391 updateSystemUiLocked(0 /* vis */, mBackDisposition);
Jeff Brownc28867a2013-03-26 15:42:39 -07002392 }
2393 sessionState.session = null;
2394 }
2395 if (sessionState.channel != null) {
2396 sessionState.channel.dispose();
2397 sessionState.channel = null;
Devin Taylor0c33ed22010-02-23 13:26:46 -06002398 }
2399 }
2400 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002401
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002402 void clearCurMethodLocked() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002403 if (mCurMethod != null) {
Yohei Yukawaac9311e2018-11-20 19:25:23 -08002404 final int numClients = mClients.size();
2405 for (int i = 0; i < numClients; ++i) {
2406 clearClientSessionLocked(mClients.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002407 }
Devin Taylor0c33ed22010-02-23 13:26:46 -06002408
Jeff Brownc28867a2013-03-26 15:42:39 -07002409 finishSessionLocked(mEnabledSession);
Devin Taylor0c33ed22010-02-23 13:26:46 -06002410 mEnabledSession = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002411 mCurMethod = null;
2412 }
Dianne Hackborn661cd522011-08-22 00:26:20 -07002413 if (mStatusBar != null) {
Jason Monk3e189872016-01-12 09:10:34 -05002414 mStatusBar.setIconVisibility(mSlotIme, false);
Dianne Hackborn661cd522011-08-22 00:26:20 -07002415 }
Yohei Yukawa2bc66172017-02-08 11:13:25 -08002416 mInFullscreenMode = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002417 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002418
satoke7c6998e2011-06-03 17:57:59 +09002419 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002420 public void onServiceDisconnected(ComponentName name) {
Yohei Yukawa817d5f72017-01-04 20:15:02 -08002421 // Note that mContext.unbindService(this) does not trigger this. Hence if we are here the
2422 // disconnection is not intended by IMMS (e.g. triggered because the current IMS crashed),
2423 // which is irregular but can eventually happen for everyone just by continuing using the
2424 // device. Thus it is important to make sure that all the internal states are properly
2425 // refreshed when this method is called back. Running
2426 // adb install -r <APK that implements the current IME>
2427 // would be a good way to trigger such a situation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002428 synchronized (mMethodMap) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002429 if (DEBUG) Slog.v(TAG, "Service disconnected: " + name
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002430 + " mCurIntent=" + mCurIntent);
2431 if (mCurMethod != null && mCurIntent != null
2432 && name.equals(mCurIntent.getComponent())) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002433 clearCurMethodLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002434 // We consider this to be a new bind attempt, since the system
2435 // should now try to restart the service for us.
2436 mLastBindTime = SystemClock.uptimeMillis();
2437 mShowRequested = mInputShown;
2438 mInputShown = false;
Yohei Yukawab7526452018-10-21 20:15:17 -07002439 unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002440 }
2441 }
2442 }
2443
Yohei Yukawaeec552e2018-09-09 20:48:41 -07002444 @BinderThread
Yohei Yukawa41b094f2018-09-09 23:58:45 -07002445 private void updateStatusIcon(@NonNull IBinder token, String packageName,
2446 @DrawableRes int iconId) {
Yohei Yukawa59377ca2017-01-31 21:32:26 -08002447 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08002448 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa59377ca2017-01-31 21:32:26 -08002449 return;
2450 }
2451 final long ident = Binder.clearCallingIdentity();
2452 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002453 if (iconId == 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002454 if (DEBUG) Slog.d(TAG, "hide the small icon for the input method");
Dianne Hackborn661cd522011-08-22 00:26:20 -07002455 if (mStatusBar != null) {
Jason Monk3e189872016-01-12 09:10:34 -05002456 mStatusBar.setIconVisibility(mSlotIme, false);
Dianne Hackborn661cd522011-08-22 00:26:20 -07002457 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002458 } else if (packageName != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002459 if (DEBUG) Slog.d(TAG, "show a small icon for the input method");
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002460 CharSequence contentDescription = null;
2461 try {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002462 // Use PackageManager to load label
2463 final PackageManager packageManager = mContext.getPackageManager();
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002464 contentDescription = packageManager.getApplicationLabel(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002465 mIPackageManager.getApplicationInfo(packageName, 0,
2466 mSettings.getCurrentUserId()));
2467 } catch (RemoteException e) {
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002468 /* ignore */
2469 }
Dianne Hackborn661cd522011-08-22 00:26:20 -07002470 if (mStatusBar != null) {
Jason Monk3e189872016-01-12 09:10:34 -05002471 mStatusBar.setIcon(mSlotIme, packageName, iconId, 0,
Dianne Hackborn661cd522011-08-22 00:26:20 -07002472 contentDescription != null
2473 ? contentDescription.toString() : null);
Jason Monk3e189872016-01-12 09:10:34 -05002474 mStatusBar.setIconVisibility(mSlotIme, true);
Dianne Hackborn661cd522011-08-22 00:26:20 -07002475 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002476 }
Yohei Yukawa59377ca2017-01-31 21:32:26 -08002477 } finally {
2478 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002479 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002480 }
2481 }
2482
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002483 private boolean shouldShowImeSwitcherLocked(int visibility) {
satok7cfc0ed2011-06-20 21:29:36 +09002484 if (!mShowOngoingImeSwitcherForPhones) return false;
Jason Monk807ef762014-05-08 15:47:46 -04002485 if (mSwitchingDialog != null) return false;
Yohei Yukawad2bc3092017-07-31 15:37:14 -07002486 if (mWindowManagerInternal.isKeyguardShowingAndNotOccluded()
2487 && mKeyguardManager != null && mKeyguardManager.isKeyguardSecure()) return false;
Tarandeep Singheadb1392018-11-09 18:15:57 +01002488 if ((visibility & InputMethodService.IME_ACTIVE) == 0
2489 || (visibility & InputMethodService.IME_INVISIBLE) != 0) {
2490 return false;
2491 }
Seigo Nonaka7309b122015-08-17 18:34:13 -07002492 if (mWindowManagerInternal.isHardKeyboardAvailable()) {
Yohei Yukawaaf023f22019-06-21 16:38:22 -07002493 // When physical keyboard is attached, we show the ime switcher (or notification if
2494 // NavBar is not available) because SHOW_IME_WITH_HARD_KEYBOARD settings currently
2495 // exists in the IME switcher dialog. Might be OK to remove this condition once
2496 // SHOW_IME_WITH_HARD_KEYBOARD settings finds a good place to live.
2497 return true;
Yohei Yukawa89398382016-03-29 11:37:04 -07002498 } else if ((visibility & InputMethodService.IME_VISIBLE) == 0) {
2499 return false;
Yohei Yukawac6c7cd22015-05-12 15:00:33 -07002500 }
Yohei Yukawac6c7cd22015-05-12 15:00:33 -07002501
2502 List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked();
2503 final int N = imis.size();
2504 if (N > 2) return true;
2505 if (N < 1) return false;
2506 int nonAuxCount = 0;
2507 int auxCount = 0;
2508 InputMethodSubtype nonAuxSubtype = null;
2509 InputMethodSubtype auxSubtype = null;
2510 for(int i = 0; i < N; ++i) {
2511 final InputMethodInfo imi = imis.get(i);
2512 final List<InputMethodSubtype> subtypes =
2513 mSettings.getEnabledInputMethodSubtypeListLocked(mContext, imi, true);
2514 final int subtypeCount = subtypes.size();
2515 if (subtypeCount == 0) {
2516 ++nonAuxCount;
2517 } else {
2518 for (int j = 0; j < subtypeCount; ++j) {
2519 final InputMethodSubtype subtype = subtypes.get(j);
2520 if (!subtype.isAuxiliary()) {
2521 ++nonAuxCount;
2522 nonAuxSubtype = subtype;
2523 } else {
2524 ++auxCount;
2525 auxSubtype = subtype;
satok7cfc0ed2011-06-20 21:29:36 +09002526 }
2527 }
satok7cfc0ed2011-06-20 21:29:36 +09002528 }
2529 }
Yohei Yukawac6c7cd22015-05-12 15:00:33 -07002530 if (nonAuxCount > 1 || auxCount > 1) {
2531 return true;
2532 } else if (nonAuxCount == 1 && auxCount == 1) {
2533 if (nonAuxSubtype != null && auxSubtype != null
2534 && (nonAuxSubtype.getLocale().equals(auxSubtype.getLocale())
2535 || auxSubtype.overridesImplicitlyEnabledSubtype()
2536 || nonAuxSubtype.overridesImplicitlyEnabledSubtype())
2537 && nonAuxSubtype.containsExtraValueKey(TAG_TRY_SUPPRESSING_IME_SWITCHER)) {
2538 return false;
2539 }
2540 return true;
2541 }
2542 return false;
satok7cfc0ed2011-06-20 21:29:36 +09002543 }
2544
John Spurlocke0980502013-10-25 11:59:29 -04002545 private boolean isKeyguardLocked() {
2546 return mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
2547 }
2548
Yohei Yukawad6475a62017-04-17 10:35:27 -07002549 @BinderThread
satokdbf29502011-08-25 15:28:23 +09002550 @SuppressWarnings("deprecation")
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08002551 private void setImeWindowStatus(@NonNull IBinder token, int vis, int backDisposition) {
lumark7570cac2019-03-07 22:14:38 +08002552 final int topFocusedDisplayId = mWindowManagerInternal.getTopFocusedDisplayId();
2553
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002554 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08002555 if (!calledWithValidTokenLocked(token)) {
2556 return;
2557 }
lumark7570cac2019-03-07 22:14:38 +08002558 // Skip update IME status when current token display is not same as focused display.
2559 // Note that we still need to update IME status when focusing external display
2560 // that does not support system decoration and fallback to show IME on default
2561 // display since it is intentional behavior.
2562 if (mCurTokenDisplayId != topFocusedDisplayId
2563 && mCurTokenDisplayId != FALLBACK_DISPLAY_ID) {
2564 return;
2565 }
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002566 mImeWindowVis = vis;
2567 mBackDisposition = backDisposition;
Yohei Yukawa849443c2019-01-21 09:02:25 -08002568 updateSystemUiLocked(vis, backDisposition);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002569 }
Yohei Yukawad6475a62017-04-17 10:35:27 -07002570
2571 final boolean dismissImeOnBackKeyPressed;
2572 switch (backDisposition) {
2573 case InputMethodService.BACK_DISPOSITION_WILL_DISMISS:
2574 dismissImeOnBackKeyPressed = true;
2575 break;
2576 case InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS:
2577 dismissImeOnBackKeyPressed = false;
2578 break;
2579 default:
2580 case InputMethodService.BACK_DISPOSITION_DEFAULT:
2581 dismissImeOnBackKeyPressed = ((vis & InputMethodService.IME_VISIBLE) != 0);
2582 break;
2583 }
Yohei Yukawaee2a7ed2017-02-15 21:38:57 -08002584 mWindowManagerInternal.updateInputMethodWindowStatus(token,
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002585 (vis & InputMethodService.IME_VISIBLE) != 0, dismissImeOnBackKeyPressed);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002586 }
2587
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002588 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08002589 private void reportStartInput(@NonNull IBinder token, IBinder startInputToken) {
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002590 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08002591 if (!calledWithValidTokenLocked(token)) {
2592 return;
2593 }
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002594 final IBinder targetWindow = mImeTargetWindowMap.get(startInputToken);
2595 if (targetWindow != null && mLastImeTargetWindow != targetWindow) {
2596 mWindowManagerInternal.updateInputMethodTargetWindow(token, targetWindow);
2597 }
2598 mLastImeTargetWindow = targetWindow;
2599 }
2600 }
2601
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002602 // Caution! This method is called in this class. Handle multi-user carefully
Yohei Yukawa849443c2019-01-21 09:02:25 -08002603 private void updateSystemUiLocked(int vis, int backDisposition) {
2604 if (mCurToken == null) {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002605 return;
2606 }
Tarandeep Singheadb1392018-11-09 18:15:57 +01002607 if (DEBUG) {
2608 Slog.d(TAG, "IME window vis: " + vis
2609 + " active: " + (vis & InputMethodService.IME_ACTIVE)
lumark7570cac2019-03-07 22:14:38 +08002610 + " inv: " + (vis & InputMethodService.IME_INVISIBLE)
2611 + " displayId: " + mCurTokenDisplayId);
Tarandeep Singheadb1392018-11-09 18:15:57 +01002612 }
2613
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002614 // TODO: Move this clearing calling identity block to setImeWindowStatus after making sure
2615 // all updateSystemUi happens on system previlege.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002616 final long ident = Binder.clearCallingIdentity();
satok06487a52010-10-29 11:37:18 +09002617 try {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002618 // apply policy for binder calls
2619 if (vis != 0 && isKeyguardLocked() && !mCurClientInKeyguard) {
2620 vis = 0;
satok06487a52010-10-29 11:37:18 +09002621 }
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002622 // mImeWindowVis should be updated before calling shouldShowImeSwitcherLocked().
2623 final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis);
2624 if (mStatusBar != null) {
lumark7570cac2019-03-07 22:14:38 +08002625 mStatusBar.setImeWindowStatus(mCurTokenDisplayId, mCurToken, vis, backDisposition,
Tarandeep Singh07b318b2019-07-17 11:12:04 -07002626 needsToShowImeSwitcher, false /*isMultiClientImeEnabled*/);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002627 }
2628 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
2629 if (imi != null && needsToShowImeSwitcher) {
2630 // Used to load label
2631 final CharSequence title = mRes.getText(
2632 com.android.internal.R.string.select_input_method);
2633 final CharSequence summary = InputMethodUtils.getImeAndSubtypeDisplayName(
2634 mContext, imi, mCurrentSubtype);
Chris Wren1ce4b6d2015-06-11 10:19:43 -04002635 mImeSwitcherNotification.setContentTitle(title)
2636 .setContentText(summary)
2637 .setContentIntent(mImeSwitchPendingIntent);
Seigo Nonaka7309b122015-08-17 18:34:13 -07002638 try {
Charles Chenea6e7f02018-11-19 21:37:45 +08002639 // TODO(b/120076400): Figure out what is the best behavior
Seigo Nonaka7309b122015-08-17 18:34:13 -07002640 if ((mNotificationManager != null)
Charles Chenea6e7f02018-11-19 21:37:45 +08002641 && !mIWindowManager.hasNavigationBar(DEFAULT_DISPLAY)) {
Seigo Nonaka7309b122015-08-17 18:34:13 -07002642 if (DEBUG) {
2643 Slog.d(TAG, "--- show notification: label = " + summary);
2644 }
2645 mNotificationManager.notifyAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04002646 SystemMessage.NOTE_SELECT_INPUT_METHOD,
Seigo Nonaka7309b122015-08-17 18:34:13 -07002647 mImeSwitcherNotification.build(), UserHandle.ALL);
2648 mNotificationShown = true;
Dianne Hackborn661cd522011-08-22 00:26:20 -07002649 }
Seigo Nonaka7309b122015-08-17 18:34:13 -07002650 } catch (RemoteException e) {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002651 }
2652 } else {
2653 if (mNotificationShown && mNotificationManager != null) {
2654 if (DEBUG) {
2655 Slog.d(TAG, "--- hide notification");
satok7cfc0ed2011-06-20 21:29:36 +09002656 }
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002657 mNotificationManager.cancelAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04002658 SystemMessage.NOTE_SELECT_INPUT_METHOD, UserHandle.ALL);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002659 mNotificationShown = false;
satok7cfc0ed2011-06-20 21:29:36 +09002660 }
satok06487a52010-10-29 11:37:18 +09002661 }
2662 } finally {
2663 Binder.restoreCallingIdentity(ident);
2664 }
2665 }
2666
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002667 void updateFromSettingsLocked(boolean enabledMayChange) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07002668 updateInputMethodsFromSettingsLocked(enabledMayChange);
2669 updateKeyboardFromSettingsLocked();
2670 }
2671
2672 void updateInputMethodsFromSettingsLocked(boolean enabledMayChange) {
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002673 if (enabledMayChange) {
2674 List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
2675 for (int i=0; i<enabled.size(); i++) {
2676 // We allow the user to select "disabled until used" apps, so if they
2677 // are enabling one of those here we now need to make it enabled.
2678 InputMethodInfo imm = enabled.get(i);
2679 try {
2680 ApplicationInfo ai = mIPackageManager.getApplicationInfo(imm.getPackageName(),
2681 PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
2682 mSettings.getCurrentUserId());
Satoshi Kataoka7987a312013-04-17 18:59:33 +09002683 if (ai != null && ai.enabledSetting
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002684 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09002685 if (DEBUG) {
2686 Slog.d(TAG, "Update state(" + imm.getId()
2687 + "): DISABLED_UNTIL_USED -> DEFAULT");
2688 }
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002689 mIPackageManager.setApplicationEnabledSetting(imm.getPackageName(),
2690 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
Dianne Hackborn3fa3c28a2013-03-26 16:15:41 -07002691 PackageManager.DONT_KILL_APP, mSettings.getCurrentUserId(),
2692 mContext.getBasePackageName());
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002693 }
2694 } catch (RemoteException e) {
2695 }
2696 }
2697 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002698 // We are assuming that whoever is changing DEFAULT_INPUT_METHOD and
2699 // ENABLED_INPUT_METHODS is taking care of keeping them correctly in
2700 // sync, so we will never have a DEFAULT_INPUT_METHOD that is not
2701 // enabled.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002702 String id = mSettings.getSelectedInputMethod();
satok03eb319a2010-11-11 18:17:42 +09002703 // There is no input method selected, try to choose new applicable input method.
2704 if (TextUtils.isEmpty(id) && chooseNewDefaultIMELocked()) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002705 id = mSettings.getSelectedInputMethod();
satok03eb319a2010-11-11 18:17:42 +09002706 }
2707 if (!TextUtils.isEmpty(id)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002708 try {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09002709 setInputMethodLocked(id, mSettings.getSelectedInputMethodSubtypeId(id));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002710 } catch (IllegalArgumentException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002711 Slog.w(TAG, "Unknown input method from prefs: " + id, e);
Yohei Yukawab7526452018-10-21 20:15:17 -07002712 resetCurrentMethodAndClient(UnbindReason.SWITCH_IME_FAILED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002713 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002714 } else {
2715 // There is no longer an input method set, so stop any current one.
Yohei Yukawab7526452018-10-21 20:15:17 -07002716 resetCurrentMethodAndClient(UnbindReason.NO_IME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002717 }
Yohei Yukawa3d46bab2014-05-30 18:10:18 +09002718 // Here is not the perfect place to reset the switching controller. Ideally
2719 // mSwitchingController and mSettings should be able to share the same state.
2720 // TODO: Make sure that mSwitchingController and mSettings are sharing the
2721 // the same enabled IMEs list.
2722 mSwitchingController.resetCircularListLocked(mContext);
Michael Wright7b5a96b2014-08-09 19:28:42 -07002723
2724 }
2725
2726 public void updateKeyboardFromSettingsLocked() {
2727 mShowImeWithHardKeyboard = mSettings.isShowImeWithHardKeyboardEnabled();
2728 if (mSwitchingDialog != null
2729 && mSwitchingDialogTitleView != null
2730 && mSwitchingDialog.isShowing()) {
2731 final Switch hardKeySwitch = (Switch)mSwitchingDialogTitleView.findViewById(
2732 com.android.internal.R.id.hard_keyboard_switch);
2733 hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
2734 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002735 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002736
satokab751aa2010-09-14 19:17:36 +09002737 /* package */ void setInputMethodLocked(String id, int subtypeId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002738 InputMethodInfo info = mMethodMap.get(id);
2739 if (info == null) {
satok913a8922010-08-26 21:53:41 +09002740 throw new IllegalArgumentException("Unknown id: " + id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002741 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002742
satokd81e9502012-05-21 12:58:45 +09002743 // See if we need to notify a subtype change within the same IME.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002744 if (id.equals(mCurMethodId)) {
satokd81e9502012-05-21 12:58:45 +09002745 final int subtypeCount = info.getSubtypeCount();
2746 if (subtypeCount <= 0) {
2747 return;
satokcd7cd292010-11-20 15:46:23 +09002748 }
satokd81e9502012-05-21 12:58:45 +09002749 final InputMethodSubtype oldSubtype = mCurrentSubtype;
2750 final InputMethodSubtype newSubtype;
2751 if (subtypeId >= 0 && subtypeId < subtypeCount) {
2752 newSubtype = info.getSubtypeAt(subtypeId);
2753 } else {
2754 // If subtype is null, try to find the most applicable one from
2755 // getCurrentInputMethodSubtype.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002756 newSubtype = getCurrentInputMethodSubtypeLocked();
satokd81e9502012-05-21 12:58:45 +09002757 }
2758 if (newSubtype == null || oldSubtype == null) {
2759 Slog.w(TAG, "Illegal subtype state: old subtype = " + oldSubtype
2760 + ", new subtype = " + newSubtype);
2761 return;
2762 }
2763 if (newSubtype != oldSubtype) {
2764 setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true);
2765 if (mCurMethod != null) {
2766 try {
Yohei Yukawa849443c2019-01-21 09:02:25 -08002767 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
satokd81e9502012-05-21 12:58:45 +09002768 mCurMethod.changeInputMethodSubtype(newSubtype);
2769 } catch (RemoteException e) {
2770 Slog.w(TAG, "Failed to call changeInputMethodSubtype");
satokab751aa2010-09-14 19:17:36 +09002771 }
2772 }
2773 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002774 return;
2775 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002776
satokd81e9502012-05-21 12:58:45 +09002777 // Changing to a different IME.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002778 final long ident = Binder.clearCallingIdentity();
2779 try {
satokab751aa2010-09-14 19:17:36 +09002780 // Set a subtype to this input method.
2781 // subtypeId the name of a subtype which will be set.
satok723a27e2010-11-11 14:58:11 +09002782 setSelectedInputMethodAndSubtypeLocked(info, subtypeId, false);
2783 // mCurMethodId should be updated after setSelectedInputMethodAndSubtypeLocked()
2784 // because mCurMethodId is stored as a history in
2785 // setSelectedInputMethodAndSubtypeLocked().
2786 mCurMethodId = id;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002787
Sudheer Shankafc46e9b2016-10-21 17:55:27 -07002788 if (LocalServices.getService(ActivityManagerInternal.class).isSystemReady()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002789 Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08002790 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002791 intent.putExtra("input_method_id", id);
Amith Yamasanicd757062012-10-19 18:23:52 -07002792 mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002793 }
Yohei Yukawab7526452018-10-21 20:15:17 -07002794 unbindCurrentClientLocked(UnbindReason.SWITCH_IME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002795 } finally {
2796 Binder.restoreCallingIdentity(ident);
2797 }
2798 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002799
satok42c5a162011-05-26 16:46:14 +09002800 @Override
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08002801 public boolean showSoftInput(IInputMethodClient client, IBinder windowToken, int flags,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002802 ResultReceiver resultReceiver) {
Dianne Hackborncef65ee2010-09-30 18:27:22 -07002803 int uid = Binder.getCallingUid();
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002804 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08002805 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002806 return false;
2807 }
2808 final long ident = Binder.clearCallingIdentity();
2809 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002810 if (mCurClient == null || client == null
2811 || mCurClient.client.asBinder() != client.asBinder()) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07002812 // We need to check if this is the current client with
2813 // focus in the window manager, to allow this call to
2814 // be made before input is started in it.
Yohei Yukawa41f89c32018-09-19 14:30:04 -07002815 final ClientState cs = mClients.get(client.asBinder());
2816 if (cs == null) {
2817 throw new IllegalArgumentException("unknown client " + client.asBinder());
2818 }
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002819 if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
2820 cs.selfReportedDisplayId)) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07002821 Slog.w(TAG, "Ignoring showSoftInput of uid " + uid + ": " + client);
The Android Open Source Project4df24232009-03-05 14:34:35 -08002822 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002823 }
2824 }
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002825 if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08002826 return showCurrentInputLocked(windowToken, flags, resultReceiver);
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002827 } finally {
2828 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002829 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002830 }
2831 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002832
Andreas Gamped6d42062018-07-20 13:08:21 -07002833 @GuardedBy("mMethodMap")
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08002834 boolean showCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002835 mShowRequested = true;
Anna Galusza9b278112016-01-04 11:37:37 -08002836 if (mAccessibilityRequestingNoSoftKeyboard) {
2837 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002838 }
Anna Galusza9b278112016-01-04 11:37:37 -08002839
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002840 if ((flags&InputMethodManager.SHOW_FORCED) != 0) {
2841 mShowExplicitlyRequested = true;
2842 mShowForced = true;
Anna Galusza9b278112016-01-04 11:37:37 -08002843 } else if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
2844 mShowExplicitlyRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002845 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002846
Dianne Hackborncc278702009-09-02 23:07:23 -07002847 if (!mSystemReady) {
2848 return false;
2849 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002850
The Android Open Source Project4df24232009-03-05 14:34:35 -08002851 boolean res = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002852 if (mCurMethod != null) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002853 if (DEBUG) Slog.d(TAG, "showCurrentInputLocked: mCurToken=" + mCurToken);
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08002854 // create a dummy token for IMS so that IMS cannot inject windows into client app.
2855 Binder showInputToken = new Binder();
2856 mShowRequestWindowMap.put(showInputToken, windowToken);
2857 executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOOO(
The Android Open Source Project4df24232009-03-05 14:34:35 -08002858 MSG_SHOW_SOFT_INPUT, getImeShowFlags(), mCurMethod,
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08002859 resultReceiver, showInputToken));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002860 mInputShown = true;
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002861 if (mHaveConnection && !mVisibleBound) {
Yohei Yukawaf80087c2018-05-21 09:47:53 -07002862 bindCurrentInputMethodServiceLocked(
Yohei Yukawaa67a4592017-03-30 15:57:02 -07002863 mCurIntent, mVisibleConnection, IME_VISIBLE_BIND_FLAGS);
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002864 mVisibleBound = true;
2865 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08002866 res = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002867 } else if (mHaveConnection && SystemClock.uptimeMillis()
satok59b424c2011-09-30 17:21:46 +09002868 >= (mLastBindTime+TIME_TO_RECONNECT)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002869 // The client has asked to have the input method shown, but
2870 // we have been sitting here too long with a connection to the
2871 // service and no interface received, so let's disconnect/connect
2872 // to try to prod things along.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002873 EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, mCurMethodId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002874 SystemClock.uptimeMillis()-mLastBindTime,1);
satok59b424c2011-09-30 17:21:46 +09002875 Slog.w(TAG, "Force disconnect/connect to the IME in showCurrentInputLocked()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002876 mContext.unbindService(this);
Yohei Yukawaf80087c2018-05-21 09:47:53 -07002877 bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002878 } else {
2879 if (DEBUG) {
2880 Slog.d(TAG, "Can't show input: connection = " + mHaveConnection + ", time = "
2881 + ((mLastBindTime+TIME_TO_RECONNECT) - SystemClock.uptimeMillis()));
2882 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002883 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002884
The Android Open Source Project4df24232009-03-05 14:34:35 -08002885 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002886 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002887
satok42c5a162011-05-26 16:46:14 +09002888 @Override
The Android Open Source Project4df24232009-03-05 14:34:35 -08002889 public boolean hideSoftInput(IInputMethodClient client, int flags,
2890 ResultReceiver resultReceiver) {
Dianne Hackborncef65ee2010-09-30 18:27:22 -07002891 int uid = Binder.getCallingUid();
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002892 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08002893 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002894 return false;
2895 }
2896 final long ident = Binder.clearCallingIdentity();
2897 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002898 if (mCurClient == null || client == null
2899 || mCurClient.client.asBinder() != client.asBinder()) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07002900 // We need to check if this is the current client with
2901 // focus in the window manager, to allow this call to
2902 // be made before input is started in it.
Yohei Yukawa41f89c32018-09-19 14:30:04 -07002903 final ClientState cs = mClients.get(client.asBinder());
2904 if (cs == null) {
2905 throw new IllegalArgumentException("unknown client " + client.asBinder());
2906 }
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002907 if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
2908 cs.selfReportedDisplayId)) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07002909 if (DEBUG) {
2910 Slog.w(TAG, "Ignoring hideSoftInput of uid " + uid + ": " + client);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002911 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08002912 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002913 }
2914 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002915
Joe Onorato8a9b2202010-02-26 18:56:32 -08002916 if (DEBUG) Slog.v(TAG, "Client requesting input be hidden");
The Android Open Source Project4df24232009-03-05 14:34:35 -08002917 return hideCurrentInputLocked(flags, resultReceiver);
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002918 } finally {
2919 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002920 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002921 }
2922 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002923
The Android Open Source Project4df24232009-03-05 14:34:35 -08002924 boolean hideCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002925 if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
2926 && (mShowExplicitlyRequested || mShowForced)) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002927 if (DEBUG) Slog.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide");
The Android Open Source Project4df24232009-03-05 14:34:35 -08002928 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002929 }
2930 if (mShowForced && (flags&InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002931 if (DEBUG) Slog.v(TAG, "Not hiding: forced show not cancelled by not-always hide");
The Android Open Source Project4df24232009-03-05 14:34:35 -08002932 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002933 }
Seigo Nonakaec928652015-06-10 15:31:20 +09002934
2935 // There is a chance that IMM#hideSoftInput() is called in a transient state where
2936 // IMMS#InputShown is already updated to be true whereas IMMS#mImeWindowVis is still waiting
2937 // to be updated with the new value sent from IME process. Even in such a transient state
2938 // historically we have accepted an incoming call of IMM#hideSoftInput() from the
2939 // application process as a valid request, and have even promised such a behavior with CTS
2940 // since Android Eclair. That's why we need to accept IMM#hideSoftInput() even when only
2941 // IMMS#InputShown indicates that the software keyboard is shown.
2942 // TODO: Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested.
2943 final boolean shouldHideSoftInput = (mCurMethod != null) && (mInputShown ||
2944 (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0);
The Android Open Source Project4df24232009-03-05 14:34:35 -08002945 boolean res;
Seigo Nonakaec928652015-06-10 15:31:20 +09002946 if (shouldHideSoftInput) {
2947 // The IME will report its visible state again after the following message finally
2948 // delivered to the IME process as an IPC. Hence the inconsistency between
2949 // IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in
2950 // the final state.
The Android Open Source Project4df24232009-03-05 14:34:35 -08002951 executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
2952 MSG_HIDE_SOFT_INPUT, mCurMethod, resultReceiver));
2953 res = true;
2954 } else {
2955 res = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002956 }
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002957 if (mHaveConnection && mVisibleBound) {
2958 mContext.unbindService(mVisibleConnection);
2959 mVisibleBound = false;
2960 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002961 mInputShown = false;
2962 mShowRequested = false;
2963 mShowExplicitlyRequested = false;
2964 mShowForced = false;
The Android Open Source Project4df24232009-03-05 14:34:35 -08002965 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002966 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002967
Yohei Yukawa2553e482017-12-15 15:47:33 -08002968 @NonNull
satok42c5a162011-05-26 16:46:14 +09002969 @Override
Yohei Yukawa05c25f82016-02-22 12:41:17 -08002970 public InputBindResult startInputOrWindowGainedFocus(
Yohei Yukawadc66e522018-10-21 10:43:14 -07002971 @StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07002972 @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
2973 int windowFlags, @Nullable EditorInfo attribute, IInputContext inputContext,
Yohei Yukawadc66e522018-10-21 10:43:14 -07002974 @MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion) {
Yohei Yukawa80498d52018-06-21 16:24:36 -07002975 if (windowToken == null) {
2976 Slog.e(TAG, "windowToken cannot be null.");
2977 return InputBindResult.NULL;
Yohei Yukawa05c25f82016-02-22 12:41:17 -08002978 }
Yohei Yukawa0f5eade2019-01-18 08:48:07 -08002979 final int callingUserId = UserHandle.getCallingUserId();
2980 final int userId;
Yohei Yukawa716897c2019-01-22 00:00:53 -08002981 if (attribute != null && attribute.targetInputMethodUser != null
Yohei Yukawa0f5eade2019-01-18 08:48:07 -08002982 && attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
2983 mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
Yohei Yukawa670abea2019-01-28 00:00:50 -08002984 "Using EditorInfo.targetInputMethodUser requires INTERACT_ACROSS_USERS_FULL.");
Yohei Yukawa0f5eade2019-01-18 08:48:07 -08002985 userId = attribute.targetInputMethodUser.getIdentifier();
2986 if (!mUserManagerInternal.isUserRunning(userId)) {
2987 // There is a chance that we hit here because of race condition. Let's just return
2988 // an error code instead of crashing the caller process, which at least has
2989 // INTERACT_ACROSS_USERS_FULL permission thus is likely to be an important process.
2990 Slog.e(TAG, "User #" + userId + " is not running.");
2991 return InputBindResult.INVALID_USER;
2992 }
2993 } else {
2994 userId = callingUserId;
2995 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08002996 final InputBindResult result;
2997 synchronized (mMethodMap) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08002998 final long ident = Binder.clearCallingIdentity();
2999 try {
3000 result = startInputOrWindowGainedFocusInternalLocked(startInputReason, client,
3001 windowToken, startInputFlags, softInputMode, windowFlags, attribute,
3002 inputContext, missingMethods, unverifiedTargetSdkVersion, userId);
3003 } finally {
3004 Binder.restoreCallingIdentity(ident);
3005 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003006 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08003007 if (result == null) {
3008 // This must never happen, but just in case.
3009 Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
Yohei Yukawaa468d702018-10-21 11:42:34 -07003010 + InputMethodDebug.startInputReasonToString(startInputReason)
Yohei Yukawa2553e482017-12-15 15:47:33 -08003011 + " windowFlags=#" + Integer.toHexString(windowFlags)
3012 + " editorInfo=" + attribute);
3013 return InputBindResult.NULL;
3014 }
3015 return result;
Yohei Yukawa05c25f82016-02-22 12:41:17 -08003016 }
3017
Yohei Yukawa2553e482017-12-15 15:47:33 -08003018 @NonNull
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003019 private InputBindResult startInputOrWindowGainedFocusInternalLocked(
Yohei Yukawadc66e522018-10-21 10:43:14 -07003020 @StartInputReason int startInputReason, IInputMethodClient client,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07003021 @NonNull IBinder windowToken, @StartInputFlags int startInputFlags,
3022 @SoftInputModeFlags int softInputMode, int windowFlags, EditorInfo attribute,
3023 IInputContext inputContext, @MissingMethodFlags int missingMethods,
Yohei Yukawa4391c202019-01-28 00:49:10 -08003024 int unverifiedTargetSdkVersion, @UserIdInt int userId) {
Yohei Yukawa67464522019-01-28 00:50:09 -08003025 if (DEBUG) {
3026 Slog.v(TAG, "startInputOrWindowGainedFocusInternalLocked: reason="
3027 + InputMethodDebug.startInputReasonToString(startInputReason)
3028 + " client=" + client.asBinder()
3029 + " inputContext=" + inputContext
3030 + " missingMethods="
3031 + InputConnectionInspector.getMissingMethodFlagsAsString(missingMethods)
3032 + " attribute=" + attribute
3033 + " startInputFlags="
3034 + InputMethodDebug.startInputFlagsToString(startInputFlags)
3035 + " softInputMode=" + InputMethodDebug.softInputModeToString(softInputMode)
3036 + " windowFlags=#" + Integer.toHexString(windowFlags)
3037 + " unverifiedTargetSdkVersion=" + unverifiedTargetSdkVersion);
3038 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003039
Yohei Yukawa67464522019-01-28 00:50:09 -08003040 final int windowDisplayId = mWindowManagerInternal.getDisplayIdForWindow(windowToken);
3041
3042 final ClientState cs = mClients.get(client.asBinder());
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003043 if (cs == null) {
Yohei Yukawa67464522019-01-28 00:50:09 -08003044 throw new IllegalArgumentException("unknown client " + client.asBinder());
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003045 }
3046 if (cs.selfReportedDisplayId != windowDisplayId) {
3047 Slog.e(TAG, "startInputOrWindowGainedFocusInternal: display ID mismatch."
3048 + " from client:" + cs.selfReportedDisplayId
3049 + " from window:" + windowDisplayId);
3050 return InputBindResult.DISPLAY_ID_MISMATCH;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003051 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08003052
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003053 if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
3054 cs.selfReportedDisplayId)) {
3055 // Check with the window manager to make sure this client actually
3056 // has a window with focus. If not, reject. This is thread safe
3057 // because if the focus changes some time before or after, the
3058 // next client receiving focus that has any interest in input will
3059 // be calling through here after that change happens.
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003060 if (DEBUG) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003061 Slog.w(TAG, "Focus gain on non-focused client " + cs.client
3062 + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003063 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003064 return InputBindResult.NOT_IME_TARGET_WINDOW;
3065 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003066
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003067 // cross-profile access is always allowed here to allow profile-switching.
3068 if (!mSettings.isCurrentProfile(userId)) {
3069 Slog.w(TAG, "A background user is requesting window. Hiding IME.");
3070 Slog.w(TAG, "If you need to impersonate a foreground user/profile from"
3071 + " a background user, use EditorInfo.targetInputMethodUser with"
3072 + " INTERACT_ACROSS_USERS_FULL permission.");
3073 hideCurrentInputLocked(0, null);
3074 return InputBindResult.INVALID_USER;
3075 }
3076
Tarandeep Singhcf5ff822019-07-08 14:06:27 -07003077 if (userId != mSettings.getCurrentUserId()) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003078 switchUserLocked(userId);
3079 }
3080 // Master feature flag that overrides other conditions and forces IME preRendering.
3081 if (DEBUG) {
3082 Slog.v(TAG, "IME PreRendering MASTER flag: "
Yohei Yukawa67464522019-01-28 00:50:09 -08003083 + DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() + ", LowRam: " + mIsLowRam);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003084 }
3085 // pre-rendering not supported on low-ram devices.
3086 cs.shouldPreRenderIme = DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() && !mIsLowRam;
3087
3088 if (mCurFocusedWindow == windowToken) {
3089 if (DEBUG) {
3090 Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
3091 + " attribute=" + attribute + ", token = " + windowToken);
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003092 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003093 if (attribute != null) {
3094 return startInputUncheckedLocked(cs, inputContext, missingMethods,
3095 attribute, startInputFlags, startInputReason);
3096 }
3097 return new InputBindResult(
3098 InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07003099 null, null, null, -1, null);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003100 }
3101 mCurFocusedWindow = windowToken;
3102 mCurFocusedWindowSoftInputMode = softInputMode;
3103 mCurFocusedWindowClient = cs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003104
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003105 // Should we auto-show the IME even if the caller has not
3106 // specified what should be done with it?
3107 // We only do this automatically if the window can resize
3108 // to accommodate the IME (so what the user sees will give
3109 // them good context without input information being obscured
3110 // by the IME) or if running on a large screen where there
3111 // is more room for the target window + IME.
3112 final boolean doAutoShow =
Yohei Yukawa6e875592019-01-28 00:49:30 -08003113 (softInputMode & LayoutParams.SOFT_INPUT_MASK_ADJUST)
3114 == LayoutParams.SOFT_INPUT_ADJUST_RESIZE
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003115 || mRes.getConfiguration().isLayoutSizeAtLeast(
3116 Configuration.SCREENLAYOUT_SIZE_LARGE);
Yohei Yukawa67464522019-01-28 00:50:09 -08003117 final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003118
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003119 // We want to start input before showing the IME, but after closing
3120 // it. We want to do this after closing it to help the IME disappear
3121 // more quickly (not get stuck behind it initializing itself for the
3122 // new focused input, even if its window wants to hide the IME).
3123 boolean didStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003124
Yohei Yukawa67464522019-01-28 00:50:09 -08003125 InputBindResult res = null;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003126 switch (softInputMode & LayoutParams.SOFT_INPUT_MASK_STATE) {
3127 case LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003128 if (!isTextEditor || !doAutoShow) {
Yohei Yukawa6e875592019-01-28 00:49:30 -08003129 if (LayoutParams.mayUseInputMethod(windowFlags)) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003130 // There is no focus view, and this window will
3131 // be behind any soft input window, so hide the
3132 // soft input window if it is shown.
3133 if (DEBUG) Slog.v(TAG, "Unspecified window will hide input");
3134 hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003135
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003136 // If focused display changed, we should unbind current method
3137 // to make app window in previous display relayout after Ime
3138 // window token removed.
3139 // Note that we can trust client's display ID as long as it matches
3140 // to the display ID obtained from the window.
3141 if (cs.selfReportedDisplayId != mCurTokenDisplayId) {
3142 unbindCurrentMethodLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003143 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003144 }
Yohei Yukawa6e875592019-01-28 00:49:30 -08003145 } else if (isTextEditor && doAutoShow
3146 && (softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003147 // There is a focus view, and we are navigating forward
3148 // into the window, so show the input window for the user.
3149 // We only do this automatically if the window can resize
3150 // to accommodate the IME (so what the user sees will give
3151 // them good context without input information being obscured
3152 // by the IME) or if running on a large screen where there
3153 // is more room for the target window + IME.
3154 if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
3155 if (attribute != null) {
3156 res = startInputUncheckedLocked(cs, inputContext, missingMethods,
3157 attribute, startInputFlags, startInputReason);
3158 didStart = true;
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003159 }
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08003160 showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003161 }
3162 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003163 case LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003164 // Do nothing.
3165 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003166 case LayoutParams.SOFT_INPUT_STATE_HIDDEN:
3167 if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003168 if (DEBUG) Slog.v(TAG, "Window asks to hide input going forward");
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003169 hideCurrentInputLocked(0, null);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003170 }
3171 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003172 case LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003173 if (DEBUG) Slog.v(TAG, "Window asks to hide input");
3174 hideCurrentInputLocked(0, null);
3175 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003176 case LayoutParams.SOFT_INPUT_STATE_VISIBLE:
3177 if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003178 if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003179 if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
3180 unverifiedTargetSdkVersion, startInputFlags)) {
3181 if (attribute != null) {
Yohei Yukawa67464522019-01-28 00:50:09 -08003182 res = startInputUncheckedLocked(cs, inputContext, missingMethods,
3183 attribute, startInputFlags, startInputReason);
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003184 didStart = true;
3185 }
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08003186 showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null);
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003187 } else {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003188 Slog.e(TAG, "SOFT_INPUT_STATE_VISIBLE is ignored because"
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003189 + " there is no focused view that also returns true from"
3190 + " View#onCheckIsTextEditor()");
3191 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003192 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003193 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003194 case LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003195 if (DEBUG) Slog.v(TAG, "Window asks to always show input");
3196 if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
3197 unverifiedTargetSdkVersion, startInputFlags)) {
3198 if (attribute != null) {
3199 res = startInputUncheckedLocked(cs, inputContext, missingMethods,
3200 attribute, startInputFlags, startInputReason);
3201 didStart = true;
3202 }
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08003203 showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003204 } else {
3205 Slog.e(TAG, "SOFT_INPUT_STATE_ALWAYS_VISIBLE is ignored because"
3206 + " there is no focused view that also returns true from"
3207 + " View#onCheckIsTextEditor()");
3208 }
3209 break;
3210 }
3211
3212 if (!didStart) {
3213 if (attribute != null) {
3214 if (!DebugFlags.FLAG_OPTIMIZE_START_INPUT.value()
3215 || (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0) {
Yohei Yukawa67464522019-01-28 00:50:09 -08003216 res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003217 startInputFlags, startInputReason);
3218 } else {
3219 res = InputBindResult.NO_EDITOR;
3220 }
3221 } else {
3222 res = InputBindResult.NULL_EDITOR_INFO;
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003223 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003224 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08003225 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003226 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003227
Guliz Tuncay6908c152017-06-02 16:06:10 -07003228 private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08003229 // TODO(yukawa): multi-display support.
Guliz Tuncay6908c152017-06-02 16:06:10 -07003230 final int uid = Binder.getCallingUid();
lumark0b05f9e2018-11-26 15:09:06 +08003231 if (mCurFocusedWindowClient != null && client != null
Tarandeep Singheb570612018-01-29 16:20:32 -08003232 && mCurFocusedWindowClient.client.asBinder() == client.asBinder()) {
Guliz Tuncay6908c152017-06-02 16:06:10 -07003233 return true;
3234 } else if (mCurIntent != null && InputMethodUtils.checkIfPackageBelongsToUid(
3235 mAppOpsManager,
3236 uid,
3237 mCurIntent.getComponent().getPackageName())) {
3238 return true;
Guliz Tuncay6908c152017-06-02 16:06:10 -07003239 }
Guliz Tuncay6908c152017-06-02 16:06:10 -07003240 return false;
3241 }
3242
satok42c5a162011-05-26 16:46:14 +09003243 @Override
Seigo Nonaka14e13912015-05-06 21:04:13 -07003244 public void showInputMethodPickerFromClient(
3245 IInputMethodClient client, int auxiliarySubtypeMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003246 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003247 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003248 return;
3249 }
Guliz Tuncay6908c152017-06-02 16:06:10 -07003250 if(!canShowInputMethodPickerLocked(client)) {
satok47a44912010-10-06 16:03:58 +09003251 Slog.w(TAG, "Ignoring showInputMethodPickerFromClient of uid "
Dianne Hackborncef65ee2010-09-30 18:27:22 -07003252 + Binder.getCallingUid() + ": " + client);
Guliz Tuncay6908c152017-06-02 16:06:10 -07003253 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003254 }
3255
satok440aab52010-11-25 09:43:11 +09003256 // Always call subtype picker, because subtype picker is a superset of input method
3257 // picker.
lumark0b05f9e2018-11-26 15:09:06 +08003258 mHandler.sendMessage(mCaller.obtainMessageII(
3259 MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode,
3260 (mCurClient != null) ? mCurClient.selfReportedDisplayId : DEFAULT_DISPLAY));
satokab751aa2010-09-14 19:17:36 +09003261 }
3262 }
3263
lumark0b05f9e2018-11-26 15:09:06 +08003264 @Override
3265 public void showInputMethodPickerFromSystem(IInputMethodClient client, int auxiliarySubtypeMode,
3266 int displayId) {
3267 if (mContext.checkCallingPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
3268 != PackageManager.PERMISSION_GRANTED) {
3269 throw new SecurityException(
3270 "showInputMethodPickerFromSystem requires WRITE_SECURE_SETTINGS permission");
3271 }
3272 // Always call subtype picker, because subtype picker is a superset of input method
3273 // picker.
3274 mHandler.sendMessage(mCaller.obtainMessageII(
3275 MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode, displayId));
3276 }
3277
Tarandeep Singheb570612018-01-29 16:20:32 -08003278 public boolean isInputMethodPickerShownForTest() {
3279 synchronized(mMethodMap) {
3280 if (mSwitchingDialog == null) {
3281 return false;
3282 }
3283 return mSwitchingDialog.isShowing();
3284 }
3285 }
3286
Yohei Yukawa0c1ebff2018-12-27 14:06:28 -08003287 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003288 private void setInputMethod(@NonNull IBinder token, String id) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003289 synchronized (mMethodMap) {
Yohei Yukawa0c1ebff2018-12-27 14:06:28 -08003290 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003291 return;
3292 }
3293 setInputMethodWithSubtypeIdLocked(token, id, NOT_A_SUBTYPE_ID);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003294 }
satok28203512010-11-24 11:06:49 +09003295 }
3296
Yohei Yukawa4773ee12018-12-24 21:13:53 -08003297 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003298 private void setInputMethodAndSubtype(@NonNull IBinder token, String id,
3299 InputMethodSubtype subtype) {
satok28203512010-11-24 11:06:49 +09003300 synchronized (mMethodMap) {
Yohei Yukawa4773ee12018-12-24 21:13:53 -08003301 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003302 return;
3303 }
satok28203512010-11-24 11:06:49 +09003304 if (subtype != null) {
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003305 setInputMethodWithSubtypeIdLocked(token, id,
3306 InputMethodUtils.getSubtypeIdFromHashCode(mMethodMap.get(id),
3307 subtype.hashCode()));
satok28203512010-11-24 11:06:49 +09003308 } else {
3309 setInputMethod(token, id);
3310 }
3311 }
satokab751aa2010-09-14 19:17:36 +09003312 }
3313
satok42c5a162011-05-26 16:46:14 +09003314 @Override
satokb416a712010-11-25 20:42:14 +09003315 public void showInputMethodAndSubtypeEnablerFromClient(
satok217f5482010-12-15 05:19:19 +09003316 IInputMethodClient client, String inputMethodId) {
satokb416a712010-11-25 20:42:14 +09003317 synchronized (mMethodMap) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003318 // TODO(yukawa): Should we verify the display ID?
Yohei Yukawa46d74762019-01-22 10:17:22 -08003319 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003320 return;
3321 }
satok7fee71f2010-12-17 18:54:26 +09003322 executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
3323 MSG_SHOW_IM_SUBTYPE_ENABLER, inputMethodId));
satokb416a712010-11-25 20:42:14 +09003324 }
3325 }
3326
Yohei Yukawa0c499082018-12-09 18:52:02 -08003327 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003328 private boolean switchToPreviousInputMethod(@NonNull IBinder token) {
satok735cf382010-11-11 20:40:09 +09003329 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003330 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa0c499082018-12-09 18:52:02 -08003331 return false;
3332 }
satokc445bcd2011-01-25 18:57:24 +09003333 final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
satok4fc87d62011-05-20 16:13:43 +09003334 final InputMethodInfo lastImi;
satok208d5632011-05-20 22:13:38 +09003335 if (lastIme != null) {
satok4fc87d62011-05-20 16:13:43 +09003336 lastImi = mMethodMap.get(lastIme.first);
3337 } else {
3338 lastImi = null;
satok735cf382010-11-11 20:40:09 +09003339 }
satok4fc87d62011-05-20 16:13:43 +09003340 String targetLastImiId = null;
3341 int subtypeId = NOT_A_SUBTYPE_ID;
3342 if (lastIme != null && lastImi != null) {
3343 final boolean imiIdIsSame = lastImi.getId().equals(mCurMethodId);
Narayan Kamatha09b4d22016-04-15 18:32:45 +01003344 final int lastSubtypeHash = Integer.parseInt(lastIme.second);
satok4fc87d62011-05-20 16:13:43 +09003345 final int currentSubtypeHash = mCurrentSubtype == null ? NOT_A_SUBTYPE_ID
3346 : mCurrentSubtype.hashCode();
3347 // If the last IME is the same as the current IME and the last subtype is not
3348 // defined, there is no need to switch to the last IME.
3349 if (!imiIdIsSame || lastSubtypeHash != currentSubtypeHash) {
3350 targetLastImiId = lastIme.first;
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003351 subtypeId = InputMethodUtils.getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
satok4fc87d62011-05-20 16:13:43 +09003352 }
3353 }
3354
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003355 if (TextUtils.isEmpty(targetLastImiId)
3356 && !InputMethodUtils.canAddToLastInputMethod(mCurrentSubtype)) {
satok4fc87d62011-05-20 16:13:43 +09003357 // This is a safety net. If the currentSubtype can't be added to the history
3358 // and the framework couldn't find the last ime, we will make the last ime be
3359 // the most applicable enabled keyboard subtype of the system imes.
3360 final List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
3361 if (enabled != null) {
3362 final int N = enabled.size();
3363 final String locale = mCurrentSubtype == null
3364 ? mRes.getConfiguration().locale.toString()
3365 : mCurrentSubtype.getLocale();
3366 for (int i = 0; i < N; ++i) {
3367 final InputMethodInfo imi = enabled.get(i);
Yohei Yukawafd70fe82018-04-08 12:19:56 -07003368 if (imi.getSubtypeCount() > 0 && imi.isSystem()) {
satok4fc87d62011-05-20 16:13:43 +09003369 InputMethodSubtype keyboardSubtype =
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003370 InputMethodUtils.findLastResortApplicableSubtypeLocked(mRes,
3371 InputMethodUtils.getSubtypes(imi),
3372 InputMethodUtils.SUBTYPE_MODE_KEYBOARD, locale, true);
satok4fc87d62011-05-20 16:13:43 +09003373 if (keyboardSubtype != null) {
3374 targetLastImiId = imi.getId();
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003375 subtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
satok4fc87d62011-05-20 16:13:43 +09003376 imi, keyboardSubtype.hashCode());
3377 if(keyboardSubtype.getLocale().equals(locale)) {
3378 break;
3379 }
3380 }
3381 }
3382 }
3383 }
3384 }
3385
3386 if (!TextUtils.isEmpty(targetLastImiId)) {
3387 if (DEBUG) {
3388 Slog.d(TAG, "Switch to: " + lastImi.getId() + ", " + lastIme.second
3389 + ", from: " + mCurMethodId + ", " + subtypeId);
3390 }
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003391 setInputMethodWithSubtypeIdLocked(token, targetLastImiId, subtypeId);
satok4fc87d62011-05-20 16:13:43 +09003392 return true;
3393 } else {
3394 return false;
3395 }
satok735cf382010-11-11 20:40:09 +09003396 }
3397 }
3398
Yohei Yukawa70f17e72018-12-09 18:51:38 -08003399 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003400 private boolean switchToNextInputMethod(@NonNull IBinder token, boolean onlyCurrentIme) {
satok688bd472012-02-09 20:09:17 +09003401 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003402 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawaa0755742014-06-04 20:28:18 +09003403 return false;
3404 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003405 final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
Yohei Yukawa136b6ce2018-05-02 10:55:35 -07003406 onlyCurrentIme, mMethodMap.get(mCurMethodId), mCurrentSubtype);
satok688bd472012-02-09 20:09:17 +09003407 if (nextSubtype == null) {
3408 return false;
3409 }
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003410 setInputMethodWithSubtypeIdLocked(token, nextSubtype.mImi.getId(),
3411 nextSubtype.mSubtypeId);
satok688bd472012-02-09 20:09:17 +09003412 return true;
3413 }
3414 }
3415
Yohei Yukawaeec552e2018-09-09 20:48:41 -07003416 @BinderThread
3417 private boolean shouldOfferSwitchingToNextInputMethod(@NonNull IBinder token) {
Satoshi Kataoka2b10b522013-08-21 20:39:12 +09003418 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003419 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawaa0755742014-06-04 20:28:18 +09003420 return false;
3421 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003422 final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
Yohei Yukawa136b6ce2018-05-02 10:55:35 -07003423 false /* onlyCurrentIme */, mMethodMap.get(mCurMethodId), mCurrentSubtype);
Satoshi Kataoka2b10b522013-08-21 20:39:12 +09003424 if (nextSubtype == null) {
3425 return false;
3426 }
3427 return true;
3428 }
3429 }
3430
3431 @Override
satok68f1b782011-04-11 14:26:04 +09003432 public InputMethodSubtype getLastInputMethodSubtype() {
3433 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003434 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003435 return null;
3436 }
satok68f1b782011-04-11 14:26:04 +09003437 final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
3438 // TODO: Handle the case of the last IME with no subtypes
3439 if (lastIme == null || TextUtils.isEmpty(lastIme.first)
3440 || TextUtils.isEmpty(lastIme.second)) return null;
3441 final InputMethodInfo lastImi = mMethodMap.get(lastIme.first);
3442 if (lastImi == null) return null;
3443 try {
Narayan Kamatha09b4d22016-04-15 18:32:45 +01003444 final int lastSubtypeHash = Integer.parseInt(lastIme.second);
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003445 final int lastSubtypeId =
3446 InputMethodUtils.getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
satok0e7d7d62011-07-05 13:28:06 +09003447 if (lastSubtypeId < 0 || lastSubtypeId >= lastImi.getSubtypeCount()) {
3448 return null;
3449 }
3450 return lastImi.getSubtypeAt(lastSubtypeId);
satok68f1b782011-04-11 14:26:04 +09003451 } catch (NumberFormatException e) {
3452 return null;
3453 }
3454 }
3455 }
3456
satoke7c6998e2011-06-03 17:57:59 +09003457 @Override
satokee5e77c2011-09-02 18:50:15 +09003458 public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
satok91e88122011-07-18 11:11:42 +09003459 // By this IPC call, only a process which shares the same uid with the IME can add
3460 // additional input method subtypes to the IME.
Yohei Yukawa70f5c482016-01-04 19:42:36 -08003461 if (TextUtils.isEmpty(imiId) || subtypes == null) return;
Yohei Yukawab557d572018-12-29 21:26:26 -08003462 final ArrayList<InputMethodSubtype> toBeAdded = new ArrayList<>();
3463 for (InputMethodSubtype subtype : subtypes) {
3464 if (!toBeAdded.contains(subtype)) {
3465 toBeAdded.add(subtype);
3466 } else {
3467 Slog.w(TAG, "Duplicated subtype definition found: "
3468 + subtype.getLocale() + ", " + subtype.getMode());
3469 }
3470 }
satoke7c6998e2011-06-03 17:57:59 +09003471 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003472 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003473 return;
3474 }
Yohei Yukawa79247822017-01-23 15:26:15 -08003475 if (!mSystemReady) {
3476 return;
3477 }
satok91e88122011-07-18 11:11:42 +09003478 final InputMethodInfo imi = mMethodMap.get(imiId);
satokee5e77c2011-09-02 18:50:15 +09003479 if (imi == null) return;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003480 final String[] packageInfos;
3481 try {
3482 packageInfos = mIPackageManager.getPackagesForUid(Binder.getCallingUid());
3483 } catch (RemoteException e) {
3484 Slog.e(TAG, "Failed to get package infos");
3485 return;
3486 }
satok91e88122011-07-18 11:11:42 +09003487 if (packageInfos != null) {
3488 final int packageNum = packageInfos.length;
3489 for (int i = 0; i < packageNum; ++i) {
3490 if (packageInfos[i].equals(imi.getPackageName())) {
Yohei Yukawa7b1c8d72018-12-19 11:21:04 -08003491 if (subtypes.length > 0) {
Yohei Yukawab557d572018-12-29 21:26:26 -08003492 mAdditionalSubtypeMap.put(imi.getId(), toBeAdded);
Yohei Yukawa7b1c8d72018-12-19 11:21:04 -08003493 } else {
Yohei Yukawab557d572018-12-29 21:26:26 -08003494 mAdditionalSubtypeMap.remove(imi.getId());
Yohei Yukawa7b1c8d72018-12-19 11:21:04 -08003495 }
Yohei Yukawab557d572018-12-29 21:26:26 -08003496 AdditionalSubtypeUtils.save(mAdditionalSubtypeMap, mMethodMap,
3497 mSettings.getCurrentUserId());
satokc5933802011-08-31 21:26:04 +09003498 final long ident = Binder.clearCallingIdentity();
3499 try {
Yohei Yukawa94e33302016-02-12 19:37:03 -08003500 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
satokc5933802011-08-31 21:26:04 +09003501 } finally {
3502 Binder.restoreCallingIdentity(ident);
3503 }
satokee5e77c2011-09-02 18:50:15 +09003504 return;
satok91e88122011-07-18 11:11:42 +09003505 }
3506 }
3507 }
satoke7c6998e2011-06-03 17:57:59 +09003508 }
satokee5e77c2011-09-02 18:50:15 +09003509 return;
satoke7c6998e2011-06-03 17:57:59 +09003510 }
3511
Yohei Yukawab985e6e2018-09-05 17:07:52 -07003512 /**
Austin Wanga63a2c02019-12-19 06:38:19 +00003513 * This is kept due to {@link android.annotation.UnsupportedAppUsage} in
Yohei Yukawab985e6e2018-09-05 17:07:52 -07003514 * {@link InputMethodManager#getInputMethodWindowVisibleHeight()} and a dependency in
3515 * {@link InputMethodService#onCreate()}.
3516 *
3517 * <p>TODO(Bug 113914148): Check if we can remove this.</p>
3518 * @return {@link WindowManagerInternal#getInputMethodWindowVisibleHeight()}
3519 */
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09003520 @Override
3521 public int getInputMethodWindowVisibleHeight() {
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08003522 // TODO(yukawa): Should we verify the display ID?
lumark90120a82018-08-15 00:33:03 +08003523 return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId);
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09003524 }
3525
Yohei Yukawab4f328a2019-05-02 08:41:27 -07003526 @Override
3527 public void reportActivityView(IInputMethodClient parentClient, int childDisplayId,
3528 float[] matrixValues) {
3529 final DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(childDisplayId);
3530 if (displayInfo == null) {
3531 throw new IllegalArgumentException(
3532 "Cannot find display for non-existent displayId: " + childDisplayId);
3533 }
3534 final int callingUid = Binder.getCallingUid();
3535 if (callingUid != displayInfo.ownerUid) {
3536 throw new SecurityException("The caller doesn't own the display.");
3537 }
3538
3539 synchronized (mMethodMap) {
3540 final ClientState cs = mClients.get(parentClient.asBinder());
3541 if (cs == null) {
3542 return;
3543 }
3544
3545 // null matrixValues means that the entry needs to be removed.
3546 if (matrixValues == null) {
3547 final ActivityViewInfo info = mActivityViewDisplayIdToParentMap.get(childDisplayId);
3548 if (info == null) {
3549 return;
3550 }
3551 if (info.mParentClient != cs) {
3552 throw new SecurityException("Only the owner client can clear"
3553 + " ActivityViewGeometry for display #" + childDisplayId);
3554 }
3555 mActivityViewDisplayIdToParentMap.remove(childDisplayId);
3556 return;
3557 }
3558
3559 ActivityViewInfo info = mActivityViewDisplayIdToParentMap.get(childDisplayId);
3560 if (info != null && info.mParentClient != cs) {
3561 throw new InvalidParameterException("Display #" + childDisplayId
3562 + " is already registered by " + info.mParentClient);
3563 }
3564 if (info == null) {
3565 if (!mWindowManagerInternal.isUidAllowedOnDisplay(childDisplayId, cs.uid)) {
3566 throw new SecurityException(cs + " cannot access to display #"
3567 + childDisplayId);
3568 }
3569 info = new ActivityViewInfo(cs, new Matrix());
3570 mActivityViewDisplayIdToParentMap.put(childDisplayId, info);
3571 }
3572 info.mMatrix.setValues(matrixValues);
3573
3574 if (mCurClient == null || mCurClient.curSession == null) {
3575 return;
3576 }
3577
3578 Matrix matrix = null;
3579 int displayId = mCurClient.selfReportedDisplayId;
3580 boolean needToNotify = false;
3581 while (true) {
3582 needToNotify |= (displayId == childDisplayId);
3583 final ActivityViewInfo next = mActivityViewDisplayIdToParentMap.get(displayId);
3584 if (next == null) {
3585 break;
3586 }
3587 if (matrix == null) {
3588 matrix = new Matrix(next.mMatrix);
3589 } else {
3590 matrix.postConcat(next.mMatrix);
3591 }
3592 if (next.mParentClient.selfReportedDisplayId == mCurTokenDisplayId) {
3593 if (needToNotify) {
3594 final float[] values = new float[9];
3595 matrix.getValues(values);
3596 try {
3597 mCurClient.client.updateActivityViewToScreenMatrix(mCurSeq, values);
3598 } catch (RemoteException e) {
3599 }
3600 }
3601 break;
3602 }
3603 displayId = info.mParentClient.selfReportedDisplayId;
3604 }
3605 }
3606 }
3607
Yohei Yukawac54c1172018-09-06 11:39:50 -07003608 @BinderThread
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003609 private void notifyUserAction(@NonNull IBinder token) {
Satoshi Kataokad7443c82013-10-15 17:45:43 +09003610 if (DEBUG) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003611 Slog.d(TAG, "Got the notification of a user action.");
Satoshi Kataokad7443c82013-10-15 17:45:43 +09003612 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003613 synchronized (mMethodMap) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003614 if (mCurToken != token) {
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09003615 if (DEBUG) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003616 Slog.d(TAG, "Ignoring the user action notification from IMEs that are no longer"
3617 + " active.");
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09003618 }
3619 return;
3620 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003621 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
3622 if (imi != null) {
Yohei Yukawa02970512014-06-05 16:16:18 +09003623 mSwitchingController.onUserActionLocked(imi, mCurrentSubtype);
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003624 }
Satoshi Kataokad7443c82013-10-15 17:45:43 +09003625 }
3626 }
3627
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08003628 @BinderThread
3629 private void reportPreRendered(IBinder token, EditorInfo info) {
3630 synchronized (mMethodMap) {
3631 if (!calledWithValidTokenLocked(token)) {
3632 return;
3633 }
3634 if (mCurClient != null && mCurClient.client != null) {
3635 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
3636 MSG_REPORT_PRE_RENDERED, info, mCurClient));
3637 }
3638 }
3639 }
3640
3641 @BinderThread
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08003642 private void applyImeVisibility(IBinder token, IBinder windowToken, boolean setVisible) {
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08003643 synchronized (mMethodMap) {
3644 if (!calledWithValidTokenLocked(token)) {
3645 return;
3646 }
Tarandeep Singh500a38f2019-09-26 13:36:40 -07003647 if (!setVisible) {
Taran Singhd7fc5862019-10-10 14:45:17 +02003648 if (mCurClient != null) {
3649 // IMMS only knows of focused window, not the actual IME target.
3650 // e.g. it isn't aware of any window that has both
3651 // NOT_FOCUSABLE, ALT_FOCUSABLE_IM flags set and can the IME target.
3652 // Send it to window manager to hide IME from IME target window.
3653 // TODO(b/139861270): send to mCurClient.client once IMMS is aware of
3654 // actual IME target.
3655 mWindowManagerInternal.hideIme(mCurClient.selfReportedDisplayId);
Tarandeep Singh500a38f2019-09-26 13:36:40 -07003656 }
3657 } else {
3658 // Send to window manager to show IME after IME layout finishes.
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08003659 mWindowManagerInternal.showImePostLayout(mShowRequestWindowMap.get(windowToken));
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08003660 }
3661 }
3662 }
3663
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003664 private void setInputMethodWithSubtypeIdLocked(IBinder token, String id, int subtypeId) {
3665 if (token == null) {
3666 if (mContext.checkCallingOrSelfPermission(
3667 android.Manifest.permission.WRITE_SECURE_SETTINGS)
3668 != PackageManager.PERMISSION_GRANTED) {
3669 throw new SecurityException(
3670 "Using null token requires permission "
3671 + android.Manifest.permission.WRITE_SECURE_SETTINGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003672 }
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003673 } else if (mCurToken != token) {
3674 Slog.w(TAG, "Ignoring setInputMethod of uid " + Binder.getCallingUid()
3675 + " token: " + token);
3676 return;
3677 }
3678
3679 final long ident = Binder.clearCallingIdentity();
3680 try {
3681 setInputMethodLocked(id, subtypeId);
3682 } finally {
3683 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003684 }
3685 }
3686
Yohei Yukawaeec552e2018-09-09 20:48:41 -07003687 @BinderThread
3688 private void hideMySoftInput(@NonNull IBinder token, int flags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003689 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003690 if (!calledWithValidTokenLocked(token)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003691 return;
3692 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003693 long ident = Binder.clearCallingIdentity();
3694 try {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003695 hideCurrentInputLocked(flags, null);
3696 } finally {
3697 Binder.restoreCallingIdentity(ident);
3698 }
3699 }
3700 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003701
Yohei Yukawaeec552e2018-09-09 20:48:41 -07003702 @BinderThread
3703 private void showMySoftInput(@NonNull IBinder token, int flags) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003704 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003705 if (!calledWithValidTokenLocked(token)) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003706 return;
3707 }
3708 long ident = Binder.clearCallingIdentity();
3709 try {
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08003710 showCurrentInputLocked(mLastImeTargetWindow, flags, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003711 } finally {
3712 Binder.restoreCallingIdentity(ident);
3713 }
3714 }
3715 }
3716
3717 void setEnabledSessionInMainThread(SessionState session) {
3718 if (mEnabledSession != session) {
Yohei Yukawa9d91b432014-05-19 16:03:24 +09003719 if (mEnabledSession != null && mEnabledSession.session != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003720 try {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003721 if (DEBUG) Slog.v(TAG, "Disabling: " + mEnabledSession);
Yohei Yukawa9d91b432014-05-19 16:03:24 +09003722 mEnabledSession.method.setSessionEnabled(mEnabledSession.session, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003723 } catch (RemoteException e) {
3724 }
3725 }
3726 mEnabledSession = session;
Yohei Yukawa9d91b432014-05-19 16:03:24 +09003727 if (mEnabledSession != null && mEnabledSession.session != null) {
3728 try {
3729 if (DEBUG) Slog.v(TAG, "Enabling: " + mEnabledSession);
3730 mEnabledSession.method.setSessionEnabled(mEnabledSession.session, true);
3731 } catch (RemoteException e) {
3732 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003733 }
3734 }
3735 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003736
Yohei Yukawa930328c2017-10-18 20:19:53 -07003737 @MainThread
satok42c5a162011-05-26 16:46:14 +09003738 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003739 public boolean handleMessage(Message msg) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003740 SomeArgs args;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003741 switch (msg.what) {
satokab751aa2010-09-14 19:17:36 +09003742 case MSG_SHOW_IM_SUBTYPE_PICKER:
Seigo Nonaka14e13912015-05-06 21:04:13 -07003743 final boolean showAuxSubtypes;
lumark0b05f9e2018-11-26 15:09:06 +08003744 final int displayId = msg.arg2;
Seigo Nonaka14e13912015-05-06 21:04:13 -07003745 switch (msg.arg1) {
3746 case InputMethodManager.SHOW_IM_PICKER_MODE_AUTO:
3747 // This is undocumented so far, but IMM#showInputMethodPicker() has been
3748 // implemented so that auxiliary subtypes will be excluded when the soft
3749 // keyboard is invisible.
3750 showAuxSubtypes = mInputShown;
3751 break;
3752 case InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES:
3753 showAuxSubtypes = true;
3754 break;
3755 case InputMethodManager.SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES:
3756 showAuxSubtypes = false;
3757 break;
3758 default:
3759 Slog.e(TAG, "Unknown subtype picker mode = " + msg.arg1);
3760 return false;
3761 }
lumark0b05f9e2018-11-26 15:09:06 +08003762 showInputMethodMenu(showAuxSubtypes, displayId);
satokab751aa2010-09-14 19:17:36 +09003763 return true;
3764
satok47a44912010-10-06 16:03:58 +09003765 case MSG_SHOW_IM_SUBTYPE_ENABLER:
Yohei Yukawa41f34272015-12-14 15:41:52 -08003766 showInputMethodAndSubtypeEnabler((String)msg.obj);
satok217f5482010-12-15 05:19:19 +09003767 return true;
3768
3769 case MSG_SHOW_IM_CONFIG:
3770 showConfigureInputMethods();
satok47a44912010-10-06 16:03:58 +09003771 return true;
3772
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003773 // ---------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003774
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003775 case MSG_UNBIND_INPUT:
3776 try {
3777 ((IInputMethod)msg.obj).unbindInput();
3778 } catch (RemoteException e) {
3779 // There is nothing interesting about the method dying.
3780 }
3781 return true;
3782 case MSG_BIND_INPUT:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003783 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003784 try {
3785 ((IInputMethod)args.arg1).bindInput((InputBinding)args.arg2);
3786 } catch (RemoteException e) {
3787 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003788 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003789 return true;
3790 case MSG_SHOW_SOFT_INPUT:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003791 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003792 try {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07003793 if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".showSoftInput("
Craig Mautner6efb4c72013-03-13 10:17:41 -07003794 + msg.arg1 + ", " + args.arg2 + ")");
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08003795 ((IInputMethod) args.arg1).showSoftInput(
3796 (IBinder) args.arg3, msg.arg1, (ResultReceiver) args.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003797 } catch (RemoteException e) {
3798 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003799 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003800 return true;
3801 case MSG_HIDE_SOFT_INPUT:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003802 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003803 try {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07003804 if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".hideSoftInput(0, "
Craig Mautner6efb4c72013-03-13 10:17:41 -07003805 + args.arg2 + ")");
Craig Mautnerca0ac712013-03-14 09:43:02 -07003806 ((IInputMethod)args.arg1).hideSoftInput(0, (ResultReceiver)args.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003807 } catch (RemoteException e) {
3808 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003809 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003810 return true;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -07003811 case MSG_HIDE_CURRENT_INPUT_METHOD:
3812 synchronized (mMethodMap) {
3813 hideCurrentInputLocked(0, null);
3814 }
3815 return true;
Yohei Yukawac54c1172018-09-06 11:39:50 -07003816 case MSG_INITIALIZE_IME:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003817 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003818 try {
lumark90120a82018-08-15 00:33:03 +08003819 if (DEBUG) {
3820 Slog.v(TAG, "Sending attach of token: " + args.arg2 + " for display: "
3821 + msg.arg1);
3822 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07003823 final IBinder token = (IBinder) args.arg2;
lumark90120a82018-08-15 00:33:03 +08003824 ((IInputMethod) args.arg1).initializeInternal(token, msg.arg1,
Yohei Yukawac54c1172018-09-06 11:39:50 -07003825 new InputMethodPrivilegedOperationsImpl(this, token));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003826 } catch (RemoteException e) {
3827 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003828 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003829 return true;
Jeff Brownc28867a2013-03-26 15:42:39 -07003830 case MSG_CREATE_SESSION: {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003831 args = (SomeArgs)msg.obj;
Jeff Brown1951ce82013-04-04 22:45:12 -07003832 IInputMethod method = (IInputMethod)args.arg1;
Jeff Brownc28867a2013-03-26 15:42:39 -07003833 InputChannel channel = (InputChannel)args.arg2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003834 try {
Jeff Brown1951ce82013-04-04 22:45:12 -07003835 method.createSession(channel, (IInputSessionCallback)args.arg3);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003836 } catch (RemoteException e) {
Jeff Brownc28867a2013-03-26 15:42:39 -07003837 } finally {
Jeff Brown1951ce82013-04-04 22:45:12 -07003838 // Dispose the channel if the input method is not local to this process
3839 // because the remote proxy will get its own copy when unparceled.
3840 if (channel != null && Binder.isProxy(method)) {
Jeff Brownc28867a2013-03-26 15:42:39 -07003841 channel.dispose();
3842 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003843 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003844 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003845 return true;
Jeff Brownc28867a2013-03-26 15:42:39 -07003846 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003847 // ---------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003848
Yohei Yukawa19a80a12016-03-14 22:57:37 -07003849 case MSG_START_INPUT: {
Yohei Yukawaf7526b52017-02-11 20:57:10 -08003850 final int missingMethods = msg.arg1;
3851 final boolean restarting = msg.arg2 != 0;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07003852 args = (SomeArgs) msg.obj;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08003853 final IBinder startInputToken = (IBinder) args.arg1;
3854 final SessionState session = (SessionState) args.arg2;
3855 final IInputContext inputContext = (IInputContext) args.arg3;
3856 final EditorInfo editorInfo = (EditorInfo) args.arg4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003857 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003858 setEnabledSessionInMainThread(session);
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08003859 session.method.startInput(startInputToken, inputContext, missingMethods,
Tarandeep Singheadb1392018-11-09 18:15:57 +01003860 editorInfo, restarting, session.client.shouldPreRenderIme);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003861 } catch (RemoteException e) {
3862 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003863 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003864 return true;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07003865 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003866
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003867 // ---------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003868
Yohei Yukawa33e81792015-11-17 21:14:42 -08003869 case MSG_UNBIND_CLIENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003870 try {
Yohei Yukawa33e81792015-11-17 21:14:42 -08003871 ((IInputMethodClient)msg.obj).onUnbindMethod(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003872 } catch (RemoteException e) {
3873 // There is nothing interesting about the last client dying.
3874 }
3875 return true;
Yohei Yukawa33e81792015-11-17 21:14:42 -08003876 case MSG_BIND_CLIENT: {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003877 args = (SomeArgs)msg.obj;
Jeff Brown1951ce82013-04-04 22:45:12 -07003878 IInputMethodClient client = (IInputMethodClient)args.arg1;
3879 InputBindResult res = (InputBindResult)args.arg2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003880 try {
Jeff Brown1951ce82013-04-04 22:45:12 -07003881 client.onBindMethod(res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003882 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003883 Slog.w(TAG, "Client died receiving input method " + args.arg2);
Jeff Brown1951ce82013-04-04 22:45:12 -07003884 } finally {
3885 // Dispose the channel if the input method is not local to this process
3886 // because the remote proxy will get its own copy when unparceled.
3887 if (res.channel != null && Binder.isProxy(client)) {
3888 res.channel.dispose();
3889 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003890 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003891 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003892 return true;
Jeff Brown1951ce82013-04-04 22:45:12 -07003893 }
Dianne Hackborna6e41342012-05-22 16:30:34 -07003894 case MSG_SET_ACTIVE:
3895 try {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08003896 ((ClientState)msg.obj).client.setActive(msg.arg1 != 0, msg.arg2 != 0);
Dianne Hackborna6e41342012-05-22 16:30:34 -07003897 } catch (RemoteException e) {
3898 Slog.w(TAG, "Got RemoteException sending setActive(false) notification to pid "
3899 + ((ClientState)msg.obj).pid + " uid "
3900 + ((ClientState)msg.obj).uid);
3901 }
3902 return true;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07003903 case MSG_SET_INTERACTIVE:
3904 handleSetInteractive(msg.arg1 != 0);
3905 return true;
Yohei Yukawa2bc66172017-02-08 11:13:25 -08003906 case MSG_REPORT_FULLSCREEN_MODE: {
3907 final boolean fullscreen = msg.arg1 != 0;
3908 final ClientState clientState = (ClientState)msg.obj;
3909 try {
3910 clientState.client.reportFullscreenMode(fullscreen);
3911 } catch (RemoteException e) {
3912 Slog.w(TAG, "Got RemoteException sending "
3913 + "reportFullscreen(" + fullscreen + ") notification to pid="
3914 + clientState.pid + " uid=" + clientState.uid);
3915 }
3916 return true;
3917 }
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08003918 case MSG_REPORT_PRE_RENDERED: {
3919 args = (SomeArgs) msg.obj;
3920 final EditorInfo info = (EditorInfo) args.arg1;
3921 final ClientState clientState = (ClientState) args.arg2;
3922 try {
3923 clientState.client.reportPreRendered(info);
3924 } catch (RemoteException e) {
3925 Slog.w(TAG, "Got RemoteException sending "
3926 + "reportPreRendered(" + info + ") notification to pid="
3927 + clientState.pid + " uid=" + clientState.uid);
3928 }
3929 args.recycle();
3930 return true;
3931 }
3932 case MSG_APPLY_IME_VISIBILITY: {
3933 final boolean setVisible = msg.arg1 != 0;
3934 final ClientState clientState = (ClientState) msg.obj;
3935 try {
3936 clientState.client.applyImeVisibility(setVisible);
3937 } catch (RemoteException e) {
3938 Slog.w(TAG, "Got RemoteException sending "
3939 + "applyImeVisibility(" + setVisible + ") notification to pid="
3940 + clientState.pid + " uid=" + clientState.uid);
3941 }
3942 return true;
3943 }
satok01038492012-04-09 21:08:27 +09003944
3945 // --------------------------------------------------------------
3946 case MSG_HARD_KEYBOARD_SWITCH_CHANGED:
Michael Wright7b5a96b2014-08-09 19:28:42 -07003947 mHardKeyboardListener.handleHardKeyboardStatusChange(msg.arg1 == 1);
satok01038492012-04-09 21:08:27 +09003948 return true;
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07003949 case MSG_SYSTEM_UNLOCK_USER:
3950 final int userId = msg.arg1;
3951 onUnlockUser(userId);
3952 return true;
Adam Hebc67f2e2019-11-13 14:34:56 -08003953
3954 // ---------------------------------------------------------------
3955 case MSG_INLINE_SUGGESTIONS_REQUEST:
3956 args = (SomeArgs) msg.obj;
3957 final ComponentName componentName = (ComponentName) args.arg2;
3958 final AutofillId autofillId = (AutofillId) args.arg3;
3959 final IInlineSuggestionsRequestCallback callback =
3960 (IInlineSuggestionsRequestCallback) args.arg4;
3961 try {
3962 ((IInputMethod) args.arg1).onCreateInlineSuggestionsRequest(componentName,
3963 autofillId, callback);
3964 } catch (RemoteException e) {
3965 Slog.w(TAG, "RemoteException calling onCreateInlineSuggestionsRequest(): " + e);
3966 }
3967 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003968 }
3969 return false;
3970 }
3971
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07003972 private void handleSetInteractive(final boolean interactive) {
3973 synchronized (mMethodMap) {
3974 mIsInteractive = interactive;
Yohei Yukawa849443c2019-01-21 09:02:25 -08003975 updateSystemUiLocked(interactive ? mImeWindowVis : 0, mBackDisposition);
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07003976
3977 // Inform the current client of the change in active status
3978 if (mCurClient != null && mCurClient.client != null) {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08003979 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
3980 MSG_SET_ACTIVE, mIsInteractive ? 1 : 0, mInFullscreenMode ? 1 : 0,
3981 mCurClient));
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07003982 }
3983 }
3984 }
3985
satokdc9ddae2011-10-06 12:22:36 +09003986 private boolean chooseNewDefaultIMELocked() {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003987 final InputMethodInfo imi = InputMethodUtils.getMostApplicableDefaultIME(
3988 mSettings.getEnabledInputMethodListLocked());
satokdc9ddae2011-10-06 12:22:36 +09003989 if (imi != null) {
satok03eb319a2010-11-11 18:17:42 +09003990 if (DEBUG) {
3991 Slog.d(TAG, "New default IME was selected: " + imi.getId());
3992 }
satok723a27e2010-11-11 14:58:11 +09003993 resetSelectedInputMethodAndSubtypeLocked(imi.getId());
Brandon Ballinger6da35a02009-10-21 00:38:13 -07003994 return true;
3995 }
3996
3997 return false;
3998 }
3999
Yohei Yukawa05139322018-12-25 10:34:14 -08004000 static void queryInputMethodServicesInternal(Context context,
4001 @UserIdInt int userId, ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap,
4002 ArrayMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList) {
4003 methodList.clear();
4004 methodMap.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004005
Yohei Yukawaed4952a2016-02-17 07:57:25 -08004006 // Note: We do not specify PackageManager.MATCH_ENCRYPTION_* flags here because the default
4007 // behavior of PackageManager is exactly what we want. It by default picks up appropriate
4008 // services depending on the unlock state for the specified user.
Yohei Yukawa05139322018-12-25 10:34:14 -08004009 final List<ResolveInfo> services = context.getPackageManager().queryIntentServicesAsUser(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004010 new Intent(InputMethod.SERVICE_INTERFACE),
Yohei Yukawa5ec1fce2018-12-17 07:56:14 -08004011 PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS,
Yohei Yukawa05139322018-12-25 10:34:14 -08004012 userId);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004013
Yohei Yukawa05139322018-12-25 10:34:14 -08004014 methodList.ensureCapacity(services.size());
4015 methodMap.ensureCapacity(services.size());
4016
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004017 for (int i = 0; i < services.size(); ++i) {
4018 ResolveInfo ri = services.get(i);
4019 ServiceInfo si = ri.serviceInfo;
Yohei Yukawaddad4b92017-02-02 01:46:13 -08004020 final String imeId = InputMethodInfo.computeId(ri);
4021 if (!android.Manifest.permission.BIND_INPUT_METHOD.equals(si.permission)) {
4022 Slog.w(TAG, "Skipping input method " + imeId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004023 + ": it does not require the permission "
4024 + android.Manifest.permission.BIND_INPUT_METHOD);
4025 continue;
4026 }
4027
Yohei Yukawaddad4b92017-02-02 01:46:13 -08004028 if (DEBUG) Slog.d(TAG, "Checking " + imeId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004029
4030 try {
Yohei Yukawa05139322018-12-25 10:34:14 -08004031 final InputMethodInfo imi = new InputMethodInfo(context, ri,
4032 additionalSubtypeMap.get(imeId));
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08004033 if (imi.isVrOnly()) {
4034 continue; // Skip VR-only IME, which isn't supported for now.
4035 }
Yohei Yukawa05139322018-12-25 10:34:14 -08004036 methodList.add(imi);
4037 methodMap.put(imi.getId(), imi);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004038 if (DEBUG) {
Yohei Yukawa05139322018-12-25 10:34:14 -08004039 Slog.d(TAG, "Found an input method " + imi);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004040 }
Tadashi G. Takaoka3c23d5b2016-09-16 11:41:07 +09004041 } catch (Exception e) {
Yohei Yukawaddad4b92017-02-02 01:46:13 -08004042 Slog.wtf(TAG, "Unable to load input method " + imeId, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004043 }
4044 }
Yohei Yukawa05139322018-12-25 10:34:14 -08004045 }
4046
4047 @GuardedBy("mMethodMap")
4048 void buildInputMethodListLocked(boolean resetDefaultEnabledIme) {
4049 if (DEBUG) {
4050 Slog.d(TAG, "--- re-buildInputMethodList reset = " + resetDefaultEnabledIme
4051 + " \n ------ caller=" + Debug.getCallers(10));
4052 }
4053 if (!mSystemReady) {
4054 Slog.e(TAG, "buildInputMethodListLocked is not allowed until system is ready");
4055 return;
4056 }
4057 mMethodMapUpdateCount++;
4058 mMyPackageMonitor.clearKnownImePackageNamesLocked();
4059
4060 queryInputMethodServicesInternal(mContext, mSettings.getCurrentUserId(),
Yohei Yukawab557d572018-12-29 21:26:26 -08004061 mAdditionalSubtypeMap, mMethodMap, mMethodList);
Brandon Ballinger6da35a02009-10-21 00:38:13 -07004062
Yohei Yukawac4e44912017-02-09 19:30:22 -08004063 // Construct the set of possible IME packages for onPackageChanged() to avoid false
4064 // negatives when the package state remains to be the same but only the component state is
4065 // changed.
4066 {
4067 // Here we intentionally use PackageManager.MATCH_DISABLED_COMPONENTS since the purpose
4068 // of this query is to avoid false negatives. PackageManager.MATCH_ALL could be more
4069 // conservative, but it seems we cannot use it for now (Issue 35176630).
Yohei Yukawa05139322018-12-25 10:34:14 -08004070 final List<ResolveInfo> allInputMethodServices =
4071 mContext.getPackageManager().queryIntentServicesAsUser(
4072 new Intent(InputMethod.SERVICE_INTERFACE),
4073 PackageManager.MATCH_DISABLED_COMPONENTS, mSettings.getCurrentUserId());
Yohei Yukawac4e44912017-02-09 19:30:22 -08004074 final int N = allInputMethodServices.size();
4075 for (int i = 0; i < N; ++i) {
4076 final ServiceInfo si = allInputMethodServices.get(i).serviceInfo;
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08004077 if (android.Manifest.permission.BIND_INPUT_METHOD.equals(si.permission)) {
4078 mMyPackageMonitor.addKnownImePackageNameLocked(si.packageName);
Yohei Yukawac4e44912017-02-09 19:30:22 -08004079 }
Yohei Yukawac4e44912017-02-09 19:30:22 -08004080 }
4081 }
4082
Yohei Yukawa9c372192018-03-20 22:54:56 -07004083 boolean reenableMinimumNonAuxSystemImes = false;
Yohei Yukawa859df052016-02-17 07:56:46 -08004084 // TODO: The following code should find better place to live.
4085 if (!resetDefaultEnabledIme) {
4086 boolean enabledImeFound = false;
Yohei Yukawa9c372192018-03-20 22:54:56 -07004087 boolean enabledNonAuxImeFound = false;
Yohei Yukawa859df052016-02-17 07:56:46 -08004088 final List<InputMethodInfo> enabledImes = mSettings.getEnabledInputMethodListLocked();
4089 final int N = enabledImes.size();
4090 for (int i = 0; i < N; ++i) {
4091 final InputMethodInfo imi = enabledImes.get(i);
4092 if (mMethodList.contains(imi)) {
4093 enabledImeFound = true;
Yohei Yukawa9c372192018-03-20 22:54:56 -07004094 if (!imi.isAuxiliaryIme()) {
4095 enabledNonAuxImeFound = true;
4096 break;
4097 }
Yohei Yukawa859df052016-02-17 07:56:46 -08004098 }
4099 }
4100 if (!enabledImeFound) {
Yohei Yukawad0332832017-02-01 13:59:43 -08004101 if (DEBUG) {
4102 Slog.i(TAG, "All the enabled IMEs are gone. Reset default enabled IMEs.");
4103 }
Yohei Yukawa859df052016-02-17 07:56:46 -08004104 resetDefaultEnabledIme = true;
4105 resetSelectedInputMethodAndSubtypeLocked("");
Yohei Yukawa9c372192018-03-20 22:54:56 -07004106 } else if (!enabledNonAuxImeFound) {
4107 if (DEBUG) {
4108 Slog.i(TAG, "All the enabled non-Aux IMEs are gone. Do partial reset.");
4109 }
4110 reenableMinimumNonAuxSystemImes = true;
Yohei Yukawa859df052016-02-17 07:56:46 -08004111 }
4112 }
4113
Yohei Yukawa9c372192018-03-20 22:54:56 -07004114 if (resetDefaultEnabledIme || reenableMinimumNonAuxSystemImes) {
Satoshi Kataokaf1367b72013-01-25 17:20:12 +09004115 final ArrayList<InputMethodInfo> defaultEnabledIme =
Yohei Yukawa9c372192018-03-20 22:54:56 -07004116 InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList,
4117 reenableMinimumNonAuxSystemImes);
Yohei Yukawa68645a62016-02-17 07:54:20 -08004118 final int N = defaultEnabledIme.size();
4119 for (int i = 0; i < N; ++i) {
Satoshi Kataokaf1367b72013-01-25 17:20:12 +09004120 final InputMethodInfo imi = defaultEnabledIme.get(i);
4121 if (DEBUG) {
4122 Slog.d(TAG, "--- enable ime = " + imi);
4123 }
4124 setInputMethodEnabledLocked(imi.getId(), true);
4125 }
4126 }
4127
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004128 final String defaultImiId = mSettings.getSelectedInputMethod();
satok0a1bcf42012-05-16 19:26:31 +09004129 if (!TextUtils.isEmpty(defaultImiId)) {
Yohei Yukawa94e33302016-02-12 19:37:03 -08004130 if (!mMethodMap.containsKey(defaultImiId)) {
satok0a1bcf42012-05-16 19:26:31 +09004131 Slog.w(TAG, "Default IME is uninstalled. Choose new default IME.");
4132 if (chooseNewDefaultIMELocked()) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07004133 updateInputMethodsFromSettingsLocked(true);
satok0a1bcf42012-05-16 19:26:31 +09004134 }
4135 } else {
4136 // Double check that the default IME is certainly enabled.
4137 setInputMethodEnabledLocked(defaultImiId, true);
Brandon Ballinger6da35a02009-10-21 00:38:13 -07004138 }
4139 }
Yohei Yukawa3d46bab2014-05-30 18:10:18 +09004140 // Here is not the perfect place to reset the switching controller. Ideally
4141 // mSwitchingController and mSettings should be able to share the same state.
4142 // TODO: Make sure that mSwitchingController and mSettings are sharing the
4143 // the same enabled IMEs list.
Yohei Yukawac834a252014-05-21 22:42:32 +09004144 mSwitchingController.resetCircularListLocked(mContext);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004145 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004146
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004147 // ----------------------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004148
satok217f5482010-12-15 05:19:19 +09004149 private void showInputMethodAndSubtypeEnabler(String inputMethodId) {
Tadashi G. Takaokaf49688f2011-01-20 17:56:13 +09004150 Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS);
satok47a44912010-10-06 16:03:58 +09004151 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
satok86417ea2010-10-27 14:11:03 +09004152 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
4153 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
satok7fee71f2010-12-17 18:54:26 +09004154 if (!TextUtils.isEmpty(inputMethodId)) {
Tadashi G. Takaoka25480202011-01-20 23:13:02 +09004155 intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, inputMethodId);
satok7fee71f2010-12-17 18:54:26 +09004156 }
Yohei Yukawa41f34272015-12-14 15:41:52 -08004157 final int userId;
4158 synchronized (mMethodMap) {
4159 userId = mSettings.getCurrentUserId();
4160 }
4161 mContext.startActivityAsUser(intent, null, UserHandle.of(userId));
satok217f5482010-12-15 05:19:19 +09004162 }
4163
4164 private void showConfigureInputMethods() {
4165 Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS);
4166 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
4167 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
4168 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
Satoshi Kataoka3ba439d2012-10-05 18:30:13 +09004169 mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
satok47a44912010-10-06 16:03:58 +09004170 }
4171
satok2c93efc2012-04-02 19:33:47 +09004172 private boolean isScreenLocked() {
4173 return mKeyguardManager != null
4174 && mKeyguardManager.isKeyguardLocked() && mKeyguardManager.isKeyguardSecure();
4175 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004176
lumark0b05f9e2018-11-26 15:09:06 +08004177 private void showInputMethodMenu(boolean showAuxSubtypes, int displayId) {
Seigo Nonaka14e13912015-05-06 21:04:13 -07004178 if (DEBUG) Slog.v(TAG, "Show switching menu. showAuxSubtypes=" + showAuxSubtypes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004179
satok2c93efc2012-04-02 19:33:47 +09004180 final boolean isScreenLocked = isScreenLocked();
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004181
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004182 final String lastInputMethodId = mSettings.getSelectedInputMethod();
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004183 int lastInputMethodSubtypeId = mSettings.getSelectedInputMethodSubtypeId(lastInputMethodId);
Joe Onorato8a9b2202010-02-26 18:56:32 -08004184 if (DEBUG) Slog.v(TAG, "Current IME: " + lastInputMethodId);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004185
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004186 synchronized (mMethodMap) {
Yohei Yukawacf3bbff2018-11-20 17:24:20 -08004187 final List<ImeSubtypeListItem> imList =
4188 mSwitchingController.getSortedInputMethodAndSubtypeListLocked(
4189 showAuxSubtypes, isScreenLocked);
4190 if (imList.isEmpty()) {
satok7f35c8c2010-10-07 21:13:11 +09004191 return;
4192 }
4193
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004194 hideInputMethodMenuLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004195
satokc3690562012-01-10 20:14:43 +09004196 if (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004197 final InputMethodSubtype currentSubtype = getCurrentInputMethodSubtypeLocked();
satokc3690562012-01-10 20:14:43 +09004198 if (currentSubtype != null) {
4199 final InputMethodInfo currentImi = mMethodMap.get(mCurMethodId);
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004200 lastInputMethodSubtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
4201 currentImi, currentSubtype.hashCode());
satokc3690562012-01-10 20:14:43 +09004202 }
4203 }
4204
Ken Wakasa761eb372011-03-04 19:06:18 +09004205 final int N = imList.size();
satokab751aa2010-09-14 19:17:36 +09004206 mIms = new InputMethodInfo[N];
4207 mSubtypeIds = new int[N];
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004208 int checkedItem = 0;
4209 for (int i = 0; i < N; ++i) {
Ken Wakasa05dbb652011-08-22 15:22:43 +09004210 final ImeSubtypeListItem item = imList.get(i);
4211 mIms[i] = item.mImi;
4212 mSubtypeIds[i] = item.mSubtypeId;
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004213 if (mIms[i].getId().equals(lastInputMethodId)) {
satokab751aa2010-09-14 19:17:36 +09004214 int subtypeId = mSubtypeIds[i];
4215 if ((subtypeId == NOT_A_SUBTYPE_ID)
4216 || (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID && subtypeId == 0)
4217 || (subtypeId == lastInputMethodSubtypeId)) {
4218 checkedItem = i;
4219 }
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004220 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004221 }
Alan Viverette505e3ab2014-11-24 15:22:11 -08004222
lumark0b05f9e2018-11-26 15:09:06 +08004223 final ActivityThread currentThread = ActivityThread.currentActivityThread();
Andrew Sapperstein8a3b4cb2017-04-28 14:35:31 -07004224 final Context settingsContext = new ContextThemeWrapper(
lumark0b05f9e2018-11-26 15:09:06 +08004225 displayId == DEFAULT_DISPLAY ? currentThread.getSystemUiContext()
4226 : currentThread.createSystemUiContext(displayId),
Alan Viverette505e3ab2014-11-24 15:22:11 -08004227 com.android.internal.R.style.Theme_DeviceDefault_Settings);
4228
4229 mDialogBuilder = new AlertDialog.Builder(settingsContext);
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004230 mDialogBuilder.setOnCancelListener(new OnCancelListener() {
4231 @Override
4232 public void onCancel(DialogInterface dialog) {
4233 hideInputMethodMenu();
4234 }
4235 });
Alan Viverette505e3ab2014-11-24 15:22:11 -08004236
4237 final Context dialogContext = mDialogBuilder.getContext();
4238 final TypedArray a = dialogContext.obtainStyledAttributes(null,
4239 com.android.internal.R.styleable.DialogPreference,
4240 com.android.internal.R.attr.alertDialogStyle, 0);
4241 final Drawable dialogIcon = a.getDrawable(
4242 com.android.internal.R.styleable.DialogPreference_dialogIcon);
4243 a.recycle();
4244
4245 mDialogBuilder.setIcon(dialogIcon);
4246
Yohei Yukawad34e1482016-02-11 08:03:52 -08004247 final LayoutInflater inflater = dialogContext.getSystemService(LayoutInflater.class);
satok01038492012-04-09 21:08:27 +09004248 final View tv = inflater.inflate(
4249 com.android.internal.R.layout.input_method_switch_dialog_title, null);
4250 mDialogBuilder.setCustomTitle(tv);
4251
4252 // Setup layout for a toggle switch of the hardware keyboard
4253 mSwitchingDialogTitleView = tv;
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004254 mSwitchingDialogTitleView
4255 .findViewById(com.android.internal.R.id.hard_keyboard_section)
Seigo Nonaka7309b122015-08-17 18:34:13 -07004256 .setVisibility(mWindowManagerInternal.isHardKeyboardAvailable()
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004257 ? View.VISIBLE : View.GONE);
Alan Viverette505e3ab2014-11-24 15:22:11 -08004258 final Switch hardKeySwitch = (Switch) mSwitchingDialogTitleView.findViewById(
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004259 com.android.internal.R.id.hard_keyboard_switch);
Michael Wright7b5a96b2014-08-09 19:28:42 -07004260 hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004261 hardKeySwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
4262 @Override
4263 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07004264 mSettings.setShowImeWithHardKeyboard(isChecked);
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004265 // Ensure that the input method dialog is dismissed when changing
4266 // the hardware keyboard state.
4267 hideInputMethodMenu();
4268 }
4269 });
4270
Alan Viverette505e3ab2014-11-24 15:22:11 -08004271 final ImeSubtypeListAdapter adapter = new ImeSubtypeListAdapter(dialogContext,
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004272 com.android.internal.R.layout.input_method_switch_item, imList, checkedItem);
4273 final OnClickListener choiceListener = new OnClickListener() {
4274 @Override
4275 public void onClick(final DialogInterface dialog, final int which) {
4276 synchronized (mMethodMap) {
4277 if (mIms == null || mIms.length <= which || mSubtypeIds == null
4278 || mSubtypeIds.length <= which) {
4279 return;
satok01038492012-04-09 21:08:27 +09004280 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004281 final InputMethodInfo im = mIms[which];
4282 int subtypeId = mSubtypeIds[which];
4283 adapter.mCheckedItem = which;
4284 adapter.notifyDataSetChanged();
4285 hideInputMethodMenu();
4286 if (im != null) {
4287 if (subtypeId < 0 || subtypeId >= im.getSubtypeCount()) {
4288 subtypeId = NOT_A_SUBTYPE_ID;
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08004289 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004290 setInputMethodLocked(im.getId(), subtypeId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004291 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004292 }
4293 }
4294 };
4295 mDialogBuilder.setSingleChoiceItems(adapter, checkedItem, choiceListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004297 mSwitchingDialog = mDialogBuilder.create();
Dianne Hackborne3a7f622011-03-03 21:48:24 -08004298 mSwitchingDialog.setCanceledOnTouchOutside(true);
Wale Ogunwale3a931692016-11-02 16:49:48 -07004299 final Window w = mSwitchingDialog.getWindow();
Yohei Yukawa6e875592019-01-28 00:49:30 -08004300 final LayoutParams attrs = w.getAttributes();
4301 w.setType(LayoutParams.TYPE_INPUT_METHOD_DIALOG);
Wale Ogunwale3a931692016-11-02 16:49:48 -07004302 // Use an alternate token for the dialog for that window manager can group the token
4303 // with other IME windows based on type vs. grouping based on whichever token happens
4304 // to get selected by the system later on.
4305 attrs.token = mSwitchingDialogToken;
Roshan Piusa3f89c62019-10-11 08:50:53 -07004306 attrs.privateFlags |= LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
Wale Ogunwale3a931692016-11-02 16:49:48 -07004307 attrs.setTitle("Select input method");
4308 w.setAttributes(attrs);
Yohei Yukawa849443c2019-01-21 09:02:25 -08004309 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004310 mSwitchingDialog.show();
4311 }
4312 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004313
Ken Wakasa05dbb652011-08-22 15:22:43 +09004314 private static class ImeSubtypeListAdapter extends ArrayAdapter<ImeSubtypeListItem> {
4315 private final LayoutInflater mInflater;
4316 private final int mTextViewResourceId;
4317 private final List<ImeSubtypeListItem> mItemsList;
Satoshi Kataokad2142962012-11-12 18:43:06 +09004318 public int mCheckedItem;
Ken Wakasa05dbb652011-08-22 15:22:43 +09004319 public ImeSubtypeListAdapter(Context context, int textViewResourceId,
4320 List<ImeSubtypeListItem> itemsList, int checkedItem) {
4321 super(context, textViewResourceId, itemsList);
Alan Viverette505e3ab2014-11-24 15:22:11 -08004322
Ken Wakasa05dbb652011-08-22 15:22:43 +09004323 mTextViewResourceId = textViewResourceId;
4324 mItemsList = itemsList;
4325 mCheckedItem = checkedItem;
Yohei Yukawad34e1482016-02-11 08:03:52 -08004326 mInflater = context.getSystemService(LayoutInflater.class);
Ken Wakasa05dbb652011-08-22 15:22:43 +09004327 }
4328
4329 @Override
4330 public View getView(int position, View convertView, ViewGroup parent) {
4331 final View view = convertView != null ? convertView
4332 : mInflater.inflate(mTextViewResourceId, null);
4333 if (position < 0 || position >= mItemsList.size()) return view;
4334 final ImeSubtypeListItem item = mItemsList.get(position);
4335 final CharSequence imeName = item.mImeName;
4336 final CharSequence subtypeName = item.mSubtypeName;
4337 final TextView firstTextView = (TextView)view.findViewById(android.R.id.text1);
4338 final TextView secondTextView = (TextView)view.findViewById(android.R.id.text2);
4339 if (TextUtils.isEmpty(subtypeName)) {
4340 firstTextView.setText(imeName);
4341 secondTextView.setVisibility(View.GONE);
4342 } else {
4343 firstTextView.setText(subtypeName);
4344 secondTextView.setText(imeName);
4345 secondTextView.setVisibility(View.VISIBLE);
4346 }
4347 final RadioButton radioButton =
4348 (RadioButton)view.findViewById(com.android.internal.R.id.radio);
4349 radioButton.setChecked(position == mCheckedItem);
4350 return view;
4351 }
4352 }
4353
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004354 void hideInputMethodMenu() {
The Android Open Source Project10592532009-03-18 17:39:46 -07004355 synchronized (mMethodMap) {
4356 hideInputMethodMenuLocked();
4357 }
4358 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004359
The Android Open Source Project10592532009-03-18 17:39:46 -07004360 void hideInputMethodMenuLocked() {
Joe Onorato8a9b2202010-02-26 18:56:32 -08004361 if (DEBUG) Slog.v(TAG, "Hide switching menu");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004362
The Android Open Source Project10592532009-03-18 17:39:46 -07004363 if (mSwitchingDialog != null) {
4364 mSwitchingDialog.dismiss();
4365 mSwitchingDialog = null;
Yohei Yukawa1fc7a1d2018-04-18 17:31:27 -07004366 mSwitchingDialogTitleView = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004367 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004368
Yohei Yukawa849443c2019-01-21 09:02:25 -08004369 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
The Android Open Source Project10592532009-03-18 17:39:46 -07004370 mDialogBuilder = null;
The Android Open Source Project10592532009-03-18 17:39:46 -07004371 mIms = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004372 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004373
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004374 // ----------------------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004375
Yohei Yukawa3d3abd22019-04-09 23:20:12 -07004376 /**
4377 * Enable or disable the given IME by updating {@link Settings.Secure#ENABLED_INPUT_METHODS}.
4378 *
4379 * @param id ID of the IME is to be manipulated. It is OK to pass IME ID that is currently not
4380 * recognized by the system.
4381 * @param enabled {@code true} if {@code id} needs to be enabled.
4382 * @return {@code true} if the IME was previously enabled. {@code false} otherwise.
4383 */
4384 private boolean setInputMethodEnabledLocked(String id, boolean enabled) {
satokd87c2592010-09-29 11:52:06 +09004385 List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings
4386 .getEnabledInputMethodsAndSubtypeListLocked();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004387
satokd87c2592010-09-29 11:52:06 +09004388 if (enabled) {
4389 for (Pair<String, ArrayList<String>> pair: enabledInputMethodsList) {
4390 if (pair.first.equals(id)) {
4391 // We are enabling this input method, but it is already enabled.
4392 // Nothing to do. The previous state was enabled.
4393 return true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004394 }
4395 }
satokd87c2592010-09-29 11:52:06 +09004396 mSettings.appendAndPutEnabledInputMethodLocked(id, false);
4397 // Previous state was disabled.
4398 return false;
4399 } else {
4400 StringBuilder builder = new StringBuilder();
4401 if (mSettings.buildAndPutEnabledInputMethodsStrRemovingIdLocked(
4402 builder, enabledInputMethodsList, id)) {
4403 // Disabled input method is currently selected, switch to another one.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004404 final String selId = mSettings.getSelectedInputMethod();
satok03eb319a2010-11-11 18:17:42 +09004405 if (id.equals(selId) && !chooseNewDefaultIMELocked()) {
4406 Slog.i(TAG, "Can't find new IME, unsetting the current input method.");
4407 resetSelectedInputMethodAndSubtypeLocked("");
satokd87c2592010-09-29 11:52:06 +09004408 }
4409 // Previous state was enabled.
4410 return true;
4411 } else {
4412 // We are disabling the input method but it is already disabled.
4413 // Nothing to do. The previous state was disabled.
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004414 return false;
4415 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004416 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004417 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08004418
satok723a27e2010-11-11 14:58:11 +09004419 private void setSelectedInputMethodAndSubtypeLocked(InputMethodInfo imi, int subtypeId,
4420 boolean setSubtypeOnly) {
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08004421 mSettings.saveCurrentInputMethodAndSubtypeToHistory(mCurMethodId, mCurrentSubtype);
Tarandeep Singh89a6c482017-11-21 14:26:11 -08004422
satok723a27e2010-11-11 14:58:11 +09004423 // Set Subtype here
4424 if (imi == null || subtypeId < 0) {
4425 mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
Tadashi G. Takaoka0ba75bb2010-11-09 12:19:32 -08004426 mCurrentSubtype = null;
satok723a27e2010-11-11 14:58:11 +09004427 } else {
Ken Wakasa586f0512011-01-20 22:31:01 +09004428 if (subtypeId < imi.getSubtypeCount()) {
4429 InputMethodSubtype subtype = imi.getSubtypeAt(subtypeId);
4430 mSettings.putSelectedSubtype(subtype.hashCode());
4431 mCurrentSubtype = subtype;
satok723a27e2010-11-11 14:58:11 +09004432 } else {
4433 mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
satokd81e9502012-05-21 12:58:45 +09004434 // If the subtype is not specified, choose the most applicable one
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004435 mCurrentSubtype = getCurrentInputMethodSubtypeLocked();
satok723a27e2010-11-11 14:58:11 +09004436 }
satokab751aa2010-09-14 19:17:36 +09004437 }
satok723a27e2010-11-11 14:58:11 +09004438
Yohei Yukawa68645a62016-02-17 07:54:20 -08004439 if (!setSubtypeOnly) {
satok723a27e2010-11-11 14:58:11 +09004440 // Set InputMethod here
4441 mSettings.putSelectedInputMethod(imi != null ? imi.getId() : "");
4442 }
4443 }
4444
4445 private void resetSelectedInputMethodAndSubtypeLocked(String newDefaultIme) {
4446 InputMethodInfo imi = mMethodMap.get(newDefaultIme);
4447 int lastSubtypeId = NOT_A_SUBTYPE_ID;
4448 // newDefaultIme is empty when there is no candidate for the selected IME.
4449 if (imi != null && !TextUtils.isEmpty(newDefaultIme)) {
4450 String subtypeHashCode = mSettings.getLastSubtypeForInputMethodLocked(newDefaultIme);
4451 if (subtypeHashCode != null) {
4452 try {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004453 lastSubtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
Narayan Kamatha09b4d22016-04-15 18:32:45 +01004454 imi, Integer.parseInt(subtypeHashCode));
satok723a27e2010-11-11 14:58:11 +09004455 } catch (NumberFormatException e) {
4456 Slog.w(TAG, "HashCode for subtype looks broken: " + subtypeHashCode, e);
4457 }
4458 }
4459 }
4460 setSelectedInputMethodAndSubtypeLocked(imi, lastSubtypeId, false);
satokab751aa2010-09-14 19:17:36 +09004461 }
4462
satokab751aa2010-09-14 19:17:36 +09004463 /**
4464 * @return Return the current subtype of this input method.
4465 */
satok42c5a162011-05-26 16:46:14 +09004466 @Override
satokab751aa2010-09-14 19:17:36 +09004467 public InputMethodSubtype getCurrentInputMethodSubtype() {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004468 synchronized (mMethodMap) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08004469 // TODO: Make this work even for non-current users?
Yohei Yukawa46d74762019-01-22 10:17:22 -08004470 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08004471 return null;
4472 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004473 return getCurrentInputMethodSubtypeLocked();
4474 }
4475 }
4476
4477 private InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
satokfdf419e2012-05-08 16:52:08 +09004478 if (mCurMethodId == null) {
4479 return null;
4480 }
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004481 final boolean subtypeIsSelected = mSettings.isSubtypeSelected();
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004482 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
4483 if (imi == null || imi.getSubtypeCount() == 0) {
4484 return null;
satok4e4569d2010-11-19 18:45:53 +09004485 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004486 if (!subtypeIsSelected || mCurrentSubtype == null
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004487 || !InputMethodUtils.isValidSubtypeId(imi, mCurrentSubtype.hashCode())) {
4488 int subtypeId = mSettings.getSelectedInputMethodSubtypeId(mCurMethodId);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004489 if (subtypeId == NOT_A_SUBTYPE_ID) {
4490 // If there are no selected subtypes, the framework will try to find
4491 // the most applicable subtype from explicitly or implicitly enabled
4492 // subtypes.
4493 List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypes =
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004494 mSettings.getEnabledInputMethodSubtypeListLocked(mContext, imi, true);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004495 // If there is only one explicitly or implicitly enabled subtype,
4496 // just returns it.
4497 if (explicitlyOrImplicitlyEnabledSubtypes.size() == 1) {
4498 mCurrentSubtype = explicitlyOrImplicitlyEnabledSubtypes.get(0);
4499 } else if (explicitlyOrImplicitlyEnabledSubtypes.size() > 1) {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004500 mCurrentSubtype = InputMethodUtils.findLastResortApplicableSubtypeLocked(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004501 mRes, explicitlyOrImplicitlyEnabledSubtypes,
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004502 InputMethodUtils.SUBTYPE_MODE_KEYBOARD, null, true);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004503 if (mCurrentSubtype == null) {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004504 mCurrentSubtype = InputMethodUtils.findLastResortApplicableSubtypeLocked(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004505 mRes, explicitlyOrImplicitlyEnabledSubtypes, null, null,
4506 true);
satok4e4569d2010-11-19 18:45:53 +09004507 }
satok3ef8b292010-11-23 06:06:29 +09004508 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004509 } else {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004510 mCurrentSubtype = InputMethodUtils.getSubtypes(imi).get(subtypeId);
satok8fbb1e82010-11-02 23:15:58 +09004511 }
4512 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004513 return mCurrentSubtype;
satokab751aa2010-09-14 19:17:36 +09004514 }
4515
Yohei Yukawaa878b952019-01-10 19:36:24 -08004516 private List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
4517 synchronized (mMethodMap) {
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08004518 return getInputMethodListLocked(userId);
Yohei Yukawaa878b952019-01-10 19:36:24 -08004519 }
4520 }
4521
4522 private List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
4523 synchronized (mMethodMap) {
4524 return getEnabledInputMethodListLocked(userId);
4525 }
4526 }
4527
Feng Cao16b2de52020-01-09 17:27:27 -08004528 private void onCreateInlineSuggestionsRequest(@UserIdInt int userId,
4529 ComponentName componentName, AutofillId autofillId,
4530 IInlineSuggestionsRequestCallback callback) {
Adam Hebc67f2e2019-11-13 14:34:56 -08004531 synchronized (mMethodMap) {
Feng Cao16b2de52020-01-09 17:27:27 -08004532 onCreateInlineSuggestionsRequestLocked(userId, componentName, autofillId, callback);
Adam Hebc67f2e2019-11-13 14:34:56 -08004533 }
4534 }
4535
mincheli850892b2019-12-05 19:47:59 +08004536 private boolean switchToInputMethod(String imeId, @UserIdInt int userId) {
4537 synchronized (mMethodMap) {
4538 if (userId == mSettings.getCurrentUserId()) {
4539 if (!mMethodMap.containsKey(imeId)
4540 || !mSettings.getEnabledInputMethodListLocked()
4541 .contains(mMethodMap.get(imeId))) {
4542 return false; // IME is not is found or not enabled.
4543 }
4544 setInputMethodLocked(imeId, NOT_A_SUBTYPE_ID);
4545 return true;
4546 }
4547 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
4548 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
4549 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
4550 new ArrayMap<>();
4551 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
4552 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
4553 methodMap, methodList);
4554 final InputMethodSettings settings = new InputMethodSettings(
4555 mContext.getResources(), mContext.getContentResolver(), methodMap,
4556 userId, false);
4557 if (!methodMap.containsKey(imeId)
4558 || !settings.getEnabledInputMethodListLocked()
4559 .contains(methodMap.get(imeId))) {
4560 return false; // IME is not is found or not enabled.
4561 }
4562 settings.putSelectedInputMethod(imeId);
4563 settings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
4564 return true;
4565 }
4566 }
4567
Yohei Yukawae24ed792018-08-28 19:10:32 -07004568 private static final class LocalServiceImpl extends InputMethodManagerInternal {
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004569 @NonNull
Yohei Yukawafffc0e52018-09-04 13:24:00 -07004570 private final InputMethodManagerService mService;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004571
Yohei Yukawafffc0e52018-09-04 13:24:00 -07004572 LocalServiceImpl(@NonNull InputMethodManagerService service) {
4573 mService = service;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004574 }
4575
4576 @Override
4577 public void setInteractive(boolean interactive) {
4578 // Do everything in handler so as not to block the caller.
Yohei Yukawaf16abb72018-09-05 11:28:42 -07004579 mService.mHandler.obtainMessage(MSG_SET_INTERACTIVE, interactive ? 1 : 0, 0)
4580 .sendToTarget();
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004581 }
Yohei Yukawaae61f712015-12-09 13:00:10 -08004582
4583 @Override
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -07004584 public void hideCurrentInputMethod() {
Yohei Yukawaf16abb72018-09-05 11:28:42 -07004585 mService.mHandler.removeMessages(MSG_HIDE_CURRENT_INPUT_METHOD);
4586 mService.mHandler.sendEmptyMessage(MSG_HIDE_CURRENT_INPUT_METHOD);
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -07004587 }
Tarandeep Singh89a6c482017-11-21 14:26:11 -08004588
4589 @Override
Yohei Yukawaa878b952019-01-10 19:36:24 -08004590 public List<InputMethodInfo> getInputMethodListAsUser(int userId) {
4591 return mService.getInputMethodListAsUser(userId);
4592 }
4593
4594 @Override
4595 public List<InputMethodInfo> getEnabledInputMethodListAsUser(int userId) {
4596 return mService.getEnabledInputMethodListAsUser(userId);
4597 }
Adam Hebc67f2e2019-11-13 14:34:56 -08004598
4599 @Override
Feng Cao16b2de52020-01-09 17:27:27 -08004600 public void onCreateInlineSuggestionsRequest(int userId, ComponentName componentName,
Adam Hebc67f2e2019-11-13 14:34:56 -08004601 AutofillId autofillId, IInlineSuggestionsRequestCallback cb) {
Feng Cao16b2de52020-01-09 17:27:27 -08004602 mService.onCreateInlineSuggestionsRequest(userId, componentName, autofillId, cb);
Adam Hebc67f2e2019-11-13 14:34:56 -08004603 }
mincheli850892b2019-12-05 19:47:59 +08004604
4605 @Override
4606 public boolean switchToInputMethod(String imeId, int userId) {
4607 return mService.switchToInputMethod(imeId, userId);
4608 }
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004609 }
4610
Yohei Yukawac54c1172018-09-06 11:39:50 -07004611 @BinderThread
4612 private IInputContentUriToken createInputContentUriToken(@Nullable IBinder token,
Yohei Yukawa25e08132016-06-22 16:31:41 -07004613 @Nullable Uri contentUri, @Nullable String packageName) {
Yohei Yukawa25e08132016-06-22 16:31:41 -07004614 if (token == null) {
4615 throw new NullPointerException("token");
4616 }
4617 if (packageName == null) {
4618 throw new NullPointerException("packageName");
4619 }
4620 if (contentUri == null) {
4621 throw new NullPointerException("contentUri");
4622 }
4623 final String contentUriScheme = contentUri.getScheme();
4624 if (!"content".equals(contentUriScheme)) {
4625 throw new InvalidParameterException("contentUri must have content scheme");
4626 }
4627
4628 synchronized (mMethodMap) {
4629 final int uid = Binder.getCallingUid();
4630 if (mCurMethodId == null) {
4631 return null;
4632 }
4633 if (mCurToken != token) {
4634 Slog.e(TAG, "Ignoring createInputContentUriToken mCurToken=" + mCurToken
4635 + " token=" + token);
4636 return null;
4637 }
4638 // We cannot simply distinguish a bad IME that reports an arbitrary package name from
4639 // an unfortunate IME whose internal state is already obsolete due to the asynchronous
4640 // nature of our system. Let's compare it with our internal record.
4641 if (!TextUtils.equals(mCurAttribute.packageName, packageName)) {
4642 Slog.e(TAG, "Ignoring createInputContentUriToken mCurAttribute.packageName="
4643 + mCurAttribute.packageName + " packageName=" + packageName);
4644 return null;
4645 }
Yohei Yukawa3933a6e2016-11-10 00:47:48 -08004646 // This user ID can never bee spoofed.
Yohei Yukawa25e08132016-06-22 16:31:41 -07004647 final int imeUserId = UserHandle.getUserId(uid);
Yohei Yukawa3933a6e2016-11-10 00:47:48 -08004648 // This user ID can never bee spoofed.
Yohei Yukawa25e08132016-06-22 16:31:41 -07004649 final int appUserId = UserHandle.getUserId(mCurClient.uid);
Yohei Yukawa3933a6e2016-11-10 00:47:48 -08004650 // This user ID may be invalid if "contentUri" embedded an invalid user ID.
4651 final int contentUriOwnerUserId = ContentProvider.getUserIdFromUri(contentUri,
4652 imeUserId);
4653 final Uri contentUriWithoutUserId = ContentProvider.getUriWithoutUserId(contentUri);
4654 // Note: InputContentUriTokenHandler.take() checks whether the IME (specified by "uid")
4655 // actually has the right to grant a read permission for "contentUriWithoutUserId" that
4656 // is claimed to belong to "contentUriOwnerUserId". For example, specifying random
4657 // content URI and/or contentUriOwnerUserId just results in a SecurityException thrown
4658 // from InputContentUriTokenHandler.take() and can never be allowed beyond what is
4659 // actually allowed to "uid", which is guaranteed to be the IME's one.
4660 return new InputContentUriTokenHandler(contentUriWithoutUserId, uid,
4661 packageName, contentUriOwnerUserId, appUserId);
Yohei Yukawa25e08132016-06-22 16:31:41 -07004662 }
4663 }
4664
Yohei Yukawac54c1172018-09-06 11:39:50 -07004665 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08004666 private void reportFullscreenMode(@NonNull IBinder token, boolean fullscreen) {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08004667 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08004668 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08004669 return;
4670 }
4671 if (mCurClient != null && mCurClient.client != null) {
4672 mInFullscreenMode = fullscreen;
4673 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
4674 MSG_REPORT_FULLSCREEN_MODE, fullscreen ? 1 : 0, mCurClient));
4675 }
4676 }
4677 }
4678
4679 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004680 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06004681 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004682
4683 IInputMethod method;
4684 ClientState client;
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08004685 ClientState focusedWindowClient;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004686
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004687 final Printer p = new PrintWriterPrinter(pw);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004688
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004689 synchronized (mMethodMap) {
4690 p.println("Current Input Method Manager state:");
4691 int N = mMethodList.size();
Yohei Yukawa5ec1fce2018-12-17 07:56:14 -08004692 p.println(" Input Methods: mMethodMapUpdateCount=" + mMethodMapUpdateCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004693 for (int i=0; i<N; i++) {
4694 InputMethodInfo info = mMethodList.get(i);
4695 p.println(" InputMethod #" + i + ":");
4696 info.dump(p, " ");
4697 }
4698 p.println(" Clients:");
Yohei Yukawaac9311e2018-11-20 19:25:23 -08004699 final int numClients = mClients.size();
4700 for (int i = 0; i < numClients; ++i) {
4701 final ClientState ci = mClients.valueAt(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004702 p.println(" Client " + ci + ":");
4703 p.println(" client=" + ci.client);
4704 p.println(" inputContext=" + ci.inputContext);
4705 p.println(" sessionRequested=" + ci.sessionRequested);
4706 p.println(" curSession=" + ci.curSession);
4707 }
The Android Open Source Project10592532009-03-18 17:39:46 -07004708 p.println(" mCurMethodId=" + mCurMethodId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004709 client = mCurClient;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07004710 p.println(" mCurClient=" + client + " mCurSeq=" + mCurSeq);
Yohei Yukawa22a89232017-02-12 16:38:59 -08004711 p.println(" mCurFocusedWindow=" + mCurFocusedWindow
4712 + " softInputMode=" +
Yohei Yukawaa468d702018-10-21 11:42:34 -07004713 InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode)
Yohei Yukawa22a89232017-02-12 16:38:59 -08004714 + " client=" + mCurFocusedWindowClient);
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08004715 focusedWindowClient = mCurFocusedWindowClient;
Yohei Yukawad3ef8422018-06-07 16:28:07 -07004716 p.println(" mCurId=" + mCurId + " mHaveConnection=" + mHaveConnection
4717 + " mBoundToMethod=" + mBoundToMethod + " mVisibleBound=" + mVisibleBound);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004718 p.println(" mCurToken=" + mCurToken);
lumark90120a82018-08-15 00:33:03 +08004719 p.println(" mCurTokenDisplayId=" + mCurTokenDisplayId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004720 p.println(" mCurIntent=" + mCurIntent);
4721 method = mCurMethod;
4722 p.println(" mCurMethod=" + mCurMethod);
4723 p.println(" mEnabledSession=" + mEnabledSession);
4724 p.println(" mShowRequested=" + mShowRequested
4725 + " mShowExplicitlyRequested=" + mShowExplicitlyRequested
4726 + " mShowForced=" + mShowForced
4727 + " mInputShown=" + mInputShown);
Yohei Yukawa2bc66172017-02-08 11:13:25 -08004728 p.println(" mInFullscreenMode=" + mInFullscreenMode);
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004729 p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
Yohei Yukawa81482972015-06-04 00:58:59 -07004730 p.println(" mSettingsObserver=" + mSettingsObserver);
Yohei Yukawad7248862015-06-03 23:56:12 -07004731 p.println(" mSwitchingController:");
4732 mSwitchingController.dump(p);
Yohei Yukawa68645a62016-02-17 07:54:20 -08004733 p.println(" mSettings:");
4734 mSettings.dumpLocked(p, " ");
Yohei Yukawa357b2f62017-02-14 09:40:03 -08004735
4736 p.println(" mStartInputHistory:");
4737 mStartInputHistory.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004738 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004739
Jeff Brownb88102f2010-09-08 11:49:43 -07004740 p.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004741 if (client != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004742 pw.flush();
4743 try {
Jeff Sharkey850c83e2016-11-09 12:25:44 -07004744 TransferPipe.dumpAsync(client.client.asBinder(), fd, args);
4745 } catch (IOException | RemoteException e) {
4746 p.println("Failed to dump input method client: " + e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004747 }
Jeff Brownb88102f2010-09-08 11:49:43 -07004748 } else {
4749 p.println("No input method client.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004750 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004751
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08004752 if (focusedWindowClient != null && client != focusedWindowClient) {
4753 p.println(" ");
4754 p.println("Warning: Current input method client doesn't match the last focused. "
4755 + "window.");
4756 p.println("Dumping input method client in the last focused window just in case.");
4757 p.println(" ");
4758 pw.flush();
4759 try {
Jeff Sharkey850c83e2016-11-09 12:25:44 -07004760 TransferPipe.dumpAsync(focusedWindowClient.client.asBinder(), fd, args);
4761 } catch (IOException | RemoteException e) {
4762 p.println("Failed to dump input method client in focused window: " + e);
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08004763 }
4764 }
4765
Jeff Brownb88102f2010-09-08 11:49:43 -07004766 p.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004767 if (method != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004768 pw.flush();
4769 try {
Jeff Sharkey850c83e2016-11-09 12:25:44 -07004770 TransferPipe.dumpAsync(method.asBinder(), fd, args);
4771 } catch (IOException | RemoteException e) {
4772 p.println("Failed to dump input method service: " + e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004773 }
Jeff Brownb88102f2010-09-08 11:49:43 -07004774 } else {
4775 p.println("No input method service.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004776 }
4777 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004778
4779 @BinderThread
4780 @Override
4781 public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
4782 @Nullable FileDescriptor err,
4783 @NonNull String[] args, @Nullable ShellCallback callback,
4784 @NonNull ResultReceiver resultReceiver) throws RemoteException {
Yohei Yukawab8d240f2018-12-26 10:03:11 -08004785 final int callingUid = Binder.getCallingUid();
4786 // Reject any incoming calls from non-shell users, including ones from the system user.
4787 if (callingUid != Process.ROOT_UID && callingUid != Process.SHELL_UID) {
4788 // Note that Binder#onTransact() will automatically close "in", "out", and "err" when
4789 // returned from this method, hence there is no need to close those FDs.
4790 // "resultReceiver" is the only thing that needs to be taken care of here.
4791 if (resultReceiver != null) {
4792 resultReceiver.send(ShellCommandResult.FAILURE, null);
4793 }
4794 final String errorMsg = "InputMethodManagerService does not support shell commands from"
4795 + " non-shell users. callingUid=" + callingUid
4796 + " args=" + Arrays.toString(args);
4797 if (Process.isCoreUid(callingUid)) {
4798 // Let's not crash the calling process if the caller is one of core components.
4799 Slog.e(TAG, errorMsg);
4800 return;
4801 }
4802 throw new SecurityException(errorMsg);
4803 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004804 new ShellCommandImpl(this).exec(
4805 this, in, out, err, args, callback, resultReceiver);
4806 }
4807
4808 private static final class ShellCommandImpl extends ShellCommand {
4809 @NonNull
4810 final InputMethodManagerService mService;
4811
4812 ShellCommandImpl(InputMethodManagerService service) {
4813 mService = service;
4814 }
4815
Yohei Yukawadb25df72018-12-27 08:40:41 -08004816 @RequiresPermission(allOf = {
Yohei Yukawa8a2b96b2018-12-28 17:23:29 -08004817 Manifest.permission.DUMP,
4818 Manifest.permission.INTERACT_ACROSS_USERS_FULL,
Yohei Yukawadb25df72018-12-27 08:40:41 -08004819 Manifest.permission.WRITE_SECURE_SETTINGS,
Yohei Yukawa8a2b96b2018-12-28 17:23:29 -08004820 })
Yohei Yukawa926488d2017-12-11 17:24:55 -08004821 @BinderThread
4822 @ShellCommandResult
4823 @Override
4824 public int onCommand(@Nullable String cmd) {
Yohei Yukawadb25df72018-12-27 08:40:41 -08004825 // For shell command, require all the permissions here in favor of code simplicity.
Yohei Yukawa8a2b96b2018-12-28 17:23:29 -08004826 Arrays.asList(
4827 Manifest.permission.DUMP,
4828 Manifest.permission.INTERACT_ACROSS_USERS_FULL,
4829 Manifest.permission.WRITE_SECURE_SETTINGS
4830 ).forEach(permission -> mService.mContext.enforceCallingPermission(permission, null));
Yohei Yukawadb25df72018-12-27 08:40:41 -08004831
4832 final long identity = Binder.clearCallingIdentity();
4833 try {
4834 return onCommandWithSystemIdentity(cmd);
4835 } finally {
4836 Binder.restoreCallingIdentity(identity);
4837 }
4838 }
4839
4840 @BinderThread
4841 @ShellCommandResult
4842 private int onCommandWithSystemIdentity(@Nullable String cmd) {
Yohei Yukawadfdab732018-02-21 07:16:30 +09004843 if ("refresh_debug_properties".equals(cmd)) {
4844 return refreshDebugProperties();
4845 }
4846
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08004847 if ("get-last-switch-user-id".equals(cmd)) {
4848 return mService.getLastSwitchUserId(this);
4849 }
4850
Yohei Yukawacac97722017-12-15 16:52:05 -08004851 // For existing "adb shell ime <command>".
4852 if ("ime".equals(cmd)) {
4853 final String imeCommand = getNextArg();
4854 if (imeCommand == null || "help".equals(imeCommand) || "-h".equals(imeCommand)) {
4855 onImeCommandHelp();
4856 return ShellCommandResult.SUCCESS;
4857 }
4858 switch (imeCommand) {
4859 case "list":
4860 return mService.handleShellCommandListInputMethods(this);
4861 case "enable":
4862 return mService.handleShellCommandEnableDisableInputMethod(this, true);
4863 case "disable":
4864 return mService.handleShellCommandEnableDisableInputMethod(this, false);
4865 case "set":
4866 return mService.handleShellCommandSetInputMethod(this);
4867 case "reset":
4868 return mService.handleShellCommandResetInputMethod(this);
4869 default:
4870 getOutPrintWriter().println("Unknown command: " + imeCommand);
4871 return ShellCommandResult.FAILURE;
4872 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004873 }
Yohei Yukawacac97722017-12-15 16:52:05 -08004874
4875 return handleDefaultCommands(cmd);
Yohei Yukawa926488d2017-12-11 17:24:55 -08004876 }
4877
4878 @BinderThread
Tarandeep Singh75a92392018-01-12 14:58:59 -08004879 @ShellCommandResult
4880 private int refreshDebugProperties() {
4881 DebugFlags.FLAG_OPTIMIZE_START_INPUT.refresh();
Tarandeep Singheadb1392018-11-09 18:15:57 +01004882 DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.refresh();
Tarandeep Singh75a92392018-01-12 14:58:59 -08004883 return ShellCommandResult.SUCCESS;
4884 }
4885
4886 @BinderThread
Yohei Yukawa926488d2017-12-11 17:24:55 -08004887 @Override
4888 public void onHelp() {
4889 try (PrintWriter pw = getOutPrintWriter()) {
4890 pw.println("InputMethodManagerService commands:");
4891 pw.println(" help");
4892 pw.println(" Prints this help text.");
4893 pw.println(" dump [options]");
4894 pw.println(" Synonym of dumpsys.");
Yohei Yukawacac97722017-12-15 16:52:05 -08004895 pw.println(" ime <command> [options]");
4896 pw.println(" Manipulate IMEs. Run \"ime help\" for details.");
4897 }
4898 }
4899
4900 private void onImeCommandHelp() {
4901 try (IndentingPrintWriter pw =
4902 new IndentingPrintWriter(getOutPrintWriter(), " ", 100)) {
4903 pw.println("ime <command>:");
4904 pw.increaseIndent();
4905
4906 pw.println("list [-a] [-s]");
4907 pw.increaseIndent();
4908 pw.println("prints all enabled input methods.");
4909 pw.increaseIndent();
4910 pw.println("-a: see all input methods");
4911 pw.println("-s: only a single summary line of each");
4912 pw.decreaseIndent();
4913 pw.decreaseIndent();
4914
Yohei Yukawae1771702019-04-10 23:20:51 -07004915 pw.println("enable [--user <USER_ID>] <ID>");
Yohei Yukawacac97722017-12-15 16:52:05 -08004916 pw.increaseIndent();
4917 pw.println("allows the given input method ID to be used.");
Yohei Yukawae1771702019-04-10 23:20:51 -07004918 pw.increaseIndent();
4919 pw.print("--user <USER_ID>: Specify which user to enable.");
4920 pw.println(" Assumes the current user if not specified.");
4921 pw.decreaseIndent();
Yohei Yukawacac97722017-12-15 16:52:05 -08004922 pw.decreaseIndent();
4923
Yohei Yukawae1771702019-04-10 23:20:51 -07004924 pw.println("disable [--user <USER_ID>] <ID>");
Yohei Yukawacac97722017-12-15 16:52:05 -08004925 pw.increaseIndent();
4926 pw.println("disallows the given input method ID to be used.");
Yohei Yukawae1771702019-04-10 23:20:51 -07004927 pw.increaseIndent();
4928 pw.print("--user <USER_ID>: Specify which user to disable.");
4929 pw.println(" Assumes the current user if not specified.");
4930 pw.decreaseIndent();
Yohei Yukawacac97722017-12-15 16:52:05 -08004931 pw.decreaseIndent();
4932
Yohei Yukawa099f80c2019-04-10 23:23:17 -07004933 pw.println("set [--user <USER_ID>] <ID>");
Yohei Yukawacac97722017-12-15 16:52:05 -08004934 pw.increaseIndent();
4935 pw.println("switches to the given input method ID.");
Yohei Yukawa099f80c2019-04-10 23:23:17 -07004936 pw.increaseIndent();
4937 pw.print("--user <USER_ID>: Specify which user to enable.");
4938 pw.println(" Assumes the current user if not specified.");
4939 pw.decreaseIndent();
Yohei Yukawacac97722017-12-15 16:52:05 -08004940 pw.decreaseIndent();
4941
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07004942 pw.println("reset [--user <USER_ID>]");
Yohei Yukawacac97722017-12-15 16:52:05 -08004943 pw.increaseIndent();
4944 pw.println("reset currently selected/enabled IMEs to the default ones as if "
4945 + "the device is initially booted with the current locale.");
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07004946 pw.increaseIndent();
4947 pw.print("--user <USER_ID>: Specify which user to reset.");
4948 pw.println(" Assumes the current user if not specified.");
4949 pw.decreaseIndent();
4950
Yohei Yukawacac97722017-12-15 16:52:05 -08004951 pw.decreaseIndent();
4952
4953 pw.decreaseIndent();
Yohei Yukawa926488d2017-12-11 17:24:55 -08004954 }
4955 }
4956 }
4957
4958 // ----------------------------------------------------------------------
4959 // Shell command handlers:
4960
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08004961 @BinderThread
4962 @ShellCommandResult
4963 private int getLastSwitchUserId(@NonNull ShellCommand shellCommand) {
4964 synchronized (mMethodMap) {
4965 shellCommand.getOutPrintWriter().println(mLastSwitchUserId);
4966 return ShellCommandResult.SUCCESS;
4967 }
4968 }
4969
Yohei Yukawa926488d2017-12-11 17:24:55 -08004970 /**
4971 * Handles {@code adb shell ime list}.
4972 * @param shellCommand {@link ShellCommand} object that is handling this command.
4973 * @return Exit code of the command.
4974 */
4975 @BinderThread
4976 @ShellCommandResult
4977 private int handleShellCommandListInputMethods(@NonNull ShellCommand shellCommand) {
4978 boolean all = false;
4979 boolean brief = false;
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08004980 int userIdToBeResolved = UserHandle.USER_CURRENT;
Yohei Yukawa926488d2017-12-11 17:24:55 -08004981 while (true) {
4982 final String nextOption = shellCommand.getNextOption();
4983 if (nextOption == null) {
4984 break;
4985 }
4986 switch (nextOption) {
4987 case "-a":
4988 all = true;
4989 break;
4990 case "-s":
4991 brief = true;
4992 break;
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08004993 case "-u":
4994 case "--user":
4995 userIdToBeResolved = UserHandle.parseUserArg(shellCommand.getNextArgRequired());
4996 break;
Yohei Yukawa926488d2017-12-11 17:24:55 -08004997 }
4998 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08004999 synchronized (mMethodMap) {
5000 final PrintWriter pr = shellCommand.getOutPrintWriter();
5001 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
5002 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
5003 for (int userId : userIds) {
5004 final List<InputMethodInfo> methods = all
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08005005 ? getInputMethodListLocked(userId)
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08005006 : getEnabledInputMethodListLocked(userId);
5007 if (userIds.length > 1) {
5008 pr.print("User #");
5009 pr.print(userId);
5010 pr.println(":");
5011 }
5012 for (InputMethodInfo info : methods) {
5013 if (brief) {
5014 pr.println(info.getId());
5015 } else {
5016 pr.print(info.getId());
5017 pr.println(":");
5018 info.dump(pr::println, " ");
5019 }
5020 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005021 }
5022 }
5023 return ShellCommandResult.SUCCESS;
5024 }
5025
5026 /**
5027 * Handles {@code adb shell ime enable} and {@code adb shell ime disable}.
5028 * @param shellCommand {@link ShellCommand} object that is handling this command.
5029 * @param enabled {@code true} if the command was {@code adb shell ime enable}.
5030 * @return Exit code of the command.
5031 */
5032 @BinderThread
5033 @ShellCommandResult
Yohei Yukawa926488d2017-12-11 17:24:55 -08005034 private int handleShellCommandEnableDisableInputMethod(
5035 @NonNull ShellCommand shellCommand, boolean enabled) {
Yohei Yukawa3403f2d2019-04-15 08:16:58 -07005036 final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
Yohei Yukawae1771702019-04-10 23:20:51 -07005037 final String imeId = shellCommand.getNextArgRequired();
5038 final PrintWriter out = shellCommand.getOutPrintWriter();
5039 final PrintWriter error = shellCommand.getErrPrintWriter();
Yohei Yukawa926488d2017-12-11 17:24:55 -08005040 synchronized (mMethodMap) {
Yohei Yukawae1771702019-04-10 23:20:51 -07005041 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
5042 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
5043 for (int userId : userIds) {
5044 if (!userHasDebugPriv(userId, shellCommand)) {
5045 continue;
5046 }
5047 handleShellCommandEnableDisableInputMethodInternalLocked(userId, imeId, enabled,
5048 out, error);
Tarandeep Singh87e2e512019-03-06 14:28:52 -08005049 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005050 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005051 return ShellCommandResult.SUCCESS;
5052 }
5053
5054 /**
Yohei Yukawae1771702019-04-10 23:20:51 -07005055 * A special helper method for commands that only have {@code -u} and {@code --user} options.
5056 *
5057 * <p>You cannot use this helper method if the command has other options.</p>
5058 *
Yohei Yukawa3403f2d2019-04-15 08:16:58 -07005059 * <p>CAVEAT: This method must be called only once before any other
5060 * {@link ShellCommand#getNextArg()} and {@link ShellCommand#getNextArgRequired()} for the
5061 * main arguments.</p>
5062 *
Yohei Yukawae1771702019-04-10 23:20:51 -07005063 * @param shellCommand {@link ShellCommand} from which options should be obtained.
5064 * @return User ID to be resolved. {@link UserHandle#CURRENT} if not specified.
5065 */
5066 @BinderThread
5067 @UserIdInt
5068 private static int handleOptionsForCommandsThatOnlyHaveUserOption(ShellCommand shellCommand) {
5069 while (true) {
5070 final String nextOption = shellCommand.getNextOption();
5071 if (nextOption == null) {
5072 break;
5073 }
5074 switch (nextOption) {
5075 case "-u":
5076 case "--user":
5077 return UserHandle.parseUserArg(shellCommand.getNextArgRequired());
5078 }
5079 }
5080 return UserHandle.USER_CURRENT;
5081 }
5082
5083 @BinderThread
5084 private void handleShellCommandEnableDisableInputMethodInternalLocked(
5085 @UserIdInt int userId, String imeId, boolean enabled, PrintWriter out,
5086 PrintWriter error) {
5087 boolean failedToEnableUnknownIme = false;
5088 boolean previouslyEnabled = false;
5089 if (userId == mSettings.getCurrentUserId()) {
5090 if (enabled && !mMethodMap.containsKey(imeId)) {
5091 failedToEnableUnknownIme = true;
5092 } else {
5093 previouslyEnabled = setInputMethodEnabledLocked(imeId, enabled);
5094 }
5095 } else {
5096 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
5097 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
5098 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
5099 new ArrayMap<>();
5100 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
5101 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
5102 methodMap, methodList);
5103 final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
5104 mContext.getContentResolver(), methodMap, userId, false);
5105 if (enabled) {
5106 if (!methodMap.containsKey(imeId)) {
5107 failedToEnableUnknownIme = true;
5108 } else {
5109 for (InputMethodInfo imi : settings.getEnabledInputMethodListLocked()) {
5110 if (TextUtils.equals(imi.getId(), imeId)) {
5111 previouslyEnabled = true;
5112 break;
5113 }
5114 }
5115 if (!previouslyEnabled) {
5116 settings.appendAndPutEnabledInputMethodLocked(imeId, false);
5117 }
5118 }
5119 } else {
5120 previouslyEnabled =
5121 settings.buildAndPutEnabledInputMethodsStrRemovingIdLocked(
5122 new StringBuilder(),
5123 settings.getEnabledInputMethodsAndSubtypeListLocked(), imeId);
5124 }
5125 }
5126 if (failedToEnableUnknownIme) {
5127 error.print("Unknown input method ");
5128 error.print(imeId);
5129 error.println(" cannot be enabled for user #" + userId);
5130 } else {
5131 out.print("Input method ");
5132 out.print(imeId);
5133 out.print(": ");
5134 out.print((enabled == previouslyEnabled) ? "already " : "now ");
5135 out.print(enabled ? "enabled" : "disabled");
5136 out.print(" for user #");
5137 out.println(userId);
5138 }
5139 }
5140
5141 /**
Yohei Yukawa926488d2017-12-11 17:24:55 -08005142 * Handles {@code adb shell ime set}.
5143 * @param shellCommand {@link ShellCommand} object that is handling this command.
5144 * @return Exit code of the command.
5145 */
5146 @BinderThread
5147 @ShellCommandResult
5148 private int handleShellCommandSetInputMethod(@NonNull ShellCommand shellCommand) {
Yohei Yukawa3403f2d2019-04-15 08:16:58 -07005149 final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005150 final String imeId = shellCommand.getNextArgRequired();
5151 final PrintWriter out = shellCommand.getOutPrintWriter();
5152 final PrintWriter error = shellCommand.getErrPrintWriter();
Yohei Yukawadb25df72018-12-27 08:40:41 -08005153 synchronized (mMethodMap) {
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005154 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
5155 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
5156 for (int userId : userIds) {
5157 if (!userHasDebugPriv(userId, shellCommand)) {
5158 continue;
5159 }
mincheli850892b2019-12-05 19:47:59 +08005160 boolean failedToSelectUnknownIme = !switchToInputMethod(imeId, userId);
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005161 if (failedToSelectUnknownIme) {
5162 error.print("Unknown input method ");
5163 error.print(imeId);
5164 error.print(" cannot be selected for user #");
5165 error.println(userId);
5166 } else {
5167 out.print("Input method ");
5168 out.print(imeId);
5169 out.print(" selected for user #");
Yohei Yukawa3403f2d2019-04-15 08:16:58 -07005170 out.println(userId);
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005171 }
Tarandeep Singh87e2e512019-03-06 14:28:52 -08005172 }
Yohei Yukawadb25df72018-12-27 08:40:41 -08005173 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005174 return ShellCommandResult.SUCCESS;
5175 }
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005176
5177 /**
5178 * Handles {@code adb shell ime reset-ime}.
5179 * @param shellCommand {@link ShellCommand} object that is handling this command.
5180 * @return Exit code of the command.
5181 */
5182 @BinderThread
5183 @ShellCommandResult
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005184 private int handleShellCommandResetInputMethod(@NonNull ShellCommand shellCommand) {
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005185 final PrintWriter out = shellCommand.getOutPrintWriter();
5186 final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005187 synchronized (mMethodMap) {
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005188 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
5189 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
5190 for (int userId : userIds) {
5191 if (!userHasDebugPriv(userId, shellCommand)) {
5192 continue;
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005193 }
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005194 final String nextIme;
5195 final List<InputMethodInfo> nextEnabledImes;
5196 if (userId == mSettings.getCurrentUserId()) {
5197 hideCurrentInputLocked(0, null);
5198 unbindCurrentMethodLocked();
5199 // Reset the current IME
5200 resetSelectedInputMethodAndSubtypeLocked(null);
5201 // Also reset the settings of the current IME
5202 mSettings.putSelectedInputMethod(null);
5203 // Disable all enabled IMEs.
5204 mSettings.getEnabledInputMethodListLocked().forEach(
5205 imi -> setInputMethodEnabledLocked(imi.getId(), false));
5206 // Re-enable with default enabled IMEs.
5207 InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList).forEach(
5208 imi -> setInputMethodEnabledLocked(imi.getId(), true));
5209 updateInputMethodsFromSettingsLocked(true /* enabledMayChange */);
5210 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
5211 mSettings.getEnabledInputMethodListLocked(),
5212 mSettings.getCurrentUserId(),
5213 mContext.getBasePackageName());
5214 nextIme = mSettings.getSelectedInputMethod();
5215 nextEnabledImes = mSettings.getEnabledInputMethodListLocked();
5216 } else {
5217 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
5218 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
5219 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
5220 new ArrayMap<>();
5221 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
5222 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
5223 methodMap, methodList);
5224 final InputMethodSettings settings = new InputMethodSettings(
5225 mContext.getResources(), mContext.getContentResolver(), methodMap,
5226 userId, false);
5227
5228 nextEnabledImes = InputMethodUtils.getDefaultEnabledImes(mContext, methodList);
5229 nextIme = InputMethodUtils.getMostApplicableDefaultIME(nextEnabledImes).getId();
5230
5231 // Reset enabled IMEs.
5232 settings.putEnabledInputMethodsStr("");
5233 nextEnabledImes.forEach(imi -> settings.appendAndPutEnabledInputMethodLocked(
5234 imi.getId(), false));
5235
5236 // Reset selected IME.
5237 settings.putSelectedInputMethod(nextIme);
5238 settings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
5239 }
5240 out.println("Reset current and enabled IMEs for user #" + userId);
5241 out.println(" Selected: " + nextIme);
5242 nextEnabledImes.forEach(ime -> out.println(" Enabled: " + ime.getId()));
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005243 }
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005244 }
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005245 return ShellCommandResult.SUCCESS;
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005246 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07005247
Tarandeep Singh87e2e512019-03-06 14:28:52 -08005248 /**
5249 * @param userId the actual user handle obtained by {@link UserHandle#getIdentifier()}
5250 * and *not* pseudo ids like {@link UserHandle#USER_ALL etc}.
5251 * @return {@code true} if userId has debugging privileges.
5252 * i.e. {@link UserManager#DISALLOW_DEBUGGING_FEATURES} is {@code false}.
5253 */
5254 private boolean userHasDebugPriv(int userId, final ShellCommand shellCommand) {
5255 if (mUserManager.hasUserRestriction(
5256 UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.of(userId))) {
5257 shellCommand.getErrPrintWriter().println("User #" + userId
5258 + " is restricted with DISALLOW_DEBUGGING_FEATURES.");
5259 return false;
5260 }
5261 return true;
5262 }
5263
Yohei Yukawac54c1172018-09-06 11:39:50 -07005264 private static final class InputMethodPrivilegedOperationsImpl
5265 extends IInputMethodPrivilegedOperations.Stub {
5266 private final InputMethodManagerService mImms;
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08005267 @NonNull
Yohei Yukawac54c1172018-09-06 11:39:50 -07005268 private final IBinder mToken;
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08005269 InputMethodPrivilegedOperationsImpl(InputMethodManagerService imms,
5270 @NonNull IBinder token) {
Yohei Yukawac54c1172018-09-06 11:39:50 -07005271 mImms = imms;
5272 mToken = token;
5273 }
5274
5275 @BinderThread
5276 @Override
5277 public void setImeWindowStatus(int vis, int backDisposition) {
5278 mImms.setImeWindowStatus(mToken, vis, backDisposition);
5279 }
5280
5281 @BinderThread
5282 @Override
5283 public void reportStartInput(IBinder startInputToken) {
5284 mImms.reportStartInput(mToken, startInputToken);
5285 }
5286
5287 @BinderThread
5288 @Override
Yohei Yukawac54c1172018-09-06 11:39:50 -07005289 public IInputContentUriToken createInputContentUriToken(Uri contentUri,
5290 String packageName) {
5291 return mImms.createInputContentUriToken(mToken, contentUri, packageName);
5292 }
5293
5294 @BinderThread
5295 @Override
5296 public void reportFullscreenMode(boolean fullscreen) {
5297 mImms.reportFullscreenMode(mToken, fullscreen);
5298 }
Yohei Yukawac7ca3682018-09-09 20:48:38 -07005299
5300 @BinderThread
5301 @Override
5302 public void setInputMethod(String id) {
5303 mImms.setInputMethod(mToken, id);
5304 }
5305
5306 @BinderThread
5307 @Override
5308 public void setInputMethodAndSubtype(String id, InputMethodSubtype subtype) {
5309 mImms.setInputMethodAndSubtype(mToken, id, subtype);
5310 }
5311
5312 @BinderThread
5313 @Override
5314 public void hideMySoftInput(int flags) {
5315 mImms.hideMySoftInput(mToken, flags);
5316 }
5317
5318 @BinderThread
5319 @Override
5320 public void showMySoftInput(int flags) {
5321 mImms.showMySoftInput(mToken, flags);
5322 }
5323
5324 @BinderThread
5325 @Override
Yohei Yukawa41b094f2018-09-09 23:58:45 -07005326 public void updateStatusIcon(String packageName, @DrawableRes int iconId) {
Yohei Yukawac7ca3682018-09-09 20:48:38 -07005327 mImms.updateStatusIcon(mToken, packageName, iconId);
5328 }
5329
5330 @BinderThread
5331 @Override
5332 public boolean switchToPreviousInputMethod() {
5333 return mImms.switchToPreviousInputMethod(mToken);
5334 }
5335
5336 @BinderThread
5337 @Override
5338 public boolean switchToNextInputMethod(boolean onlyCurrentIme) {
5339 return mImms.switchToNextInputMethod(mToken, onlyCurrentIme);
5340 }
5341
5342 @BinderThread
5343 @Override
5344 public boolean shouldOfferSwitchingToNextInputMethod() {
5345 return mImms.shouldOfferSwitchingToNextInputMethod(mToken);
5346 }
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07005347
5348 @BinderThread
5349 @Override
Yohei Yukawa9b60ba02019-01-21 00:06:27 -08005350 public void notifyUserAction() {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07005351 mImms.notifyUserAction(mToken);
5352 }
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08005353
5354 @BinderThread
5355 @Override
5356 public void reportPreRendered(EditorInfo info) {
5357 mImms.reportPreRendered(mToken, info);
5358 }
5359
5360 @BinderThread
5361 @Override
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08005362 public void applyImeVisibility(IBinder windowToken, boolean setVisible) {
5363 mImms.applyImeVisibility(mToken, windowToken, setVisible);
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08005364 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07005365 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005366}