blob: b647a1ab9873abcb767252f62bc286e298868910 [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;
Yohei Yukawad5f402b2020-05-15 10:23:32 -070059import android.content.pm.PackageManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import android.content.pm.ResolveInfo;
61import android.content.pm.ServiceInfo;
Amith Yamasanie861ec12010-03-24 21:39:27 -070062import android.content.res.Configuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.content.res.Resources;
64import android.content.res.TypedArray;
65import android.database.ContentObserver;
Yohei Yukawab4f328a2019-05-02 08:41:27 -070066import android.graphics.Matrix;
Alan Viverette505e3ab2014-11-24 15:22:11 -080067import android.graphics.drawable.Drawable;
Yohei Yukawab4f328a2019-05-02 08:41:27 -070068import android.hardware.display.DisplayManagerInternal;
lpeter133fce02020-03-05 20:32:16 +080069import android.hardware.input.InputManagerInternal;
Joe Onorato857fd9b2011-01-27 15:08:35 -080070import android.inputmethodservice.InputMethodService;
Yohei Yukawad5f402b2020-05-15 10:23:32 -070071import android.media.AudioManagerInternal;
Michael Wright7b5a96b2014-08-09 19:28:42 -070072import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.os.Binder;
Chris Wren1ce4b6d2015-06-11 10:19:43 -040074import android.os.Bundle;
Seigo Nonakae27dc2b2015-08-14 18:21:27 -070075import android.os.Debug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076import android.os.Handler;
77import android.os.IBinder;
78import android.os.IInterface;
Yohei Yukawa23cbe852016-05-17 16:42:58 -070079import android.os.LocaleList;
Yohei Yukawa0569a182018-08-28 16:09:28 -070080import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081import android.os.Parcel;
Yohei Yukawa6ab1a822015-08-25 14:01:28 -070082import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083import android.os.RemoteException;
The Android Open Source Project4df24232009-03-05 14:34:35 -080084import android.os.ResultReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.os.ServiceManager;
Yohei Yukawa926488d2017-12-11 17:24:55 -080086import android.os.ShellCallback;
87import android.os.ShellCommand;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088import android.os.SystemClock;
Tarandeep Singh75a92392018-01-12 14:58:59 -080089import android.os.SystemProperties;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +090090import android.os.UserHandle;
Amith Yamasani734983f2014-03-04 16:48:05 -080091import android.os.UserManager;
Yohei Yukawa42081402019-01-15 09:57:50 -080092import android.os.UserManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093import android.provider.Settings;
94import android.text.TextUtils;
satokf9f01002011-05-19 21:31:50 +090095import android.text.style.SuggestionSpan;
Yohei Yukawaac9311e2018-11-20 19:25:23 -080096import android.util.ArrayMap;
Christopher Tate7b9a28c2015-03-18 13:06:16 -070097import android.util.ArraySet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098import android.util.EventLog;
satokf9f01002011-05-19 21:31:50 +090099import android.util.LruCache;
satokab751aa2010-09-14 19:17:36 +0900100import android.util.Pair;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101import android.util.PrintWriterPrinter;
102import android.util.Printer;
satoke7c6998e2011-06-03 17:57:59 +0900103import android.util.Slog;
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700104import android.util.SparseArray;
Tadashi G. Takaokad130b802014-08-01 14:05:47 +0900105import android.view.ContextThemeWrapper;
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700106import android.view.DisplayInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107import android.view.IWindowManager;
Jeff Brownc28867a2013-03-26 15:42:39 -0700108import android.view.InputChannel;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900109import android.view.LayoutInflater;
110import android.view.View;
111import android.view.ViewGroup;
Wale Ogunwale3a931692016-11-02 16:49:48 -0700112import android.view.Window;
Yohei Yukawa6e875592019-01-28 00:49:30 -0800113import android.view.WindowManager.LayoutParams;
Yohei Yukawab0c26452018-10-21 10:42:52 -0700114import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
Feng Cao7c85eb72020-02-28 11:39:56 -0800115import android.view.autofill.AutofillId;
satokab751aa2010-09-14 19:17:36 +0900116import android.view.inputmethod.EditorInfo;
Feng Cao16b2de52020-01-09 17:27:27 -0800117import android.view.inputmethod.InlineSuggestionsRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118import android.view.inputmethod.InputBinding;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800119import android.view.inputmethod.InputConnection;
Yohei Yukawa19a80a12016-03-14 22:57:37 -0700120import android.view.inputmethod.InputConnectionInspector;
Yohei Yukawa432cf602018-10-21 10:41:37 -0700121import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122import android.view.inputmethod.InputMethod;
123import android.view.inputmethod.InputMethodInfo;
124import android.view.inputmethod.InputMethodManager;
satokab751aa2010-09-14 19:17:36 +0900125import android.view.inputmethod.InputMethodSubtype;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900126import android.widget.ArrayAdapter;
satok01038492012-04-09 21:08:27 +0900127import android.widget.CompoundButton;
128import android.widget.CompoundButton.OnCheckedChangeListener;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900129import android.widget.RadioButton;
satok01038492012-04-09 21:08:27 +0900130import android.widget.Switch;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900131import android.widget.TextView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132
Yohei Yukawa0569a182018-08-28 16:09:28 -0700133import com.android.internal.annotations.GuardedBy;
134import com.android.internal.content.PackageMonitor;
135import com.android.internal.inputmethod.IInputContentUriToken;
Yohei Yukawac54c1172018-09-06 11:39:50 -0700136import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
Yohei Yukawaa468d702018-10-21 11:42:34 -0700137import com.android.internal.inputmethod.InputMethodDebug;
lumarkd85e1582019-12-29 20:20:41 +0800138import com.android.internal.inputmethod.SoftInputShowHideReason;
Yohei Yukawa35fa6d52018-10-31 11:33:32 -0700139import com.android.internal.inputmethod.StartInputFlags;
Yohei Yukawac6632df2018-10-21 11:47:16 -0700140import com.android.internal.inputmethod.StartInputReason;
Yohei Yukawa499e3f72018-10-21 20:15:11 -0700141import com.android.internal.inputmethod.UnbindReason;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700142import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
143import com.android.internal.notification.SystemNotificationChannels;
144import com.android.internal.os.HandlerCaller;
145import com.android.internal.os.SomeArgs;
146import com.android.internal.os.TransferPipe;
147import com.android.internal.util.DumpUtils;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700148import com.android.internal.util.IndentingPrintWriter;
Adam Hebc67f2e2019-11-13 14:34:56 -0800149import com.android.internal.view.IInlineSuggestionsRequestCallback;
Feng Cao16b2de52020-01-09 17:27:27 -0800150import com.android.internal.view.IInlineSuggestionsResponseCallback;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700151import com.android.internal.view.IInputContext;
152import com.android.internal.view.IInputMethod;
153import com.android.internal.view.IInputMethodClient;
154import com.android.internal.view.IInputMethodManager;
155import com.android.internal.view.IInputMethodSession;
156import com.android.internal.view.IInputSessionCallback;
Feng Cao36960ee2020-02-18 18:23:30 -0800157import com.android.internal.view.InlineSuggestionsRequestInfo;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700158import com.android.internal.view.InputBindResult;
Yohei Yukawa603f4d02018-09-11 15:04:58 -0700159import com.android.server.EventLogTags;
160import com.android.server.LocalServices;
161import com.android.server.SystemService;
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +0900162import com.android.server.inputmethod.InputMethodManagerInternal.InputMethodListListener;
Yohei Yukawae6b6e0e2018-09-12 16:42:48 -0700163import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
164import com.android.server.inputmethod.InputMethodUtils.InputMethodSettings;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700165import com.android.server.statusbar.StatusBarManagerService;
Adrian Roose99bc052017-11-20 17:55:31 +0100166import com.android.server.wm.WindowManagerInternal;
167
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168import java.io.FileDescriptor;
169import java.io.IOException;
170import java.io.PrintWriter;
Yohei Yukawafa0e47e2016-04-05 09:55:56 -0700171import java.lang.annotation.Retention;
Yohei Yukawa25e08132016-06-22 16:31:41 -0700172import java.security.InvalidParameterException;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800173import java.text.SimpleDateFormat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174import java.util.ArrayList;
Yohei Yukawab8d240f2018-12-26 10:03:11 -0800175import java.util.Arrays;
satok688bd472012-02-09 20:09:17 +0900176import java.util.Collections;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800177import java.util.Date;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178import java.util.List;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800179import java.util.Locale;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800180import java.util.WeakHashMap;
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +0900181import java.util.concurrent.CopyOnWriteArrayList;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800182import java.util.concurrent.atomic.AtomicInteger;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183
184/**
185 * This class provides a system service that manages input methods.
186 */
187public class InputMethodManagerService extends IInputMethodManager.Stub
188 implements ServiceConnection, Handler.Callback {
189 static final boolean DEBUG = false;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700190 static final String TAG = "InputMethodManagerService";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191
Yohei Yukawa926488d2017-12-11 17:24:55 -0800192 @Retention(SOURCE)
193 @IntDef({ShellCommandResult.SUCCESS, ShellCommandResult.FAILURE})
194 private @interface ShellCommandResult {
195 int SUCCESS = 0;
196 int FAILURE = -1;
197 }
198
Seigo Nonakad4474cb2015-05-04 16:53:24 -0700199 static final int MSG_SHOW_IM_SUBTYPE_PICKER = 1;
200 static final int MSG_SHOW_IM_SUBTYPE_ENABLER = 2;
201 static final int MSG_SHOW_IM_CONFIG = 3;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800202
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 static final int MSG_UNBIND_INPUT = 1000;
204 static final int MSG_BIND_INPUT = 1010;
205 static final int MSG_SHOW_SOFT_INPUT = 1020;
206 static final int MSG_HIDE_SOFT_INPUT = 1030;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700207 static final int MSG_HIDE_CURRENT_INPUT_METHOD = 1035;
Yohei Yukawac54c1172018-09-06 11:39:50 -0700208 static final int MSG_INITIALIZE_IME = 1040;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 static final int MSG_CREATE_SESSION = 1050;
Yunfan Chenc02a5ac2020-06-16 01:52:41 +0000210 static final int MSG_REMOVE_IME_SURFACE = 1060;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 static final int MSG_START_INPUT = 2000;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800213
Yohei Yukawa33e81792015-11-17 21:14:42 -0800214 static final int MSG_UNBIND_CLIENT = 3000;
215 static final int MSG_BIND_CLIENT = 3010;
Dianne Hackborna6e41342012-05-22 16:30:34 -0700216 static final int MSG_SET_ACTIVE = 3020;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700217 static final int MSG_SET_INTERACTIVE = 3030;
Yohei Yukawa2bc66172017-02-08 11:13:25 -0800218 static final int MSG_REPORT_FULLSCREEN_MODE = 3045;
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -0800219 static final int MSG_REPORT_PRE_RENDERED = 3060;
220 static final int MSG_APPLY_IME_VISIBILITY = 3070;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800221
satok01038492012-04-09 21:08:27 +0900222 static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000;
223
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -0700224 static final int MSG_SYSTEM_UNLOCK_USER = 5000;
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +0900225 static final int MSG_DISPATCH_ON_INPUT_METHOD_LIST_UPDATED = 5010;
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -0700226
Adam Hebc67f2e2019-11-13 14:34:56 -0800227 static final int MSG_INLINE_SUGGESTIONS_REQUEST = 6000;
228
Yohei Yukawad5f402b2020-05-15 10:23:32 -0700229 static final int MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE = 7000;
230
Satoshi Kataokabcacc322013-10-21 17:57:27 -0700231 static final long TIME_TO_RECONNECT = 3 * 1000;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800232
satokf9f01002011-05-19 21:31:50 +0900233 static final int SECURE_SUGGESTION_SPANS_MAX_SIZE = 20;
234
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +0900235 private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID;
satokb6359412011-06-28 17:47:41 +0900236 private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +0900237
Yohei Yukawaa67a4592017-03-30 15:57:02 -0700238 /**
239 * Binding flags for establishing connection to the {@link InputMethodService}.
240 */
241 private static final int IME_CONNECTION_BIND_FLAGS =
242 Context.BIND_AUTO_CREATE
243 | Context.BIND_NOT_VISIBLE
244 | Context.BIND_NOT_FOREGROUND
Yohei Yukawaad78a612017-08-04 01:57:27 -0700245 | Context.BIND_IMPORTANT_BACKGROUND;
Yohei Yukawaa67a4592017-03-30 15:57:02 -0700246
247 /**
248 * Binding flags used only while the {@link InputMethodService} is showing window.
249 */
250 private static final int IME_VISIBLE_BIND_FLAGS =
251 Context.BIND_AUTO_CREATE
252 | Context.BIND_TREAT_LIKE_ACTIVITY
Yohei Yukawaad78a612017-08-04 01:57:27 -0700253 | Context.BIND_FOREGROUND_SERVICE
Amith Yamasanic45a9902019-04-05 16:29:30 -0700254 | Context.BIND_INCLUDE_CAPABILITIES
Yohei Yukawa59730962019-03-18 10:47:22 -0700255 | Context.BIND_SHOWING_UI
256 | Context.BIND_SCHEDULE_LIKE_TOP_APP;
Yohei Yukawaa67a4592017-03-30 15:57:02 -0700257
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +0900258 /**
259 * A protected broadcast intent action for internal use for {@link PendingIntent} in
260 * the notification.
261 */
262 private static final String ACTION_SHOW_INPUT_METHOD_PICKER =
Yohei Yukawa603f4d02018-09-11 15:04:58 -0700263 "com.android.server.inputmethod.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER";
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +0900264
Tarandeep Singh75a92392018-01-12 14:58:59 -0800265 /**
266 * Debug flag for overriding runtime {@link SystemProperties}.
267 */
268 @AnyThread
269 private static final class DebugFlag {
270 private static final Object LOCK = new Object();
271 private final String mKey;
Tarandeep Singh9df4ad12018-04-03 13:35:50 -0700272 private final boolean mDefaultValue;
Tarandeep Singh75a92392018-01-12 14:58:59 -0800273 @GuardedBy("LOCK")
274 private boolean mValue;
275
Tarandeep Singh1c042c52018-03-29 17:04:44 -0700276 public DebugFlag(String key, boolean defaultValue) {
Tarandeep Singh75a92392018-01-12 14:58:59 -0800277 mKey = key;
Tarandeep Singh9df4ad12018-04-03 13:35:50 -0700278 mDefaultValue = defaultValue;
Tarandeep Singh1c042c52018-03-29 17:04:44 -0700279 mValue = SystemProperties.getBoolean(key, defaultValue);
Tarandeep Singh75a92392018-01-12 14:58:59 -0800280 }
281
282 void refresh() {
283 synchronized (LOCK) {
Tarandeep Singh9df4ad12018-04-03 13:35:50 -0700284 mValue = SystemProperties.getBoolean(mKey, mDefaultValue);
Tarandeep Singh75a92392018-01-12 14:58:59 -0800285 }
286 }
287
288 boolean value() {
289 synchronized (LOCK) {
290 return mValue;
291 }
292 }
293 }
294
295 /**
296 * Debug flags that can be overridden using "adb shell setprop <key>"
297 * Note: These flags are cached. To refresh, run "adb shell ime refresh_debug_properties".
298 */
299 private static final class DebugFlags {
300 static final DebugFlag FLAG_OPTIMIZE_START_INPUT =
Tarandeep Singh1c042c52018-03-29 17:04:44 -0700301 new DebugFlag("debug.optimize_startinput", false);
Tarandeep Singheadb1392018-11-09 18:15:57 +0100302 static final DebugFlag FLAG_PRE_RENDER_IME_VIEWS =
303 new DebugFlag("persist.pre_render_ime_views", false);
Tarandeep Singh75a92392018-01-12 14:58:59 -0800304 }
305
Yohei Yukawaa7babbb2019-01-08 16:45:34 -0800306 @UserIdInt
307 private int mLastSwitchUserId;
Tarandeep Singh75a92392018-01-12 14:58:59 -0800308
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309 final Context mContext;
Dianne Hackborn7d3a5bc2010-11-29 22:52:12 -0800310 final Resources mRes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311 final Handler mHandler;
satokd87c2592010-09-29 11:52:06 +0900312 final InputMethodSettings mSettings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313 final SettingsObserver mSettingsObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314 final IWindowManager mIWindowManager;
Seigo Nonaka7309b122015-08-17 18:34:13 -0700315 final WindowManagerInternal mWindowManagerInternal;
Yohei Yukawad5f402b2020-05-15 10:23:32 -0700316 final PackageManagerInternal mPackageManagerInternal;
lpeter133fce02020-03-05 20:32:16 +0800317 final InputManagerInternal mInputManagerInternal;
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700318 private final DisplayManagerInternal mDisplayManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 final HandlerCaller mCaller;
Dianne Hackborn119bbc32013-03-22 17:27:25 -0700320 final boolean mHasFeature;
Yohei Yukawab557d572018-12-29 21:26:26 -0800321 private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypeMap =
322 new ArrayMap<>();
Tarandeep Singheadb1392018-11-09 18:15:57 +0100323 private final boolean mIsLowRam;
satok01038492012-04-09 21:08:27 +0900324 private final HardKeyboardListener mHardKeyboardListener;
Yohei Yukawae63b5fa2014-09-19 13:14:55 +0900325 private final AppOpsManager mAppOpsManager;
Yohei Yukawaed4952a2016-02-17 07:57:25 -0800326 private final UserManager mUserManager;
Yohei Yukawa42081402019-01-15 09:57:50 -0800327 private final UserManagerInternal mUserManagerInternal;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800328
Yohei Yukawad5f402b2020-05-15 10:23:32 -0700329 /**
330 * Cache the result of {@code LocalServices.getService(AudioManagerInternal.class)}.
331 *
332 * <p>This field is used only within {@link #handleMessage(Message)} hence synchronization is
333 * not necessary.</p>
334 */
335 @Nullable
336 private AudioManagerInternal mAudioManagerInternal = null;
337
338
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 // All known input methods. mMethodMap also serves as the global
340 // lock for this class.
Yohei Yukawab0377bb2015-08-10 21:06:30 -0700341 final ArrayList<InputMethodInfo> mMethodList = new ArrayList<>();
Yohei Yukawa1dd7de62018-11-20 19:25:29 -0800342 final ArrayMap<String, InputMethodInfo> mMethodMap = new ArrayMap<>();
satokf9f01002011-05-19 21:31:50 +0900343 private final LruCache<SuggestionSpan, InputMethodInfo> mSecureSuggestionSpans =
Yohei Yukawab0377bb2015-08-10 21:06:30 -0700344 new LruCache<>(SECURE_SUGGESTION_SPANS_MAX_SIZE);
Satoshi Kataokad787f692013-10-26 04:44:21 +0900345 private final InputMethodSubtypeSwitchingController mSwitchingController;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800346
Yohei Yukawae0733062017-02-09 22:49:35 -0800347 /**
348 * Tracks how many times {@link #mMethodMap} was updated.
349 */
350 @GuardedBy("mMethodMap")
351 private int mMethodMapUpdateCount = 0;
352
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -0700353 // Used to bring IME service up to visible adjustment while it is being shown.
354 final ServiceConnection mVisibleConnection = new ServiceConnection() {
Yohei Yukawad3ef8422018-06-07 16:28:07 -0700355 @Override public void onBindingDied(ComponentName name) {
356 synchronized (mMethodMap) {
357 if (mVisibleBound) {
358 mContext.unbindService(mVisibleConnection);
359 mVisibleBound = false;
360 }
361 }
362 }
363
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -0700364 @Override public void onServiceConnected(ComponentName name, IBinder service) {
365 }
366
367 @Override public void onServiceDisconnected(ComponentName name) {
368 }
369 };
370 boolean mVisibleBound = false;
371
satok7cfc0ed2011-06-20 21:29:36 +0900372 // Ongoing notification
Dianne Hackborn661cd522011-08-22 00:26:20 -0700373 private NotificationManager mNotificationManager;
374 private KeyguardManager mKeyguardManager;
Griff Hazen6090c262016-03-25 08:11:24 -0700375 private @Nullable StatusBarManagerService mStatusBar;
Chris Wren1ce4b6d2015-06-11 10:19:43 -0400376 private Notification.Builder mImeSwitcherNotification;
Dianne Hackborn661cd522011-08-22 00:26:20 -0700377 private PendingIntent mImeSwitchPendingIntent;
satokb858c732011-07-22 19:54:34 +0900378 private boolean mShowOngoingImeSwitcherForPhones;
satok7cfc0ed2011-06-20 21:29:36 +0900379 private boolean mNotificationShown;
380
Tadashi G. Takaoka8c6d4772014-08-05 15:29:17 +0900381 static class SessionState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 final ClientState client;
383 final IInputMethod method;
Jeff Brownc28867a2013-03-26 15:42:39 -0700384
385 IInputMethodSession session;
386 InputChannel channel;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388 @Override
389 public String toString() {
390 return "SessionState{uid " + client.uid + " pid " + client.pid
391 + " method " + Integer.toHexString(
392 System.identityHashCode(method))
393 + " session " + Integer.toHexString(
394 System.identityHashCode(session))
Jeff Brownc28867a2013-03-26 15:42:39 -0700395 + " channel " + channel
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 + "}";
397 }
398
399 SessionState(ClientState _client, IInputMethod _method,
Jeff Brownc28867a2013-03-26 15:42:39 -0700400 IInputMethodSession _session, InputChannel _channel) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 client = _client;
402 method = _method;
403 session = _session;
Jeff Brownc28867a2013-03-26 15:42:39 -0700404 channel = _channel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800405 }
406 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800407
Yohei Yukawaa71bb252018-09-19 19:21:24 -0700408 private static final class ClientDeathRecipient implements IBinder.DeathRecipient {
409 private final InputMethodManagerService mImms;
410 private final IInputMethodClient mClient;
411
412 ClientDeathRecipient(InputMethodManagerService imms, IInputMethodClient client) {
413 mImms = imms;
414 mClient = client;
415 }
416
417 @Override
418 public void binderDied() {
419 mImms.removeClient(mClient);
420 }
421 }
422
Jeff Brownc28867a2013-03-26 15:42:39 -0700423 static final class ClientState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 final IInputMethodClient client;
425 final IInputContext inputContext;
426 final int uid;
427 final int pid;
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800428 final int selfReportedDisplayId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 final InputBinding binding;
Yohei Yukawaa71bb252018-09-19 19:21:24 -0700430 final ClientDeathRecipient clientDeathRecipient;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800431
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432 boolean sessionRequested;
Tarandeep Singheadb1392018-11-09 18:15:57 +0100433 // Determines if IMEs should be pre-rendered.
434 // DebugFlag can be flipped anytime. This flag is kept per-client to maintain behavior
435 // through the life of the current client.
436 boolean shouldPreRenderIme;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800437 SessionState curSession;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800438
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 @Override
440 public String toString() {
441 return "ClientState{" + Integer.toHexString(
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800442 System.identityHashCode(this)) + " uid=" + uid
443 + " pid=" + pid + " displayId=" + selfReportedDisplayId + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 }
445
446 ClientState(IInputMethodClient _client, IInputContext _inputContext,
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800447 int _uid, int _pid, int _selfReportedDisplayId,
448 ClientDeathRecipient _clientDeathRecipient) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 client = _client;
450 inputContext = _inputContext;
451 uid = _uid;
452 pid = _pid;
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800453 selfReportedDisplayId = _selfReportedDisplayId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454 binding = new InputBinding(null, inputContext.asBinder(), uid, pid);
Yohei Yukawaa71bb252018-09-19 19:21:24 -0700455 clientDeathRecipient = _clientDeathRecipient;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456 }
457 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800458
Yohei Yukawaac9311e2018-11-20 19:25:23 -0800459 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800460
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700461 private static final class ActivityViewInfo {
462 /**
463 * {@link ClientState} where {@link android.app.ActivityView} is running.
464 */
465 private final ClientState mParentClient;
466 /**
467 * {@link Matrix} to convert screen coordinates in the embedded virtual display to
468 * screen coordinates where {@link #mParentClient} exists.
469 */
470 private final Matrix mMatrix;
471
472 ActivityViewInfo(ClientState parentClient, Matrix matrix) {
473 mParentClient = parentClient;
474 mMatrix = matrix;
475 }
476 }
477
478 /**
479 * A mapping table from virtual display IDs created for {@link android.app.ActivityView}
480 * to its parent IME client where {@link android.app.ActivityView} is running.
481 *
482 * <p>Note: this can be used only for virtual display IDs created by
483 * {@link android.app.ActivityView}.</p>
484 */
485 private SparseArray<ActivityViewInfo> mActivityViewDisplayIdToParentMap = new SparseArray<>();
486
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 /**
Dianne Hackborna34f1ad2009-09-02 13:26:28 -0700488 * Set once the system is ready to run third party code.
489 */
490 boolean mSystemReady;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800491
Dianne Hackborna34f1ad2009-09-02 13:26:28 -0700492 /**
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700493 * Id obtained with {@link InputMethodInfo#getId()} for the currently selected input method.
494 * method. This is to be synchronized with the secure settings keyed with
495 * {@link Settings.Secure#DEFAULT_INPUT_METHOD}.
496 *
497 * <p>This can be transiently {@code null} when the system is re-initializing input method
498 * settings, e.g., the system locale is just changed.</p>
499 *
500 * <p>Note that {@link #mCurId} is used to track which IME is being connected to
501 * {@link InputMethodManagerService}.</p>
502 *
503 * @see #mCurId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 */
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700505 @Nullable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 String mCurMethodId;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800507
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 /**
509 * The current binding sequence number, incremented every time there is
510 * a new bind performed.
511 */
512 int mCurSeq;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800513
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800514 /**
515 * The client that is currently bound to an input method.
516 */
517 ClientState mCurClient;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800518
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519 /**
Yohei Yukawae39d4ed2015-11-19 03:38:49 -0800520 * The last window token that we confirmed to be focused. This is always updated upon reports
521 * from the input method client. If the window state is already changed before the report is
522 * handled, this field just keeps the last value.
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700523 */
524 IBinder mCurFocusedWindow;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800525
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700526 /**
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -0700527 * The last window token that we confirmed that IME started talking to. This is always updated
528 * upon reports from the input method. If the window state is already changed before the report
529 * is handled, this field just keeps the last value.
530 */
531 IBinder mLastImeTargetWindow;
532
533 /**
Yohei Yukawa6e875592019-01-28 00:49:30 -0800534 * {@link LayoutParams#softInputMode} of {@link #mCurFocusedWindow}.
Yohei Yukawa22a89232017-02-12 16:38:59 -0800535 *
536 * @see #mCurFocusedWindow
537 */
Yohei Yukawab0c26452018-10-21 10:42:52 -0700538 @SoftInputModeFlags
Yohei Yukawa22a89232017-02-12 16:38:59 -0800539 int mCurFocusedWindowSoftInputMode;
540
541 /**
Tarandeep Singheb570612018-01-29 16:20:32 -0800542 * The client by which {@link #mCurFocusedWindow} was reported.
Yohei Yukawae39d4ed2015-11-19 03:38:49 -0800543 */
544 ClientState mCurFocusedWindowClient;
545
546 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547 * The input context last provided by the current client.
548 */
549 IInputContext mCurInputContext;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800550
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 /**
Yohei Yukawa19a80a12016-03-14 22:57:37 -0700552 * The missing method flags for the input context last provided by the current client.
553 *
554 * @see android.view.inputmethod.InputConnectionInspector.MissingMethodFlags
555 */
Yohei Yukawa432cf602018-10-21 10:41:37 -0700556 @MissingMethodFlags
Yohei Yukawa19a80a12016-03-14 22:57:37 -0700557 int mCurInputContextMissingMethods;
558
559 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 * The attributes last provided by the current client.
561 */
562 EditorInfo mCurAttribute;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800563
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 /**
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700565 * A special {@link Matrix} to convert virtual screen coordinates to the IME target display
566 * coordinates.
567 *
568 * <p>Used only while the IME client is running in a virtual display inside
569 * {@link android.app.ActivityView}. {@code null} otherwise.</p>
570 */
571 @Nullable
572 private Matrix mCurActivityViewToScreenMatrix = null;
573
574 /**
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700575 * Id obtained with {@link InputMethodInfo#getId()} for the input method that we are currently
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576 * connected to or in the process of connecting to.
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700577 *
578 * <p>This can be {@code null} when no input method is connected.</p>
579 *
580 * @see #mCurMethodId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 */
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700582 @Nullable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 String mCurId;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 /**
satokab751aa2010-09-14 19:17:36 +0900586 * The current subtype of the current input method.
587 */
588 private InputMethodSubtype mCurrentSubtype;
589
John Spurlocke0980502013-10-25 11:59:29 -0400590 // Was the keyguard locked when this client became current?
591 private boolean mCurClientInKeyguard;
592
satokab751aa2010-09-14 19:17:36 +0900593 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 * Set to true if our ServiceConnection is currently actively bound to
595 * a service (whether or not we have gotten its IBinder back yet).
596 */
597 boolean mHaveConnection;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800598
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 /**
600 * Set if the client has asked for the input method to be shown.
601 */
602 boolean mShowRequested;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800603
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 /**
605 * Set if we were explicitly told to show the input method.
606 */
607 boolean mShowExplicitlyRequested;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800608
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 /**
610 * Set if we were forced to be shown.
611 */
612 boolean mShowForced;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800613
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614 /**
615 * Set if we last told the input method to show itself.
616 */
617 boolean mInputShown;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800618
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 /**
Yohei Yukawa2bc66172017-02-08 11:13:25 -0800620 * {@code true} if the current input method is in fullscreen mode.
621 */
622 boolean mInFullscreenMode;
623
624 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800625 * The Intent used to connect to the current input method.
626 */
627 Intent mCurIntent;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800628
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629 /**
630 * The token we have made for the currently active input method, to
631 * identify it in the future.
632 */
633 IBinder mCurToken;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 /**
lumark90120a82018-08-15 00:33:03 +0800636 * The displayId of current active input method.
637 */
638 int mCurTokenDisplayId = INVALID_DISPLAY;
639
lumark7570cac2019-03-07 22:14:38 +0800640 /**
lpeter133fce02020-03-05 20:32:16 +0800641 * The host input token of the current active input method.
642 */
643 @GuardedBy("mMethodMap")
644 @Nullable
645 private IBinder mCurHostInputToken;
646
647 /**
lumark7570cac2019-03-07 22:14:38 +0800648 * The display ID of the input method indicates the fallback display which returned by
649 * {@link #computeImeDisplayIdForTarget}.
650 */
651 private static final int FALLBACK_DISPLAY_ID = DEFAULT_DISPLAY;
652
lumarkef1965b2018-09-12 17:42:53 +0800653 final ImeDisplayValidator mImeDisplayValidator;
654
lumark90120a82018-08-15 00:33:03 +0800655 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800656 * If non-null, this is the input method service we are currently connected
657 * to.
658 */
659 IInputMethod mCurMethod;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800660
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800661 /**
Yohei Yukawad5f402b2020-05-15 10:23:32 -0700662 * If not {@link Process#INVALID_UID}, then the UID of {@link #mCurIntent}.
663 */
664 int mCurMethodUid = Process.INVALID_UID;
665
666 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 * Time that we last initiated a bind to the input method, to determine
668 * if we should try to disconnect and reconnect to it.
669 */
670 long mLastBindTime;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800671
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800672 /**
673 * Have we called mCurMethod.bindInput()?
674 */
675 boolean mBoundToMethod;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800676
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677 /**
678 * Currently enabled session. Only touched by service thread, not
679 * protected by a lock.
680 */
681 SessionState mEnabledSession;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800682
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 /**
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700684 * True if the device is currently interactive with user. The value is true initially.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 */
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700686 boolean mIsInteractive = true;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800687
Joe Onorato857fd9b2011-01-27 15:08:35 -0800688 int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
Seigo Nonakad9eb9112015-05-26 20:54:43 +0900689
690 /**
691 * A set of status bits regarding the active IME.
692 *
693 * <p>This value is a combination of following two bits:</p>
694 * <dl>
695 * <dt>{@link InputMethodService#IME_ACTIVE}</dt>
696 * <dd>
697 * If this bit is ON, connected IME is ready to accept touch/key events.
698 * </dd>
699 * <dt>{@link InputMethodService#IME_VISIBLE}</dt>
700 * <dd>
701 * If this bit is ON, some of IME view, e.g. software input, candidate view, is visible.
702 * </dd>
Tarandeep Singheadb1392018-11-09 18:15:57 +0100703 * dt>{@link InputMethodService#IME_INVISIBLE}</dt>
704 * <dd> If this bit is ON, IME is ready with views from last EditorInfo but is
705 * currently invisible.
706 * </dd>
Seigo Nonakad9eb9112015-05-26 20:54:43 +0900707 * </dl>
lumark7570cac2019-03-07 22:14:38 +0800708 * <em>Do not update this value outside of {@link #setImeWindowStatus(IBinder, int, int)} and
709 * {@link #unbindCurrentMethodLocked()}.</em>
Seigo Nonakad9eb9112015-05-26 20:54:43 +0900710 */
Joe Onorato857fd9b2011-01-27 15:08:35 -0800711 int mImeWindowVis;
712
Ken Wakasa05dbb652011-08-22 15:22:43 +0900713 private AlertDialog.Builder mDialogBuilder;
714 private AlertDialog mSwitchingDialog;
Wale Ogunwale3a931692016-11-02 16:49:48 -0700715 private IBinder mSwitchingDialogToken = new Binder();
satok01038492012-04-09 21:08:27 +0900716 private View mSwitchingDialogTitleView;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900717 private InputMethodInfo[] mIms;
718 private int[] mSubtypeIds;
Yohei Yukawae985c242016-02-24 18:27:04 -0800719 private LocaleList mLastSystemLocales;
Michael Wright7b5a96b2014-08-09 19:28:42 -0700720 private boolean mShowImeWithHardKeyboard;
Anna Galusza9b278112016-01-04 11:37:37 -0800721 private boolean mAccessibilityRequestingNoSoftKeyboard;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +0900722 private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
723 private final IPackageManager mIPackageManager;
Jason Monk3e189872016-01-12 09:10:34 -0500724 private final String mSlotIme;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800725
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800726 /**
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +0900727 * Registered {@link InputMethodListListeners}.
728 * This variable can be accessed from both of MainThread and BinderThread.
729 */
730 private final CopyOnWriteArrayList<InputMethodListListener> mInputMethodListListeners =
731 new CopyOnWriteArrayList<>();
732
733 /**
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800734 * Internal state snapshot when {@link #MSG_START_INPUT} message is about to be posted to the
735 * internal message queue. Any subsequent state change inside {@link InputMethodManagerService}
736 * will not affect those tasks that are already posted.
737 *
738 * <p>Posting {@link #MSG_START_INPUT} message basically means that
739 * {@link InputMethodService#doStartInput(InputConnection, EditorInfo, boolean)} will be called
740 * back in the current IME process shortly, which will also affect what the current IME starts
741 * receiving from {@link InputMethodService#getCurrentInputConnection()}. In other words, this
742 * snapshot will be taken every time when {@link InputMethodManagerService} is initiating a new
743 * logical input session between the client application and the current IME.</p>
744 *
745 * <p>Be careful to not keep strong references to this object forever, which can prevent
746 * {@link StartInputInfo#mImeToken} and {@link StartInputInfo#mTargetWindow} from being GC-ed.
747 * </p>
748 */
749 private static class StartInputInfo {
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800750 private static final AtomicInteger sSequenceNumber = new AtomicInteger(0);
751
752 final int mSequenceNumber;
753 final long mTimestamp;
754 final long mWallTime;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800755 @UserIdInt
756 final int mImeUserId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800757 @NonNull
758 final IBinder mImeToken;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800759 final int mImeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800760 @NonNull
761 final String mImeId;
Yohei Yukawadc66e522018-10-21 10:43:14 -0700762 @StartInputReason
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800763 final int mStartInputReason;
764 final boolean mRestarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800765 @UserIdInt
766 final int mTargetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800767 final int mTargetDisplayId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800768 @Nullable
769 final IBinder mTargetWindow;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800770 @NonNull
771 final EditorInfo mEditorInfo;
Yohei Yukawab0c26452018-10-21 10:42:52 -0700772 @SoftInputModeFlags
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800773 final int mTargetWindowSoftInputMode;
774 final int mClientBindSequenceNumber;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800775
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800776 StartInputInfo(@UserIdInt int imeUserId, @NonNull IBinder imeToken, int imeDisplayId,
777 @NonNull String imeId, @StartInputReason int startInputReason, boolean restarting,
778 @UserIdInt int targetUserId, int targetDisplayId, @Nullable IBinder targetWindow,
779 @NonNull EditorInfo editorInfo, @SoftInputModeFlags int targetWindowSoftInputMode,
780 int clientBindSequenceNumber) {
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800781 mSequenceNumber = sSequenceNumber.getAndIncrement();
782 mTimestamp = SystemClock.uptimeMillis();
783 mWallTime = System.currentTimeMillis();
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800784 mImeUserId = imeUserId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800785 mImeToken = imeToken;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800786 mImeDisplayId = imeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800787 mImeId = imeId;
788 mStartInputReason = startInputReason;
789 mRestarting = restarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800790 mTargetUserId = targetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800791 mTargetDisplayId = targetDisplayId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800792 mTargetWindow = targetWindow;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800793 mEditorInfo = editorInfo;
794 mTargetWindowSoftInputMode = targetWindowSoftInputMode;
795 mClientBindSequenceNumber = clientBindSequenceNumber;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800796 }
797 }
798
Yohei Yukawab37d8bd2017-02-13 18:29:05 -0800799 @GuardedBy("mMethodMap")
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -0700800 private final WeakHashMap<IBinder, IBinder> mImeTargetWindowMap = new WeakHashMap<>();
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800801
lumarkd85e1582019-12-29 20:20:41 +0800802 private static final class SoftInputShowHideHistory {
803 private Entry[] mEntries = new Entry[16];
804 private int mNextIndex = 0;
805 private static final AtomicInteger sSequenceNumber = new AtomicInteger(0);
806
lumarkd85e1582019-12-29 20:20:41 +0800807 private static final class Entry {
Ming-Shin Lua0605a62020-04-15 23:49:40 +0800808 final int mSequenceNumber = sSequenceNumber.getAndIncrement();
Anmol Gupta29f209d2020-03-11 11:34:46 -0700809 final ClientState mClientState;
lumarkd85e1582019-12-29 20:20:41 +0800810 @SoftInputModeFlags
Anmol Gupta29f209d2020-03-11 11:34:46 -0700811 final int mFocusedWindowSoftInputMode;
lumarkd85e1582019-12-29 20:20:41 +0800812 @SoftInputShowHideReason
Anmol Gupta29f209d2020-03-11 11:34:46 -0700813 final int mReason;
lumarkd85e1582019-12-29 20:20:41 +0800814 // The timing of handling MSG_SHOW_SOFT_INPUT or MSG_HIDE_SOFT_INPUT.
Anmol Gupta29f209d2020-03-11 11:34:46 -0700815 final long mTimestamp;
816 final long mWallTime;
817 final boolean mInFullscreenMode;
818 @NonNull
819 final String mFocusedWindowName;
820 @NonNull
821 final EditorInfo mEditorInfo;
822 @NonNull
823 final String mRequestWindowName;
Ming-Shin Lud0bc1712020-05-11 09:23:37 +0800824 @Nullable
825 final String mImeControlTargetName;
826 @Nullable
827 final String mImeTargetNameFromWm;
lumarkd85e1582019-12-29 20:20:41 +0800828
Anmol Gupta29f209d2020-03-11 11:34:46 -0700829 Entry(ClientState client, EditorInfo editorInfo, String focusedWindowName,
830 @SoftInputModeFlags int softInputMode, @SoftInputShowHideReason int reason,
Ming-Shin Lud0bc1712020-05-11 09:23:37 +0800831 boolean inFullscreenMode, String requestWindowName,
832 @Nullable String imeControlTargetName, @Nullable String imeTargetName) {
lumarkd85e1582019-12-29 20:20:41 +0800833 mClientState = client;
Anmol Gupta29f209d2020-03-11 11:34:46 -0700834 mEditorInfo = editorInfo;
835 mFocusedWindowName = focusedWindowName;
lumarkd85e1582019-12-29 20:20:41 +0800836 mFocusedWindowSoftInputMode = softInputMode;
837 mReason = reason;
lumarkd85e1582019-12-29 20:20:41 +0800838 mTimestamp = SystemClock.uptimeMillis();
839 mWallTime = System.currentTimeMillis();
Anmol Gupta29f209d2020-03-11 11:34:46 -0700840 mInFullscreenMode = inFullscreenMode;
841 mRequestWindowName = requestWindowName;
Ming-Shin Lud0bc1712020-05-11 09:23:37 +0800842 mImeControlTargetName = imeControlTargetName;
843 mImeTargetNameFromWm = imeTargetName;
lumarkd85e1582019-12-29 20:20:41 +0800844 }
845 }
846
847 void addEntry(@NonNull Entry entry) {
848 final int index = mNextIndex;
849 mEntries[index] = entry;
850 mNextIndex = (mNextIndex + 1) % mEntries.length;
851 }
852
853 void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
854 final SimpleDateFormat dataFormat =
855 new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
856
857 for (int i = 0; i < mEntries.length; ++i) {
858 final Entry entry = mEntries[(i + mNextIndex) % mEntries.length];
859 if (entry == null) {
860 continue;
861 }
862 pw.print(prefix);
Ming-Shin Lua0605a62020-04-15 23:49:40 +0800863 pw.println("SoftInputShowHideHistory #" + entry.mSequenceNumber + ":");
lumarkd85e1582019-12-29 20:20:41 +0800864
865 pw.print(prefix);
866 pw.println(" time=" + dataFormat.format(new Date(entry.mWallTime))
867 + " (timestamp=" + entry.mTimestamp + ")");
868
869 pw.print(prefix);
Anmol Gupta29f209d2020-03-11 11:34:46 -0700870 pw.print(" reason=" + InputMethodDebug.softInputDisplayReasonToString(
871 entry.mReason));
872 pw.println(" inFullscreenMode=" + entry.mInFullscreenMode);
lumarkd85e1582019-12-29 20:20:41 +0800873
874 pw.print(prefix);
Anmol Gupta29f209d2020-03-11 11:34:46 -0700875 pw.println(" requestClient=" + entry.mClientState);
876
877 pw.print(prefix);
878 pw.println(" focusedWindowName=" + entry.mFocusedWindowName);
879
880 pw.print(prefix);
881 pw.println(" requestWindowName=" + entry.mRequestWindowName);
882
883 pw.print(prefix);
Ming-Shin Lud0bc1712020-05-11 09:23:37 +0800884 pw.println(" imeControlTargetName=" + entry.mImeControlTargetName);
885
886 pw.print(prefix);
887 pw.println(" imeTargetNameFromWm=" + entry.mImeTargetNameFromWm);
888
889 pw.print(prefix);
Anmol Gupta29f209d2020-03-11 11:34:46 -0700890 pw.print(" editorInfo: ");
891 pw.print(" inputType=" + entry.mEditorInfo.inputType);
892 pw.print(" privateImeOptions=" + entry.mEditorInfo.privateImeOptions);
893 pw.println(" fieldId (viewId)=" + entry.mEditorInfo.fieldId);
lumarkd85e1582019-12-29 20:20:41 +0800894
895 pw.print(prefix);
896 pw.println(" focusedWindowSoftInputMode=" + InputMethodDebug.softInputModeToString(
897 entry.mFocusedWindowSoftInputMode));
898 }
899 }
900 }
901
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800902 /**
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -0800903 * Map of generated token to windowToken that is requesting
904 * {@link InputMethodManager#showSoftInput(View, int)}.
905 * This map tracks origin of showSoftInput requests.
906 */
907 @GuardedBy("mMethodMap")
908 private final WeakHashMap<IBinder, IBinder> mShowRequestWindowMap = new WeakHashMap<>();
909
910 /**
Tarandeep Singh4fe5b652020-02-20 17:20:19 -0800911 * Map of generated token to windowToken that is requesting
912 * {@link InputMethodManager#hideSoftInputFromWindow(IBinder, int)}.
913 * This map tracks origin of hideSoftInput requests.
914 */
915 @GuardedBy("mMethodMap")
916 private final WeakHashMap<IBinder, IBinder> mHideRequestWindowMap = new WeakHashMap<>();
917
918 /**
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800919 * A ring buffer to store the history of {@link StartInputInfo}.
920 */
921 private static final class StartInputHistory {
922 /**
923 * Entry size for non low-RAM devices.
924 *
925 * <p>TODO: Consider to follow what other system services have been doing to manage
926 * constants (e.g. {@link android.provider.Settings.Global#ACTIVITY_MANAGER_CONSTANTS}).</p>
927 */
928 private final static int ENTRY_SIZE_FOR_HIGH_RAM_DEVICE = 16;
929
930 /**
931 * Entry size for non low-RAM devices.
932 *
933 * <p>TODO: Consider to follow what other system services have been doing to manage
934 * constants (e.g. {@link android.provider.Settings.Global#ACTIVITY_MANAGER_CONSTANTS}).</p>
935 */
936 private final static int ENTRY_SIZE_FOR_LOW_RAM_DEVICE = 5;
937
938 private static int getEntrySize() {
939 if (ActivityManager.isLowRamDeviceStatic()) {
940 return ENTRY_SIZE_FOR_LOW_RAM_DEVICE;
941 } else {
942 return ENTRY_SIZE_FOR_HIGH_RAM_DEVICE;
943 }
944 }
945
946 /**
947 * Backing store for the ring bugger.
948 */
949 private final Entry[] mEntries = new Entry[getEntrySize()];
950
951 /**
952 * An index of {@link #mEntries}, to which next {@link #addEntry(StartInputInfo)} should
953 * write.
954 */
955 private int mNextIndex = 0;
956
957 /**
958 * Recyclable entry to store the information in {@link StartInputInfo}.
959 */
960 private static final class Entry {
961 int mSequenceNumber;
962 long mTimestamp;
963 long mWallTime;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800964 @UserIdInt
965 int mImeUserId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800966 @NonNull
967 String mImeTokenString;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800968 int mImeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800969 @NonNull
970 String mImeId;
Yohei Yukawadc66e522018-10-21 10:43:14 -0700971 @StartInputReason
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800972 int mStartInputReason;
973 boolean mRestarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800974 @UserIdInt
975 int mTargetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800976 int mTargetDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800977 @NonNull
978 String mTargetWindowString;
979 @NonNull
980 EditorInfo mEditorInfo;
Yohei Yukawab0c26452018-10-21 10:42:52 -0700981 @SoftInputModeFlags
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800982 int mTargetWindowSoftInputMode;
983 int mClientBindSequenceNumber;
984
985 Entry(@NonNull StartInputInfo original) {
986 set(original);
987 }
988
989 void set(@NonNull StartInputInfo original) {
990 mSequenceNumber = original.mSequenceNumber;
991 mTimestamp = original.mTimestamp;
992 mWallTime = original.mWallTime;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800993 mImeUserId = original.mImeUserId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800994 // Intentionally convert to String so as not to keep a strong reference to a Binder
995 // object.
996 mImeTokenString = String.valueOf(original.mImeToken);
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800997 mImeDisplayId = original.mImeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800998 mImeId = original.mImeId;
999 mStartInputReason = original.mStartInputReason;
1000 mRestarting = original.mRestarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -08001001 mTargetUserId = original.mTargetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -08001002 mTargetDisplayId = original.mTargetDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -08001003 // Intentionally convert to String so as not to keep a strong reference to a Binder
1004 // object.
1005 mTargetWindowString = String.valueOf(original.mTargetWindow);
1006 mEditorInfo = original.mEditorInfo;
1007 mTargetWindowSoftInputMode = original.mTargetWindowSoftInputMode;
1008 mClientBindSequenceNumber = original.mClientBindSequenceNumber;
1009 }
1010 }
1011
1012 /**
1013 * Add a new entry and discard the oldest entry as needed.
1014 * @param info {@lin StartInputInfo} to be added.
1015 */
1016 void addEntry(@NonNull StartInputInfo info) {
1017 final int index = mNextIndex;
1018 if (mEntries[index] == null) {
1019 mEntries[index] = new Entry(info);
1020 } else {
1021 mEntries[index].set(info);
1022 }
1023 mNextIndex = (mNextIndex + 1) % mEntries.length;
1024 }
1025
1026 void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
1027 final SimpleDateFormat dataFormat =
1028 new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
1029
1030 for (int i = 0; i < mEntries.length; ++i) {
1031 final Entry entry = mEntries[(i + mNextIndex) % mEntries.length];
1032 if (entry == null) {
1033 continue;
1034 }
1035 pw.print(prefix);
1036 pw.println("StartInput #" + entry.mSequenceNumber + ":");
1037
1038 pw.print(prefix);
1039 pw.println(" time=" + dataFormat.format(new Date(entry.mWallTime))
1040 + " (timestamp=" + entry.mTimestamp + ")"
1041 + " reason="
Yohei Yukawaa468d702018-10-21 11:42:34 -07001042 + InputMethodDebug.startInputReasonToString(entry.mStartInputReason)
Yohei Yukawa357b2f62017-02-14 09:40:03 -08001043 + " restarting=" + entry.mRestarting);
1044
1045 pw.print(prefix);
Yohei Yukawa557afbb2019-02-12 02:01:00 -08001046 pw.print(" imeToken=" + entry.mImeTokenString + " [" + entry.mImeId + "]");
Yohei Yukawa7979e1a2019-02-12 02:01:10 -08001047 pw.print(" imeUserId=" + entry.mImeUserId);
Yohei Yukawa557afbb2019-02-12 02:01:00 -08001048 pw.println(" imeDisplayId=" + entry.mImeDisplayId);
Yohei Yukawa357b2f62017-02-14 09:40:03 -08001049
1050 pw.print(prefix);
1051 pw.println(" targetWin=" + entry.mTargetWindowString
1052 + " [" + entry.mEditorInfo.packageName + "]"
Yohei Yukawa7979e1a2019-02-12 02:01:10 -08001053 + " targetUserId=" + entry.mTargetUserId
Yohei Yukawa557afbb2019-02-12 02:01:00 -08001054 + " targetDisplayId=" + entry.mTargetDisplayId
Yohei Yukawa357b2f62017-02-14 09:40:03 -08001055 + " clientBindSeq=" + entry.mClientBindSequenceNumber);
1056
1057 pw.print(prefix);
Yohei Yukawaa468d702018-10-21 11:42:34 -07001058 pw.println(" softInputMode=" + InputMethodDebug.softInputModeToString(
Yohei Yukawa357b2f62017-02-14 09:40:03 -08001059 entry.mTargetWindowSoftInputMode));
1060
1061 pw.print(prefix);
1062 pw.println(" inputType=0x" + Integer.toHexString(entry.mEditorInfo.inputType)
1063 + " imeOptions=0x" + Integer.toHexString(entry.mEditorInfo.imeOptions)
1064 + " fieldId=0x" + Integer.toHexString(entry.mEditorInfo.fieldId)
1065 + " fieldName=" + entry.mEditorInfo.fieldName
1066 + " actionId=" + entry.mEditorInfo.actionId
1067 + " actionLabel=" + entry.mEditorInfo.actionLabel);
1068 }
1069 }
1070 }
1071
1072 @GuardedBy("mMethodMap")
1073 @NonNull
1074 private final StartInputHistory mStartInputHistory = new StartInputHistory();
1075
lumarkd85e1582019-12-29 20:20:41 +08001076 @GuardedBy("mMethodMap")
1077 @NonNull
1078 private final SoftInputShowHideHistory mSoftInputShowHideHistory =
1079 new SoftInputShowHideHistory();
1080
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001081 class SettingsObserver extends ContentObserver {
Yohei Yukawa81482972015-06-04 00:58:59 -07001082 int mUserId;
1083 boolean mRegistered = false;
Yohei Yukawa7b574cb2016-03-16 17:22:22 -07001084 @NonNull
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08001085 String mLastEnabled = "";
1086
Yohei Yukawa81482972015-06-04 00:58:59 -07001087 /**
1088 * <em>This constructor must be called within the lock.</em>
1089 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001090 SettingsObserver(Handler handler) {
1091 super(handler);
Yohei Yukawa81482972015-06-04 00:58:59 -07001092 }
1093
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001094 public void registerContentObserverLocked(@UserIdInt int userId) {
Yohei Yukawa81482972015-06-04 00:58:59 -07001095 if (mRegistered && mUserId == userId) {
1096 return;
1097 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001098 ContentResolver resolver = mContext.getContentResolver();
Yohei Yukawa81482972015-06-04 00:58:59 -07001099 if (mRegistered) {
1100 mContext.getContentResolver().unregisterContentObserver(this);
1101 mRegistered = false;
1102 }
1103 if (mUserId != userId) {
1104 mLastEnabled = "";
1105 mUserId = userId;
1106 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -07001108 Settings.Secure.DEFAULT_INPUT_METHOD), false, this, userId);
satokab751aa2010-09-14 19:17:36 +09001109 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -07001110 Settings.Secure.ENABLED_INPUT_METHODS), false, this, userId);
satokb6109bb2011-02-03 22:24:54 +09001111 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -07001112 Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this, userId);
Michael Wright7b5a96b2014-08-09 19:28:42 -07001113 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -07001114 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, this, userId);
Anna Galusza9b278112016-01-04 11:37:37 -08001115 resolver.registerContentObserver(Settings.Secure.getUriFor(
1116 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE), false, this, userId);
Yohei Yukawa81482972015-06-04 00:58:59 -07001117 mRegistered = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001118 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001119
Michael Wright7b5a96b2014-08-09 19:28:42 -07001120 @Override public void onChange(boolean selfChange, Uri uri) {
Anna Galusza9b278112016-01-04 11:37:37 -08001121 final Uri showImeUri = Settings.Secure.getUriFor(
1122 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
1123 final Uri accessibilityRequestingNoImeUri = Settings.Secure.getUriFor(
1124 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 synchronized (mMethodMap) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07001126 if (showImeUri.equals(uri)) {
1127 updateKeyboardFromSettingsLocked();
Anna Galusza9b278112016-01-04 11:37:37 -08001128 } else if (accessibilityRequestingNoImeUri.equals(uri)) {
Phil Weaver03a65b02018-07-19 16:07:57 -07001129 final int accessibilitySoftKeyboardSetting = Settings.Secure.getIntForUser(
Anna Galusza9b278112016-01-04 11:37:37 -08001130 mContext.getContentResolver(),
Phil Weaver03a65b02018-07-19 16:07:57 -07001131 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0, mUserId);
1132 mAccessibilityRequestingNoSoftKeyboard =
1133 (accessibilitySoftKeyboardSetting & AccessibilityService.SHOW_MODE_MASK)
1134 == AccessibilityService.SHOW_MODE_HIDDEN;
Anna Galusza9b278112016-01-04 11:37:37 -08001135 if (mAccessibilityRequestingNoSoftKeyboard) {
1136 final boolean showRequested = mShowRequested;
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08001137 hideCurrentInputLocked(mCurFocusedWindow, 0, null,
lumarkd85e1582019-12-29 20:20:41 +08001138 SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE);
Anna Galusza9b278112016-01-04 11:37:37 -08001139 mShowRequested = showRequested;
1140 } else if (mShowRequested) {
lumarkd85e1582019-12-29 20:20:41 +08001141 showCurrentInputLocked(mCurFocusedWindow,
1142 InputMethodManager.SHOW_IMPLICIT, null,
1143 SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE);
Anna Galusza9b278112016-01-04 11:37:37 -08001144 }
Michael Wright7b5a96b2014-08-09 19:28:42 -07001145 } else {
1146 boolean enabledChanged = false;
1147 String newEnabled = mSettings.getEnabledInputMethodsStr();
1148 if (!mLastEnabled.equals(newEnabled)) {
1149 mLastEnabled = newEnabled;
1150 enabledChanged = true;
1151 }
1152 updateInputMethodsFromSettingsLocked(enabledChanged);
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08001153 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001154 }
1155 }
Yohei Yukawa81482972015-06-04 00:58:59 -07001156
1157 @Override
1158 public String toString() {
1159 return "SettingsObserver{mUserId=" + mUserId + " mRegistered=" + mRegistered
1160 + " mLastEnabled=" + mLastEnabled + "}";
1161 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001163
Yohei Yukawa0ec08002019-03-08 10:48:26 -08001164 /**
1165 * {@link BroadcastReceiver} that is intended to listen to broadcasts sent to the system user
1166 * only.
1167 */
1168 private final class ImmsBroadcastReceiverForSystemUser extends BroadcastReceiver {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001169 @Override
1170 public void onReceive(Context context, Intent intent) {
1171 final String action = intent.getAction();
Yohei Yukawa4225c7d2019-03-08 00:06:11 -08001172 if (Intent.ACTION_USER_ADDED.equals(action)
Amith Yamasani734983f2014-03-04 16:48:05 -08001173 || Intent.ACTION_USER_REMOVED.equals(action)) {
Kenny Guy2a764942014-04-02 13:29:20 +01001174 updateCurrentProfileIds();
Amith Yamasani734983f2014-03-04 16:48:05 -08001175 return;
Yohei Yukawa79247822017-01-23 15:26:15 -08001176 } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001177 onActionLocaleChanged();
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001178 } else if (ACTION_SHOW_INPUT_METHOD_PICKER.equals(action)) {
1179 // ACTION_SHOW_INPUT_METHOD_PICKER action is a protected-broadcast and it is
1180 // guaranteed to be send only from the system, so that there is no need for extra
1181 // security check such as
1182 // {@link #canShowInputMethodPickerLocked(IInputMethodClient)}.
1183 mHandler.obtainMessage(
1184 MSG_SHOW_IM_SUBTYPE_PICKER,
lumark0b05f9e2018-11-26 15:09:06 +08001185 // TODO(b/120076400): Design and implement IME switcher for heterogeneous
1186 // navbar configuration.
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001187 InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES,
lumark0b05f9e2018-11-26 15:09:06 +08001188 DEFAULT_DISPLAY).sendToTarget();
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001189 } else {
1190 Slog.w(TAG, "Unexpected intent " + intent);
1191 }
1192 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001194
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001195 /**
Yohei Yukawa0ec08002019-03-08 10:48:26 -08001196 * {@link BroadcastReceiver} that is intended to listen to broadcasts sent to all the users.
1197 */
1198 private final class ImmsBroadcastReceiverForAllUsers extends BroadcastReceiver {
1199 @Override
1200 public void onReceive(Context context, Intent intent) {
1201 final String action = intent.getAction();
1202 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
1203 final PendingResult pendingResult = getPendingResult();
1204 if (pendingResult == null) {
1205 return;
1206 }
1207 // sender userId can be a real user ID or USER_ALL.
1208 final int senderUserId = pendingResult.getSendingUserId();
1209 if (senderUserId != UserHandle.USER_ALL) {
Tarandeep Singhcf5ff822019-07-08 14:06:27 -07001210 if (senderUserId != mSettings.getCurrentUserId()) {
Yohei Yukawa0ec08002019-03-08 10:48:26 -08001211 // A background user is trying to hide the dialog. Ignore.
1212 return;
1213 }
1214 }
1215 hideInputMethodMenu();
1216 } else {
1217 Slog.w(TAG, "Unexpected intent " + intent);
1218 }
1219 }
1220 }
1221
1222 /**
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001223 * Handles {@link Intent#ACTION_LOCALE_CHANGED}.
1224 *
1225 * <p>Note: For historical reasons, {@link Intent#ACTION_LOCALE_CHANGED} has been sent to all
1226 * the users. We should ignore this event if this is about any background user's locale.</p>
1227 *
1228 * <p>Caution: This method must not be called when system is not ready.</p>
1229 */
1230 void onActionLocaleChanged() {
1231 synchronized (mMethodMap) {
1232 final LocaleList possibleNewLocale = mRes.getConfiguration().getLocales();
1233 if (possibleNewLocale != null && possibleNewLocale.equals(mLastSystemLocales)) {
1234 return;
1235 }
1236 buildInputMethodListLocked(true);
1237 // If the locale is changed, needs to reset the default ime
1238 resetDefaultImeLocked(mContext);
1239 updateFromSettingsLocked(true);
1240 mLastSystemLocales = possibleNewLocale;
1241 }
1242 }
1243
Yohei Yukawac4e44912017-02-09 19:30:22 -08001244 final class MyPackageMonitor extends PackageMonitor {
1245 /**
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001246 * Package names that are known to contain {@link InputMethodService}.
Yohei Yukawac4e44912017-02-09 19:30:22 -08001247 *
1248 * <p>No need to include packages because of direct-boot unaware IMEs since we always rescan
1249 * all the packages when the user is unlocked, and direct-boot awareness will not be changed
1250 * dynamically unless the entire package is updated, which also always triggers package
1251 * rescanning.</p>
1252 */
1253 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001254 final private ArraySet<String> mKnownImePackageNames = new ArraySet<>();
1255
1256 /**
1257 * Packages that are appeared, disappeared, or modified for whatever reason.
1258 *
1259 * <p>Note: For now we intentionally use {@link ArrayList} instead of {@link ArraySet}
1260 * because 1) the number of elements is almost always 1 or so, and 2) we do not care
1261 * duplicate elements for our use case.</p>
1262 *
1263 * <p>This object must be accessed only from callback methods in {@link PackageMonitor},
1264 * which should be bound to {@link #getRegisteredHandler()}.</p>
1265 */
1266 private final ArrayList<String> mChangedPackages = new ArrayList<>();
1267
1268 /**
1269 * {@code true} if one or more packages that contain {@link InputMethodService} appeared.
1270 *
1271 * <p>This field must be accessed only from callback methods in {@link PackageMonitor},
1272 * which should be bound to {@link #getRegisteredHandler()}.</p>
1273 */
1274 private boolean mImePackageAppeared = false;
Yohei Yukawac4e44912017-02-09 19:30:22 -08001275
1276 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001277 void clearKnownImePackageNamesLocked() {
1278 mKnownImePackageNames.clear();
Yohei Yukawac4e44912017-02-09 19:30:22 -08001279 }
1280
1281 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001282 final void addKnownImePackageNameLocked(@NonNull String packageName) {
1283 mKnownImePackageNames.add(packageName);
Yohei Yukawac4e44912017-02-09 19:30:22 -08001284 }
1285
Yohei Yukawa278f2ab2017-02-14 19:51:33 -08001286 @GuardedBy("mMethodMap")
1287 private boolean isChangingPackagesOfCurrentUserLocked() {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001288 final int userId = getChangingUserId();
1289 final boolean retval = userId == mSettings.getCurrentUserId();
1290 if (DEBUG) {
satok81f8b7c2012-12-04 20:42:56 +09001291 if (!retval) {
1292 Slog.d(TAG, "--- ignore this call back from a background user: " + userId);
1293 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001294 }
1295 return retval;
1296 }
1297
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001298 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001299 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001300 synchronized (mMethodMap) {
Yohei Yukawa278f2ab2017-02-14 19:51:33 -08001301 if (!isChangingPackagesOfCurrentUserLocked()) {
1302 return false;
1303 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001304 String curInputMethodId = mSettings.getSelectedInputMethod();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001305 final int N = mMethodList.size();
1306 if (curInputMethodId != null) {
1307 for (int i=0; i<N; i++) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001308 InputMethodInfo imi = mMethodList.get(i);
1309 if (imi.getId().equals(curInputMethodId)) {
1310 for (String pkg : packages) {
1311 if (imi.getPackageName().equals(pkg)) {
1312 if (!doit) {
1313 return true;
1314 }
satok723a27e2010-11-11 14:58:11 +09001315 resetSelectedInputMethodAndSubtypeLocked("");
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001316 chooseNewDefaultIMELocked();
1317 return true;
1318 }
1319 }
1320 }
1321 }
1322 }
1323 }
1324 return false;
1325 }
1326
1327 @Override
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001328 public void onBeginPackageChanges() {
1329 clearPackageChangeState();
1330 }
1331
1332 @Override
1333 public void onPackageAppeared(String packageName, int reason) {
1334 if (!mImePackageAppeared) {
1335 final PackageManager pm = mContext.getPackageManager();
1336 final List<ResolveInfo> services = pm.queryIntentServicesAsUser(
1337 new Intent(InputMethod.SERVICE_INTERFACE).setPackage(packageName),
Yohei Yukawa5ec1fce2018-12-17 07:56:14 -08001338 PackageManager.MATCH_DISABLED_COMPONENTS, getChangingUserId());
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001339 // No need to lock this because we access it only on getRegisteredHandler().
1340 if (!services.isEmpty()) {
1341 mImePackageAppeared = true;
1342 }
1343 }
1344 // No need to lock this because we access it only on getRegisteredHandler().
1345 mChangedPackages.add(packageName);
1346 }
1347
1348 @Override
1349 public void onPackageDisappeared(String packageName, int reason) {
1350 // No need to lock this because we access it only on getRegisteredHandler().
1351 mChangedPackages.add(packageName);
1352 }
1353
1354 @Override
1355 public void onPackageModified(String packageName) {
1356 // No need to lock this because we access it only on getRegisteredHandler().
1357 mChangedPackages.add(packageName);
1358 }
1359
1360 @Override
1361 public void onPackagesSuspended(String[] packages) {
1362 // No need to lock this because we access it only on getRegisteredHandler().
1363 for (String packageName : packages) {
1364 mChangedPackages.add(packageName);
Yohei Yukawac4e44912017-02-09 19:30:22 -08001365 }
1366 }
1367
1368 @Override
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001369 public void onPackagesUnsuspended(String[] packages) {
1370 // No need to lock this because we access it only on getRegisteredHandler().
1371 for (String packageName : packages) {
1372 mChangedPackages.add(packageName);
1373 }
1374 }
1375
1376 @Override
1377 public void onFinishPackageChanges() {
1378 onFinishPackageChangesInternal();
1379 clearPackageChangeState();
1380 }
1381
1382 private void clearPackageChangeState() {
1383 // No need to lock them because we access these fields only on getRegisteredHandler().
1384 mChangedPackages.clear();
1385 mImePackageAppeared = false;
1386 }
1387
Andreas Gampea36dc622018-02-05 17:19:22 -08001388 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001389 private boolean shouldRebuildInputMethodListLocked() {
1390 // This method is guaranteed to be called only by getRegisteredHandler().
1391
1392 // If there is any new package that contains at least one IME, then rebuilt the list
1393 // of IMEs.
1394 if (mImePackageAppeared) {
1395 return true;
1396 }
1397
1398 // Otherwise, check if mKnownImePackageNames and mChangedPackages have any intersection.
1399 // TODO: Consider to create a utility method to do the following test. List.retainAll()
1400 // is an option, but it may still do some extra operations that we do not need here.
1401 final int N = mChangedPackages.size();
1402 for (int i = 0; i < N; ++i) {
1403 final String packageName = mChangedPackages.get(i);
1404 if (mKnownImePackageNames.contains(packageName)) {
1405 return true;
1406 }
1407 }
1408 return false;
1409 }
1410
1411 private void onFinishPackageChangesInternal() {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001412 synchronized (mMethodMap) {
Yohei Yukawa278f2ab2017-02-14 19:51:33 -08001413 if (!isChangingPackagesOfCurrentUserLocked()) {
1414 return;
1415 }
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001416 if (!shouldRebuildInputMethodListLocked()) {
1417 return;
1418 }
1419
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001420 InputMethodInfo curIm = null;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001421 String curInputMethodId = mSettings.getSelectedInputMethod();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001422 final int N = mMethodList.size();
1423 if (curInputMethodId != null) {
1424 for (int i=0; i<N; i++) {
1425 InputMethodInfo imi = mMethodList.get(i);
satoke7c6998e2011-06-03 17:57:59 +09001426 final String imiId = imi.getId();
1427 if (imiId.equals(curInputMethodId)) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001428 curIm = imi;
1429 }
satoke7c6998e2011-06-03 17:57:59 +09001430
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001431 int change = isPackageDisappearing(imi.getPackageName());
satoke7c6998e2011-06-03 17:57:59 +09001432 if (isPackageModified(imi.getPackageName())) {
Yohei Yukawab557d572018-12-29 21:26:26 -08001433 mAdditionalSubtypeMap.remove(imi.getId());
1434 AdditionalSubtypeUtils.save(mAdditionalSubtypeMap, mMethodMap,
1435 mSettings.getCurrentUserId());
satoke7c6998e2011-06-03 17:57:59 +09001436 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001437 if (change == PACKAGE_TEMPORARY_CHANGE
1438 || change == PACKAGE_PERMANENT_CHANGE) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001439 Slog.i(TAG, "Input method uninstalled, disabling: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001440 + imi.getComponent());
1441 setInputMethodEnabledLocked(imi.getId(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001442 }
1443 }
1444 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001445
Yohei Yukawa94e33302016-02-12 19:37:03 -08001446 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001447
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 boolean changed = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001449
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001450 if (curIm != null) {
Anna Galusza9b278112016-01-04 11:37:37 -08001451 int change = isPackageDisappearing(curIm.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001452 if (change == PACKAGE_TEMPORARY_CHANGE
1453 || change == PACKAGE_PERMANENT_CHANGE) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001454 ServiceInfo si = null;
1455 try {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001456 si = mIPackageManager.getServiceInfo(
1457 curIm.getComponent(), 0, mSettings.getCurrentUserId());
1458 } catch (RemoteException ex) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001459 }
1460 if (si == null) {
1461 // Uh oh, current input method is no longer around!
1462 // Pick another one...
Joe Onorato8a9b2202010-02-26 18:56:32 -08001463 Slog.i(TAG, "Current input method removed: " + curInputMethodId);
Yohei Yukawa849443c2019-01-21 09:02:25 -08001464 updateSystemUiLocked(0 /* vis */, mBackDisposition);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001465 if (!chooseNewDefaultIMELocked()) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001466 changed = true;
1467 curIm = null;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001468 Slog.i(TAG, "Unsetting current input method");
satok723a27e2010-11-11 14:58:11 +09001469 resetSelectedInputMethodAndSubtypeLocked("");
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001470 }
1471 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001472 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001473 }
satokab751aa2010-09-14 19:17:36 +09001474
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001475 if (curIm == null) {
1476 // We currently don't have a default input method... is
1477 // one now available?
1478 changed = chooseNewDefaultIMELocked();
Yohei Yukawa54d512c2015-05-19 22:15:02 -07001479 } else if (!changed && isPackageModified(curIm.getPackageName())) {
1480 // Even if the current input method is still available, mCurrentSubtype could
1481 // be obsolete when the package is modified in practice.
1482 changed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001483 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001484
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001485 if (changed) {
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08001486 updateFromSettingsLocked(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001487 }
1488 }
1489 }
1490 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001491
Jeff Brownc28867a2013-03-26 15:42:39 -07001492 private static final class MethodCallback extends IInputSessionCallback.Stub {
Jean Chalarde0d32a62011-10-20 20:36:07 +09001493 private final InputMethodManagerService mParentIMMS;
Jeff Brownc28867a2013-03-26 15:42:39 -07001494 private final IInputMethod mMethod;
1495 private final InputChannel mChannel;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001496
Jeff Brownc28867a2013-03-26 15:42:39 -07001497 MethodCallback(InputMethodManagerService imms, IInputMethod method,
1498 InputChannel channel) {
Jean Chalarde0d32a62011-10-20 20:36:07 +09001499 mParentIMMS = imms;
Jeff Brownc28867a2013-03-26 15:42:39 -07001500 mMethod = method;
1501 mChannel = channel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001502 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001503
satoke7c6998e2011-06-03 17:57:59 +09001504 @Override
Jeff Brownc28867a2013-03-26 15:42:39 -07001505 public void sessionCreated(IInputMethodSession session) {
Dianne Hackborn6b6b3fd2014-03-24 11:27:18 -07001506 long ident = Binder.clearCallingIdentity();
1507 try {
1508 mParentIMMS.onSessionCreated(mMethod, session, mChannel);
1509 } finally {
1510 Binder.restoreCallingIdentity(ident);
1511 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001512 }
1513 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001514
satok01038492012-04-09 21:08:27 +09001515 private class HardKeyboardListener
Seigo Nonaka7309b122015-08-17 18:34:13 -07001516 implements WindowManagerInternal.OnHardKeyboardStatusChangeListener {
satok01038492012-04-09 21:08:27 +09001517 @Override
Michael Wright7b5a96b2014-08-09 19:28:42 -07001518 public void onHardKeyboardStatusChange(boolean available) {
1519 mHandler.sendMessage(mHandler.obtainMessage(MSG_HARD_KEYBOARD_SWITCH_CHANGED,
1520 available ? 1 : 0));
satok01038492012-04-09 21:08:27 +09001521 }
1522
Michael Wright7b5a96b2014-08-09 19:28:42 -07001523 public void handleHardKeyboardStatusChange(boolean available) {
satok01038492012-04-09 21:08:27 +09001524 if (DEBUG) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07001525 Slog.w(TAG, "HardKeyboardStatusChanged: available=" + available);
satok01038492012-04-09 21:08:27 +09001526 }
1527 synchronized(mMethodMap) {
1528 if (mSwitchingDialog != null && mSwitchingDialogTitleView != null
1529 && mSwitchingDialog.isShowing()) {
1530 mSwitchingDialogTitleView.findViewById(
1531 com.android.internal.R.id.hard_keyboard_section).setVisibility(
1532 available ? View.VISIBLE : View.GONE);
1533 }
1534 }
1535 }
1536 }
1537
Yohei Yukawad277d692020-02-19 17:12:17 -08001538 private static final class UserSwitchHandlerTask implements Runnable {
1539 final InputMethodManagerService mService;
1540
1541 @UserIdInt
1542 final int mToUserId;
1543
1544 @Nullable
1545 IInputMethodClient mClientToBeReset;
1546
1547 UserSwitchHandlerTask(InputMethodManagerService service, @UserIdInt int toUserId,
1548 @Nullable IInputMethodClient clientToBeReset) {
1549 mService = service;
1550 mToUserId = toUserId;
1551 mClientToBeReset = clientToBeReset;
1552 }
1553
1554 @Override
1555 public void run() {
1556 synchronized (mService.mMethodMap) {
1557 if (mService.mUserSwitchHandlerTask != this) {
1558 // This task was already canceled before it is handled here. So do nothing.
1559 return;
1560 }
1561 mService.switchUserOnHandlerLocked(mService.mUserSwitchHandlerTask.mToUserId,
1562 mClientToBeReset);
1563 mService.mUserSwitchHandlerTask = null;
1564 }
1565 }
1566 }
1567
1568 /**
1569 * When non-{@code null}, this represents pending user-switch task, which is to be executed as
1570 * a handler callback. This needs to be set and unset only within the lock.
1571 */
1572 @Nullable
1573 @GuardedBy("mMethodMap")
1574 private UserSwitchHandlerTask mUserSwitchHandlerTask;
1575
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001576 public static final class Lifecycle extends SystemService {
1577 private InputMethodManagerService mService;
1578
1579 public Lifecycle(Context context) {
1580 super(context);
1581 mService = new InputMethodManagerService(context);
1582 }
1583
1584 @Override
1585 public void onStart() {
1586 LocalServices.addService(InputMethodManagerInternal.class,
Yohei Yukawafffc0e52018-09-04 13:24:00 -07001587 new LocalServiceImpl(mService));
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001588 publishBinderService(Context.INPUT_METHOD_SERVICE, mService);
1589 }
1590
1591 @Override
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001592 public void onSwitchUser(@UserIdInt int userHandle) {
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07001593 // Called on ActivityManager thread.
Yohei Yukawad277d692020-02-19 17:12:17 -08001594 synchronized (mService.mMethodMap) {
1595 mService.scheduleSwitchUserTaskLocked(userHandle, null /* clientToBeReset */);
1596 }
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001597 }
1598
1599 @Override
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001600 public void onBootPhase(int phase) {
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07001601 // Called on ActivityManager thread.
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001602 // TODO: Dispatch this to a worker thread as needed.
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001603 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
1604 StatusBarManagerService statusBarService = (StatusBarManagerService) ServiceManager
1605 .getService(Context.STATUS_BAR_SERVICE);
1606 mService.systemRunning(statusBarService);
1607 }
1608 }
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001609
1610 @Override
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07001611 public void onUnlockUser(final @UserIdInt int userHandle) {
1612 // Called on ActivityManager thread.
1613 mService.mHandler.sendMessage(mService.mHandler.obtainMessage(MSG_SYSTEM_UNLOCK_USER,
Fyodor Kupolov0f57cce2016-09-09 10:36:30 -07001614 userHandle /* arg1 */, 0 /* arg2 */));
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001615 }
1616 }
1617
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001618 void onUnlockUser(@UserIdInt int userId) {
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001619 synchronized(mMethodMap) {
1620 final int currentUserId = mSettings.getCurrentUserId();
1621 if (DEBUG) {
1622 Slog.d(TAG, "onUnlockUser: userId=" + userId + " curUserId=" + currentUserId);
1623 }
1624 if (userId != currentUserId) {
1625 return;
1626 }
1627 mSettings.switchCurrentUser(currentUserId, !mSystemReady);
Yohei Yukawa79247822017-01-23 15:26:15 -08001628 if (mSystemReady) {
1629 // We need to rebuild IMEs.
1630 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
1631 updateInputMethodsFromSettingsLocked(true /* enabledChanged */);
1632 }
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001633 }
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001634 }
1635
Yohei Yukawad277d692020-02-19 17:12:17 -08001636 @GuardedBy("mMethodMap")
1637 void scheduleSwitchUserTaskLocked(@UserIdInt int userId,
1638 @Nullable IInputMethodClient clientToBeReset) {
1639 if (mUserSwitchHandlerTask != null) {
1640 if (mUserSwitchHandlerTask.mToUserId == userId) {
1641 mUserSwitchHandlerTask.mClientToBeReset = clientToBeReset;
1642 return;
1643 }
1644 mHandler.removeCallbacks(mUserSwitchHandlerTask);
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001645 }
Yohei Yukawad277d692020-02-19 17:12:17 -08001646 final UserSwitchHandlerTask task = new UserSwitchHandlerTask(this, userId,
1647 clientToBeReset);
1648 mUserSwitchHandlerTask = task;
1649 mHandler.post(task);
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001650 }
1651
Seigo Nonaka7309b122015-08-17 18:34:13 -07001652 public InputMethodManagerService(Context context) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001653 mIPackageManager = AppGlobals.getPackageManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001654 mContext = context;
Dianne Hackborn7d3a5bc2010-11-29 22:52:12 -08001655 mRes = context.getResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001656 mHandler = new Handler(this);
Yohei Yukawa81482972015-06-04 00:58:59 -07001657 // Note: SettingsObserver doesn't register observers in its constructor.
1658 mSettingsObserver = new SettingsObserver(mHandler);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001659 mIWindowManager = IWindowManager.Stub.asInterface(
1660 ServiceManager.getService(Context.WINDOW_SERVICE));
Seigo Nonaka7309b122015-08-17 18:34:13 -07001661 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
Yohei Yukawad5f402b2020-05-15 10:23:32 -07001662 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
lpeter133fce02020-03-05 20:32:16 +08001663 mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
Yohei Yukawab4f328a2019-05-02 08:41:27 -07001664 mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
lumark9a72d222019-03-30 18:31:45 +08001665 mImeDisplayValidator = displayId -> mWindowManagerInternal.shouldShowIme(displayId);
Mita Yuned218c72012-12-06 17:18:25 -08001666 mCaller = new HandlerCaller(context, null, new HandlerCaller.Callback() {
satoke7c6998e2011-06-03 17:57:59 +09001667 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001668 public void executeMessage(Message msg) {
1669 handleMessage(msg);
1670 }
Mita Yuned218c72012-12-06 17:18:25 -08001671 }, true /*asyncHandler*/);
Yohei Yukawad34e1482016-02-11 08:03:52 -08001672 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001673 mUserManager = mContext.getSystemService(UserManager.class);
Yohei Yukawa42081402019-01-15 09:57:50 -08001674 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
satok01038492012-04-09 21:08:27 +09001675 mHardKeyboardListener = new HardKeyboardListener();
Dianne Hackborn119bbc32013-03-22 17:27:25 -07001676 mHasFeature = context.getPackageManager().hasSystemFeature(
1677 PackageManager.FEATURE_INPUT_METHODS);
Jason Monk3e189872016-01-12 09:10:34 -05001678 mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
Tarandeep Singheadb1392018-11-09 18:15:57 +01001679 mIsLowRam = ActivityManager.isLowRamDeviceStatic();
satok7cfc0ed2011-06-20 21:29:36 +09001680
Chris Wren1ce4b6d2015-06-11 10:19:43 -04001681 Bundle extras = new Bundle();
1682 extras.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, true);
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001683 @ColorInt final int accentColor = mContext.getColor(
1684 com.android.internal.R.color.system_notification_accent_color);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05001685 mImeSwitcherNotification =
1686 new Notification.Builder(mContext, SystemNotificationChannels.VIRTUAL_KEYBOARD)
1687 .setSmallIcon(com.android.internal.R.drawable.ic_notification_ime_default)
1688 .setWhen(0)
1689 .setOngoing(true)
1690 .addExtras(extras)
1691 .setCategory(Notification.CATEGORY_SYSTEM)
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001692 .setColor(accentColor);
Daniel Sandler590d5152012-06-14 16:10:13 -04001693
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001694 Intent intent = new Intent(ACTION_SHOW_INPUT_METHOD_PICKER)
1695 .setPackage(mContext.getPackageName());
satok683e2382011-07-12 08:28:52 +09001696 mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
satokb858c732011-07-22 19:54:34 +09001697
1698 mShowOngoingImeSwitcherForPhones = false;
satok7cfc0ed2011-06-20 21:29:36 +09001699
satok7cfc0ed2011-06-20 21:29:36 +09001700 mNotificationShown = false;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001701 int userId = 0;
1702 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001703 userId = ActivityManager.getService().getCurrentUser().id;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001704 } catch (RemoteException e) {
1705 Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
1706 }
satok913a8922010-08-26 21:53:41 +09001707
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08001708 mLastSwitchUserId = userId;
1709
satokd87c2592010-09-29 11:52:06 +09001710 // mSettings should be created before buildInputMethodListLocked
satokdf31ae62011-01-15 06:19:44 +09001711 mSettings = new InputMethodSettings(
Yohei Yukawaf9277532019-01-25 02:47:32 -08001712 mRes, context.getContentResolver(), mMethodMap, userId, !mSystemReady);
Svet Ganovadc1cf42015-06-15 16:36:24 -07001713
Kenny Guy2a764942014-04-02 13:29:20 +01001714 updateCurrentProfileIds();
Yohei Yukawab557d572018-12-29 21:26:26 -08001715 AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, userId);
Yohei Yukawa79247822017-01-23 15:26:15 -08001716 mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
1717 mSettings, context);
satok5b927c432012-05-01 20:09:34 +09001718 }
1719
satok5b927c432012-05-01 20:09:34 +09001720 private void resetDefaultImeLocked(Context context) {
1721 // Do not reset the default (current) IME when it is a 3rd-party IME
Yohei Yukawafd70fe82018-04-08 12:19:56 -07001722 if (mCurMethodId != null && !mMethodMap.get(mCurMethodId).isSystem()) {
satok5b927c432012-05-01 20:09:34 +09001723 return;
1724 }
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001725 final List<InputMethodInfo> suitableImes = InputMethodUtils.getDefaultEnabledImes(
Yohei Yukawaaf5cee82017-01-23 16:17:11 -08001726 context, mSettings.getEnabledInputMethodListLocked());
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001727 if (suitableImes.isEmpty()) {
1728 Slog.i(TAG, "No default found");
1729 return;
satok5b927c432012-05-01 20:09:34 +09001730 }
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001731 final InputMethodInfo defIm = suitableImes.get(0);
Yohei Yukawad0332832017-02-01 13:59:43 -08001732 if (DEBUG) {
1733 Slog.i(TAG, "Default found, using " + defIm.getId());
1734 }
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001735 setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
satok5b927c432012-05-01 20:09:34 +09001736 }
1737
Andreas Gampea36dc622018-02-05 17:19:22 -08001738 @GuardedBy("mMethodMap")
Yohei Yukawad277d692020-02-19 17:12:17 -08001739 private void switchUserOnHandlerLocked(@UserIdInt int newUserId,
1740 IInputMethodClient clientToBeReset) {
Yohei Yukawa90bf7082015-06-03 23:50:27 -07001741 if (DEBUG) Slog.d(TAG, "Switching user stage 1/3. newUserId=" + newUserId
1742 + " currentUserId=" + mSettings.getCurrentUserId());
1743
Yohei Yukawa81482972015-06-04 00:58:59 -07001744 // ContentObserver should be registered again when the user is changed
1745 mSettingsObserver.registerContentObserverLocked(newUserId);
Yohei Yukawa68645a62016-02-17 07:54:20 -08001746
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001747 // If the system is not ready or the device is not yed unlocked by the user, then we use
1748 // copy-on-write settings.
1749 final boolean useCopyOnWriteSettings =
Yohei Yukawa42081402019-01-15 09:57:50 -08001750 !mSystemReady || !mUserManagerInternal.isUserUnlockingOrUnlocked(newUserId);
Yohei Yukawa68645a62016-02-17 07:54:20 -08001751 mSettings.switchCurrentUser(newUserId, useCopyOnWriteSettings);
Kenny Guy2a764942014-04-02 13:29:20 +01001752 updateCurrentProfileIds();
Yohei Yukawab557d572018-12-29 21:26:26 -08001753 // Additional subtypes should be reset when the user is changed
1754 AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, newUserId);
Satoshi Kataoka7f7535f2013-02-18 12:54:16 +09001755 final String defaultImiId = mSettings.getSelectedInputMethod();
Yohei Yukawa90bf7082015-06-03 23:50:27 -07001756
1757 if (DEBUG) Slog.d(TAG, "Switching user stage 2/3. newUserId=" + newUserId
1758 + " defaultImiId=" + defaultImiId);
1759
Satoshi Kataoka7c4a2a12013-02-25 15:25:43 +09001760 // For secondary users, the list of enabled IMEs may not have been updated since the
1761 // callbacks to PackageMonitor are ignored for the secondary user. Here, defaultImiId may
1762 // not be empty even if the IME has been uninstalled by the primary user.
1763 // Even in such cases, IMMS works fine because it will find the most applicable
1764 // IME for that user.
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09001765 final boolean initialUserSwitch = TextUtils.isEmpty(defaultImiId);
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001766 mLastSystemLocales = mRes.getConfiguration().getLocales();
1767
1768 // TODO: Is it really possible that switchUserLocked() happens before system ready?
1769 if (mSystemReady) {
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08001770 hideCurrentInputLocked(
1771 mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_SWITCH_USER);
1772
Yohei Yukawab7526452018-10-21 20:15:17 -07001773 resetCurrentMethodAndClient(UnbindReason.SWITCH_USER);
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001774 buildInputMethodListLocked(initialUserSwitch);
1775 if (TextUtils.isEmpty(mSettings.getSelectedInputMethod())) {
1776 // This is the first time of the user switch and
1777 // set the current ime to the proper one.
1778 resetDefaultImeLocked(mContext);
1779 }
1780 updateFromSettingsLocked(true);
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001781 }
1782
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09001783 if (initialUserSwitch) {
Yohei Yukawa094c71f2015-06-20 00:41:31 -07001784 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
1785 mSettings.getEnabledInputMethodListLocked(), newUserId,
1786 mContext.getBasePackageName());
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09001787 }
Yohei Yukawa90bf7082015-06-03 23:50:27 -07001788
1789 if (DEBUG) Slog.d(TAG, "Switching user stage 3/3. newUserId=" + newUserId
1790 + " selectedIme=" + mSettings.getSelectedInputMethod());
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08001791
1792 mLastSwitchUserId = newUserId;
Yohei Yukawad277d692020-02-19 17:12:17 -08001793
1794 if (mIsInteractive && clientToBeReset != null) {
1795 final ClientState cs = mClients.get(clientToBeReset.asBinder());
1796 if (cs == null) {
1797 // The client is already gone.
1798 return;
1799 }
1800 try {
1801 cs.client.scheduleStartInputIfNecessary(mInFullscreenMode);
1802 } catch (RemoteException e) {
1803 }
1804 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001805 }
1806
Kenny Guy2a764942014-04-02 13:29:20 +01001807 void updateCurrentProfileIds() {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -07001808 mSettings.setCurrentProfileIds(
1809 mUserManager.getProfileIdsWithDisabled(mSettings.getCurrentUserId()));
Amith Yamasani734983f2014-03-04 16:48:05 -08001810 }
1811
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001812 @Override
1813 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1814 throws RemoteException {
1815 try {
1816 return super.onTransact(code, data, reply, flags);
1817 } catch (RuntimeException e) {
1818 // The input method manager only throws security exceptions, so let's
1819 // log all others.
1820 if (!(e instanceof SecurityException)) {
Dianne Hackborn164371f2013-10-01 19:10:13 -07001821 Slog.wtf(TAG, "Input Method Manager Crash", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001822 }
1823 throw e;
1824 }
1825 }
1826
Svetoslav Ganova0027152013-06-25 14:59:53 -07001827 public void systemRunning(StatusBarManagerService statusBar) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07001828 synchronized (mMethodMap) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001829 if (DEBUG) {
1830 Slog.d(TAG, "--- systemReady");
1831 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07001832 if (!mSystemReady) {
1833 mSystemReady = true;
Yohei Yukawa79247822017-01-23 15:26:15 -08001834 mLastSystemLocales = mRes.getConfiguration().getLocales();
Yohei Yukawa68645a62016-02-17 07:54:20 -08001835 final int currentUserId = mSettings.getCurrentUserId();
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001836 mSettings.switchCurrentUser(currentUserId,
Yohei Yukawa42081402019-01-15 09:57:50 -08001837 !mUserManagerInternal.isUserUnlockingOrUnlocked(currentUserId));
Yohei Yukawad34e1482016-02-11 08:03:52 -08001838 mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
1839 mNotificationManager = mContext.getSystemService(NotificationManager.class);
Dianne Hackborn661cd522011-08-22 00:26:20 -07001840 mStatusBar = statusBar;
Griff Hazen6090c262016-03-25 08:11:24 -07001841 if (mStatusBar != null) {
1842 mStatusBar.setIconVisibility(mSlotIme, false);
1843 }
Yohei Yukawa849443c2019-01-21 09:02:25 -08001844 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
satokb858c732011-07-22 19:54:34 +09001845 mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
1846 com.android.internal.R.bool.show_ongoing_ime_switcher);
satok01038492012-04-09 21:08:27 +09001847 if (mShowOngoingImeSwitcherForPhones) {
Seigo Nonaka7309b122015-08-17 18:34:13 -07001848 mWindowManagerInternal.setOnHardKeyboardStatusChangeListener(
satok01038492012-04-09 21:08:27 +09001849 mHardKeyboardListener);
1850 }
Yohei Yukawa79247822017-01-23 15:26:15 -08001851
1852 mMyPackageMonitor.register(mContext, null, UserHandle.ALL, true);
1853 mSettingsObserver.registerContentObserverLocked(currentUserId);
1854
Yohei Yukawa0ec08002019-03-08 10:48:26 -08001855 final IntentFilter broadcastFilterForSystemUser = new IntentFilter();
1856 broadcastFilterForSystemUser.addAction(Intent.ACTION_USER_ADDED);
1857 broadcastFilterForSystemUser.addAction(Intent.ACTION_USER_REMOVED);
1858 broadcastFilterForSystemUser.addAction(Intent.ACTION_LOCALE_CHANGED);
1859 broadcastFilterForSystemUser.addAction(ACTION_SHOW_INPUT_METHOD_PICKER);
1860 mContext.registerReceiver(new ImmsBroadcastReceiverForSystemUser(),
1861 broadcastFilterForSystemUser);
1862
1863 final IntentFilter broadcastFilterForAllUsers = new IntentFilter();
1864 broadcastFilterForAllUsers.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
1865 mContext.registerReceiverAsUser(new ImmsBroadcastReceiverForAllUsers(),
1866 UserHandle.ALL, broadcastFilterForAllUsers, null, null);
Yohei Yukawa79247822017-01-23 15:26:15 -08001867
Yohei Yukawa1f9a3cb2017-10-26 15:00:59 -07001868 final String defaultImiId = mSettings.getSelectedInputMethod();
1869 final boolean imeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId);
1870 buildInputMethodListLocked(!imeSelectedOnBoot /* resetDefaultEnabledIme */);
Yohei Yukawa79247822017-01-23 15:26:15 -08001871 updateFromSettingsLocked(true);
1872 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
1873 mSettings.getEnabledInputMethodListLocked(), currentUserId,
1874 mContext.getBasePackageName());
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07001875 }
1876 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001877 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001878
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001879 // ---------------------------------------------------------------------------------------
1880 // Check whether or not this is a valid IPC. Assumes an IPC is valid when either
1881 // 1) it comes from the system process
1882 // 2) the calling process' user id is identical to the current user id IMMS thinks.
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08001883 @GuardedBy("mMethodMap")
Yohei Yukawa46d74762019-01-22 10:17:22 -08001884 private boolean calledFromValidUserLocked() {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001885 final int uid = Binder.getCallingUid();
1886 final int userId = UserHandle.getUserId(uid);
1887 if (DEBUG) {
1888 Slog.d(TAG, "--- calledFromForegroundUserOrSystemProcess ? "
1889 + "calling uid = " + uid + " system uid = " + Process.SYSTEM_UID
1890 + " calling userId = " + userId + ", foreground user id = "
Satoshi Kataoka87c29142013-07-31 23:11:54 +09001891 + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid()
1892 + InputMethodUtils.getApiCallStack());
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001893 }
Yohei Yukawaa878b952019-01-10 19:36:24 -08001894 if (uid == Process.SYSTEM_UID) {
1895 return true;
1896 }
1897 if (userId == mSettings.getCurrentUserId()) {
1898 return true;
1899 }
Satoshi Kataoka135e5fb2012-09-28 18:25:06 +09001900
1901 // Caveat: A process which has INTERACT_ACROSS_USERS_FULL gets results for the
1902 // foreground user, not for the user of that process. Accordingly InputMethodManagerService
1903 // must not manage background users' states in any functions.
1904 // Note that privacy-sensitive IPCs, such as setInputMethod, are still securely guarded
1905 // by a token.
1906 if (mContext.checkCallingOrSelfPermission(
1907 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1908 == PackageManager.PERMISSION_GRANTED) {
1909 if (DEBUG) {
1910 Slog.d(TAG, "--- Access granted because the calling process has "
1911 + "the INTERACT_ACROSS_USERS_FULL permission");
1912 }
1913 return true;
1914 }
Yohei Yukawad0332832017-02-01 13:59:43 -08001915 // TODO(b/34886274): The semantics of this verification is actually not well-defined.
Seigo Nonakae27dc2b2015-08-14 18:21:27 -07001916 Slog.w(TAG, "--- IPC called from background users. Ignore. callers="
1917 + Debug.getCallers(10));
Satoshi Kataoka135e5fb2012-09-28 18:25:06 +09001918 return false;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001919 }
1920
Yohei Yukawa22c97be2014-06-04 19:43:36 +09001921
1922 /**
1923 * Returns true iff the caller is identified to be the current input method with the token.
1924 * @param token The window token given to the input method when it was started.
1925 * @return true if and only if non-null valid token is specified.
1926 */
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08001927 @GuardedBy("mMethodMap")
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08001928 private boolean calledWithValidTokenLocked(@NonNull IBinder token) {
1929 if (token == null) {
1930 throw new InvalidParameterException("token must not be null.");
Yohei Yukawad0332832017-02-01 13:59:43 -08001931 }
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08001932 if (token != mCurToken) {
Yohei Yukawad0332832017-02-01 13:59:43 -08001933 Slog.e(TAG, "Ignoring " + Debug.getCaller() + " due to an invalid token."
1934 + " uid:" + Binder.getCallingUid() + " token:" + token);
Yohei Yukawa22c97be2014-06-04 19:43:36 +09001935 return false;
1936 }
1937 return true;
1938 }
1939
Yohei Yukawaf80087c2018-05-21 09:47:53 -07001940 @GuardedBy("mMethodMap")
1941 private boolean bindCurrentInputMethodServiceLocked(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001942 Intent service, ServiceConnection conn, int flags) {
1943 if (service == null || conn == null) {
1944 Slog.e(TAG, "--- bind failed: service = " + service + ", conn = " + conn);
1945 return false;
1946 }
Amith Yamasani27b89e62013-01-16 12:30:11 -08001947 return mContext.bindServiceAsUser(service, conn, flags,
1948 new UserHandle(mSettings.getCurrentUserId()));
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001949 }
1950
satoke7c6998e2011-06-03 17:57:59 +09001951 @Override
Yohei Yukawad20eef82019-02-05 10:45:32 -08001952 public List<InputMethodInfo> getInputMethodList(@UserIdInt int userId) {
1953 if (UserHandle.getCallingUserId() != userId) {
1954 mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
1955 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001956 synchronized (mMethodMap) {
Yohei Yukawad20eef82019-02-05 10:45:32 -08001957 final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001958 mSettings.getCurrentUserId(), null);
1959 if (resolvedUserIds.length != 1) {
1960 return Collections.emptyList();
1961 }
1962 final long ident = Binder.clearCallingIdentity();
1963 try {
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08001964 return getInputMethodListLocked(resolvedUserIds[0]);
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001965 } finally {
1966 Binder.restoreCallingIdentity(ident);
Tarandeep Singh89a6c482017-11-21 14:26:11 -08001967 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001968 }
1969 }
1970
satoke7c6998e2011-06-03 17:57:59 +09001971 @Override
Yohei Yukawa1fb13c52019-02-05 07:55:28 -08001972 public List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) {
1973 if (UserHandle.getCallingUserId() != userId) {
1974 mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
1975 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001976 synchronized (mMethodMap) {
Yohei Yukawa1fb13c52019-02-05 07:55:28 -08001977 final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001978 mSettings.getCurrentUserId(), null);
1979 if (resolvedUserIds.length != 1) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08001980 return Collections.emptyList();
1981 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001982 final long ident = Binder.clearCallingIdentity();
1983 try {
1984 return getEnabledInputMethodListLocked(resolvedUserIds[0]);
1985 } finally {
1986 Binder.restoreCallingIdentity(ident);
1987 }
1988 }
1989 }
1990
1991 @GuardedBy("mMethodMap")
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08001992 private List<InputMethodInfo> getInputMethodListLocked(@UserIdInt int userId) {
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001993 final ArrayList<InputMethodInfo> methodList;
1994 if (userId == mSettings.getCurrentUserId()) {
1995 // Create a copy.
1996 methodList = new ArrayList<>(mMethodList);
1997 } else {
1998 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
1999 methodList = new ArrayList<>();
2000 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
2001 new ArrayMap<>();
2002 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
2003 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
2004 methodList);
2005 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08002006 return methodList;
2007 }
2008
2009 @GuardedBy("mMethodMap")
2010 private List<InputMethodInfo> getEnabledInputMethodListLocked(@UserIdInt int userId) {
2011 if (userId == mSettings.getCurrentUserId()) {
satokd87c2592010-09-29 11:52:06 +09002012 return mSettings.getEnabledInputMethodListLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002013 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08002014 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
2015 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
2016 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
2017 new ArrayMap<>();
2018 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
2019 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
2020 methodList);
2021 final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
Yohei Yukawaf9277532019-01-25 02:47:32 -08002022 mContext.getContentResolver(), methodMap, userId, true);
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08002023 return settings.getEnabledInputMethodListLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002024 }
2025
Adam Hebc67f2e2019-11-13 14:34:56 -08002026 @GuardedBy("mMethodMap")
Feng Cao16b2de52020-01-09 17:27:27 -08002027 private void onCreateInlineSuggestionsRequestLocked(@UserIdInt int userId,
Feng Cao36960ee2020-02-18 18:23:30 -08002028 InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback) {
Adam He7bc8f602019-12-12 17:00:34 -08002029 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
2030 try {
Feng Cao16b2de52020-01-09 17:27:27 -08002031 if (userId == mSettings.getCurrentUserId() && imi != null
2032 && imi.isInlineSuggestionsEnabled() && mCurMethod != null) {
Adam He7bc8f602019-12-12 17:00:34 -08002033 executeOrSendMessage(mCurMethod,
Feng Cao36960ee2020-02-18 18:23:30 -08002034 mCaller.obtainMessageOOO(MSG_INLINE_SUGGESTIONS_REQUEST, mCurMethod,
2035 requestInfo, new InlineSuggestionsRequestCallbackDecorator(callback,
lpeter133fce02020-03-05 20:32:16 +08002036 imi.getPackageName(), mCurTokenDisplayId, mCurToken,
2037 this)));
Adam He7bc8f602019-12-12 17:00:34 -08002038 } else {
2039 callback.onInlineSuggestionsUnsupported();
2040 }
2041 } catch (RemoteException e) {
2042 Slog.w(TAG, "RemoteException calling onCreateInlineSuggestionsRequest(): " + e);
Adam Hebc67f2e2019-11-13 14:34:56 -08002043 }
2044 }
2045
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09002046 /**
Feng Cao16b2de52020-01-09 17:27:27 -08002047 * The decorator which validates the host package name in the
2048 * {@link InlineSuggestionsRequest} argument to make sure it matches the IME package name.
2049 */
2050 private static final class InlineSuggestionsRequestCallbackDecorator
2051 extends IInlineSuggestionsRequestCallback.Stub {
2052 @NonNull
2053 private final IInlineSuggestionsRequestCallback mCallback;
2054 @NonNull
2055 private final String mImePackageName;
2056
Svet Ganov02fdd342020-02-20 20:48:34 -08002057 private final int mImeDisplayId;
2058
lpeter133fce02020-03-05 20:32:16 +08002059 @NonNull
2060 private final IBinder mImeToken;
2061 @NonNull
2062 private final InputMethodManagerService mImms;
2063
Feng Cao16b2de52020-01-09 17:27:27 -08002064 InlineSuggestionsRequestCallbackDecorator(
lpeter133fce02020-03-05 20:32:16 +08002065 @NonNull IInlineSuggestionsRequestCallback callback, @NonNull String imePackageName,
2066 int displayId, @NonNull IBinder imeToken, @NonNull InputMethodManagerService imms) {
Feng Cao16b2de52020-01-09 17:27:27 -08002067 mCallback = callback;
2068 mImePackageName = imePackageName;
Svet Ganov02fdd342020-02-20 20:48:34 -08002069 mImeDisplayId = displayId;
lpeter133fce02020-03-05 20:32:16 +08002070 mImeToken = imeToken;
2071 mImms = imms;
Feng Cao16b2de52020-01-09 17:27:27 -08002072 }
2073
2074 @Override
2075 public void onInlineSuggestionsUnsupported() throws RemoteException {
2076 mCallback.onInlineSuggestionsUnsupported();
2077 }
2078
2079 @Override
2080 public void onInlineSuggestionsRequest(InlineSuggestionsRequest request,
Feng Cao97ec1c42020-03-25 12:20:42 -07002081 IInlineSuggestionsResponseCallback callback)
Feng Cao7c85eb72020-02-28 11:39:56 -08002082 throws RemoteException {
Feng Cao16b2de52020-01-09 17:27:27 -08002083 if (!mImePackageName.equals(request.getHostPackageName())) {
2084 throw new SecurityException(
2085 "Host package name in the provide request=[" + request.getHostPackageName()
2086 + "] doesn't match the IME package name=[" + mImePackageName
2087 + "].");
2088 }
Svet Ganov02fdd342020-02-20 20:48:34 -08002089 request.setHostDisplayId(mImeDisplayId);
lpeter133fce02020-03-05 20:32:16 +08002090 mImms.setCurHostInputToken(mImeToken, request.getHostInputToken());
Feng Cao97ec1c42020-03-25 12:20:42 -07002091 mCallback.onInlineSuggestionsRequest(request, callback);
Feng Cao7c85eb72020-02-28 11:39:56 -08002092 }
2093
2094 @Override
Feng Cao97ec1c42020-03-25 12:20:42 -07002095 public void onInputMethodStartInput(AutofillId imeFieldId) throws RemoteException {
2096 mCallback.onInputMethodStartInput(imeFieldId);
Feng Cao7c85eb72020-02-28 11:39:56 -08002097 }
2098
2099 @Override
Feng Cao97ec1c42020-03-25 12:20:42 -07002100 public void onInputMethodShowInputRequested(boolean requestResult) throws RemoteException {
2101 mCallback.onInputMethodShowInputRequested(requestResult);
2102 }
2103
2104 @Override
2105 public void onInputMethodStartInputView() throws RemoteException {
2106 mCallback.onInputMethodStartInputView();
2107 }
2108
2109 @Override
2110 public void onInputMethodFinishInputView() throws RemoteException {
2111 mCallback.onInputMethodFinishInputView();
2112 }
2113
2114 @Override
2115 public void onInputMethodFinishInput() throws RemoteException {
2116 mCallback.onInputMethodFinishInput();
Feng Cao16b2de52020-01-09 17:27:27 -08002117 }
2118 }
2119
2120 /**
lpeter133fce02020-03-05 20:32:16 +08002121 * Sets current host input token.
2122 *
2123 * @param callerImeToken the token has been made for the current active input method
2124 * @param hostInputToken the host input token of the current active input method
2125 */
2126 void setCurHostInputToken(@NonNull IBinder callerImeToken, @Nullable IBinder hostInputToken) {
2127 synchronized (mMethodMap) {
2128 if (!calledWithValidTokenLocked(callerImeToken)) {
2129 return;
2130 }
2131 mCurHostInputToken = hostInputToken;
2132 }
2133 }
2134
2135 /**
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09002136 * @param imiId if null, returns enabled subtypes for the current imi
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09002137 * @return enabled subtypes of the specified imi
2138 */
satoke7c6998e2011-06-03 17:57:59 +09002139 @Override
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09002140 public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
satok16331c82010-12-20 23:48:46 +09002141 boolean allowsImplicitlySelectedSubtypes) {
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08002142 final int callingUserId = UserHandle.getCallingUserId();
satok67ddf9c2010-11-17 09:45:54 +09002143 synchronized (mMethodMap) {
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08002144 final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
2145 mSettings.getCurrentUserId(), null);
2146 if (resolvedUserIds.length != 1) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002147 return Collections.emptyList();
2148 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08002149 final long ident = Binder.clearCallingIdentity();
2150 try {
2151 return getEnabledInputMethodSubtypeListLocked(imiId,
2152 allowsImplicitlySelectedSubtypes, resolvedUserIds[0]);
2153 } finally {
2154 Binder.restoreCallingIdentity(ident);
2155 }
2156 }
2157 }
2158
2159 @GuardedBy("mMethodMap")
2160 private List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(String imiId,
2161 boolean allowsImplicitlySelectedSubtypes, @UserIdInt int userId) {
2162 if (userId == mSettings.getCurrentUserId()) {
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09002163 final InputMethodInfo imi;
2164 if (imiId == null && mCurMethodId != null) {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09002165 imi = mMethodMap.get(mCurMethodId);
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09002166 } else {
2167 imi = mMethodMap.get(imiId);
2168 }
2169 if (imi == null) {
Yohei Yukawab0377bb2015-08-10 21:06:30 -07002170 return Collections.emptyList();
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09002171 }
2172 return mSettings.getEnabledInputMethodSubtypeListLocked(
2173 mContext, imi, allowsImplicitlySelectedSubtypes);
satok67ddf9c2010-11-17 09:45:54 +09002174 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08002175 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
2176 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
2177 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
2178 new ArrayMap<>();
2179 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
2180 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
2181 methodList);
2182 final InputMethodInfo imi = methodMap.get(imiId);
2183 if (imi == null) {
2184 return Collections.emptyList();
2185 }
2186 final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
Yohei Yukawaf9277532019-01-25 02:47:32 -08002187 mContext.getContentResolver(), methodMap, userId, true);
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08002188 return settings.getEnabledInputMethodSubtypeListLocked(
2189 mContext, imi, allowsImplicitlySelectedSubtypes);
satok67ddf9c2010-11-17 09:45:54 +09002190 }
2191
Yohei Yukawaa71bb252018-09-19 19:21:24 -07002192 /**
2193 * Called by each application process as a preparation to start interacting with
2194 * {@link InputMethodManagerService}.
2195 *
2196 * <p>As a general principle, IPCs from the application process that take
Yohei Yukawa499e3f72018-10-21 20:15:11 -07002197 * {@link IInputMethodClient} will be rejected without this step.</p>
Yohei Yukawaa71bb252018-09-19 19:21:24 -07002198 *
2199 * @param client {@link android.os.Binder} proxy that is associated with the singleton instance
2200 * of {@link android.view.inputmethod.InputMethodManager} that runs on the client
2201 * process
2202 * @param inputContext communication channel for the dummy
2203 * {@link android.view.inputmethod.InputConnection}
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002204 * @param selfReportedDisplayId self-reported display ID to which the client is associated.
2205 * Whether the client is still allowed to access to this display
2206 * or not needs to be evaluated every time the client interacts
2207 * with the display
Yohei Yukawaa71bb252018-09-19 19:21:24 -07002208 */
2209 @Override
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002210 public void addClient(IInputMethodClient client, IInputContext inputContext,
2211 int selfReportedDisplayId) {
Yohei Yukawacb768bc2018-10-24 16:05:09 -07002212 // Here there are two scenarios where this method is called:
2213 // A. IMM is being instantiated in a different process and this is an IPC from that process
2214 // B. IMM is being instantiated in the same process but Binder.clearCallingIdentity() is
2215 // called in the caller side if necessary.
2216 // In either case the following UID/PID should be the ones where InputMethodManager is
2217 // actually running.
Yohei Yukawaa71bb252018-09-19 19:21:24 -07002218 final int callerUid = Binder.getCallingUid();
2219 final int callerPid = Binder.getCallingPid();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002220 synchronized (mMethodMap) {
Yohei Yukawaa71bb252018-09-19 19:21:24 -07002221 // TODO: Optimize this linear search.
Yohei Yukawaac9311e2018-11-20 19:25:23 -08002222 final int numClients = mClients.size();
2223 for (int i = 0; i < numClients; ++i) {
2224 final ClientState state = mClients.valueAt(i);
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002225 if (state.uid == callerUid && state.pid == callerPid
2226 && state.selfReportedDisplayId == selfReportedDisplayId) {
Yohei Yukawaa71bb252018-09-19 19:21:24 -07002227 throw new SecurityException("uid=" + callerUid + "/pid=" + callerPid
Yohei Yukawacb768bc2018-10-24 16:05:09 -07002228 + "/displayId=" + selfReportedDisplayId + " is already registered.");
Yohei Yukawaa71bb252018-09-19 19:21:24 -07002229 }
2230 }
2231 final ClientDeathRecipient deathRecipient = new ClientDeathRecipient(this, client);
2232 try {
2233 client.asBinder().linkToDeath(deathRecipient, 0);
2234 } catch (RemoteException e) {
2235 throw new IllegalStateException(e);
2236 }
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002237 // We cannot fully avoid race conditions where the client UID already lost the access to
2238 // the given self-reported display ID, even if the client is not maliciously reporting
2239 // a fake display ID. Unconditionally returning SecurityException just because the
2240 // client doesn't pass display ID verification can cause many test failures hence not an
2241 // option right now. At the same time
2242 // context.getSystemService(InputMethodManager.class)
2243 // is expected to return a valid non-null instance at any time if we do not choose to
2244 // have the client crash. Thus we do not verify the display ID at all here. Instead we
2245 // later check the display ID every time the client needs to interact with the specified
2246 // display.
2247 mClients.put(client.asBinder(), new ClientState(client, inputContext, callerUid,
2248 callerPid, selfReportedDisplayId, deathRecipient));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002249 }
2250 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002251
Yohei Yukawae24ed792018-08-28 19:10:32 -07002252 void removeClient(IInputMethodClient client) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002253 synchronized (mMethodMap) {
Jeff Brownc28867a2013-03-26 15:42:39 -07002254 ClientState cs = mClients.remove(client.asBinder());
2255 if (cs != null) {
Yohei Yukawaa71bb252018-09-19 19:21:24 -07002256 client.asBinder().unlinkToDeath(cs.clientDeathRecipient, 0);
Jeff Brownc28867a2013-03-26 15:42:39 -07002257 clearClientSessionLocked(cs);
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002258
2259 final int numItems = mActivityViewDisplayIdToParentMap.size();
2260 for (int i = numItems - 1; i >= 0; --i) {
2261 final ActivityViewInfo info = mActivityViewDisplayIdToParentMap.valueAt(i);
2262 if (info.mParentClient == cs) {
2263 mActivityViewDisplayIdToParentMap.removeAt(i);
2264 }
2265 }
2266
Yohei Yukawa072b1b52015-11-18 15:54:34 -08002267 if (mCurClient == cs) {
Tarandeep Singh93c00cea2018-02-16 14:31:17 -08002268 if (mBoundToMethod) {
2269 mBoundToMethod = false;
2270 if (mCurMethod != null) {
2271 executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
2272 MSG_UNBIND_INPUT, mCurMethod));
2273 }
2274 }
Yohei Yukawa072b1b52015-11-18 15:54:34 -08002275 mCurClient = null;
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002276 mCurActivityViewToScreenMatrix = null;
Yohei Yukawa072b1b52015-11-18 15:54:34 -08002277 }
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08002278 if (mCurFocusedWindowClient == cs) {
2279 mCurFocusedWindowClient = null;
2280 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002281 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002282 }
2283 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002285 void executeOrSendMessage(IInterface target, Message msg) {
2286 if (target.asBinder() instanceof Binder) {
2287 mCaller.sendMessage(msg);
2288 } else {
2289 handleMessage(msg);
2290 msg.recycle();
2291 }
2292 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002293
Yohei Yukawa4afd9332018-10-21 10:43:53 -07002294 void unbindCurrentClientLocked(@UnbindReason int unbindClientReason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002295 if (mCurClient != null) {
Yohei Yukawa35d3f372015-11-25 11:07:19 -08002296 if (DEBUG) Slog.v(TAG, "unbindCurrentInputLocked: client="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002297 + mCurClient.client.asBinder());
2298 if (mBoundToMethod) {
2299 mBoundToMethod = false;
2300 if (mCurMethod != null) {
2301 executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
2302 MSG_UNBIND_INPUT, mCurMethod));
2303 }
2304 }
Dianne Hackborna6e41342012-05-22 16:30:34 -07002305
Yohei Yukawa2bc66172017-02-08 11:13:25 -08002306 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
2307 MSG_SET_ACTIVE, 0, 0, mCurClient));
Yohei Yukawa33e81792015-11-17 21:14:42 -08002308 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
2309 MSG_UNBIND_CLIENT, mCurSeq, unbindClientReason, mCurClient.client));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002310 mCurClient.sessionRequested = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002311 mCurClient = null;
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002312 mCurActivityViewToScreenMatrix = null;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002313
The Android Open Source Project10592532009-03-18 17:39:46 -07002314 hideInputMethodMenuLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002315 }
2316 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002318 private int getImeShowFlags() {
2319 int flags = 0;
2320 if (mShowForced) {
2321 flags |= InputMethod.SHOW_FORCED
2322 | InputMethod.SHOW_EXPLICIT;
2323 } else if (mShowExplicitlyRequested) {
2324 flags |= InputMethod.SHOW_EXPLICIT;
2325 }
2326 return flags;
2327 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002329 private int getAppShowFlags() {
2330 int flags = 0;
2331 if (mShowForced) {
2332 flags |= InputMethodManager.SHOW_FORCED;
2333 } else if (!mShowExplicitlyRequested) {
2334 flags |= InputMethodManager.SHOW_IMPLICIT;
2335 }
2336 return flags;
2337 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002338
Andreas Gampea36dc622018-02-05 17:19:22 -08002339 @GuardedBy("mMethodMap")
Yohei Yukawa2553e482017-12-15 15:47:33 -08002340 @NonNull
Yohei Yukawadc66e522018-10-21 10:43:14 -07002341 InputBindResult attachNewInputLocked(@StartInputReason int startInputReason, boolean initial) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002342 if (!mBoundToMethod) {
2343 executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
2344 MSG_BIND_INPUT, mCurMethod, mCurClient.binding));
2345 mBoundToMethod = true;
2346 }
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08002347
2348 final Binder startInputToken = new Binder();
Yohei Yukawa7979e1a2019-02-12 02:01:10 -08002349 final StartInputInfo info = new StartInputInfo(mSettings.getCurrentUserId(), mCurToken,
2350 mCurTokenDisplayId, mCurId, startInputReason, !initial,
2351 UserHandle.getUserId(mCurClient.uid), mCurClient.selfReportedDisplayId,
2352 mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode, mCurSeq);
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002353 mImeTargetWindowMap.put(startInputToken, mCurFocusedWindow);
Yohei Yukawa357b2f62017-02-14 09:40:03 -08002354 mStartInputHistory.addEntry(info);
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08002355
Yohei Yukawa724c5bb2020-06-10 17:05:17 -07002356 // Seems that PackageManagerInternal#grantImplicitAccess() doesn't handle cross-user
2357 // implicit visibility (e.g. IME[user=10] -> App[user=0]) thus we do this only for the
2358 // same-user scenarios.
2359 // That said ignoring cross-user scenario will never affect IMEs that do not have
2360 // INTERACT_ACROSS_USERS(_FULL) permissions, which is actually almost always the case.
2361 if (mSettings.getCurrentUserId() == UserHandle.getUserId(mCurClient.uid)) {
2362 mPackageManagerInternal.grantImplicitAccess(mSettings.getCurrentUserId(),
2363 null /* intent */, UserHandle.getAppId(mCurMethodUid), mCurClient.uid, true);
2364 }
2365
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002366 final SessionState session = mCurClient.curSession;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08002367 executeOrSendMessage(session.method, mCaller.obtainMessageIIOOOO(
Yohei Yukawaf7526b52017-02-11 20:57:10 -08002368 MSG_START_INPUT, mCurInputContextMissingMethods, initial ? 0 : 1 /* restarting */,
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08002369 startInputToken, session, mCurInputContext, mCurAttribute));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002370 if (mShowRequested) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002371 if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
lumarkd85e1582019-12-29 20:20:41 +08002372 showCurrentInputLocked(mCurFocusedWindow, getAppShowFlags(), null,
2373 SoftInputShowHideReason.ATTACH_NEW_INPUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002374 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002375 return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
2376 session.session, (session.channel != null ? session.channel.dup() : null),
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002377 mCurId, mCurSeq, mCurActivityViewToScreenMatrix);
2378 }
2379
2380 @Nullable
2381 private Matrix getActivityViewToScreenMatrixLocked(int clientDisplayId, int imeDisplayId) {
2382 if (clientDisplayId == imeDisplayId) {
2383 return null;
2384 }
2385 int displayId = clientDisplayId;
2386 Matrix matrix = null;
2387 while (true) {
2388 final ActivityViewInfo info = mActivityViewDisplayIdToParentMap.get(displayId);
2389 if (info == null) {
2390 return null;
2391 }
2392 if (matrix == null) {
2393 matrix = new Matrix(info.mMatrix);
2394 } else {
2395 matrix.postConcat(info.mMatrix);
2396 }
2397 if (info.mParentClient.selfReportedDisplayId == imeDisplayId) {
2398 return matrix;
2399 }
2400 displayId = info.mParentClient.selfReportedDisplayId;
2401 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002402 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002403
Andreas Gampea36dc622018-02-05 17:19:22 -08002404 @GuardedBy("mMethodMap")
Yohei Yukawa2553e482017-12-15 15:47:33 -08002405 @NonNull
Yohei Yukawa35d3f372015-11-25 11:07:19 -08002406 InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07002407 @MissingMethodFlags int missingMethods, @NonNull EditorInfo attribute,
2408 @StartInputFlags int startInputFlags, @StartInputReason int startInputReason) {
Dianne Hackborn7663d802012-02-24 13:08:49 -08002409 // If no method is currently selected, do nothing.
2410 if (mCurMethodId == null) {
Yohei Yukawa2553e482017-12-15 15:47:33 -08002411 return InputBindResult.NO_IME;
Dianne Hackborn7663d802012-02-24 13:08:49 -08002412 }
2413
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002414 if (!mSystemReady) {
2415 // If the system is not yet ready, we shouldn't be running third
2416 // party code.
2417 return new InputBindResult(
2418 InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002419 null, null, mCurMethodId, mCurSeq, null);
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002420 }
2421
Yohei Yukawad57ba672015-06-08 16:39:46 -07002422 if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid,
2423 attribute.packageName)) {
2424 Slog.e(TAG, "Rejecting this client as it reported an invalid package name."
2425 + " uid=" + cs.uid + " package=" + attribute.packageName);
Yohei Yukawa2553e482017-12-15 15:47:33 -08002426 return InputBindResult.INVALID_PACKAGE_NAME;
Yohei Yukawa0f3ad12015-04-06 16:48:24 -07002427 }
2428
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002429 if (!mWindowManagerInternal.isUidAllowedOnDisplay(cs.selfReportedDisplayId, cs.uid)) {
2430 // Wait, the client no longer has access to the display.
2431 return InputBindResult.INVALID_DISPLAY_ID;
2432 }
lumarkef1965b2018-09-12 17:42:53 +08002433 // Compute the final shown display ID with validated cs.selfReportedDisplayId for this
2434 // session & other conditions.
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08002435 final int displayIdToShowIme = computeImeDisplayIdForTarget(cs.selfReportedDisplayId,
2436 mImeDisplayValidator);
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002437
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002438 if (mCurClient != cs) {
John Spurlocke0980502013-10-25 11:59:29 -04002439 // Was the keyguard locked when switching over to the new client?
2440 mCurClientInKeyguard = isKeyguardLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002441 // If the client is changing, we need to switch over to the new
2442 // one.
Yohei Yukawab7526452018-10-21 20:15:17 -07002443 unbindCurrentClientLocked(UnbindReason.SWITCH_CLIENT);
Yohei Yukawa35d3f372015-11-25 11:07:19 -08002444 if (DEBUG) Slog.v(TAG, "switching to client: client="
John Spurlocke0980502013-10-25 11:59:29 -04002445 + cs.client.asBinder() + " keyguard=" + mCurClientInKeyguard);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002446
2447 // If the screen is on, inform the new client it is active
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07002448 if (mIsInteractive) {
tiansiming [田思明]e102c972018-04-17 18:15:33 +08002449 executeOrSendMessage(cs.client, mCaller.obtainMessageIO(MSG_SET_ACTIVE, 1, cs));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002450 }
2451 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002452
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002453 // Bump up the sequence for this client and attach it.
2454 mCurSeq++;
2455 if (mCurSeq <= 0) mCurSeq = 1;
2456 mCurClient = cs;
2457 mCurInputContext = inputContext;
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002458 mCurActivityViewToScreenMatrix =
2459 getActivityViewToScreenMatrixLocked(cs.selfReportedDisplayId, displayIdToShowIme);
2460 if (cs.selfReportedDisplayId != displayIdToShowIme
2461 && mCurActivityViewToScreenMatrix == null) {
Yohei Yukawa3d2cc0f2019-04-25 18:32:15 -07002462 // CursorAnchorInfo API does not work as-is for cross-display scenario. Pretend that
2463 // InputConnection#requestCursorUpdates() is not implemented in the application so that
2464 // IMEs will always receive false from this API.
2465 missingMethods |= MissingMethodFlags.REQUEST_CURSOR_UPDATES;
2466 }
Yohei Yukawa19a80a12016-03-14 22:57:37 -07002467 mCurInputContextMissingMethods = missingMethods;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002468 mCurAttribute = attribute;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002469
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002470 // Check if the input method is changing.
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002471 // We expect the caller has already verified that the client is allowed to access this
2472 // display ID.
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002473 if (mCurId != null && mCurId.equals(mCurMethodId)
2474 && displayIdToShowIme == mCurTokenDisplayId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002475 if (cs.curSession != null) {
2476 // Fast case: if we are already connected to the input method,
2477 // then just return it.
Yohei Yukawa87ca8402017-02-07 00:13:14 -08002478 return attachNewInputLocked(startInputReason,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07002479 (startInputFlags & StartInputFlags.INITIAL_CONNECTION) != 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002480 }
2481 if (mHaveConnection) {
2482 if (mCurMethod != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002483 // Return to client, and we will get back with it when
2484 // we have had a session made for it.
Jeff Brownc28867a2013-03-26 15:42:39 -07002485 requestClientSessionLocked(cs);
Yohei Yukawa2553e482017-12-15 15:47:33 -08002486 return new InputBindResult(
2487 InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002488 null, null, mCurId, mCurSeq, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002489 } else if (SystemClock.uptimeMillis()
2490 < (mLastBindTime+TIME_TO_RECONNECT)) {
2491 // In this case we have connected to the service, but
2492 // don't yet have its interface. If it hasn't been too
2493 // long since we did the connection, we'll return to
2494 // the client and wait to get the service interface so
2495 // we can report back. If it has been too long, we want
2496 // to fall through so we can try a disconnect/reconnect
2497 // to see if we can get back in touch with the service.
Yohei Yukawa2553e482017-12-15 15:47:33 -08002498 return new InputBindResult(
2499 InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002500 null, null, mCurId, mCurSeq, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002501 } else {
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002502 EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
2503 mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002504 }
2505 }
2506 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002507
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002508 InputMethodInfo info = mMethodMap.get(mCurMethodId);
2509 if (info == null) {
2510 throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
2511 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002512
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002513 unbindCurrentMethodLocked();
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002514
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002515 mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE);
2516 mCurIntent.setComponent(info.getComponent());
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07002517 mCurIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
2518 com.android.internal.R.string.input_method_binding_label);
2519 mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
2520 mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002521
Yohei Yukawaf80087c2018-05-21 09:47:53 -07002522 if (bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002523 mLastBindTime = SystemClock.uptimeMillis();
2524 mHaveConnection = true;
2525 mCurId = info.getId();
2526 mCurToken = new Binder();
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002527 mCurTokenDisplayId = displayIdToShowIme;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002528 try {
lumark90120a82018-08-15 00:33:03 +08002529 if (DEBUG) {
2530 Slog.v(TAG, "Adding window token: " + mCurToken + " for display: "
2531 + mCurTokenDisplayId);
2532 }
Yohei Yukawa6e875592019-01-28 00:49:30 -08002533 mIWindowManager.addWindowToken(mCurToken, LayoutParams.TYPE_INPUT_METHOD,
2534 mCurTokenDisplayId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002535 } catch (RemoteException e) {
2536 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002537 return new InputBindResult(
2538 InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002539 null, null, mCurId, mCurSeq, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002540 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002541 mCurIntent = null;
2542 Slog.w(TAG, "Failure connecting to input method service: " + mCurIntent);
2543 return InputBindResult.IME_NOT_CONNECTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002544 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002545
lumarkef1965b2018-09-12 17:42:53 +08002546 @FunctionalInterface
2547 interface ImeDisplayValidator {
2548 boolean displayCanShowIme(int displayId);
2549 }
2550
2551 /**
2552 * Find the display where the IME should be shown.
2553 *
2554 * @param displayId the ID of the display where the IME client target is.
lumarkef1965b2018-09-12 17:42:53 +08002555 * @param checker instance of {@link ImeDisplayValidator} which is used for
2556 * checking display config to adjust the final target display.
2557 * @return The ID of the display where the IME should be shown.
2558 */
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08002559 static int computeImeDisplayIdForTarget(int displayId, @NonNull ImeDisplayValidator checker) {
lumarkef1965b2018-09-12 17:42:53 +08002560 if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) {
lumark7570cac2019-03-07 22:14:38 +08002561 return FALLBACK_DISPLAY_ID;
lumarkef1965b2018-09-12 17:42:53 +08002562 }
lumark9a72d222019-03-30 18:31:45 +08002563
2564 // Show IME window on fallback display when the display doesn't support system decorations
2565 // or the display is virtual and isn't owned by system for security concern.
lumark7570cac2019-03-07 22:14:38 +08002566 return checker.displayCanShowIme(displayId) ? displayId : FALLBACK_DISPLAY_ID;
lumarkef1965b2018-09-12 17:42:53 +08002567 }
2568
Yohei Yukawad5f402b2020-05-15 10:23:32 -07002569 @AnyThread
2570 private void scheduleNotifyImeUidToAudioService(int uid) {
2571 mCaller.removeMessages(MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE);
2572 mCaller.obtainMessageI(MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE, uid).sendToTarget();
2573 }
2574
satoke7c6998e2011-06-03 17:57:59 +09002575 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002576 public void onServiceConnected(ComponentName name, IBinder service) {
2577 synchronized (mMethodMap) {
2578 if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
2579 mCurMethod = IInputMethod.Stub.asInterface(service);
Yohei Yukawad5f402b2020-05-15 10:23:32 -07002580 final String curMethodPackage = mCurIntent.getComponent().getPackageName();
2581 final int curMethodUid = mPackageManagerInternal.getPackageUidInternal(
2582 curMethodPackage, 0 /* flags */, mSettings.getCurrentUserId());
2583 if (curMethodUid < 0) {
2584 Slog.e(TAG, "Failed to get UID for package=" + curMethodPackage);
2585 mCurMethodUid = Process.INVALID_UID;
2586 } else {
2587 mCurMethodUid = curMethodUid;
2588 }
Dianne Hackborncc278702009-09-02 23:07:23 -07002589 if (mCurToken == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002590 Slog.w(TAG, "Service connected without a token!");
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002591 unbindCurrentMethodLocked();
Dianne Hackborncc278702009-09-02 23:07:23 -07002592 return;
2593 }
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002594 if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
lumark90120a82018-08-15 00:33:03 +08002595 // Dispatch display id for InputMethodService to update context display.
2596 executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
2597 MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken));
Yohei Yukawad5f402b2020-05-15 10:23:32 -07002598 scheduleNotifyImeUidToAudioService(mCurMethodUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002599 if (mCurClient != null) {
Jeff Brownc28867a2013-03-26 15:42:39 -07002600 clearClientSessionLocked(mCurClient);
2601 requestClientSessionLocked(mCurClient);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002602 }
2603 }
2604 }
2605 }
2606
Jeff Brownc28867a2013-03-26 15:42:39 -07002607 void onSessionCreated(IInputMethod method, IInputMethodSession session,
2608 InputChannel channel) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002609 synchronized (mMethodMap) {
Yohei Yukawa32807ad2020-03-04 12:27:29 -08002610 if (mUserSwitchHandlerTask != null) {
2611 // We have a pending user-switching task so it's better to just ignore this session.
2612 channel.dispose();
2613 return;
2614 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002615 if (mCurMethod != null && method != null
2616 && mCurMethod.asBinder() == method.asBinder()) {
2617 if (mCurClient != null) {
Jeff Brownc28867a2013-03-26 15:42:39 -07002618 clearClientSessionLocked(mCurClient);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002619 mCurClient.curSession = new SessionState(mCurClient,
Jeff Brownc28867a2013-03-26 15:42:39 -07002620 method, session, channel);
Yohei Yukawa87ca8402017-02-07 00:13:14 -08002621 InputBindResult res = attachNewInputLocked(
Yohei Yukawa42194222018-10-21 20:14:40 -07002622 StartInputReason.SESSION_CREATED_BY_IME, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002623 if (res.method != null) {
2624 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
Yohei Yukawa33e81792015-11-17 21:14:42 -08002625 MSG_BIND_CLIENT, mCurClient.client, res));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002626 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002627 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002628 }
2629 }
2630 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002631
2632 // Session abandoned. Close its associated input channel.
2633 channel.dispose();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002634 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002635
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002636 void unbindCurrentMethodLocked() {
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002637 if (mVisibleBound) {
2638 mContext.unbindService(mVisibleConnection);
2639 mVisibleBound = false;
2640 }
2641
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002642 if (mHaveConnection) {
2643 mContext.unbindService(this);
2644 mHaveConnection = false;
2645 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002646
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002647 if (mCurToken != null) {
2648 try {
lumark90120a82018-08-15 00:33:03 +08002649 if (DEBUG) {
2650 Slog.v(TAG, "Removing window token: " + mCurToken + " for display: "
2651 + mCurTokenDisplayId);
2652 }
lumark90120a82018-08-15 00:33:03 +08002653 mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId);
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002654 } catch (RemoteException e) {
2655 }
lumark7570cac2019-03-07 22:14:38 +08002656 // Set IME window status as invisible when unbind current method.
2657 mImeWindowVis = 0;
2658 mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
2659 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002660 mCurToken = null;
lumark90120a82018-08-15 00:33:03 +08002661 mCurTokenDisplayId = INVALID_DISPLAY;
lpeter133fce02020-03-05 20:32:16 +08002662 mCurHostInputToken = null;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002663 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002664
The Android Open Source Project10592532009-03-18 17:39:46 -07002665 mCurId = null;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002666 clearCurMethodLocked();
Yohei Yukawabc7b5262015-11-17 17:38:41 -08002667 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002668
Yohei Yukawa4afd9332018-10-21 10:43:53 -07002669 void resetCurrentMethodAndClient(@UnbindReason int unbindClientReason) {
Yohei Yukawabc7b5262015-11-17 17:38:41 -08002670 mCurMethodId = null;
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002671 unbindCurrentMethodLocked();
Yohei Yukawa33e81792015-11-17 21:14:42 -08002672 unbindCurrentClientLocked(unbindClientReason);
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002673 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002674
2675 void requestClientSessionLocked(ClientState cs) {
2676 if (!cs.sessionRequested) {
2677 if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs);
2678 InputChannel[] channels = InputChannel.openInputChannelPair(cs.toString());
2679 cs.sessionRequested = true;
2680 executeOrSendMessage(mCurMethod, mCaller.obtainMessageOOO(
2681 MSG_CREATE_SESSION, mCurMethod, channels[1],
2682 new MethodCallback(this, mCurMethod, channels[0])));
2683 }
2684 }
2685
2686 void clearClientSessionLocked(ClientState cs) {
2687 finishSessionLocked(cs.curSession);
2688 cs.curSession = null;
2689 cs.sessionRequested = false;
2690 }
2691
2692 private void finishSessionLocked(SessionState sessionState) {
2693 if (sessionState != null) {
2694 if (sessionState.session != null) {
2695 try {
2696 sessionState.session.finishSession();
2697 } catch (RemoteException e) {
2698 Slog.w(TAG, "Session failed to close due to remote exception", e);
Yohei Yukawa849443c2019-01-21 09:02:25 -08002699 updateSystemUiLocked(0 /* vis */, mBackDisposition);
Jeff Brownc28867a2013-03-26 15:42:39 -07002700 }
2701 sessionState.session = null;
2702 }
2703 if (sessionState.channel != null) {
2704 sessionState.channel.dispose();
2705 sessionState.channel = null;
Devin Taylor0c33ed22010-02-23 13:26:46 -06002706 }
2707 }
2708 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002709
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002710 void clearCurMethodLocked() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002711 if (mCurMethod != null) {
Yohei Yukawaac9311e2018-11-20 19:25:23 -08002712 final int numClients = mClients.size();
2713 for (int i = 0; i < numClients; ++i) {
2714 clearClientSessionLocked(mClients.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002715 }
Devin Taylor0c33ed22010-02-23 13:26:46 -06002716
Jeff Brownc28867a2013-03-26 15:42:39 -07002717 finishSessionLocked(mEnabledSession);
Devin Taylor0c33ed22010-02-23 13:26:46 -06002718 mEnabledSession = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002719 mCurMethod = null;
Yohei Yukawad5f402b2020-05-15 10:23:32 -07002720 mCurMethodUid = Process.INVALID_UID;
2721 scheduleNotifyImeUidToAudioService(mCurMethodUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002722 }
Dianne Hackborn661cd522011-08-22 00:26:20 -07002723 if (mStatusBar != null) {
Jason Monk3e189872016-01-12 09:10:34 -05002724 mStatusBar.setIconVisibility(mSlotIme, false);
Dianne Hackborn661cd522011-08-22 00:26:20 -07002725 }
Yohei Yukawa2bc66172017-02-08 11:13:25 -08002726 mInFullscreenMode = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002727 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002728
satoke7c6998e2011-06-03 17:57:59 +09002729 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002730 public void onServiceDisconnected(ComponentName name) {
Yohei Yukawa817d5f72017-01-04 20:15:02 -08002731 // Note that mContext.unbindService(this) does not trigger this. Hence if we are here the
2732 // disconnection is not intended by IMMS (e.g. triggered because the current IMS crashed),
2733 // which is irregular but can eventually happen for everyone just by continuing using the
2734 // device. Thus it is important to make sure that all the internal states are properly
2735 // refreshed when this method is called back. Running
2736 // adb install -r <APK that implements the current IME>
2737 // would be a good way to trigger such a situation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002738 synchronized (mMethodMap) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002739 if (DEBUG) Slog.v(TAG, "Service disconnected: " + name
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002740 + " mCurIntent=" + mCurIntent);
2741 if (mCurMethod != null && mCurIntent != null
2742 && name.equals(mCurIntent.getComponent())) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002743 clearCurMethodLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002744 // We consider this to be a new bind attempt, since the system
2745 // should now try to restart the service for us.
2746 mLastBindTime = SystemClock.uptimeMillis();
2747 mShowRequested = mInputShown;
2748 mInputShown = false;
Yohei Yukawab7526452018-10-21 20:15:17 -07002749 unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002750 }
2751 }
2752 }
2753
Yohei Yukawaeec552e2018-09-09 20:48:41 -07002754 @BinderThread
Yohei Yukawa41b094f2018-09-09 23:58:45 -07002755 private void updateStatusIcon(@NonNull IBinder token, String packageName,
2756 @DrawableRes int iconId) {
Yohei Yukawa59377ca2017-01-31 21:32:26 -08002757 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08002758 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa59377ca2017-01-31 21:32:26 -08002759 return;
2760 }
2761 final long ident = Binder.clearCallingIdentity();
2762 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002763 if (iconId == 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002764 if (DEBUG) Slog.d(TAG, "hide the small icon for the input method");
Dianne Hackborn661cd522011-08-22 00:26:20 -07002765 if (mStatusBar != null) {
Jason Monk3e189872016-01-12 09:10:34 -05002766 mStatusBar.setIconVisibility(mSlotIme, false);
Dianne Hackborn661cd522011-08-22 00:26:20 -07002767 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002768 } else if (packageName != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002769 if (DEBUG) Slog.d(TAG, "show a small icon for the input method");
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002770 CharSequence contentDescription = null;
2771 try {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002772 // Use PackageManager to load label
2773 final PackageManager packageManager = mContext.getPackageManager();
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002774 contentDescription = packageManager.getApplicationLabel(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002775 mIPackageManager.getApplicationInfo(packageName, 0,
2776 mSettings.getCurrentUserId()));
2777 } catch (RemoteException e) {
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002778 /* ignore */
2779 }
Dianne Hackborn661cd522011-08-22 00:26:20 -07002780 if (mStatusBar != null) {
Jason Monk3e189872016-01-12 09:10:34 -05002781 mStatusBar.setIcon(mSlotIme, packageName, iconId, 0,
Dianne Hackborn661cd522011-08-22 00:26:20 -07002782 contentDescription != null
2783 ? contentDescription.toString() : null);
Jason Monk3e189872016-01-12 09:10:34 -05002784 mStatusBar.setIconVisibility(mSlotIme, true);
Dianne Hackborn661cd522011-08-22 00:26:20 -07002785 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002786 }
Yohei Yukawa59377ca2017-01-31 21:32:26 -08002787 } finally {
2788 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002789 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002790 }
2791 }
2792
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002793 private boolean shouldShowImeSwitcherLocked(int visibility) {
satok7cfc0ed2011-06-20 21:29:36 +09002794 if (!mShowOngoingImeSwitcherForPhones) return false;
Jason Monk807ef762014-05-08 15:47:46 -04002795 if (mSwitchingDialog != null) return false;
Yohei Yukawad2bc3092017-07-31 15:37:14 -07002796 if (mWindowManagerInternal.isKeyguardShowingAndNotOccluded()
2797 && mKeyguardManager != null && mKeyguardManager.isKeyguardSecure()) return false;
Tarandeep Singheadb1392018-11-09 18:15:57 +01002798 if ((visibility & InputMethodService.IME_ACTIVE) == 0
2799 || (visibility & InputMethodService.IME_INVISIBLE) != 0) {
2800 return false;
2801 }
Seigo Nonaka7309b122015-08-17 18:34:13 -07002802 if (mWindowManagerInternal.isHardKeyboardAvailable()) {
Yohei Yukawaaf023f22019-06-21 16:38:22 -07002803 // When physical keyboard is attached, we show the ime switcher (or notification if
2804 // NavBar is not available) because SHOW_IME_WITH_HARD_KEYBOARD settings currently
2805 // exists in the IME switcher dialog. Might be OK to remove this condition once
2806 // SHOW_IME_WITH_HARD_KEYBOARD settings finds a good place to live.
2807 return true;
Yohei Yukawa89398382016-03-29 11:37:04 -07002808 } else if ((visibility & InputMethodService.IME_VISIBLE) == 0) {
2809 return false;
Yohei Yukawac6c7cd22015-05-12 15:00:33 -07002810 }
Yohei Yukawac6c7cd22015-05-12 15:00:33 -07002811
2812 List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked();
2813 final int N = imis.size();
2814 if (N > 2) return true;
2815 if (N < 1) return false;
2816 int nonAuxCount = 0;
2817 int auxCount = 0;
2818 InputMethodSubtype nonAuxSubtype = null;
2819 InputMethodSubtype auxSubtype = null;
2820 for(int i = 0; i < N; ++i) {
2821 final InputMethodInfo imi = imis.get(i);
2822 final List<InputMethodSubtype> subtypes =
2823 mSettings.getEnabledInputMethodSubtypeListLocked(mContext, imi, true);
2824 final int subtypeCount = subtypes.size();
2825 if (subtypeCount == 0) {
2826 ++nonAuxCount;
2827 } else {
2828 for (int j = 0; j < subtypeCount; ++j) {
2829 final InputMethodSubtype subtype = subtypes.get(j);
2830 if (!subtype.isAuxiliary()) {
2831 ++nonAuxCount;
2832 nonAuxSubtype = subtype;
2833 } else {
2834 ++auxCount;
2835 auxSubtype = subtype;
satok7cfc0ed2011-06-20 21:29:36 +09002836 }
2837 }
satok7cfc0ed2011-06-20 21:29:36 +09002838 }
2839 }
Yohei Yukawac6c7cd22015-05-12 15:00:33 -07002840 if (nonAuxCount > 1 || auxCount > 1) {
2841 return true;
2842 } else if (nonAuxCount == 1 && auxCount == 1) {
2843 if (nonAuxSubtype != null && auxSubtype != null
2844 && (nonAuxSubtype.getLocale().equals(auxSubtype.getLocale())
2845 || auxSubtype.overridesImplicitlyEnabledSubtype()
2846 || nonAuxSubtype.overridesImplicitlyEnabledSubtype())
2847 && nonAuxSubtype.containsExtraValueKey(TAG_TRY_SUPPRESSING_IME_SWITCHER)) {
2848 return false;
2849 }
2850 return true;
2851 }
2852 return false;
satok7cfc0ed2011-06-20 21:29:36 +09002853 }
2854
John Spurlocke0980502013-10-25 11:59:29 -04002855 private boolean isKeyguardLocked() {
2856 return mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
2857 }
2858
Yohei Yukawad6475a62017-04-17 10:35:27 -07002859 @BinderThread
satokdbf29502011-08-25 15:28:23 +09002860 @SuppressWarnings("deprecation")
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08002861 private void setImeWindowStatus(@NonNull IBinder token, int vis, int backDisposition) {
lumark7570cac2019-03-07 22:14:38 +08002862 final int topFocusedDisplayId = mWindowManagerInternal.getTopFocusedDisplayId();
2863
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002864 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08002865 if (!calledWithValidTokenLocked(token)) {
2866 return;
2867 }
lumark7570cac2019-03-07 22:14:38 +08002868 // Skip update IME status when current token display is not same as focused display.
2869 // Note that we still need to update IME status when focusing external display
2870 // that does not support system decoration and fallback to show IME on default
2871 // display since it is intentional behavior.
2872 if (mCurTokenDisplayId != topFocusedDisplayId
2873 && mCurTokenDisplayId != FALLBACK_DISPLAY_ID) {
2874 return;
2875 }
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002876 mImeWindowVis = vis;
2877 mBackDisposition = backDisposition;
Yohei Yukawa849443c2019-01-21 09:02:25 -08002878 updateSystemUiLocked(vis, backDisposition);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002879 }
Yohei Yukawad6475a62017-04-17 10:35:27 -07002880
2881 final boolean dismissImeOnBackKeyPressed;
2882 switch (backDisposition) {
2883 case InputMethodService.BACK_DISPOSITION_WILL_DISMISS:
2884 dismissImeOnBackKeyPressed = true;
2885 break;
2886 case InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS:
2887 dismissImeOnBackKeyPressed = false;
2888 break;
2889 default:
2890 case InputMethodService.BACK_DISPOSITION_DEFAULT:
2891 dismissImeOnBackKeyPressed = ((vis & InputMethodService.IME_VISIBLE) != 0);
2892 break;
2893 }
Yohei Yukawaee2a7ed2017-02-15 21:38:57 -08002894 mWindowManagerInternal.updateInputMethodWindowStatus(token,
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002895 (vis & InputMethodService.IME_VISIBLE) != 0, dismissImeOnBackKeyPressed);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002896 }
2897
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002898 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08002899 private void reportStartInput(@NonNull IBinder token, IBinder startInputToken) {
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002900 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08002901 if (!calledWithValidTokenLocked(token)) {
2902 return;
2903 }
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002904 final IBinder targetWindow = mImeTargetWindowMap.get(startInputToken);
2905 if (targetWindow != null && mLastImeTargetWindow != targetWindow) {
2906 mWindowManagerInternal.updateInputMethodTargetWindow(token, targetWindow);
2907 }
2908 mLastImeTargetWindow = targetWindow;
2909 }
2910 }
2911
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002912 // Caution! This method is called in this class. Handle multi-user carefully
Yohei Yukawa849443c2019-01-21 09:02:25 -08002913 private void updateSystemUiLocked(int vis, int backDisposition) {
2914 if (mCurToken == null) {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002915 return;
2916 }
Tarandeep Singheadb1392018-11-09 18:15:57 +01002917 if (DEBUG) {
2918 Slog.d(TAG, "IME window vis: " + vis
2919 + " active: " + (vis & InputMethodService.IME_ACTIVE)
lumark7570cac2019-03-07 22:14:38 +08002920 + " inv: " + (vis & InputMethodService.IME_INVISIBLE)
2921 + " displayId: " + mCurTokenDisplayId);
Tarandeep Singheadb1392018-11-09 18:15:57 +01002922 }
2923
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002924 // TODO: Move this clearing calling identity block to setImeWindowStatus after making sure
2925 // all updateSystemUi happens on system previlege.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002926 final long ident = Binder.clearCallingIdentity();
satok06487a52010-10-29 11:37:18 +09002927 try {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002928 // apply policy for binder calls
2929 if (vis != 0 && isKeyguardLocked() && !mCurClientInKeyguard) {
2930 vis = 0;
satok06487a52010-10-29 11:37:18 +09002931 }
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002932 // mImeWindowVis should be updated before calling shouldShowImeSwitcherLocked().
2933 final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis);
2934 if (mStatusBar != null) {
lumark7570cac2019-03-07 22:14:38 +08002935 mStatusBar.setImeWindowStatus(mCurTokenDisplayId, mCurToken, vis, backDisposition,
Tarandeep Singh07b318b2019-07-17 11:12:04 -07002936 needsToShowImeSwitcher, false /*isMultiClientImeEnabled*/);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002937 }
2938 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
2939 if (imi != null && needsToShowImeSwitcher) {
2940 // Used to load label
2941 final CharSequence title = mRes.getText(
2942 com.android.internal.R.string.select_input_method);
2943 final CharSequence summary = InputMethodUtils.getImeAndSubtypeDisplayName(
2944 mContext, imi, mCurrentSubtype);
Chris Wren1ce4b6d2015-06-11 10:19:43 -04002945 mImeSwitcherNotification.setContentTitle(title)
2946 .setContentText(summary)
2947 .setContentIntent(mImeSwitchPendingIntent);
Seigo Nonaka7309b122015-08-17 18:34:13 -07002948 try {
Charles Chenea6e7f02018-11-19 21:37:45 +08002949 // TODO(b/120076400): Figure out what is the best behavior
Seigo Nonaka7309b122015-08-17 18:34:13 -07002950 if ((mNotificationManager != null)
Charles Chenea6e7f02018-11-19 21:37:45 +08002951 && !mIWindowManager.hasNavigationBar(DEFAULT_DISPLAY)) {
Seigo Nonaka7309b122015-08-17 18:34:13 -07002952 if (DEBUG) {
2953 Slog.d(TAG, "--- show notification: label = " + summary);
2954 }
2955 mNotificationManager.notifyAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04002956 SystemMessage.NOTE_SELECT_INPUT_METHOD,
Seigo Nonaka7309b122015-08-17 18:34:13 -07002957 mImeSwitcherNotification.build(), UserHandle.ALL);
2958 mNotificationShown = true;
Dianne Hackborn661cd522011-08-22 00:26:20 -07002959 }
Seigo Nonaka7309b122015-08-17 18:34:13 -07002960 } catch (RemoteException e) {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002961 }
2962 } else {
2963 if (mNotificationShown && mNotificationManager != null) {
2964 if (DEBUG) {
2965 Slog.d(TAG, "--- hide notification");
satok7cfc0ed2011-06-20 21:29:36 +09002966 }
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002967 mNotificationManager.cancelAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04002968 SystemMessage.NOTE_SELECT_INPUT_METHOD, UserHandle.ALL);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002969 mNotificationShown = false;
satok7cfc0ed2011-06-20 21:29:36 +09002970 }
satok06487a52010-10-29 11:37:18 +09002971 }
2972 } finally {
2973 Binder.restoreCallingIdentity(ident);
2974 }
2975 }
2976
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002977 void updateFromSettingsLocked(boolean enabledMayChange) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07002978 updateInputMethodsFromSettingsLocked(enabledMayChange);
2979 updateKeyboardFromSettingsLocked();
2980 }
2981
2982 void updateInputMethodsFromSettingsLocked(boolean enabledMayChange) {
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002983 if (enabledMayChange) {
2984 List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
2985 for (int i=0; i<enabled.size(); i++) {
2986 // We allow the user to select "disabled until used" apps, so if they
2987 // are enabling one of those here we now need to make it enabled.
2988 InputMethodInfo imm = enabled.get(i);
2989 try {
2990 ApplicationInfo ai = mIPackageManager.getApplicationInfo(imm.getPackageName(),
2991 PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
2992 mSettings.getCurrentUserId());
Satoshi Kataoka7987a312013-04-17 18:59:33 +09002993 if (ai != null && ai.enabledSetting
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002994 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09002995 if (DEBUG) {
2996 Slog.d(TAG, "Update state(" + imm.getId()
2997 + "): DISABLED_UNTIL_USED -> DEFAULT");
2998 }
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002999 mIPackageManager.setApplicationEnabledSetting(imm.getPackageName(),
3000 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
Dianne Hackborn3fa3c28a2013-03-26 16:15:41 -07003001 PackageManager.DONT_KILL_APP, mSettings.getCurrentUserId(),
3002 mContext.getBasePackageName());
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08003003 }
3004 } catch (RemoteException e) {
3005 }
3006 }
3007 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07003008 // We are assuming that whoever is changing DEFAULT_INPUT_METHOD and
3009 // ENABLED_INPUT_METHODS is taking care of keeping them correctly in
3010 // sync, so we will never have a DEFAULT_INPUT_METHOD that is not
3011 // enabled.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003012 String id = mSettings.getSelectedInputMethod();
satok03eb319a2010-11-11 18:17:42 +09003013 // There is no input method selected, try to choose new applicable input method.
3014 if (TextUtils.isEmpty(id) && chooseNewDefaultIMELocked()) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003015 id = mSettings.getSelectedInputMethod();
satok03eb319a2010-11-11 18:17:42 +09003016 }
3017 if (!TextUtils.isEmpty(id)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003018 try {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003019 setInputMethodLocked(id, mSettings.getSelectedInputMethodSubtypeId(id));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003020 } catch (IllegalArgumentException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003021 Slog.w(TAG, "Unknown input method from prefs: " + id, e);
Yohei Yukawab7526452018-10-21 20:15:17 -07003022 resetCurrentMethodAndClient(UnbindReason.SWITCH_IME_FAILED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003023 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07003024 } else {
3025 // There is no longer an input method set, so stop any current one.
Yohei Yukawab7526452018-10-21 20:15:17 -07003026 resetCurrentMethodAndClient(UnbindReason.NO_IME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003027 }
Yohei Yukawa3d46bab2014-05-30 18:10:18 +09003028 // Here is not the perfect place to reset the switching controller. Ideally
3029 // mSwitchingController and mSettings should be able to share the same state.
3030 // TODO: Make sure that mSwitchingController and mSettings are sharing the
3031 // the same enabled IMEs list.
3032 mSwitchingController.resetCircularListLocked(mContext);
Michael Wright7b5a96b2014-08-09 19:28:42 -07003033
3034 }
3035
3036 public void updateKeyboardFromSettingsLocked() {
3037 mShowImeWithHardKeyboard = mSettings.isShowImeWithHardKeyboardEnabled();
3038 if (mSwitchingDialog != null
3039 && mSwitchingDialogTitleView != null
3040 && mSwitchingDialog.isShowing()) {
3041 final Switch hardKeySwitch = (Switch)mSwitchingDialogTitleView.findViewById(
3042 com.android.internal.R.id.hard_keyboard_switch);
3043 hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
3044 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003045 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003046
satokab751aa2010-09-14 19:17:36 +09003047 /* package */ void setInputMethodLocked(String id, int subtypeId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003048 InputMethodInfo info = mMethodMap.get(id);
3049 if (info == null) {
satok913a8922010-08-26 21:53:41 +09003050 throw new IllegalArgumentException("Unknown id: " + id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003051 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003052
satokd81e9502012-05-21 12:58:45 +09003053 // See if we need to notify a subtype change within the same IME.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003054 if (id.equals(mCurMethodId)) {
satokd81e9502012-05-21 12:58:45 +09003055 final int subtypeCount = info.getSubtypeCount();
3056 if (subtypeCount <= 0) {
3057 return;
satokcd7cd292010-11-20 15:46:23 +09003058 }
satokd81e9502012-05-21 12:58:45 +09003059 final InputMethodSubtype oldSubtype = mCurrentSubtype;
3060 final InputMethodSubtype newSubtype;
3061 if (subtypeId >= 0 && subtypeId < subtypeCount) {
3062 newSubtype = info.getSubtypeAt(subtypeId);
3063 } else {
3064 // If subtype is null, try to find the most applicable one from
3065 // getCurrentInputMethodSubtype.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003066 newSubtype = getCurrentInputMethodSubtypeLocked();
satokd81e9502012-05-21 12:58:45 +09003067 }
3068 if (newSubtype == null || oldSubtype == null) {
3069 Slog.w(TAG, "Illegal subtype state: old subtype = " + oldSubtype
3070 + ", new subtype = " + newSubtype);
3071 return;
3072 }
3073 if (newSubtype != oldSubtype) {
3074 setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true);
3075 if (mCurMethod != null) {
3076 try {
Yohei Yukawa849443c2019-01-21 09:02:25 -08003077 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
satokd81e9502012-05-21 12:58:45 +09003078 mCurMethod.changeInputMethodSubtype(newSubtype);
3079 } catch (RemoteException e) {
3080 Slog.w(TAG, "Failed to call changeInputMethodSubtype");
satokab751aa2010-09-14 19:17:36 +09003081 }
3082 }
3083 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003084 return;
3085 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003086
satokd81e9502012-05-21 12:58:45 +09003087 // Changing to a different IME.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003088 final long ident = Binder.clearCallingIdentity();
3089 try {
satokab751aa2010-09-14 19:17:36 +09003090 // Set a subtype to this input method.
3091 // subtypeId the name of a subtype which will be set.
satok723a27e2010-11-11 14:58:11 +09003092 setSelectedInputMethodAndSubtypeLocked(info, subtypeId, false);
3093 // mCurMethodId should be updated after setSelectedInputMethodAndSubtypeLocked()
3094 // because mCurMethodId is stored as a history in
3095 // setSelectedInputMethodAndSubtypeLocked().
3096 mCurMethodId = id;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003097
Sudheer Shankafc46e9b2016-10-21 17:55:27 -07003098 if (LocalServices.getService(ActivityManagerInternal.class).isSystemReady()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003099 Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08003100 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003101 intent.putExtra("input_method_id", id);
Amith Yamasanicd757062012-10-19 18:23:52 -07003102 mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003103 }
Yohei Yukawab7526452018-10-21 20:15:17 -07003104 unbindCurrentClientLocked(UnbindReason.SWITCH_IME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003105 } finally {
3106 Binder.restoreCallingIdentity(ident);
3107 }
3108 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003109
satok42c5a162011-05-26 16:46:14 +09003110 @Override
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08003111 public boolean showSoftInput(IInputMethodClient client, IBinder windowToken, int flags,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003112 ResultReceiver resultReceiver) {
Dianne Hackborncef65ee2010-09-30 18:27:22 -07003113 int uid = Binder.getCallingUid();
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003114 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003115 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003116 return false;
3117 }
3118 final long ident = Binder.clearCallingIdentity();
3119 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003120 if (mCurClient == null || client == null
3121 || mCurClient.client.asBinder() != client.asBinder()) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07003122 // We need to check if this is the current client with
3123 // focus in the window manager, to allow this call to
3124 // be made before input is started in it.
Yohei Yukawa41f89c32018-09-19 14:30:04 -07003125 final ClientState cs = mClients.get(client.asBinder());
3126 if (cs == null) {
3127 throw new IllegalArgumentException("unknown client " + client.asBinder());
3128 }
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08003129 if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
3130 cs.selfReportedDisplayId)) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07003131 Slog.w(TAG, "Ignoring showSoftInput of uid " + uid + ": " + client);
The Android Open Source Project4df24232009-03-05 14:34:35 -08003132 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003133 }
3134 }
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07003135 if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
lumarkd85e1582019-12-29 20:20:41 +08003136 return showCurrentInputLocked(windowToken, flags, resultReceiver,
3137 SoftInputShowHideReason.SHOW_SOFT_INPUT);
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003138 } finally {
3139 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003140 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003141 }
3142 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003143
Andreas Gamped6d42062018-07-20 13:08:21 -07003144 @GuardedBy("mMethodMap")
lumarkd85e1582019-12-29 20:20:41 +08003145 boolean showCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver,
3146 @SoftInputShowHideReason int reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003147 mShowRequested = true;
Anna Galusza9b278112016-01-04 11:37:37 -08003148 if (mAccessibilityRequestingNoSoftKeyboard) {
3149 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003150 }
Anna Galusza9b278112016-01-04 11:37:37 -08003151
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003152 if ((flags&InputMethodManager.SHOW_FORCED) != 0) {
3153 mShowExplicitlyRequested = true;
3154 mShowForced = true;
Anna Galusza9b278112016-01-04 11:37:37 -08003155 } else if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
3156 mShowExplicitlyRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003157 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003158
Dianne Hackborncc278702009-09-02 23:07:23 -07003159 if (!mSystemReady) {
3160 return false;
3161 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003162
The Android Open Source Project4df24232009-03-05 14:34:35 -08003163 boolean res = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003164 if (mCurMethod != null) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07003165 if (DEBUG) Slog.d(TAG, "showCurrentInputLocked: mCurToken=" + mCurToken);
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08003166 // create a dummy token for IMS so that IMS cannot inject windows into client app.
3167 Binder showInputToken = new Binder();
3168 mShowRequestWindowMap.put(showInputToken, windowToken);
lumarkd85e1582019-12-29 20:20:41 +08003169 executeOrSendMessage(mCurMethod, mCaller.obtainMessageIIOOO(
3170 MSG_SHOW_SOFT_INPUT, getImeShowFlags(), reason, mCurMethod, resultReceiver,
3171 showInputToken));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003172 mInputShown = true;
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07003173 if (mHaveConnection && !mVisibleBound) {
Yohei Yukawaf80087c2018-05-21 09:47:53 -07003174 bindCurrentInputMethodServiceLocked(
Yohei Yukawaa67a4592017-03-30 15:57:02 -07003175 mCurIntent, mVisibleConnection, IME_VISIBLE_BIND_FLAGS);
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07003176 mVisibleBound = true;
3177 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08003178 res = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003179 } else if (mHaveConnection && SystemClock.uptimeMillis()
satok59b424c2011-09-30 17:21:46 +09003180 >= (mLastBindTime+TIME_TO_RECONNECT)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003181 // The client has asked to have the input method shown, but
3182 // we have been sitting here too long with a connection to the
3183 // service and no interface received, so let's disconnect/connect
3184 // to try to prod things along.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003185 EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, mCurMethodId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003186 SystemClock.uptimeMillis()-mLastBindTime,1);
satok59b424c2011-09-30 17:21:46 +09003187 Slog.w(TAG, "Force disconnect/connect to the IME in showCurrentInputLocked()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003188 mContext.unbindService(this);
Yohei Yukawaf80087c2018-05-21 09:47:53 -07003189 bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003190 } else {
3191 if (DEBUG) {
3192 Slog.d(TAG, "Can't show input: connection = " + mHaveConnection + ", time = "
3193 + ((mLastBindTime+TIME_TO_RECONNECT) - SystemClock.uptimeMillis()));
3194 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003195 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003196
The Android Open Source Project4df24232009-03-05 14:34:35 -08003197 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003198 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003199
satok42c5a162011-05-26 16:46:14 +09003200 @Override
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08003201 public boolean hideSoftInput(IInputMethodClient client, IBinder windowToken, int flags,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003202 ResultReceiver resultReceiver) {
Dianne Hackborncef65ee2010-09-30 18:27:22 -07003203 int uid = Binder.getCallingUid();
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003204 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003205 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003206 return false;
3207 }
3208 final long ident = Binder.clearCallingIdentity();
3209 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003210 if (mCurClient == null || client == null
3211 || mCurClient.client.asBinder() != client.asBinder()) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07003212 // We need to check if this is the current client with
3213 // focus in the window manager, to allow this call to
3214 // be made before input is started in it.
Yohei Yukawa41f89c32018-09-19 14:30:04 -07003215 final ClientState cs = mClients.get(client.asBinder());
3216 if (cs == null) {
3217 throw new IllegalArgumentException("unknown client " + client.asBinder());
3218 }
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08003219 if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
3220 cs.selfReportedDisplayId)) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07003221 if (DEBUG) {
3222 Slog.w(TAG, "Ignoring hideSoftInput of uid " + uid + ": " + client);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003223 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08003224 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003225 }
3226 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003227
Joe Onorato8a9b2202010-02-26 18:56:32 -08003228 if (DEBUG) Slog.v(TAG, "Client requesting input be hidden");
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08003229 return hideCurrentInputLocked(windowToken, flags, resultReceiver,
lumarkd85e1582019-12-29 20:20:41 +08003230 SoftInputShowHideReason.HIDE_SOFT_INPUT);
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003231 } finally {
3232 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003233 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003234 }
3235 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003236
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08003237 boolean hideCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver,
lumarkd85e1582019-12-29 20:20:41 +08003238 @SoftInputShowHideReason int reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003239 if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
3240 && (mShowExplicitlyRequested || mShowForced)) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07003241 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 -08003242 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003243 }
3244 if (mShowForced && (flags&InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07003245 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 -08003246 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003247 }
Seigo Nonakaec928652015-06-10 15:31:20 +09003248
3249 // There is a chance that IMM#hideSoftInput() is called in a transient state where
3250 // IMMS#InputShown is already updated to be true whereas IMMS#mImeWindowVis is still waiting
3251 // to be updated with the new value sent from IME process. Even in such a transient state
3252 // historically we have accepted an incoming call of IMM#hideSoftInput() from the
3253 // application process as a valid request, and have even promised such a behavior with CTS
3254 // since Android Eclair. That's why we need to accept IMM#hideSoftInput() even when only
3255 // IMMS#InputShown indicates that the software keyboard is shown.
3256 // TODO: Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested.
3257 final boolean shouldHideSoftInput = (mCurMethod != null) && (mInputShown ||
3258 (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0);
The Android Open Source Project4df24232009-03-05 14:34:35 -08003259 boolean res;
Seigo Nonakaec928652015-06-10 15:31:20 +09003260 if (shouldHideSoftInput) {
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08003261 final Binder hideInputToken = new Binder();
3262 mHideRequestWindowMap.put(hideInputToken, windowToken);
Seigo Nonakaec928652015-06-10 15:31:20 +09003263 // The IME will report its visible state again after the following message finally
3264 // delivered to the IME process as an IPC. Hence the inconsistency between
3265 // IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in
3266 // the final state.
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08003267 executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOOO(MSG_HIDE_SOFT_INPUT,
3268 reason, mCurMethod, resultReceiver, hideInputToken));
The Android Open Source Project4df24232009-03-05 14:34:35 -08003269 res = true;
3270 } else {
3271 res = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003272 }
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07003273 if (mHaveConnection && mVisibleBound) {
3274 mContext.unbindService(mVisibleConnection);
3275 mVisibleBound = false;
3276 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003277 mInputShown = false;
3278 mShowRequested = false;
3279 mShowExplicitlyRequested = false;
3280 mShowForced = false;
The Android Open Source Project4df24232009-03-05 14:34:35 -08003281 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003282 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003283
Yohei Yukawa2553e482017-12-15 15:47:33 -08003284 @NonNull
satok42c5a162011-05-26 16:46:14 +09003285 @Override
Yohei Yukawa05c25f82016-02-22 12:41:17 -08003286 public InputBindResult startInputOrWindowGainedFocus(
Yohei Yukawadc66e522018-10-21 10:43:14 -07003287 @StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07003288 @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
3289 int windowFlags, @Nullable EditorInfo attribute, IInputContext inputContext,
Yohei Yukawadc66e522018-10-21 10:43:14 -07003290 @MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion) {
Yohei Yukawa80498d52018-06-21 16:24:36 -07003291 if (windowToken == null) {
3292 Slog.e(TAG, "windowToken cannot be null.");
3293 return InputBindResult.NULL;
Yohei Yukawa05c25f82016-02-22 12:41:17 -08003294 }
Yohei Yukawa0f5eade2019-01-18 08:48:07 -08003295 final int callingUserId = UserHandle.getCallingUserId();
3296 final int userId;
Yohei Yukawa716897c2019-01-22 00:00:53 -08003297 if (attribute != null && attribute.targetInputMethodUser != null
Yohei Yukawa0f5eade2019-01-18 08:48:07 -08003298 && attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
3299 mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
Yohei Yukawa670abea2019-01-28 00:00:50 -08003300 "Using EditorInfo.targetInputMethodUser requires INTERACT_ACROSS_USERS_FULL.");
Yohei Yukawa0f5eade2019-01-18 08:48:07 -08003301 userId = attribute.targetInputMethodUser.getIdentifier();
3302 if (!mUserManagerInternal.isUserRunning(userId)) {
3303 // There is a chance that we hit here because of race condition. Let's just return
3304 // an error code instead of crashing the caller process, which at least has
3305 // INTERACT_ACROSS_USERS_FULL permission thus is likely to be an important process.
3306 Slog.e(TAG, "User #" + userId + " is not running.");
3307 return InputBindResult.INVALID_USER;
3308 }
3309 } else {
3310 userId = callingUserId;
3311 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003312 final InputBindResult result;
3313 synchronized (mMethodMap) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003314 final long ident = Binder.clearCallingIdentity();
3315 try {
3316 result = startInputOrWindowGainedFocusInternalLocked(startInputReason, client,
3317 windowToken, startInputFlags, softInputMode, windowFlags, attribute,
3318 inputContext, missingMethods, unverifiedTargetSdkVersion, userId);
3319 } finally {
3320 Binder.restoreCallingIdentity(ident);
3321 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003322 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08003323 if (result == null) {
3324 // This must never happen, but just in case.
3325 Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
Yohei Yukawaa468d702018-10-21 11:42:34 -07003326 + InputMethodDebug.startInputReasonToString(startInputReason)
Yohei Yukawa2553e482017-12-15 15:47:33 -08003327 + " windowFlags=#" + Integer.toHexString(windowFlags)
3328 + " editorInfo=" + attribute);
3329 return InputBindResult.NULL;
3330 }
3331 return result;
Yohei Yukawa05c25f82016-02-22 12:41:17 -08003332 }
3333
Yohei Yukawa2553e482017-12-15 15:47:33 -08003334 @NonNull
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003335 private InputBindResult startInputOrWindowGainedFocusInternalLocked(
Yohei Yukawadc66e522018-10-21 10:43:14 -07003336 @StartInputReason int startInputReason, IInputMethodClient client,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07003337 @NonNull IBinder windowToken, @StartInputFlags int startInputFlags,
3338 @SoftInputModeFlags int softInputMode, int windowFlags, EditorInfo attribute,
3339 IInputContext inputContext, @MissingMethodFlags int missingMethods,
Yohei Yukawa4391c202019-01-28 00:49:10 -08003340 int unverifiedTargetSdkVersion, @UserIdInt int userId) {
Yohei Yukawa67464522019-01-28 00:50:09 -08003341 if (DEBUG) {
3342 Slog.v(TAG, "startInputOrWindowGainedFocusInternalLocked: reason="
3343 + InputMethodDebug.startInputReasonToString(startInputReason)
3344 + " client=" + client.asBinder()
3345 + " inputContext=" + inputContext
3346 + " missingMethods="
3347 + InputConnectionInspector.getMissingMethodFlagsAsString(missingMethods)
3348 + " attribute=" + attribute
3349 + " startInputFlags="
3350 + InputMethodDebug.startInputFlagsToString(startInputFlags)
3351 + " softInputMode=" + InputMethodDebug.softInputModeToString(softInputMode)
3352 + " windowFlags=#" + Integer.toHexString(windowFlags)
3353 + " unverifiedTargetSdkVersion=" + unverifiedTargetSdkVersion);
3354 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003355
Yohei Yukawa67464522019-01-28 00:50:09 -08003356 final int windowDisplayId = mWindowManagerInternal.getDisplayIdForWindow(windowToken);
3357
3358 final ClientState cs = mClients.get(client.asBinder());
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003359 if (cs == null) {
Yohei Yukawa67464522019-01-28 00:50:09 -08003360 throw new IllegalArgumentException("unknown client " + client.asBinder());
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003361 }
3362 if (cs.selfReportedDisplayId != windowDisplayId) {
3363 Slog.e(TAG, "startInputOrWindowGainedFocusInternal: display ID mismatch."
3364 + " from client:" + cs.selfReportedDisplayId
3365 + " from window:" + windowDisplayId);
3366 return InputBindResult.DISPLAY_ID_MISMATCH;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003367 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08003368
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003369 if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
3370 cs.selfReportedDisplayId)) {
3371 // Check with the window manager to make sure this client actually
3372 // has a window with focus. If not, reject. This is thread safe
3373 // because if the focus changes some time before or after, the
3374 // next client receiving focus that has any interest in input will
3375 // be calling through here after that change happens.
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003376 if (DEBUG) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003377 Slog.w(TAG, "Focus gain on non-focused client " + cs.client
3378 + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003379 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003380 return InputBindResult.NOT_IME_TARGET_WINDOW;
3381 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003382
Yohei Yukawad277d692020-02-19 17:12:17 -08003383 if (mUserSwitchHandlerTask != null) {
3384 // There is already an on-going pending user switch task.
3385 final int nextUserId = mUserSwitchHandlerTask.mToUserId;
3386 if (userId == nextUserId) {
3387 scheduleSwitchUserTaskLocked(userId, cs.client);
3388 return InputBindResult.USER_SWITCHING;
3389 }
3390 for (int profileId : mUserManager.getProfileIdsWithDisabled(nextUserId)) {
3391 if (profileId == userId) {
3392 scheduleSwitchUserTaskLocked(userId, cs.client);
3393 return InputBindResult.USER_SWITCHING;
3394 }
3395 }
3396 return InputBindResult.INVALID_USER;
3397 }
3398
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003399 // cross-profile access is always allowed here to allow profile-switching.
3400 if (!mSettings.isCurrentProfile(userId)) {
3401 Slog.w(TAG, "A background user is requesting window. Hiding IME.");
3402 Slog.w(TAG, "If you need to impersonate a foreground user/profile from"
3403 + " a background user, use EditorInfo.targetInputMethodUser with"
3404 + " INTERACT_ACROSS_USERS_FULL permission.");
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08003405 hideCurrentInputLocked(
3406 mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_INVALID_USER);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003407 return InputBindResult.INVALID_USER;
3408 }
3409
Tarandeep Singhcf5ff822019-07-08 14:06:27 -07003410 if (userId != mSettings.getCurrentUserId()) {
Yohei Yukawad277d692020-02-19 17:12:17 -08003411 scheduleSwitchUserTaskLocked(userId, cs.client);
3412 return InputBindResult.USER_SWITCHING;
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003413 }
Yohei Yukawad277d692020-02-19 17:12:17 -08003414
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003415 // Master feature flag that overrides other conditions and forces IME preRendering.
3416 if (DEBUG) {
3417 Slog.v(TAG, "IME PreRendering MASTER flag: "
Yohei Yukawa67464522019-01-28 00:50:09 -08003418 + DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() + ", LowRam: " + mIsLowRam);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003419 }
3420 // pre-rendering not supported on low-ram devices.
3421 cs.shouldPreRenderIme = DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() && !mIsLowRam;
3422
3423 if (mCurFocusedWindow == windowToken) {
3424 if (DEBUG) {
3425 Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
3426 + " attribute=" + attribute + ", token = " + windowToken);
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003427 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003428 if (attribute != null) {
3429 return startInputUncheckedLocked(cs, inputContext, missingMethods,
3430 attribute, startInputFlags, startInputReason);
3431 }
3432 return new InputBindResult(
3433 InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07003434 null, null, null, -1, null);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003435 }
3436 mCurFocusedWindow = windowToken;
3437 mCurFocusedWindowSoftInputMode = softInputMode;
3438 mCurFocusedWindowClient = cs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003439
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003440 // Should we auto-show the IME even if the caller has not
3441 // specified what should be done with it?
3442 // We only do this automatically if the window can resize
3443 // to accommodate the IME (so what the user sees will give
3444 // them good context without input information being obscured
3445 // by the IME) or if running on a large screen where there
3446 // is more room for the target window + IME.
3447 final boolean doAutoShow =
Yohei Yukawa6e875592019-01-28 00:49:30 -08003448 (softInputMode & LayoutParams.SOFT_INPUT_MASK_ADJUST)
3449 == LayoutParams.SOFT_INPUT_ADJUST_RESIZE
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003450 || mRes.getConfiguration().isLayoutSizeAtLeast(
3451 Configuration.SCREENLAYOUT_SIZE_LARGE);
Yohei Yukawa67464522019-01-28 00:50:09 -08003452 final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003453
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003454 // We want to start input before showing the IME, but after closing
3455 // it. We want to do this after closing it to help the IME disappear
3456 // more quickly (not get stuck behind it initializing itself for the
3457 // new focused input, even if its window wants to hide the IME).
3458 boolean didStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003459
Yohei Yukawa67464522019-01-28 00:50:09 -08003460 InputBindResult res = null;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003461 switch (softInputMode & LayoutParams.SOFT_INPUT_MASK_STATE) {
3462 case LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003463 if (!isTextEditor || !doAutoShow) {
Yohei Yukawa6e875592019-01-28 00:49:30 -08003464 if (LayoutParams.mayUseInputMethod(windowFlags)) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003465 // There is no focus view, and this window will
3466 // be behind any soft input window, so hide the
3467 // soft input window if it is shown.
3468 if (DEBUG) Slog.v(TAG, "Unspecified window will hide input");
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08003469 hideCurrentInputLocked(
3470 mCurFocusedWindow, InputMethodManager.HIDE_NOT_ALWAYS, null,
lumarkd85e1582019-12-29 20:20:41 +08003471 SoftInputShowHideReason.HIDE_UNSPECIFIED_WINDOW);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003472
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003473 // If focused display changed, we should unbind current method
3474 // to make app window in previous display relayout after Ime
3475 // window token removed.
3476 // Note that we can trust client's display ID as long as it matches
3477 // to the display ID obtained from the window.
3478 if (cs.selfReportedDisplayId != mCurTokenDisplayId) {
3479 unbindCurrentMethodLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003480 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003481 }
Yohei Yukawa6e875592019-01-28 00:49:30 -08003482 } else if (isTextEditor && doAutoShow
3483 && (softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003484 // There is a focus view, and we are navigating forward
3485 // into the window, so show the input window for the user.
3486 // We only do this automatically if the window can resize
3487 // to accommodate the IME (so what the user sees will give
3488 // them good context without input information being obscured
3489 // by the IME) or if running on a large screen where there
3490 // is more room for the target window + IME.
3491 if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
3492 if (attribute != null) {
3493 res = startInputUncheckedLocked(cs, inputContext, missingMethods,
3494 attribute, startInputFlags, startInputReason);
3495 didStart = true;
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003496 }
lumarkd85e1582019-12-29 20:20:41 +08003497 showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
3498 SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003499 }
3500 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003501 case LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003502 // Do nothing.
3503 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003504 case LayoutParams.SOFT_INPUT_STATE_HIDDEN:
3505 if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003506 if (DEBUG) Slog.v(TAG, "Window asks to hide input going forward");
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08003507 hideCurrentInputLocked(mCurFocusedWindow, 0, null,
lumarkd85e1582019-12-29 20:20:41 +08003508 SoftInputShowHideReason.HIDE_STATE_HIDDEN_FORWARD_NAV);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003509 }
3510 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003511 case LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003512 if (DEBUG) Slog.v(TAG, "Window asks to hide input");
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08003513 hideCurrentInputLocked(mCurFocusedWindow, 0, null,
lumarkd85e1582019-12-29 20:20:41 +08003514 SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003515 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003516 case LayoutParams.SOFT_INPUT_STATE_VISIBLE:
3517 if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003518 if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003519 if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
3520 unverifiedTargetSdkVersion, startInputFlags)) {
3521 if (attribute != null) {
Yohei Yukawa67464522019-01-28 00:50:09 -08003522 res = startInputUncheckedLocked(cs, inputContext, missingMethods,
3523 attribute, startInputFlags, startInputReason);
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003524 didStart = true;
3525 }
lumarkd85e1582019-12-29 20:20:41 +08003526 showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
3527 SoftInputShowHideReason.SHOW_STATE_VISIBLE_FORWARD_NAV);
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003528 } else {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003529 Slog.e(TAG, "SOFT_INPUT_STATE_VISIBLE is ignored because"
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003530 + " there is no focused view that also returns true from"
3531 + " View#onCheckIsTextEditor()");
3532 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003533 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003534 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003535 case LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003536 if (DEBUG) Slog.v(TAG, "Window asks to always show input");
3537 if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
3538 unverifiedTargetSdkVersion, startInputFlags)) {
3539 if (attribute != null) {
3540 res = startInputUncheckedLocked(cs, inputContext, missingMethods,
3541 attribute, startInputFlags, startInputReason);
3542 didStart = true;
3543 }
lumarkd85e1582019-12-29 20:20:41 +08003544 showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
3545 SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003546 } else {
3547 Slog.e(TAG, "SOFT_INPUT_STATE_ALWAYS_VISIBLE is ignored because"
3548 + " there is no focused view that also returns true from"
3549 + " View#onCheckIsTextEditor()");
3550 }
3551 break;
3552 }
3553
3554 if (!didStart) {
3555 if (attribute != null) {
3556 if (!DebugFlags.FLAG_OPTIMIZE_START_INPUT.value()
3557 || (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0) {
Yohei Yukawa67464522019-01-28 00:50:09 -08003558 res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003559 startInputFlags, startInputReason);
3560 } else {
3561 res = InputBindResult.NO_EDITOR;
3562 }
3563 } else {
3564 res = InputBindResult.NULL_EDITOR_INFO;
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003565 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003566 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08003567 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003568 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003569
Guliz Tuncay6908c152017-06-02 16:06:10 -07003570 private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08003571 // TODO(yukawa): multi-display support.
Guliz Tuncay6908c152017-06-02 16:06:10 -07003572 final int uid = Binder.getCallingUid();
lumark0b05f9e2018-11-26 15:09:06 +08003573 if (mCurFocusedWindowClient != null && client != null
Tarandeep Singheb570612018-01-29 16:20:32 -08003574 && mCurFocusedWindowClient.client.asBinder() == client.asBinder()) {
Guliz Tuncay6908c152017-06-02 16:06:10 -07003575 return true;
3576 } else if (mCurIntent != null && InputMethodUtils.checkIfPackageBelongsToUid(
3577 mAppOpsManager,
3578 uid,
3579 mCurIntent.getComponent().getPackageName())) {
3580 return true;
Guliz Tuncay6908c152017-06-02 16:06:10 -07003581 }
Guliz Tuncay6908c152017-06-02 16:06:10 -07003582 return false;
3583 }
3584
satok42c5a162011-05-26 16:46:14 +09003585 @Override
Seigo Nonaka14e13912015-05-06 21:04:13 -07003586 public void showInputMethodPickerFromClient(
3587 IInputMethodClient client, int auxiliarySubtypeMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003588 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003589 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003590 return;
3591 }
Guliz Tuncay6908c152017-06-02 16:06:10 -07003592 if(!canShowInputMethodPickerLocked(client)) {
satok47a44912010-10-06 16:03:58 +09003593 Slog.w(TAG, "Ignoring showInputMethodPickerFromClient of uid "
Dianne Hackborncef65ee2010-09-30 18:27:22 -07003594 + Binder.getCallingUid() + ": " + client);
Guliz Tuncay6908c152017-06-02 16:06:10 -07003595 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003596 }
3597
satok440aab52010-11-25 09:43:11 +09003598 // Always call subtype picker, because subtype picker is a superset of input method
3599 // picker.
lumark0b05f9e2018-11-26 15:09:06 +08003600 mHandler.sendMessage(mCaller.obtainMessageII(
3601 MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode,
3602 (mCurClient != null) ? mCurClient.selfReportedDisplayId : DEFAULT_DISPLAY));
satokab751aa2010-09-14 19:17:36 +09003603 }
3604 }
3605
lumark0b05f9e2018-11-26 15:09:06 +08003606 @Override
3607 public void showInputMethodPickerFromSystem(IInputMethodClient client, int auxiliarySubtypeMode,
3608 int displayId) {
3609 if (mContext.checkCallingPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
3610 != PackageManager.PERMISSION_GRANTED) {
3611 throw new SecurityException(
3612 "showInputMethodPickerFromSystem requires WRITE_SECURE_SETTINGS permission");
3613 }
3614 // Always call subtype picker, because subtype picker is a superset of input method
3615 // picker.
3616 mHandler.sendMessage(mCaller.obtainMessageII(
3617 MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode, displayId));
3618 }
3619
Tarandeep Singheb570612018-01-29 16:20:32 -08003620 public boolean isInputMethodPickerShownForTest() {
3621 synchronized(mMethodMap) {
3622 if (mSwitchingDialog == null) {
3623 return false;
3624 }
3625 return mSwitchingDialog.isShowing();
3626 }
3627 }
3628
Yohei Yukawa0c1ebff2018-12-27 14:06:28 -08003629 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003630 private void setInputMethod(@NonNull IBinder token, String id) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003631 synchronized (mMethodMap) {
Yohei Yukawa0c1ebff2018-12-27 14:06:28 -08003632 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003633 return;
3634 }
3635 setInputMethodWithSubtypeIdLocked(token, id, NOT_A_SUBTYPE_ID);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003636 }
satok28203512010-11-24 11:06:49 +09003637 }
3638
Yohei Yukawa4773ee12018-12-24 21:13:53 -08003639 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003640 private void setInputMethodAndSubtype(@NonNull IBinder token, String id,
3641 InputMethodSubtype subtype) {
satok28203512010-11-24 11:06:49 +09003642 synchronized (mMethodMap) {
Yohei Yukawa4773ee12018-12-24 21:13:53 -08003643 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003644 return;
3645 }
satok28203512010-11-24 11:06:49 +09003646 if (subtype != null) {
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003647 setInputMethodWithSubtypeIdLocked(token, id,
3648 InputMethodUtils.getSubtypeIdFromHashCode(mMethodMap.get(id),
3649 subtype.hashCode()));
satok28203512010-11-24 11:06:49 +09003650 } else {
3651 setInputMethod(token, id);
3652 }
3653 }
satokab751aa2010-09-14 19:17:36 +09003654 }
3655
satok42c5a162011-05-26 16:46:14 +09003656 @Override
satokb416a712010-11-25 20:42:14 +09003657 public void showInputMethodAndSubtypeEnablerFromClient(
satok217f5482010-12-15 05:19:19 +09003658 IInputMethodClient client, String inputMethodId) {
satokb416a712010-11-25 20:42:14 +09003659 synchronized (mMethodMap) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003660 // TODO(yukawa): Should we verify the display ID?
Yohei Yukawa46d74762019-01-22 10:17:22 -08003661 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003662 return;
3663 }
satok7fee71f2010-12-17 18:54:26 +09003664 executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
3665 MSG_SHOW_IM_SUBTYPE_ENABLER, inputMethodId));
satokb416a712010-11-25 20:42:14 +09003666 }
3667 }
3668
Yohei Yukawa0c499082018-12-09 18:52:02 -08003669 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003670 private boolean switchToPreviousInputMethod(@NonNull IBinder token) {
satok735cf382010-11-11 20:40:09 +09003671 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003672 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa0c499082018-12-09 18:52:02 -08003673 return false;
3674 }
satokc445bcd2011-01-25 18:57:24 +09003675 final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
satok4fc87d62011-05-20 16:13:43 +09003676 final InputMethodInfo lastImi;
satok208d5632011-05-20 22:13:38 +09003677 if (lastIme != null) {
satok4fc87d62011-05-20 16:13:43 +09003678 lastImi = mMethodMap.get(lastIme.first);
3679 } else {
3680 lastImi = null;
satok735cf382010-11-11 20:40:09 +09003681 }
satok4fc87d62011-05-20 16:13:43 +09003682 String targetLastImiId = null;
3683 int subtypeId = NOT_A_SUBTYPE_ID;
3684 if (lastIme != null && lastImi != null) {
3685 final boolean imiIdIsSame = lastImi.getId().equals(mCurMethodId);
Narayan Kamatha09b4d22016-04-15 18:32:45 +01003686 final int lastSubtypeHash = Integer.parseInt(lastIme.second);
satok4fc87d62011-05-20 16:13:43 +09003687 final int currentSubtypeHash = mCurrentSubtype == null ? NOT_A_SUBTYPE_ID
3688 : mCurrentSubtype.hashCode();
3689 // If the last IME is the same as the current IME and the last subtype is not
3690 // defined, there is no need to switch to the last IME.
3691 if (!imiIdIsSame || lastSubtypeHash != currentSubtypeHash) {
3692 targetLastImiId = lastIme.first;
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003693 subtypeId = InputMethodUtils.getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
satok4fc87d62011-05-20 16:13:43 +09003694 }
3695 }
3696
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003697 if (TextUtils.isEmpty(targetLastImiId)
3698 && !InputMethodUtils.canAddToLastInputMethod(mCurrentSubtype)) {
satok4fc87d62011-05-20 16:13:43 +09003699 // This is a safety net. If the currentSubtype can't be added to the history
3700 // and the framework couldn't find the last ime, we will make the last ime be
3701 // the most applicable enabled keyboard subtype of the system imes.
3702 final List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
3703 if (enabled != null) {
3704 final int N = enabled.size();
3705 final String locale = mCurrentSubtype == null
3706 ? mRes.getConfiguration().locale.toString()
3707 : mCurrentSubtype.getLocale();
3708 for (int i = 0; i < N; ++i) {
3709 final InputMethodInfo imi = enabled.get(i);
Yohei Yukawafd70fe82018-04-08 12:19:56 -07003710 if (imi.getSubtypeCount() > 0 && imi.isSystem()) {
satok4fc87d62011-05-20 16:13:43 +09003711 InputMethodSubtype keyboardSubtype =
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003712 InputMethodUtils.findLastResortApplicableSubtypeLocked(mRes,
3713 InputMethodUtils.getSubtypes(imi),
3714 InputMethodUtils.SUBTYPE_MODE_KEYBOARD, locale, true);
satok4fc87d62011-05-20 16:13:43 +09003715 if (keyboardSubtype != null) {
3716 targetLastImiId = imi.getId();
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003717 subtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
satok4fc87d62011-05-20 16:13:43 +09003718 imi, keyboardSubtype.hashCode());
3719 if(keyboardSubtype.getLocale().equals(locale)) {
3720 break;
3721 }
3722 }
3723 }
3724 }
3725 }
3726 }
3727
3728 if (!TextUtils.isEmpty(targetLastImiId)) {
3729 if (DEBUG) {
3730 Slog.d(TAG, "Switch to: " + lastImi.getId() + ", " + lastIme.second
3731 + ", from: " + mCurMethodId + ", " + subtypeId);
3732 }
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003733 setInputMethodWithSubtypeIdLocked(token, targetLastImiId, subtypeId);
satok4fc87d62011-05-20 16:13:43 +09003734 return true;
3735 } else {
3736 return false;
3737 }
satok735cf382010-11-11 20:40:09 +09003738 }
3739 }
3740
Yohei Yukawa70f17e72018-12-09 18:51:38 -08003741 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003742 private boolean switchToNextInputMethod(@NonNull IBinder token, boolean onlyCurrentIme) {
satok688bd472012-02-09 20:09:17 +09003743 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003744 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawaa0755742014-06-04 20:28:18 +09003745 return false;
3746 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003747 final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
Yohei Yukawa136b6ce2018-05-02 10:55:35 -07003748 onlyCurrentIme, mMethodMap.get(mCurMethodId), mCurrentSubtype);
satok688bd472012-02-09 20:09:17 +09003749 if (nextSubtype == null) {
3750 return false;
3751 }
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003752 setInputMethodWithSubtypeIdLocked(token, nextSubtype.mImi.getId(),
3753 nextSubtype.mSubtypeId);
satok688bd472012-02-09 20:09:17 +09003754 return true;
3755 }
3756 }
3757
Yohei Yukawaeec552e2018-09-09 20:48:41 -07003758 @BinderThread
3759 private boolean shouldOfferSwitchingToNextInputMethod(@NonNull IBinder token) {
Satoshi Kataoka2b10b522013-08-21 20:39:12 +09003760 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003761 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawaa0755742014-06-04 20:28:18 +09003762 return false;
3763 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003764 final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
Yohei Yukawa136b6ce2018-05-02 10:55:35 -07003765 false /* onlyCurrentIme */, mMethodMap.get(mCurMethodId), mCurrentSubtype);
Satoshi Kataoka2b10b522013-08-21 20:39:12 +09003766 if (nextSubtype == null) {
3767 return false;
3768 }
3769 return true;
3770 }
3771 }
3772
3773 @Override
satok68f1b782011-04-11 14:26:04 +09003774 public InputMethodSubtype getLastInputMethodSubtype() {
3775 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003776 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003777 return null;
3778 }
satok68f1b782011-04-11 14:26:04 +09003779 final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
3780 // TODO: Handle the case of the last IME with no subtypes
3781 if (lastIme == null || TextUtils.isEmpty(lastIme.first)
3782 || TextUtils.isEmpty(lastIme.second)) return null;
3783 final InputMethodInfo lastImi = mMethodMap.get(lastIme.first);
3784 if (lastImi == null) return null;
3785 try {
Narayan Kamatha09b4d22016-04-15 18:32:45 +01003786 final int lastSubtypeHash = Integer.parseInt(lastIme.second);
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003787 final int lastSubtypeId =
3788 InputMethodUtils.getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
satok0e7d7d62011-07-05 13:28:06 +09003789 if (lastSubtypeId < 0 || lastSubtypeId >= lastImi.getSubtypeCount()) {
3790 return null;
3791 }
3792 return lastImi.getSubtypeAt(lastSubtypeId);
satok68f1b782011-04-11 14:26:04 +09003793 } catch (NumberFormatException e) {
3794 return null;
3795 }
3796 }
3797 }
3798
satoke7c6998e2011-06-03 17:57:59 +09003799 @Override
satokee5e77c2011-09-02 18:50:15 +09003800 public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
satok91e88122011-07-18 11:11:42 +09003801 // By this IPC call, only a process which shares the same uid with the IME can add
3802 // additional input method subtypes to the IME.
Yohei Yukawa70f5c482016-01-04 19:42:36 -08003803 if (TextUtils.isEmpty(imiId) || subtypes == null) return;
Yohei Yukawab557d572018-12-29 21:26:26 -08003804 final ArrayList<InputMethodSubtype> toBeAdded = new ArrayList<>();
3805 for (InputMethodSubtype subtype : subtypes) {
3806 if (!toBeAdded.contains(subtype)) {
3807 toBeAdded.add(subtype);
3808 } else {
3809 Slog.w(TAG, "Duplicated subtype definition found: "
3810 + subtype.getLocale() + ", " + subtype.getMode());
3811 }
3812 }
satoke7c6998e2011-06-03 17:57:59 +09003813 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003814 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003815 return;
3816 }
Yohei Yukawa79247822017-01-23 15:26:15 -08003817 if (!mSystemReady) {
3818 return;
3819 }
satok91e88122011-07-18 11:11:42 +09003820 final InputMethodInfo imi = mMethodMap.get(imiId);
satokee5e77c2011-09-02 18:50:15 +09003821 if (imi == null) return;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003822 final String[] packageInfos;
3823 try {
3824 packageInfos = mIPackageManager.getPackagesForUid(Binder.getCallingUid());
3825 } catch (RemoteException e) {
3826 Slog.e(TAG, "Failed to get package infos");
3827 return;
3828 }
satok91e88122011-07-18 11:11:42 +09003829 if (packageInfos != null) {
3830 final int packageNum = packageInfos.length;
3831 for (int i = 0; i < packageNum; ++i) {
3832 if (packageInfos[i].equals(imi.getPackageName())) {
Yohei Yukawa7b1c8d72018-12-19 11:21:04 -08003833 if (subtypes.length > 0) {
Yohei Yukawab557d572018-12-29 21:26:26 -08003834 mAdditionalSubtypeMap.put(imi.getId(), toBeAdded);
Yohei Yukawa7b1c8d72018-12-19 11:21:04 -08003835 } else {
Yohei Yukawab557d572018-12-29 21:26:26 -08003836 mAdditionalSubtypeMap.remove(imi.getId());
Yohei Yukawa7b1c8d72018-12-19 11:21:04 -08003837 }
Yohei Yukawab557d572018-12-29 21:26:26 -08003838 AdditionalSubtypeUtils.save(mAdditionalSubtypeMap, mMethodMap,
3839 mSettings.getCurrentUserId());
satokc5933802011-08-31 21:26:04 +09003840 final long ident = Binder.clearCallingIdentity();
3841 try {
Yohei Yukawa94e33302016-02-12 19:37:03 -08003842 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
satokc5933802011-08-31 21:26:04 +09003843 } finally {
3844 Binder.restoreCallingIdentity(ident);
3845 }
satokee5e77c2011-09-02 18:50:15 +09003846 return;
satok91e88122011-07-18 11:11:42 +09003847 }
3848 }
3849 }
satoke7c6998e2011-06-03 17:57:59 +09003850 }
satokee5e77c2011-09-02 18:50:15 +09003851 return;
satoke7c6998e2011-06-03 17:57:59 +09003852 }
3853
Yohei Yukawab985e6e2018-09-05 17:07:52 -07003854 /**
Artur Satayev192ca302020-01-22 21:38:23 +00003855 * This is kept due to {@code @UnsupportedAppUsage} in
Yohei Yukawab985e6e2018-09-05 17:07:52 -07003856 * {@link InputMethodManager#getInputMethodWindowVisibleHeight()} and a dependency in
3857 * {@link InputMethodService#onCreate()}.
3858 *
3859 * <p>TODO(Bug 113914148): Check if we can remove this.</p>
3860 * @return {@link WindowManagerInternal#getInputMethodWindowVisibleHeight()}
3861 */
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09003862 @Override
3863 public int getInputMethodWindowVisibleHeight() {
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08003864 // TODO(yukawa): Should we verify the display ID?
lumark90120a82018-08-15 00:33:03 +08003865 return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId);
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09003866 }
3867
Yohei Yukawab4f328a2019-05-02 08:41:27 -07003868 @Override
3869 public void reportActivityView(IInputMethodClient parentClient, int childDisplayId,
3870 float[] matrixValues) {
3871 final DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(childDisplayId);
3872 if (displayInfo == null) {
3873 throw new IllegalArgumentException(
3874 "Cannot find display for non-existent displayId: " + childDisplayId);
3875 }
3876 final int callingUid = Binder.getCallingUid();
3877 if (callingUid != displayInfo.ownerUid) {
3878 throw new SecurityException("The caller doesn't own the display.");
3879 }
3880
3881 synchronized (mMethodMap) {
3882 final ClientState cs = mClients.get(parentClient.asBinder());
3883 if (cs == null) {
3884 return;
3885 }
3886
3887 // null matrixValues means that the entry needs to be removed.
3888 if (matrixValues == null) {
3889 final ActivityViewInfo info = mActivityViewDisplayIdToParentMap.get(childDisplayId);
3890 if (info == null) {
3891 return;
3892 }
3893 if (info.mParentClient != cs) {
3894 throw new SecurityException("Only the owner client can clear"
3895 + " ActivityViewGeometry for display #" + childDisplayId);
3896 }
3897 mActivityViewDisplayIdToParentMap.remove(childDisplayId);
3898 return;
3899 }
3900
3901 ActivityViewInfo info = mActivityViewDisplayIdToParentMap.get(childDisplayId);
3902 if (info != null && info.mParentClient != cs) {
3903 throw new InvalidParameterException("Display #" + childDisplayId
3904 + " is already registered by " + info.mParentClient);
3905 }
3906 if (info == null) {
3907 if (!mWindowManagerInternal.isUidAllowedOnDisplay(childDisplayId, cs.uid)) {
3908 throw new SecurityException(cs + " cannot access to display #"
3909 + childDisplayId);
3910 }
3911 info = new ActivityViewInfo(cs, new Matrix());
3912 mActivityViewDisplayIdToParentMap.put(childDisplayId, info);
3913 }
3914 info.mMatrix.setValues(matrixValues);
3915
3916 if (mCurClient == null || mCurClient.curSession == null) {
3917 return;
3918 }
3919
3920 Matrix matrix = null;
3921 int displayId = mCurClient.selfReportedDisplayId;
3922 boolean needToNotify = false;
3923 while (true) {
3924 needToNotify |= (displayId == childDisplayId);
3925 final ActivityViewInfo next = mActivityViewDisplayIdToParentMap.get(displayId);
3926 if (next == null) {
3927 break;
3928 }
3929 if (matrix == null) {
3930 matrix = new Matrix(next.mMatrix);
3931 } else {
3932 matrix.postConcat(next.mMatrix);
3933 }
3934 if (next.mParentClient.selfReportedDisplayId == mCurTokenDisplayId) {
3935 if (needToNotify) {
3936 final float[] values = new float[9];
3937 matrix.getValues(values);
3938 try {
3939 mCurClient.client.updateActivityViewToScreenMatrix(mCurSeq, values);
3940 } catch (RemoteException e) {
3941 }
3942 }
3943 break;
3944 }
3945 displayId = info.mParentClient.selfReportedDisplayId;
3946 }
3947 }
3948 }
3949
Yunfan Chenc02a5ac2020-06-16 01:52:41 +00003950 @Override
3951 public void removeImeSurface() {
3952 mContext.enforceCallingPermission(Manifest.permission.INTERNAL_SYSTEM_WINDOW, null);
3953 mHandler.sendMessage(mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE));
3954 }
3955
Yohei Yukawac54c1172018-09-06 11:39:50 -07003956 @BinderThread
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003957 private void notifyUserAction(@NonNull IBinder token) {
Satoshi Kataokad7443c82013-10-15 17:45:43 +09003958 if (DEBUG) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003959 Slog.d(TAG, "Got the notification of a user action.");
Satoshi Kataokad7443c82013-10-15 17:45:43 +09003960 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003961 synchronized (mMethodMap) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003962 if (mCurToken != token) {
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09003963 if (DEBUG) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003964 Slog.d(TAG, "Ignoring the user action notification from IMEs that are no longer"
3965 + " active.");
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09003966 }
3967 return;
3968 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003969 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
3970 if (imi != null) {
Yohei Yukawa02970512014-06-05 16:16:18 +09003971 mSwitchingController.onUserActionLocked(imi, mCurrentSubtype);
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003972 }
Satoshi Kataokad7443c82013-10-15 17:45:43 +09003973 }
3974 }
3975
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08003976 @BinderThread
3977 private void reportPreRendered(IBinder token, EditorInfo info) {
3978 synchronized (mMethodMap) {
3979 if (!calledWithValidTokenLocked(token)) {
3980 return;
3981 }
3982 if (mCurClient != null && mCurClient.client != null) {
3983 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
3984 MSG_REPORT_PRE_RENDERED, info, mCurClient));
3985 }
3986 }
3987 }
3988
3989 @BinderThread
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08003990 private void applyImeVisibility(IBinder token, IBinder windowToken, boolean setVisible) {
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08003991 synchronized (mMethodMap) {
3992 if (!calledWithValidTokenLocked(token)) {
3993 return;
3994 }
Tarandeep Singh500a38f2019-09-26 13:36:40 -07003995 if (!setVisible) {
Taran Singhd7fc5862019-10-10 14:45:17 +02003996 if (mCurClient != null) {
3997 // IMMS only knows of focused window, not the actual IME target.
3998 // e.g. it isn't aware of any window that has both
3999 // NOT_FOCUSABLE, ALT_FOCUSABLE_IM flags set and can the IME target.
4000 // Send it to window manager to hide IME from IME target window.
4001 // TODO(b/139861270): send to mCurClient.client once IMMS is aware of
4002 // actual IME target.
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08004003 mWindowManagerInternal.hideIme(mHideRequestWindowMap.get(windowToken));
Tarandeep Singh500a38f2019-09-26 13:36:40 -07004004 }
4005 } else {
4006 // Send to window manager to show IME after IME layout finishes.
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08004007 mWindowManagerInternal.showImePostLayout(mShowRequestWindowMap.get(windowToken));
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08004008 }
4009 }
4010 }
4011
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09004012 private void setInputMethodWithSubtypeIdLocked(IBinder token, String id, int subtypeId) {
4013 if (token == null) {
4014 if (mContext.checkCallingOrSelfPermission(
4015 android.Manifest.permission.WRITE_SECURE_SETTINGS)
4016 != PackageManager.PERMISSION_GRANTED) {
4017 throw new SecurityException(
4018 "Using null token requires permission "
4019 + android.Manifest.permission.WRITE_SECURE_SETTINGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004020 }
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09004021 } else if (mCurToken != token) {
4022 Slog.w(TAG, "Ignoring setInputMethod of uid " + Binder.getCallingUid()
4023 + " token: " + token);
4024 return;
4025 }
4026
4027 final long ident = Binder.clearCallingIdentity();
4028 try {
4029 setInputMethodLocked(id, subtypeId);
4030 } finally {
4031 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004032 }
4033 }
4034
Yohei Yukawaeec552e2018-09-09 20:48:41 -07004035 @BinderThread
4036 private void hideMySoftInput(@NonNull IBinder token, int flags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004037 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08004038 if (!calledWithValidTokenLocked(token)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004039 return;
4040 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004041 long ident = Binder.clearCallingIdentity();
4042 try {
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08004043 hideCurrentInputLocked(
4044 mLastImeTargetWindow, flags, null,
4045 SoftInputShowHideReason.HIDE_MY_SOFT_INPUT);
4046
The Android Open Source Project4df24232009-03-05 14:34:35 -08004047 } finally {
4048 Binder.restoreCallingIdentity(ident);
4049 }
4050 }
4051 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004052
Yohei Yukawaeec552e2018-09-09 20:48:41 -07004053 @BinderThread
4054 private void showMySoftInput(@NonNull IBinder token, int flags) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08004055 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08004056 if (!calledWithValidTokenLocked(token)) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08004057 return;
4058 }
4059 long ident = Binder.clearCallingIdentity();
4060 try {
lumarkd85e1582019-12-29 20:20:41 +08004061 showCurrentInputLocked(mLastImeTargetWindow, flags, null,
4062 SoftInputShowHideReason.SHOW_MY_SOFT_INPUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004063 } finally {
4064 Binder.restoreCallingIdentity(ident);
4065 }
4066 }
4067 }
4068
4069 void setEnabledSessionInMainThread(SessionState session) {
4070 if (mEnabledSession != session) {
Yohei Yukawa9d91b432014-05-19 16:03:24 +09004071 if (mEnabledSession != null && mEnabledSession.session != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004072 try {
Joe Onorato8a9b2202010-02-26 18:56:32 -08004073 if (DEBUG) Slog.v(TAG, "Disabling: " + mEnabledSession);
Yohei Yukawa9d91b432014-05-19 16:03:24 +09004074 mEnabledSession.method.setSessionEnabled(mEnabledSession.session, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004075 } catch (RemoteException e) {
4076 }
4077 }
4078 mEnabledSession = session;
Yohei Yukawa9d91b432014-05-19 16:03:24 +09004079 if (mEnabledSession != null && mEnabledSession.session != null) {
4080 try {
4081 if (DEBUG) Slog.v(TAG, "Enabling: " + mEnabledSession);
4082 mEnabledSession.method.setSessionEnabled(mEnabledSession.session, true);
4083 } catch (RemoteException e) {
4084 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004085 }
4086 }
4087 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004088
Yohei Yukawa930328c2017-10-18 20:19:53 -07004089 @MainThread
satok42c5a162011-05-26 16:46:14 +09004090 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004091 public boolean handleMessage(Message msg) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004092 SomeArgs args;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004093 switch (msg.what) {
satokab751aa2010-09-14 19:17:36 +09004094 case MSG_SHOW_IM_SUBTYPE_PICKER:
Seigo Nonaka14e13912015-05-06 21:04:13 -07004095 final boolean showAuxSubtypes;
lumark0b05f9e2018-11-26 15:09:06 +08004096 final int displayId = msg.arg2;
Seigo Nonaka14e13912015-05-06 21:04:13 -07004097 switch (msg.arg1) {
4098 case InputMethodManager.SHOW_IM_PICKER_MODE_AUTO:
4099 // This is undocumented so far, but IMM#showInputMethodPicker() has been
4100 // implemented so that auxiliary subtypes will be excluded when the soft
4101 // keyboard is invisible.
4102 showAuxSubtypes = mInputShown;
4103 break;
4104 case InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES:
4105 showAuxSubtypes = true;
4106 break;
4107 case InputMethodManager.SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES:
4108 showAuxSubtypes = false;
4109 break;
4110 default:
4111 Slog.e(TAG, "Unknown subtype picker mode = " + msg.arg1);
4112 return false;
4113 }
lumark0b05f9e2018-11-26 15:09:06 +08004114 showInputMethodMenu(showAuxSubtypes, displayId);
satokab751aa2010-09-14 19:17:36 +09004115 return true;
4116
satok47a44912010-10-06 16:03:58 +09004117 case MSG_SHOW_IM_SUBTYPE_ENABLER:
Yohei Yukawa41f34272015-12-14 15:41:52 -08004118 showInputMethodAndSubtypeEnabler((String)msg.obj);
satok217f5482010-12-15 05:19:19 +09004119 return true;
4120
4121 case MSG_SHOW_IM_CONFIG:
4122 showConfigureInputMethods();
satok47a44912010-10-06 16:03:58 +09004123 return true;
4124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004125 // ---------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004126
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004127 case MSG_UNBIND_INPUT:
4128 try {
4129 ((IInputMethod)msg.obj).unbindInput();
4130 } catch (RemoteException e) {
4131 // There is nothing interesting about the method dying.
4132 }
4133 return true;
4134 case MSG_BIND_INPUT:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004135 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004136 try {
4137 ((IInputMethod)args.arg1).bindInput((InputBinding)args.arg2);
4138 } catch (RemoteException e) {
4139 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004140 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004141 return true;
4142 case MSG_SHOW_SOFT_INPUT:
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08004143 args = (SomeArgs) msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004144 try {
lumarkd85e1582019-12-29 20:20:41 +08004145 final @SoftInputShowHideReason int reason = msg.arg2;
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07004146 if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".showSoftInput("
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08004147 + args.arg3 + ", " + msg.arg1 + ", " + args.arg2 + ") for reason: "
lumarkd85e1582019-12-29 20:20:41 +08004148 + InputMethodDebug.softInputDisplayReasonToString(reason));
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08004149 ((IInputMethod) args.arg1).showSoftInput(
4150 (IBinder) args.arg3, msg.arg1, (ResultReceiver) args.arg2);
Anmol Gupta29f209d2020-03-11 11:34:46 -07004151 mSoftInputShowHideHistory.addEntry(new SoftInputShowHideHistory.Entry(
4152 mCurClient, mCurAttribute,
4153 mWindowManagerInternal.getWindowName(mCurFocusedWindow),
4154 mCurFocusedWindowSoftInputMode, reason, mInFullscreenMode,
4155 mWindowManagerInternal.getWindowName(
Ming-Shin Lud0bc1712020-05-11 09:23:37 +08004156 mShowRequestWindowMap.get(args.arg3)),
4157 mWindowManagerInternal.getImeControlTargetNameForLogging(
4158 mCurTokenDisplayId),
4159 mWindowManagerInternal.getImeTargetNameForLogging(
4160 mCurTokenDisplayId)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004161 } catch (RemoteException e) {
4162 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004163 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004164 return true;
4165 case MSG_HIDE_SOFT_INPUT:
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08004166 args = (SomeArgs) msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004167 try {
lumarkd85e1582019-12-29 20:20:41 +08004168 final @SoftInputShowHideReason int reason = msg.arg1;
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07004169 if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".hideSoftInput(0, "
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08004170 + args.arg3 + ", " + args.arg2 + ") for reason: "
lumarkd85e1582019-12-29 20:20:41 +08004171 + InputMethodDebug.softInputDisplayReasonToString(reason));
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08004172 ((IInputMethod)args.arg1).hideSoftInput(
4173 (IBinder) args.arg3, 0, (ResultReceiver)args.arg2);
Anmol Gupta29f209d2020-03-11 11:34:46 -07004174 mSoftInputShowHideHistory.addEntry(new SoftInputShowHideHistory.Entry(
4175 mCurClient, mCurAttribute,
4176 mWindowManagerInternal.getWindowName(mCurFocusedWindow),
4177 mCurFocusedWindowSoftInputMode, reason, mInFullscreenMode,
4178 mWindowManagerInternal.getWindowName(
Ming-Shin Lud0bc1712020-05-11 09:23:37 +08004179 mHideRequestWindowMap.get(args.arg3)),
4180 mWindowManagerInternal.getImeControlTargetNameForLogging(
4181 mCurTokenDisplayId),
4182 mWindowManagerInternal.getImeTargetNameForLogging(
4183 mCurTokenDisplayId)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004184 } catch (RemoteException e) {
4185 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004186 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004187 return true;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -07004188 case MSG_HIDE_CURRENT_INPUT_METHOD:
4189 synchronized (mMethodMap) {
lumarkd85e1582019-12-29 20:20:41 +08004190 final @SoftInputShowHideReason int reason = (int) msg.obj;
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08004191 hideCurrentInputLocked(mCurFocusedWindow, 0, null, reason);
4192
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -07004193 }
4194 return true;
Yohei Yukawac54c1172018-09-06 11:39:50 -07004195 case MSG_INITIALIZE_IME:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004196 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004197 try {
lumark90120a82018-08-15 00:33:03 +08004198 if (DEBUG) {
4199 Slog.v(TAG, "Sending attach of token: " + args.arg2 + " for display: "
4200 + msg.arg1);
4201 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07004202 final IBinder token = (IBinder) args.arg2;
lumark90120a82018-08-15 00:33:03 +08004203 ((IInputMethod) args.arg1).initializeInternal(token, msg.arg1,
Yohei Yukawac54c1172018-09-06 11:39:50 -07004204 new InputMethodPrivilegedOperationsImpl(this, token));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004205 } catch (RemoteException e) {
4206 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004207 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004208 return true;
Jeff Brownc28867a2013-03-26 15:42:39 -07004209 case MSG_CREATE_SESSION: {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004210 args = (SomeArgs)msg.obj;
Jeff Brown1951ce82013-04-04 22:45:12 -07004211 IInputMethod method = (IInputMethod)args.arg1;
Jeff Brownc28867a2013-03-26 15:42:39 -07004212 InputChannel channel = (InputChannel)args.arg2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004213 try {
Jeff Brown1951ce82013-04-04 22:45:12 -07004214 method.createSession(channel, (IInputSessionCallback)args.arg3);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004215 } catch (RemoteException e) {
Jeff Brownc28867a2013-03-26 15:42:39 -07004216 } finally {
Jeff Brown1951ce82013-04-04 22:45:12 -07004217 // Dispose the channel if the input method is not local to this process
4218 // because the remote proxy will get its own copy when unparceled.
4219 if (channel != null && Binder.isProxy(method)) {
Jeff Brownc28867a2013-03-26 15:42:39 -07004220 channel.dispose();
4221 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004222 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004223 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004224 return true;
Jeff Brownc28867a2013-03-26 15:42:39 -07004225 }
Yunfan Chenc02a5ac2020-06-16 01:52:41 +00004226 case MSG_REMOVE_IME_SURFACE: {
4227 try {
4228 if (mEnabledSession != null && mEnabledSession.session != null) {
4229 mEnabledSession.session.removeImeSurface();
4230 }
4231 } catch (RemoteException e) {
4232 }
4233 return true;
4234 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004235 // ---------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004236
Yohei Yukawa19a80a12016-03-14 22:57:37 -07004237 case MSG_START_INPUT: {
Yohei Yukawaf7526b52017-02-11 20:57:10 -08004238 final int missingMethods = msg.arg1;
4239 final boolean restarting = msg.arg2 != 0;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07004240 args = (SomeArgs) msg.obj;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08004241 final IBinder startInputToken = (IBinder) args.arg1;
4242 final SessionState session = (SessionState) args.arg2;
4243 final IInputContext inputContext = (IInputContext) args.arg3;
4244 final EditorInfo editorInfo = (EditorInfo) args.arg4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004245 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004246 setEnabledSessionInMainThread(session);
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08004247 session.method.startInput(startInputToken, inputContext, missingMethods,
Tarandeep Singheadb1392018-11-09 18:15:57 +01004248 editorInfo, restarting, session.client.shouldPreRenderIme);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004249 } catch (RemoteException e) {
4250 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004251 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004252 return true;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07004253 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004255 // ---------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004256
Yohei Yukawa33e81792015-11-17 21:14:42 -08004257 case MSG_UNBIND_CLIENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004258 try {
Yohei Yukawa33e81792015-11-17 21:14:42 -08004259 ((IInputMethodClient)msg.obj).onUnbindMethod(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004260 } catch (RemoteException e) {
4261 // There is nothing interesting about the last client dying.
4262 }
4263 return true;
Yohei Yukawa33e81792015-11-17 21:14:42 -08004264 case MSG_BIND_CLIENT: {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004265 args = (SomeArgs)msg.obj;
Jeff Brown1951ce82013-04-04 22:45:12 -07004266 IInputMethodClient client = (IInputMethodClient)args.arg1;
4267 InputBindResult res = (InputBindResult)args.arg2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004268 try {
Jeff Brown1951ce82013-04-04 22:45:12 -07004269 client.onBindMethod(res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004270 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08004271 Slog.w(TAG, "Client died receiving input method " + args.arg2);
Jeff Brown1951ce82013-04-04 22:45:12 -07004272 } finally {
4273 // Dispose the channel if the input method is not local to this process
4274 // because the remote proxy will get its own copy when unparceled.
4275 if (res.channel != null && Binder.isProxy(client)) {
4276 res.channel.dispose();
4277 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004278 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004279 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004280 return true;
Jeff Brown1951ce82013-04-04 22:45:12 -07004281 }
Dianne Hackborna6e41342012-05-22 16:30:34 -07004282 case MSG_SET_ACTIVE:
4283 try {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08004284 ((ClientState)msg.obj).client.setActive(msg.arg1 != 0, msg.arg2 != 0);
Dianne Hackborna6e41342012-05-22 16:30:34 -07004285 } catch (RemoteException e) {
4286 Slog.w(TAG, "Got RemoteException sending setActive(false) notification to pid "
4287 + ((ClientState)msg.obj).pid + " uid "
4288 + ((ClientState)msg.obj).uid);
4289 }
4290 return true;
Ming-Shin Lu2c6e80b2020-05-13 00:12:26 +08004291 case MSG_SET_INTERACTIVE:
4292 handleSetInteractive(msg.arg1 != 0);
4293 return true;
Yohei Yukawa2bc66172017-02-08 11:13:25 -08004294 case MSG_REPORT_FULLSCREEN_MODE: {
4295 final boolean fullscreen = msg.arg1 != 0;
4296 final ClientState clientState = (ClientState)msg.obj;
4297 try {
4298 clientState.client.reportFullscreenMode(fullscreen);
4299 } catch (RemoteException e) {
4300 Slog.w(TAG, "Got RemoteException sending "
4301 + "reportFullscreen(" + fullscreen + ") notification to pid="
4302 + clientState.pid + " uid=" + clientState.uid);
4303 }
4304 return true;
4305 }
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08004306 case MSG_REPORT_PRE_RENDERED: {
4307 args = (SomeArgs) msg.obj;
4308 final EditorInfo info = (EditorInfo) args.arg1;
4309 final ClientState clientState = (ClientState) args.arg2;
4310 try {
4311 clientState.client.reportPreRendered(info);
4312 } catch (RemoteException e) {
4313 Slog.w(TAG, "Got RemoteException sending "
4314 + "reportPreRendered(" + info + ") notification to pid="
4315 + clientState.pid + " uid=" + clientState.uid);
4316 }
4317 args.recycle();
4318 return true;
4319 }
4320 case MSG_APPLY_IME_VISIBILITY: {
4321 final boolean setVisible = msg.arg1 != 0;
4322 final ClientState clientState = (ClientState) msg.obj;
4323 try {
4324 clientState.client.applyImeVisibility(setVisible);
4325 } catch (RemoteException e) {
4326 Slog.w(TAG, "Got RemoteException sending "
4327 + "applyImeVisibility(" + setVisible + ") notification to pid="
4328 + clientState.pid + " uid=" + clientState.uid);
4329 }
4330 return true;
4331 }
satok01038492012-04-09 21:08:27 +09004332
4333 // --------------------------------------------------------------
4334 case MSG_HARD_KEYBOARD_SWITCH_CHANGED:
Michael Wright7b5a96b2014-08-09 19:28:42 -07004335 mHardKeyboardListener.handleHardKeyboardStatusChange(msg.arg1 == 1);
satok01038492012-04-09 21:08:27 +09004336 return true;
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +09004337 case MSG_SYSTEM_UNLOCK_USER: {
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07004338 final int userId = msg.arg1;
4339 onUnlockUser(userId);
4340 return true;
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +09004341 }
4342 case MSG_DISPATCH_ON_INPUT_METHOD_LIST_UPDATED: {
4343 final int userId = msg.arg1;
4344 final List<InputMethodInfo> imes = (List<InputMethodInfo>) msg.obj;
4345 mInputMethodListListeners.forEach(
4346 listener -> listener.onInputMethodListUpdated(imes, userId));
4347 return true;
4348 }
Adam Hebc67f2e2019-11-13 14:34:56 -08004349
4350 // ---------------------------------------------------------------
Yohei Yukawa6e9768e2020-05-14 18:14:24 -07004351 case MSG_INLINE_SUGGESTIONS_REQUEST: {
Adam Hebc67f2e2019-11-13 14:34:56 -08004352 args = (SomeArgs) msg.obj;
Feng Cao36960ee2020-02-18 18:23:30 -08004353 final InlineSuggestionsRequestInfo requestInfo =
4354 (InlineSuggestionsRequestInfo) args.arg2;
Adam Hebc67f2e2019-11-13 14:34:56 -08004355 final IInlineSuggestionsRequestCallback callback =
Feng Cao36960ee2020-02-18 18:23:30 -08004356 (IInlineSuggestionsRequestCallback) args.arg3;
Adam Hebc67f2e2019-11-13 14:34:56 -08004357 try {
Feng Cao36960ee2020-02-18 18:23:30 -08004358 ((IInputMethod) args.arg1).onCreateInlineSuggestionsRequest(requestInfo,
4359 callback);
Adam Hebc67f2e2019-11-13 14:34:56 -08004360 } catch (RemoteException e) {
4361 Slog.w(TAG, "RemoteException calling onCreateInlineSuggestionsRequest(): " + e);
4362 }
Yohei Yukawa6e9768e2020-05-14 18:14:24 -07004363 args.recycle();
Adam Hebc67f2e2019-11-13 14:34:56 -08004364 return true;
Yohei Yukawa6e9768e2020-05-14 18:14:24 -07004365 }
Yohei Yukawad5f402b2020-05-15 10:23:32 -07004366
4367 // ---------------------------------------------------------------
4368 case MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE: {
4369 if (mAudioManagerInternal == null) {
4370 mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
4371 }
4372 if (mAudioManagerInternal != null) {
4373 mAudioManagerInternal.setInputMethodServiceUid(msg.arg1 /* uid */);
4374 }
4375 return true;
4376 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004377 }
4378 return false;
4379 }
4380
Ming-Shin Lu2c6e80b2020-05-13 00:12:26 +08004381 private void handleSetInteractive(final boolean interactive) {
4382 synchronized (mMethodMap) {
4383 mIsInteractive = interactive;
4384 updateSystemUiLocked(interactive ? mImeWindowVis : 0, mBackDisposition);
4385
4386 // Inform the current client of the change in active status
4387 if (mCurClient != null && mCurClient.client != null) {
4388 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
4389 MSG_SET_ACTIVE, mIsInteractive ? 1 : 0, mInFullscreenMode ? 1 : 0,
4390 mCurClient));
4391 }
4392 }
4393 }
4394
satokdc9ddae2011-10-06 12:22:36 +09004395 private boolean chooseNewDefaultIMELocked() {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004396 final InputMethodInfo imi = InputMethodUtils.getMostApplicableDefaultIME(
4397 mSettings.getEnabledInputMethodListLocked());
satokdc9ddae2011-10-06 12:22:36 +09004398 if (imi != null) {
satok03eb319a2010-11-11 18:17:42 +09004399 if (DEBUG) {
4400 Slog.d(TAG, "New default IME was selected: " + imi.getId());
4401 }
satok723a27e2010-11-11 14:58:11 +09004402 resetSelectedInputMethodAndSubtypeLocked(imi.getId());
Brandon Ballinger6da35a02009-10-21 00:38:13 -07004403 return true;
4404 }
4405
4406 return false;
4407 }
4408
Yohei Yukawa05139322018-12-25 10:34:14 -08004409 static void queryInputMethodServicesInternal(Context context,
4410 @UserIdInt int userId, ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap,
4411 ArrayMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList) {
4412 methodList.clear();
4413 methodMap.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004414
Yohei Yukawaed4952a2016-02-17 07:57:25 -08004415 // Note: We do not specify PackageManager.MATCH_ENCRYPTION_* flags here because the default
4416 // behavior of PackageManager is exactly what we want. It by default picks up appropriate
4417 // services depending on the unlock state for the specified user.
Yohei Yukawa05139322018-12-25 10:34:14 -08004418 final List<ResolveInfo> services = context.getPackageManager().queryIntentServicesAsUser(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004419 new Intent(InputMethod.SERVICE_INTERFACE),
Yohei Yukawa5ec1fce2018-12-17 07:56:14 -08004420 PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS,
Yohei Yukawa05139322018-12-25 10:34:14 -08004421 userId);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004422
Yohei Yukawa05139322018-12-25 10:34:14 -08004423 methodList.ensureCapacity(services.size());
4424 methodMap.ensureCapacity(services.size());
4425
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004426 for (int i = 0; i < services.size(); ++i) {
4427 ResolveInfo ri = services.get(i);
4428 ServiceInfo si = ri.serviceInfo;
Yohei Yukawaddad4b92017-02-02 01:46:13 -08004429 final String imeId = InputMethodInfo.computeId(ri);
4430 if (!android.Manifest.permission.BIND_INPUT_METHOD.equals(si.permission)) {
4431 Slog.w(TAG, "Skipping input method " + imeId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004432 + ": it does not require the permission "
4433 + android.Manifest.permission.BIND_INPUT_METHOD);
4434 continue;
4435 }
4436
Yohei Yukawaddad4b92017-02-02 01:46:13 -08004437 if (DEBUG) Slog.d(TAG, "Checking " + imeId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004438
4439 try {
Yohei Yukawa05139322018-12-25 10:34:14 -08004440 final InputMethodInfo imi = new InputMethodInfo(context, ri,
4441 additionalSubtypeMap.get(imeId));
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08004442 if (imi.isVrOnly()) {
4443 continue; // Skip VR-only IME, which isn't supported for now.
4444 }
Yohei Yukawa05139322018-12-25 10:34:14 -08004445 methodList.add(imi);
4446 methodMap.put(imi.getId(), imi);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004447 if (DEBUG) {
Yohei Yukawa05139322018-12-25 10:34:14 -08004448 Slog.d(TAG, "Found an input method " + imi);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004449 }
Tadashi G. Takaoka3c23d5b2016-09-16 11:41:07 +09004450 } catch (Exception e) {
Yohei Yukawaddad4b92017-02-02 01:46:13 -08004451 Slog.wtf(TAG, "Unable to load input method " + imeId, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004452 }
4453 }
Yohei Yukawa05139322018-12-25 10:34:14 -08004454 }
4455
4456 @GuardedBy("mMethodMap")
4457 void buildInputMethodListLocked(boolean resetDefaultEnabledIme) {
4458 if (DEBUG) {
4459 Slog.d(TAG, "--- re-buildInputMethodList reset = " + resetDefaultEnabledIme
4460 + " \n ------ caller=" + Debug.getCallers(10));
4461 }
4462 if (!mSystemReady) {
4463 Slog.e(TAG, "buildInputMethodListLocked is not allowed until system is ready");
4464 return;
4465 }
4466 mMethodMapUpdateCount++;
4467 mMyPackageMonitor.clearKnownImePackageNamesLocked();
4468
4469 queryInputMethodServicesInternal(mContext, mSettings.getCurrentUserId(),
Yohei Yukawab557d572018-12-29 21:26:26 -08004470 mAdditionalSubtypeMap, mMethodMap, mMethodList);
Brandon Ballinger6da35a02009-10-21 00:38:13 -07004471
Yohei Yukawac4e44912017-02-09 19:30:22 -08004472 // Construct the set of possible IME packages for onPackageChanged() to avoid false
4473 // negatives when the package state remains to be the same but only the component state is
4474 // changed.
4475 {
4476 // Here we intentionally use PackageManager.MATCH_DISABLED_COMPONENTS since the purpose
4477 // of this query is to avoid false negatives. PackageManager.MATCH_ALL could be more
4478 // conservative, but it seems we cannot use it for now (Issue 35176630).
Yohei Yukawa05139322018-12-25 10:34:14 -08004479 final List<ResolveInfo> allInputMethodServices =
4480 mContext.getPackageManager().queryIntentServicesAsUser(
4481 new Intent(InputMethod.SERVICE_INTERFACE),
4482 PackageManager.MATCH_DISABLED_COMPONENTS, mSettings.getCurrentUserId());
Yohei Yukawac4e44912017-02-09 19:30:22 -08004483 final int N = allInputMethodServices.size();
4484 for (int i = 0; i < N; ++i) {
4485 final ServiceInfo si = allInputMethodServices.get(i).serviceInfo;
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08004486 if (android.Manifest.permission.BIND_INPUT_METHOD.equals(si.permission)) {
4487 mMyPackageMonitor.addKnownImePackageNameLocked(si.packageName);
Yohei Yukawac4e44912017-02-09 19:30:22 -08004488 }
Yohei Yukawac4e44912017-02-09 19:30:22 -08004489 }
4490 }
4491
Yohei Yukawa9c372192018-03-20 22:54:56 -07004492 boolean reenableMinimumNonAuxSystemImes = false;
Yohei Yukawa859df052016-02-17 07:56:46 -08004493 // TODO: The following code should find better place to live.
4494 if (!resetDefaultEnabledIme) {
4495 boolean enabledImeFound = false;
Yohei Yukawa9c372192018-03-20 22:54:56 -07004496 boolean enabledNonAuxImeFound = false;
Yohei Yukawa859df052016-02-17 07:56:46 -08004497 final List<InputMethodInfo> enabledImes = mSettings.getEnabledInputMethodListLocked();
4498 final int N = enabledImes.size();
4499 for (int i = 0; i < N; ++i) {
4500 final InputMethodInfo imi = enabledImes.get(i);
4501 if (mMethodList.contains(imi)) {
4502 enabledImeFound = true;
Yohei Yukawa9c372192018-03-20 22:54:56 -07004503 if (!imi.isAuxiliaryIme()) {
4504 enabledNonAuxImeFound = true;
4505 break;
4506 }
Yohei Yukawa859df052016-02-17 07:56:46 -08004507 }
4508 }
4509 if (!enabledImeFound) {
Yohei Yukawad0332832017-02-01 13:59:43 -08004510 if (DEBUG) {
4511 Slog.i(TAG, "All the enabled IMEs are gone. Reset default enabled IMEs.");
4512 }
Yohei Yukawa859df052016-02-17 07:56:46 -08004513 resetDefaultEnabledIme = true;
4514 resetSelectedInputMethodAndSubtypeLocked("");
Yohei Yukawa9c372192018-03-20 22:54:56 -07004515 } else if (!enabledNonAuxImeFound) {
4516 if (DEBUG) {
4517 Slog.i(TAG, "All the enabled non-Aux IMEs are gone. Do partial reset.");
4518 }
4519 reenableMinimumNonAuxSystemImes = true;
Yohei Yukawa859df052016-02-17 07:56:46 -08004520 }
4521 }
4522
Yohei Yukawa9c372192018-03-20 22:54:56 -07004523 if (resetDefaultEnabledIme || reenableMinimumNonAuxSystemImes) {
Satoshi Kataokaf1367b72013-01-25 17:20:12 +09004524 final ArrayList<InputMethodInfo> defaultEnabledIme =
Yohei Yukawa9c372192018-03-20 22:54:56 -07004525 InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList,
4526 reenableMinimumNonAuxSystemImes);
Yohei Yukawa68645a62016-02-17 07:54:20 -08004527 final int N = defaultEnabledIme.size();
4528 for (int i = 0; i < N; ++i) {
Satoshi Kataokaf1367b72013-01-25 17:20:12 +09004529 final InputMethodInfo imi = defaultEnabledIme.get(i);
4530 if (DEBUG) {
4531 Slog.d(TAG, "--- enable ime = " + imi);
4532 }
4533 setInputMethodEnabledLocked(imi.getId(), true);
4534 }
4535 }
4536
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004537 final String defaultImiId = mSettings.getSelectedInputMethod();
satok0a1bcf42012-05-16 19:26:31 +09004538 if (!TextUtils.isEmpty(defaultImiId)) {
Yohei Yukawa94e33302016-02-12 19:37:03 -08004539 if (!mMethodMap.containsKey(defaultImiId)) {
satok0a1bcf42012-05-16 19:26:31 +09004540 Slog.w(TAG, "Default IME is uninstalled. Choose new default IME.");
4541 if (chooseNewDefaultIMELocked()) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07004542 updateInputMethodsFromSettingsLocked(true);
satok0a1bcf42012-05-16 19:26:31 +09004543 }
4544 } else {
4545 // Double check that the default IME is certainly enabled.
4546 setInputMethodEnabledLocked(defaultImiId, true);
Brandon Ballinger6da35a02009-10-21 00:38:13 -07004547 }
4548 }
Yohei Yukawa3d46bab2014-05-30 18:10:18 +09004549 // Here is not the perfect place to reset the switching controller. Ideally
4550 // mSwitchingController and mSettings should be able to share the same state.
4551 // TODO: Make sure that mSwitchingController and mSettings are sharing the
4552 // the same enabled IMEs list.
Yohei Yukawac834a252014-05-21 22:42:32 +09004553 mSwitchingController.resetCircularListLocked(mContext);
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +09004554
4555 // Notify InputMethodListListeners of the new installed InputMethods.
4556 final List<InputMethodInfo> inputMethodList = new ArrayList<>(mMethodList);
4557 mHandler.obtainMessage(MSG_DISPATCH_ON_INPUT_METHOD_LIST_UPDATED,
4558 mSettings.getCurrentUserId(), 0 /* unused */, inputMethodList).sendToTarget();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004559 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004560
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004561 // ----------------------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004562
satok217f5482010-12-15 05:19:19 +09004563 private void showInputMethodAndSubtypeEnabler(String inputMethodId) {
Tadashi G. Takaokaf49688f2011-01-20 17:56:13 +09004564 Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS);
satok47a44912010-10-06 16:03:58 +09004565 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
satok86417ea2010-10-27 14:11:03 +09004566 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
4567 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
satok7fee71f2010-12-17 18:54:26 +09004568 if (!TextUtils.isEmpty(inputMethodId)) {
Tadashi G. Takaoka25480202011-01-20 23:13:02 +09004569 intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, inputMethodId);
satok7fee71f2010-12-17 18:54:26 +09004570 }
Yohei Yukawa41f34272015-12-14 15:41:52 -08004571 final int userId;
4572 synchronized (mMethodMap) {
4573 userId = mSettings.getCurrentUserId();
4574 }
4575 mContext.startActivityAsUser(intent, null, UserHandle.of(userId));
satok217f5482010-12-15 05:19:19 +09004576 }
4577
4578 private void showConfigureInputMethods() {
4579 Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS);
4580 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
4581 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
4582 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
Satoshi Kataoka3ba439d2012-10-05 18:30:13 +09004583 mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
satok47a44912010-10-06 16:03:58 +09004584 }
4585
satok2c93efc2012-04-02 19:33:47 +09004586 private boolean isScreenLocked() {
4587 return mKeyguardManager != null
4588 && mKeyguardManager.isKeyguardLocked() && mKeyguardManager.isKeyguardSecure();
4589 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004590
lumark0b05f9e2018-11-26 15:09:06 +08004591 private void showInputMethodMenu(boolean showAuxSubtypes, int displayId) {
Seigo Nonaka14e13912015-05-06 21:04:13 -07004592 if (DEBUG) Slog.v(TAG, "Show switching menu. showAuxSubtypes=" + showAuxSubtypes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004593
satok2c93efc2012-04-02 19:33:47 +09004594 final boolean isScreenLocked = isScreenLocked();
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004595
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004596 final String lastInputMethodId = mSettings.getSelectedInputMethod();
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004597 int lastInputMethodSubtypeId = mSettings.getSelectedInputMethodSubtypeId(lastInputMethodId);
Joe Onorato8a9b2202010-02-26 18:56:32 -08004598 if (DEBUG) Slog.v(TAG, "Current IME: " + lastInputMethodId);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004599
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004600 synchronized (mMethodMap) {
Yohei Yukawacf3bbff2018-11-20 17:24:20 -08004601 final List<ImeSubtypeListItem> imList =
4602 mSwitchingController.getSortedInputMethodAndSubtypeListLocked(
4603 showAuxSubtypes, isScreenLocked);
4604 if (imList.isEmpty()) {
satok7f35c8c2010-10-07 21:13:11 +09004605 return;
4606 }
4607
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004608 hideInputMethodMenuLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004609
satokc3690562012-01-10 20:14:43 +09004610 if (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004611 final InputMethodSubtype currentSubtype = getCurrentInputMethodSubtypeLocked();
satokc3690562012-01-10 20:14:43 +09004612 if (currentSubtype != null) {
4613 final InputMethodInfo currentImi = mMethodMap.get(mCurMethodId);
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004614 lastInputMethodSubtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
4615 currentImi, currentSubtype.hashCode());
satokc3690562012-01-10 20:14:43 +09004616 }
4617 }
4618
Ken Wakasa761eb372011-03-04 19:06:18 +09004619 final int N = imList.size();
satokab751aa2010-09-14 19:17:36 +09004620 mIms = new InputMethodInfo[N];
4621 mSubtypeIds = new int[N];
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004622 int checkedItem = 0;
4623 for (int i = 0; i < N; ++i) {
Ken Wakasa05dbb652011-08-22 15:22:43 +09004624 final ImeSubtypeListItem item = imList.get(i);
4625 mIms[i] = item.mImi;
4626 mSubtypeIds[i] = item.mSubtypeId;
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004627 if (mIms[i].getId().equals(lastInputMethodId)) {
satokab751aa2010-09-14 19:17:36 +09004628 int subtypeId = mSubtypeIds[i];
4629 if ((subtypeId == NOT_A_SUBTYPE_ID)
4630 || (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID && subtypeId == 0)
4631 || (subtypeId == lastInputMethodSubtypeId)) {
4632 checkedItem = i;
4633 }
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004634 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004635 }
Alan Viverette505e3ab2014-11-24 15:22:11 -08004636
lumark0b05f9e2018-11-26 15:09:06 +08004637 final ActivityThread currentThread = ActivityThread.currentActivityThread();
Andrew Sapperstein8a3b4cb2017-04-28 14:35:31 -07004638 final Context settingsContext = new ContextThemeWrapper(
lumark0b05f9e2018-11-26 15:09:06 +08004639 displayId == DEFAULT_DISPLAY ? currentThread.getSystemUiContext()
4640 : currentThread.createSystemUiContext(displayId),
Alan Viverette505e3ab2014-11-24 15:22:11 -08004641 com.android.internal.R.style.Theme_DeviceDefault_Settings);
4642
4643 mDialogBuilder = new AlertDialog.Builder(settingsContext);
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004644 mDialogBuilder.setOnCancelListener(new OnCancelListener() {
4645 @Override
4646 public void onCancel(DialogInterface dialog) {
4647 hideInputMethodMenu();
4648 }
4649 });
Alan Viverette505e3ab2014-11-24 15:22:11 -08004650
4651 final Context dialogContext = mDialogBuilder.getContext();
4652 final TypedArray a = dialogContext.obtainStyledAttributes(null,
4653 com.android.internal.R.styleable.DialogPreference,
4654 com.android.internal.R.attr.alertDialogStyle, 0);
4655 final Drawable dialogIcon = a.getDrawable(
4656 com.android.internal.R.styleable.DialogPreference_dialogIcon);
4657 a.recycle();
4658
4659 mDialogBuilder.setIcon(dialogIcon);
4660
Yohei Yukawad34e1482016-02-11 08:03:52 -08004661 final LayoutInflater inflater = dialogContext.getSystemService(LayoutInflater.class);
satok01038492012-04-09 21:08:27 +09004662 final View tv = inflater.inflate(
4663 com.android.internal.R.layout.input_method_switch_dialog_title, null);
4664 mDialogBuilder.setCustomTitle(tv);
4665
4666 // Setup layout for a toggle switch of the hardware keyboard
4667 mSwitchingDialogTitleView = tv;
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004668 mSwitchingDialogTitleView
4669 .findViewById(com.android.internal.R.id.hard_keyboard_section)
Seigo Nonaka7309b122015-08-17 18:34:13 -07004670 .setVisibility(mWindowManagerInternal.isHardKeyboardAvailable()
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004671 ? View.VISIBLE : View.GONE);
Alan Viverette505e3ab2014-11-24 15:22:11 -08004672 final Switch hardKeySwitch = (Switch) mSwitchingDialogTitleView.findViewById(
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004673 com.android.internal.R.id.hard_keyboard_switch);
Michael Wright7b5a96b2014-08-09 19:28:42 -07004674 hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004675 hardKeySwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
4676 @Override
4677 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07004678 mSettings.setShowImeWithHardKeyboard(isChecked);
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004679 // Ensure that the input method dialog is dismissed when changing
4680 // the hardware keyboard state.
4681 hideInputMethodMenu();
4682 }
4683 });
4684
Alan Viverette505e3ab2014-11-24 15:22:11 -08004685 final ImeSubtypeListAdapter adapter = new ImeSubtypeListAdapter(dialogContext,
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004686 com.android.internal.R.layout.input_method_switch_item, imList, checkedItem);
4687 final OnClickListener choiceListener = new OnClickListener() {
4688 @Override
4689 public void onClick(final DialogInterface dialog, final int which) {
4690 synchronized (mMethodMap) {
4691 if (mIms == null || mIms.length <= which || mSubtypeIds == null
4692 || mSubtypeIds.length <= which) {
4693 return;
satok01038492012-04-09 21:08:27 +09004694 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004695 final InputMethodInfo im = mIms[which];
4696 int subtypeId = mSubtypeIds[which];
4697 adapter.mCheckedItem = which;
4698 adapter.notifyDataSetChanged();
4699 hideInputMethodMenu();
4700 if (im != null) {
4701 if (subtypeId < 0 || subtypeId >= im.getSubtypeCount()) {
4702 subtypeId = NOT_A_SUBTYPE_ID;
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08004703 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004704 setInputMethodLocked(im.getId(), subtypeId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004705 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004706 }
4707 }
4708 };
4709 mDialogBuilder.setSingleChoiceItems(adapter, checkedItem, choiceListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004710
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004711 mSwitchingDialog = mDialogBuilder.create();
Dianne Hackborne3a7f622011-03-03 21:48:24 -08004712 mSwitchingDialog.setCanceledOnTouchOutside(true);
Wale Ogunwale3a931692016-11-02 16:49:48 -07004713 final Window w = mSwitchingDialog.getWindow();
Yohei Yukawa6e875592019-01-28 00:49:30 -08004714 final LayoutParams attrs = w.getAttributes();
4715 w.setType(LayoutParams.TYPE_INPUT_METHOD_DIALOG);
Wale Ogunwale3a931692016-11-02 16:49:48 -07004716 // Use an alternate token for the dialog for that window manager can group the token
4717 // with other IME windows based on type vs. grouping based on whichever token happens
4718 // to get selected by the system later on.
4719 attrs.token = mSwitchingDialogToken;
Roshan Piusa3f89c62019-10-11 08:50:53 -07004720 attrs.privateFlags |= LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
Wale Ogunwale3a931692016-11-02 16:49:48 -07004721 attrs.setTitle("Select input method");
4722 w.setAttributes(attrs);
Yohei Yukawa849443c2019-01-21 09:02:25 -08004723 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004724 mSwitchingDialog.show();
4725 }
4726 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004727
Ken Wakasa05dbb652011-08-22 15:22:43 +09004728 private static class ImeSubtypeListAdapter extends ArrayAdapter<ImeSubtypeListItem> {
4729 private final LayoutInflater mInflater;
4730 private final int mTextViewResourceId;
4731 private final List<ImeSubtypeListItem> mItemsList;
Satoshi Kataokad2142962012-11-12 18:43:06 +09004732 public int mCheckedItem;
Ken Wakasa05dbb652011-08-22 15:22:43 +09004733 public ImeSubtypeListAdapter(Context context, int textViewResourceId,
4734 List<ImeSubtypeListItem> itemsList, int checkedItem) {
4735 super(context, textViewResourceId, itemsList);
Alan Viverette505e3ab2014-11-24 15:22:11 -08004736
Ken Wakasa05dbb652011-08-22 15:22:43 +09004737 mTextViewResourceId = textViewResourceId;
4738 mItemsList = itemsList;
4739 mCheckedItem = checkedItem;
Yohei Yukawad34e1482016-02-11 08:03:52 -08004740 mInflater = context.getSystemService(LayoutInflater.class);
Ken Wakasa05dbb652011-08-22 15:22:43 +09004741 }
4742
4743 @Override
4744 public View getView(int position, View convertView, ViewGroup parent) {
4745 final View view = convertView != null ? convertView
4746 : mInflater.inflate(mTextViewResourceId, null);
4747 if (position < 0 || position >= mItemsList.size()) return view;
4748 final ImeSubtypeListItem item = mItemsList.get(position);
4749 final CharSequence imeName = item.mImeName;
4750 final CharSequence subtypeName = item.mSubtypeName;
4751 final TextView firstTextView = (TextView)view.findViewById(android.R.id.text1);
4752 final TextView secondTextView = (TextView)view.findViewById(android.R.id.text2);
4753 if (TextUtils.isEmpty(subtypeName)) {
4754 firstTextView.setText(imeName);
4755 secondTextView.setVisibility(View.GONE);
4756 } else {
4757 firstTextView.setText(subtypeName);
4758 secondTextView.setText(imeName);
4759 secondTextView.setVisibility(View.VISIBLE);
4760 }
4761 final RadioButton radioButton =
4762 (RadioButton)view.findViewById(com.android.internal.R.id.radio);
4763 radioButton.setChecked(position == mCheckedItem);
4764 return view;
4765 }
4766 }
4767
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004768 void hideInputMethodMenu() {
The Android Open Source Project10592532009-03-18 17:39:46 -07004769 synchronized (mMethodMap) {
4770 hideInputMethodMenuLocked();
4771 }
4772 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004773
The Android Open Source Project10592532009-03-18 17:39:46 -07004774 void hideInputMethodMenuLocked() {
Joe Onorato8a9b2202010-02-26 18:56:32 -08004775 if (DEBUG) Slog.v(TAG, "Hide switching menu");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004776
The Android Open Source Project10592532009-03-18 17:39:46 -07004777 if (mSwitchingDialog != null) {
4778 mSwitchingDialog.dismiss();
4779 mSwitchingDialog = null;
Yohei Yukawa1fc7a1d2018-04-18 17:31:27 -07004780 mSwitchingDialogTitleView = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004781 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004782
Yohei Yukawa849443c2019-01-21 09:02:25 -08004783 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
The Android Open Source Project10592532009-03-18 17:39:46 -07004784 mDialogBuilder = null;
The Android Open Source Project10592532009-03-18 17:39:46 -07004785 mIms = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004786 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004787
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004788 // ----------------------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004789
Yohei Yukawa3d3abd22019-04-09 23:20:12 -07004790 /**
4791 * Enable or disable the given IME by updating {@link Settings.Secure#ENABLED_INPUT_METHODS}.
4792 *
4793 * @param id ID of the IME is to be manipulated. It is OK to pass IME ID that is currently not
4794 * recognized by the system.
4795 * @param enabled {@code true} if {@code id} needs to be enabled.
4796 * @return {@code true} if the IME was previously enabled. {@code false} otherwise.
4797 */
4798 private boolean setInputMethodEnabledLocked(String id, boolean enabled) {
satokd87c2592010-09-29 11:52:06 +09004799 List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings
4800 .getEnabledInputMethodsAndSubtypeListLocked();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004801
satokd87c2592010-09-29 11:52:06 +09004802 if (enabled) {
4803 for (Pair<String, ArrayList<String>> pair: enabledInputMethodsList) {
4804 if (pair.first.equals(id)) {
4805 // We are enabling this input method, but it is already enabled.
4806 // Nothing to do. The previous state was enabled.
4807 return true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004808 }
4809 }
satokd87c2592010-09-29 11:52:06 +09004810 mSettings.appendAndPutEnabledInputMethodLocked(id, false);
4811 // Previous state was disabled.
4812 return false;
4813 } else {
4814 StringBuilder builder = new StringBuilder();
4815 if (mSettings.buildAndPutEnabledInputMethodsStrRemovingIdLocked(
4816 builder, enabledInputMethodsList, id)) {
4817 // Disabled input method is currently selected, switch to another one.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004818 final String selId = mSettings.getSelectedInputMethod();
satok03eb319a2010-11-11 18:17:42 +09004819 if (id.equals(selId) && !chooseNewDefaultIMELocked()) {
4820 Slog.i(TAG, "Can't find new IME, unsetting the current input method.");
4821 resetSelectedInputMethodAndSubtypeLocked("");
satokd87c2592010-09-29 11:52:06 +09004822 }
4823 // Previous state was enabled.
4824 return true;
4825 } else {
4826 // We are disabling the input method but it is already disabled.
4827 // Nothing to do. The previous state was disabled.
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004828 return false;
4829 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004830 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004831 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08004832
satok723a27e2010-11-11 14:58:11 +09004833 private void setSelectedInputMethodAndSubtypeLocked(InputMethodInfo imi, int subtypeId,
4834 boolean setSubtypeOnly) {
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08004835 mSettings.saveCurrentInputMethodAndSubtypeToHistory(mCurMethodId, mCurrentSubtype);
Tarandeep Singh89a6c482017-11-21 14:26:11 -08004836
satok723a27e2010-11-11 14:58:11 +09004837 // Set Subtype here
4838 if (imi == null || subtypeId < 0) {
4839 mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
Tadashi G. Takaoka0ba75bb2010-11-09 12:19:32 -08004840 mCurrentSubtype = null;
satok723a27e2010-11-11 14:58:11 +09004841 } else {
Ken Wakasa586f0512011-01-20 22:31:01 +09004842 if (subtypeId < imi.getSubtypeCount()) {
4843 InputMethodSubtype subtype = imi.getSubtypeAt(subtypeId);
4844 mSettings.putSelectedSubtype(subtype.hashCode());
4845 mCurrentSubtype = subtype;
satok723a27e2010-11-11 14:58:11 +09004846 } else {
4847 mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
satokd81e9502012-05-21 12:58:45 +09004848 // If the subtype is not specified, choose the most applicable one
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004849 mCurrentSubtype = getCurrentInputMethodSubtypeLocked();
satok723a27e2010-11-11 14:58:11 +09004850 }
satokab751aa2010-09-14 19:17:36 +09004851 }
satok723a27e2010-11-11 14:58:11 +09004852
Yohei Yukawa68645a62016-02-17 07:54:20 -08004853 if (!setSubtypeOnly) {
satok723a27e2010-11-11 14:58:11 +09004854 // Set InputMethod here
4855 mSettings.putSelectedInputMethod(imi != null ? imi.getId() : "");
4856 }
4857 }
4858
4859 private void resetSelectedInputMethodAndSubtypeLocked(String newDefaultIme) {
4860 InputMethodInfo imi = mMethodMap.get(newDefaultIme);
4861 int lastSubtypeId = NOT_A_SUBTYPE_ID;
4862 // newDefaultIme is empty when there is no candidate for the selected IME.
4863 if (imi != null && !TextUtils.isEmpty(newDefaultIme)) {
4864 String subtypeHashCode = mSettings.getLastSubtypeForInputMethodLocked(newDefaultIme);
4865 if (subtypeHashCode != null) {
4866 try {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004867 lastSubtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
Narayan Kamatha09b4d22016-04-15 18:32:45 +01004868 imi, Integer.parseInt(subtypeHashCode));
satok723a27e2010-11-11 14:58:11 +09004869 } catch (NumberFormatException e) {
4870 Slog.w(TAG, "HashCode for subtype looks broken: " + subtypeHashCode, e);
4871 }
4872 }
4873 }
4874 setSelectedInputMethodAndSubtypeLocked(imi, lastSubtypeId, false);
satokab751aa2010-09-14 19:17:36 +09004875 }
4876
satokab751aa2010-09-14 19:17:36 +09004877 /**
4878 * @return Return the current subtype of this input method.
4879 */
satok42c5a162011-05-26 16:46:14 +09004880 @Override
satokab751aa2010-09-14 19:17:36 +09004881 public InputMethodSubtype getCurrentInputMethodSubtype() {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004882 synchronized (mMethodMap) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08004883 // TODO: Make this work even for non-current users?
Yohei Yukawa46d74762019-01-22 10:17:22 -08004884 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08004885 return null;
4886 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004887 return getCurrentInputMethodSubtypeLocked();
4888 }
4889 }
4890
4891 private InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
satokfdf419e2012-05-08 16:52:08 +09004892 if (mCurMethodId == null) {
4893 return null;
4894 }
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004895 final boolean subtypeIsSelected = mSettings.isSubtypeSelected();
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004896 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
4897 if (imi == null || imi.getSubtypeCount() == 0) {
4898 return null;
satok4e4569d2010-11-19 18:45:53 +09004899 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004900 if (!subtypeIsSelected || mCurrentSubtype == null
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004901 || !InputMethodUtils.isValidSubtypeId(imi, mCurrentSubtype.hashCode())) {
4902 int subtypeId = mSettings.getSelectedInputMethodSubtypeId(mCurMethodId);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004903 if (subtypeId == NOT_A_SUBTYPE_ID) {
4904 // If there are no selected subtypes, the framework will try to find
4905 // the most applicable subtype from explicitly or implicitly enabled
4906 // subtypes.
4907 List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypes =
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004908 mSettings.getEnabledInputMethodSubtypeListLocked(mContext, imi, true);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004909 // If there is only one explicitly or implicitly enabled subtype,
4910 // just returns it.
4911 if (explicitlyOrImplicitlyEnabledSubtypes.size() == 1) {
4912 mCurrentSubtype = explicitlyOrImplicitlyEnabledSubtypes.get(0);
4913 } else if (explicitlyOrImplicitlyEnabledSubtypes.size() > 1) {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004914 mCurrentSubtype = InputMethodUtils.findLastResortApplicableSubtypeLocked(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004915 mRes, explicitlyOrImplicitlyEnabledSubtypes,
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004916 InputMethodUtils.SUBTYPE_MODE_KEYBOARD, null, true);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004917 if (mCurrentSubtype == null) {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004918 mCurrentSubtype = InputMethodUtils.findLastResortApplicableSubtypeLocked(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004919 mRes, explicitlyOrImplicitlyEnabledSubtypes, null, null,
4920 true);
satok4e4569d2010-11-19 18:45:53 +09004921 }
satok3ef8b292010-11-23 06:06:29 +09004922 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004923 } else {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004924 mCurrentSubtype = InputMethodUtils.getSubtypes(imi).get(subtypeId);
satok8fbb1e82010-11-02 23:15:58 +09004925 }
4926 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004927 return mCurrentSubtype;
satokab751aa2010-09-14 19:17:36 +09004928 }
4929
Yohei Yukawaa878b952019-01-10 19:36:24 -08004930 private List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
4931 synchronized (mMethodMap) {
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08004932 return getInputMethodListLocked(userId);
Yohei Yukawaa878b952019-01-10 19:36:24 -08004933 }
4934 }
4935
4936 private List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
4937 synchronized (mMethodMap) {
4938 return getEnabledInputMethodListLocked(userId);
4939 }
4940 }
4941
Feng Cao16b2de52020-01-09 17:27:27 -08004942 private void onCreateInlineSuggestionsRequest(@UserIdInt int userId,
Feng Cao36960ee2020-02-18 18:23:30 -08004943 InlineSuggestionsRequestInfo requestInfo,
Feng Cao16b2de52020-01-09 17:27:27 -08004944 IInlineSuggestionsRequestCallback callback) {
Adam Hebc67f2e2019-11-13 14:34:56 -08004945 synchronized (mMethodMap) {
Feng Cao36960ee2020-02-18 18:23:30 -08004946 onCreateInlineSuggestionsRequestLocked(userId, requestInfo, callback);
Adam Hebc67f2e2019-11-13 14:34:56 -08004947 }
4948 }
4949
mincheli850892b2019-12-05 19:47:59 +08004950 private boolean switchToInputMethod(String imeId, @UserIdInt int userId) {
4951 synchronized (mMethodMap) {
4952 if (userId == mSettings.getCurrentUserId()) {
4953 if (!mMethodMap.containsKey(imeId)
4954 || !mSettings.getEnabledInputMethodListLocked()
4955 .contains(mMethodMap.get(imeId))) {
4956 return false; // IME is not is found or not enabled.
4957 }
4958 setInputMethodLocked(imeId, NOT_A_SUBTYPE_ID);
4959 return true;
4960 }
4961 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
4962 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
4963 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
4964 new ArrayMap<>();
4965 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
4966 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
4967 methodMap, methodList);
4968 final InputMethodSettings settings = new InputMethodSettings(
4969 mContext.getResources(), mContext.getContentResolver(), methodMap,
4970 userId, false);
4971 if (!methodMap.containsKey(imeId)
4972 || !settings.getEnabledInputMethodListLocked()
4973 .contains(methodMap.get(imeId))) {
4974 return false; // IME is not is found or not enabled.
4975 }
4976 settings.putSelectedInputMethod(imeId);
4977 settings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
4978 return true;
4979 }
4980 }
4981
lpeter133fce02020-03-05 20:32:16 +08004982 private boolean transferTouchFocusToImeWindow(@NonNull IBinder sourceInputToken,
4983 int displayId) {
4984 //TODO(b/150843766): Check if Input Token is valid.
4985 final IBinder curHostInputToken;
4986 synchronized (mMethodMap) {
4987 if (displayId != mCurTokenDisplayId || mCurHostInputToken == null) {
4988 return false;
4989 }
4990 curHostInputToken = mCurHostInputToken;
4991 }
4992 return mInputManagerInternal.transferTouchFocus(sourceInputToken, curHostInputToken);
4993 }
4994
Yohei Yukawae24ed792018-08-28 19:10:32 -07004995 private static final class LocalServiceImpl extends InputMethodManagerInternal {
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004996 @NonNull
Yohei Yukawafffc0e52018-09-04 13:24:00 -07004997 private final InputMethodManagerService mService;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004998
Yohei Yukawafffc0e52018-09-04 13:24:00 -07004999 LocalServiceImpl(@NonNull InputMethodManagerService service) {
5000 mService = service;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07005001 }
5002
5003 @Override
Ming-Shin Lu2c6e80b2020-05-13 00:12:26 +08005004 public void setInteractive(boolean interactive) {
5005 // Do everything in handler so as not to block the caller.
5006 mService.mHandler.obtainMessage(MSG_SET_INTERACTIVE, interactive ? 1 : 0, 0)
5007 .sendToTarget();
5008 }
5009
5010 @Override
lumarkd85e1582019-12-29 20:20:41 +08005011 public void hideCurrentInputMethod(@SoftInputShowHideReason int reason) {
Yohei Yukawaf16abb72018-09-05 11:28:42 -07005012 mService.mHandler.removeMessages(MSG_HIDE_CURRENT_INPUT_METHOD);
lumarkd85e1582019-12-29 20:20:41 +08005013 mService.mHandler.obtainMessage(MSG_HIDE_CURRENT_INPUT_METHOD, reason).sendToTarget();
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -07005014 }
Tarandeep Singh89a6c482017-11-21 14:26:11 -08005015
5016 @Override
Yohei Yukawaa878b952019-01-10 19:36:24 -08005017 public List<InputMethodInfo> getInputMethodListAsUser(int userId) {
5018 return mService.getInputMethodListAsUser(userId);
5019 }
5020
5021 @Override
5022 public List<InputMethodInfo> getEnabledInputMethodListAsUser(int userId) {
5023 return mService.getEnabledInputMethodListAsUser(userId);
5024 }
Adam Hebc67f2e2019-11-13 14:34:56 -08005025
5026 @Override
Feng Cao36960ee2020-02-18 18:23:30 -08005027 public void onCreateInlineSuggestionsRequest(int userId,
5028 InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback cb) {
5029 mService.onCreateInlineSuggestionsRequest(userId, requestInfo, cb);
Adam Hebc67f2e2019-11-13 14:34:56 -08005030 }
mincheli850892b2019-12-05 19:47:59 +08005031
5032 @Override
5033 public boolean switchToInputMethod(String imeId, int userId) {
5034 return mService.switchToInputMethod(imeId, userId);
5035 }
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +09005036
5037 @Override
5038 public void registerInputMethodListListener(InputMethodListListener listener) {
5039 mService.mInputMethodListListeners.addIfAbsent(listener);
5040 }
lpeter133fce02020-03-05 20:32:16 +08005041
5042 @Override
5043 public boolean transferTouchFocusToImeWindow(@NonNull IBinder sourceInputToken,
5044 int displayId) {
5045 return mService.transferTouchFocusToImeWindow(sourceInputToken, displayId);
5046 }
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07005047 }
5048
Yohei Yukawac54c1172018-09-06 11:39:50 -07005049 @BinderThread
5050 private IInputContentUriToken createInputContentUriToken(@Nullable IBinder token,
Yohei Yukawa25e08132016-06-22 16:31:41 -07005051 @Nullable Uri contentUri, @Nullable String packageName) {
Yohei Yukawa25e08132016-06-22 16:31:41 -07005052 if (token == null) {
5053 throw new NullPointerException("token");
5054 }
5055 if (packageName == null) {
5056 throw new NullPointerException("packageName");
5057 }
5058 if (contentUri == null) {
5059 throw new NullPointerException("contentUri");
5060 }
5061 final String contentUriScheme = contentUri.getScheme();
5062 if (!"content".equals(contentUriScheme)) {
5063 throw new InvalidParameterException("contentUri must have content scheme");
5064 }
5065
5066 synchronized (mMethodMap) {
5067 final int uid = Binder.getCallingUid();
5068 if (mCurMethodId == null) {
5069 return null;
5070 }
5071 if (mCurToken != token) {
5072 Slog.e(TAG, "Ignoring createInputContentUriToken mCurToken=" + mCurToken
5073 + " token=" + token);
5074 return null;
5075 }
5076 // We cannot simply distinguish a bad IME that reports an arbitrary package name from
5077 // an unfortunate IME whose internal state is already obsolete due to the asynchronous
5078 // nature of our system. Let's compare it with our internal record.
5079 if (!TextUtils.equals(mCurAttribute.packageName, packageName)) {
5080 Slog.e(TAG, "Ignoring createInputContentUriToken mCurAttribute.packageName="
5081 + mCurAttribute.packageName + " packageName=" + packageName);
5082 return null;
5083 }
Yohei Yukawa3933a6e2016-11-10 00:47:48 -08005084 // This user ID can never bee spoofed.
Yohei Yukawa25e08132016-06-22 16:31:41 -07005085 final int imeUserId = UserHandle.getUserId(uid);
Yohei Yukawa3933a6e2016-11-10 00:47:48 -08005086 // This user ID can never bee spoofed.
Yohei Yukawa25e08132016-06-22 16:31:41 -07005087 final int appUserId = UserHandle.getUserId(mCurClient.uid);
Yohei Yukawa3933a6e2016-11-10 00:47:48 -08005088 // This user ID may be invalid if "contentUri" embedded an invalid user ID.
5089 final int contentUriOwnerUserId = ContentProvider.getUserIdFromUri(contentUri,
5090 imeUserId);
5091 final Uri contentUriWithoutUserId = ContentProvider.getUriWithoutUserId(contentUri);
5092 // Note: InputContentUriTokenHandler.take() checks whether the IME (specified by "uid")
5093 // actually has the right to grant a read permission for "contentUriWithoutUserId" that
5094 // is claimed to belong to "contentUriOwnerUserId". For example, specifying random
5095 // content URI and/or contentUriOwnerUserId just results in a SecurityException thrown
5096 // from InputContentUriTokenHandler.take() and can never be allowed beyond what is
5097 // actually allowed to "uid", which is guaranteed to be the IME's one.
5098 return new InputContentUriTokenHandler(contentUriWithoutUserId, uid,
5099 packageName, contentUriOwnerUserId, appUserId);
Yohei Yukawa25e08132016-06-22 16:31:41 -07005100 }
5101 }
5102
Yohei Yukawac54c1172018-09-06 11:39:50 -07005103 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08005104 private void reportFullscreenMode(@NonNull IBinder token, boolean fullscreen) {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08005105 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08005106 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08005107 return;
5108 }
5109 if (mCurClient != null && mCurClient.client != null) {
5110 mInFullscreenMode = fullscreen;
5111 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
5112 MSG_REPORT_FULLSCREEN_MODE, fullscreen ? 1 : 0, mCurClient));
5113 }
5114 }
5115 }
5116
5117 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005118 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06005119 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005120
5121 IInputMethod method;
5122 ClientState client;
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08005123 ClientState focusedWindowClient;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005125 final Printer p = new PrintWriterPrinter(pw);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005126
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005127 synchronized (mMethodMap) {
5128 p.println("Current Input Method Manager state:");
5129 int N = mMethodList.size();
Yohei Yukawa5ec1fce2018-12-17 07:56:14 -08005130 p.println(" Input Methods: mMethodMapUpdateCount=" + mMethodMapUpdateCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005131 for (int i=0; i<N; i++) {
5132 InputMethodInfo info = mMethodList.get(i);
5133 p.println(" InputMethod #" + i + ":");
5134 info.dump(p, " ");
5135 }
5136 p.println(" Clients:");
Yohei Yukawaac9311e2018-11-20 19:25:23 -08005137 final int numClients = mClients.size();
5138 for (int i = 0; i < numClients; ++i) {
5139 final ClientState ci = mClients.valueAt(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005140 p.println(" Client " + ci + ":");
5141 p.println(" client=" + ci.client);
5142 p.println(" inputContext=" + ci.inputContext);
5143 p.println(" sessionRequested=" + ci.sessionRequested);
5144 p.println(" curSession=" + ci.curSession);
5145 }
The Android Open Source Project10592532009-03-18 17:39:46 -07005146 p.println(" mCurMethodId=" + mCurMethodId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005147 client = mCurClient;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07005148 p.println(" mCurClient=" + client + " mCurSeq=" + mCurSeq);
Yohei Yukawa22a89232017-02-12 16:38:59 -08005149 p.println(" mCurFocusedWindow=" + mCurFocusedWindow
5150 + " softInputMode=" +
Yohei Yukawaa468d702018-10-21 11:42:34 -07005151 InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode)
Yohei Yukawa22a89232017-02-12 16:38:59 -08005152 + " client=" + mCurFocusedWindowClient);
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08005153 focusedWindowClient = mCurFocusedWindowClient;
Yohei Yukawad3ef8422018-06-07 16:28:07 -07005154 p.println(" mCurId=" + mCurId + " mHaveConnection=" + mHaveConnection
5155 + " mBoundToMethod=" + mBoundToMethod + " mVisibleBound=" + mVisibleBound);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005156 p.println(" mCurToken=" + mCurToken);
lumark90120a82018-08-15 00:33:03 +08005157 p.println(" mCurTokenDisplayId=" + mCurTokenDisplayId);
lpeter133fce02020-03-05 20:32:16 +08005158 p.println(" mCurHostInputToken=" + mCurHostInputToken);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005159 p.println(" mCurIntent=" + mCurIntent);
5160 method = mCurMethod;
5161 p.println(" mCurMethod=" + mCurMethod);
5162 p.println(" mEnabledSession=" + mEnabledSession);
5163 p.println(" mShowRequested=" + mShowRequested
5164 + " mShowExplicitlyRequested=" + mShowExplicitlyRequested
5165 + " mShowForced=" + mShowForced
5166 + " mInputShown=" + mInputShown);
Yohei Yukawa2bc66172017-02-08 11:13:25 -08005167 p.println(" mInFullscreenMode=" + mInFullscreenMode);
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07005168 p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
Yohei Yukawa81482972015-06-04 00:58:59 -07005169 p.println(" mSettingsObserver=" + mSettingsObserver);
Yohei Yukawad7248862015-06-03 23:56:12 -07005170 p.println(" mSwitchingController:");
5171 mSwitchingController.dump(p);
Yohei Yukawa68645a62016-02-17 07:54:20 -08005172 p.println(" mSettings:");
5173 mSettings.dumpLocked(p, " ");
Yohei Yukawa357b2f62017-02-14 09:40:03 -08005174
5175 p.println(" mStartInputHistory:");
5176 mStartInputHistory.dump(pw, " ");
lumarkd85e1582019-12-29 20:20:41 +08005177
5178 p.println(" mSoftInputShowHideHistory:");
5179 mSoftInputShowHideHistory.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005180 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005181
Jeff Brownb88102f2010-09-08 11:49:43 -07005182 p.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005183 if (client != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005184 pw.flush();
5185 try {
Jeff Sharkey850c83e2016-11-09 12:25:44 -07005186 TransferPipe.dumpAsync(client.client.asBinder(), fd, args);
5187 } catch (IOException | RemoteException e) {
5188 p.println("Failed to dump input method client: " + e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005189 }
Jeff Brownb88102f2010-09-08 11:49:43 -07005190 } else {
5191 p.println("No input method client.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005192 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005193
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08005194 if (focusedWindowClient != null && client != focusedWindowClient) {
5195 p.println(" ");
5196 p.println("Warning: Current input method client doesn't match the last focused. "
5197 + "window.");
5198 p.println("Dumping input method client in the last focused window just in case.");
5199 p.println(" ");
5200 pw.flush();
5201 try {
Jeff Sharkey850c83e2016-11-09 12:25:44 -07005202 TransferPipe.dumpAsync(focusedWindowClient.client.asBinder(), fd, args);
5203 } catch (IOException | RemoteException e) {
5204 p.println("Failed to dump input method client in focused window: " + e);
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08005205 }
5206 }
5207
Jeff Brownb88102f2010-09-08 11:49:43 -07005208 p.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005209 if (method != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005210 pw.flush();
5211 try {
Jeff Sharkey850c83e2016-11-09 12:25:44 -07005212 TransferPipe.dumpAsync(method.asBinder(), fd, args);
5213 } catch (IOException | RemoteException e) {
5214 p.println("Failed to dump input method service: " + e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005215 }
Jeff Brownb88102f2010-09-08 11:49:43 -07005216 } else {
5217 p.println("No input method service.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005218 }
5219 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005220
5221 @BinderThread
5222 @Override
5223 public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
5224 @Nullable FileDescriptor err,
5225 @NonNull String[] args, @Nullable ShellCallback callback,
5226 @NonNull ResultReceiver resultReceiver) throws RemoteException {
Yohei Yukawab8d240f2018-12-26 10:03:11 -08005227 final int callingUid = Binder.getCallingUid();
5228 // Reject any incoming calls from non-shell users, including ones from the system user.
5229 if (callingUid != Process.ROOT_UID && callingUid != Process.SHELL_UID) {
5230 // Note that Binder#onTransact() will automatically close "in", "out", and "err" when
5231 // returned from this method, hence there is no need to close those FDs.
5232 // "resultReceiver" is the only thing that needs to be taken care of here.
5233 if (resultReceiver != null) {
5234 resultReceiver.send(ShellCommandResult.FAILURE, null);
5235 }
5236 final String errorMsg = "InputMethodManagerService does not support shell commands from"
5237 + " non-shell users. callingUid=" + callingUid
5238 + " args=" + Arrays.toString(args);
5239 if (Process.isCoreUid(callingUid)) {
5240 // Let's not crash the calling process if the caller is one of core components.
5241 Slog.e(TAG, errorMsg);
5242 return;
5243 }
5244 throw new SecurityException(errorMsg);
5245 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005246 new ShellCommandImpl(this).exec(
5247 this, in, out, err, args, callback, resultReceiver);
5248 }
5249
5250 private static final class ShellCommandImpl extends ShellCommand {
5251 @NonNull
5252 final InputMethodManagerService mService;
5253
5254 ShellCommandImpl(InputMethodManagerService service) {
5255 mService = service;
5256 }
5257
Yohei Yukawadb25df72018-12-27 08:40:41 -08005258 @RequiresPermission(allOf = {
Yohei Yukawa8a2b96b2018-12-28 17:23:29 -08005259 Manifest.permission.DUMP,
5260 Manifest.permission.INTERACT_ACROSS_USERS_FULL,
Yohei Yukawadb25df72018-12-27 08:40:41 -08005261 Manifest.permission.WRITE_SECURE_SETTINGS,
Yohei Yukawa8a2b96b2018-12-28 17:23:29 -08005262 })
Yohei Yukawa926488d2017-12-11 17:24:55 -08005263 @BinderThread
5264 @ShellCommandResult
5265 @Override
5266 public int onCommand(@Nullable String cmd) {
Yohei Yukawadb25df72018-12-27 08:40:41 -08005267 // For shell command, require all the permissions here in favor of code simplicity.
Yohei Yukawa8a2b96b2018-12-28 17:23:29 -08005268 Arrays.asList(
5269 Manifest.permission.DUMP,
5270 Manifest.permission.INTERACT_ACROSS_USERS_FULL,
5271 Manifest.permission.WRITE_SECURE_SETTINGS
5272 ).forEach(permission -> mService.mContext.enforceCallingPermission(permission, null));
Yohei Yukawadb25df72018-12-27 08:40:41 -08005273
5274 final long identity = Binder.clearCallingIdentity();
5275 try {
5276 return onCommandWithSystemIdentity(cmd);
5277 } finally {
5278 Binder.restoreCallingIdentity(identity);
5279 }
5280 }
5281
5282 @BinderThread
5283 @ShellCommandResult
5284 private int onCommandWithSystemIdentity(@Nullable String cmd) {
Yohei Yukawadfdab732018-02-21 07:16:30 +09005285 if ("refresh_debug_properties".equals(cmd)) {
5286 return refreshDebugProperties();
5287 }
5288
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08005289 if ("get-last-switch-user-id".equals(cmd)) {
5290 return mService.getLastSwitchUserId(this);
5291 }
5292
Yohei Yukawacac97722017-12-15 16:52:05 -08005293 // For existing "adb shell ime <command>".
5294 if ("ime".equals(cmd)) {
5295 final String imeCommand = getNextArg();
5296 if (imeCommand == null || "help".equals(imeCommand) || "-h".equals(imeCommand)) {
5297 onImeCommandHelp();
5298 return ShellCommandResult.SUCCESS;
5299 }
5300 switch (imeCommand) {
5301 case "list":
5302 return mService.handleShellCommandListInputMethods(this);
5303 case "enable":
5304 return mService.handleShellCommandEnableDisableInputMethod(this, true);
5305 case "disable":
5306 return mService.handleShellCommandEnableDisableInputMethod(this, false);
5307 case "set":
5308 return mService.handleShellCommandSetInputMethod(this);
5309 case "reset":
5310 return mService.handleShellCommandResetInputMethod(this);
5311 default:
5312 getOutPrintWriter().println("Unknown command: " + imeCommand);
5313 return ShellCommandResult.FAILURE;
5314 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005315 }
Yohei Yukawacac97722017-12-15 16:52:05 -08005316
5317 return handleDefaultCommands(cmd);
Yohei Yukawa926488d2017-12-11 17:24:55 -08005318 }
5319
5320 @BinderThread
Tarandeep Singh75a92392018-01-12 14:58:59 -08005321 @ShellCommandResult
5322 private int refreshDebugProperties() {
5323 DebugFlags.FLAG_OPTIMIZE_START_INPUT.refresh();
Tarandeep Singheadb1392018-11-09 18:15:57 +01005324 DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.refresh();
Tarandeep Singh75a92392018-01-12 14:58:59 -08005325 return ShellCommandResult.SUCCESS;
5326 }
5327
5328 @BinderThread
Yohei Yukawa926488d2017-12-11 17:24:55 -08005329 @Override
5330 public void onHelp() {
5331 try (PrintWriter pw = getOutPrintWriter()) {
5332 pw.println("InputMethodManagerService commands:");
5333 pw.println(" help");
5334 pw.println(" Prints this help text.");
5335 pw.println(" dump [options]");
5336 pw.println(" Synonym of dumpsys.");
Yohei Yukawacac97722017-12-15 16:52:05 -08005337 pw.println(" ime <command> [options]");
5338 pw.println(" Manipulate IMEs. Run \"ime help\" for details.");
5339 }
5340 }
5341
5342 private void onImeCommandHelp() {
5343 try (IndentingPrintWriter pw =
5344 new IndentingPrintWriter(getOutPrintWriter(), " ", 100)) {
5345 pw.println("ime <command>:");
5346 pw.increaseIndent();
5347
5348 pw.println("list [-a] [-s]");
5349 pw.increaseIndent();
5350 pw.println("prints all enabled input methods.");
5351 pw.increaseIndent();
5352 pw.println("-a: see all input methods");
5353 pw.println("-s: only a single summary line of each");
5354 pw.decreaseIndent();
5355 pw.decreaseIndent();
5356
Yohei Yukawae1771702019-04-10 23:20:51 -07005357 pw.println("enable [--user <USER_ID>] <ID>");
Yohei Yukawacac97722017-12-15 16:52:05 -08005358 pw.increaseIndent();
5359 pw.println("allows the given input method ID to be used.");
Yohei Yukawae1771702019-04-10 23:20:51 -07005360 pw.increaseIndent();
5361 pw.print("--user <USER_ID>: Specify which user to enable.");
5362 pw.println(" Assumes the current user if not specified.");
5363 pw.decreaseIndent();
Yohei Yukawacac97722017-12-15 16:52:05 -08005364 pw.decreaseIndent();
5365
Yohei Yukawae1771702019-04-10 23:20:51 -07005366 pw.println("disable [--user <USER_ID>] <ID>");
Yohei Yukawacac97722017-12-15 16:52:05 -08005367 pw.increaseIndent();
5368 pw.println("disallows the given input method ID to be used.");
Yohei Yukawae1771702019-04-10 23:20:51 -07005369 pw.increaseIndent();
5370 pw.print("--user <USER_ID>: Specify which user to disable.");
5371 pw.println(" Assumes the current user if not specified.");
5372 pw.decreaseIndent();
Yohei Yukawacac97722017-12-15 16:52:05 -08005373 pw.decreaseIndent();
5374
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005375 pw.println("set [--user <USER_ID>] <ID>");
Yohei Yukawacac97722017-12-15 16:52:05 -08005376 pw.increaseIndent();
5377 pw.println("switches to the given input method ID.");
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005378 pw.increaseIndent();
5379 pw.print("--user <USER_ID>: Specify which user to enable.");
5380 pw.println(" Assumes the current user if not specified.");
5381 pw.decreaseIndent();
Yohei Yukawacac97722017-12-15 16:52:05 -08005382 pw.decreaseIndent();
5383
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005384 pw.println("reset [--user <USER_ID>]");
Yohei Yukawacac97722017-12-15 16:52:05 -08005385 pw.increaseIndent();
5386 pw.println("reset currently selected/enabled IMEs to the default ones as if "
5387 + "the device is initially booted with the current locale.");
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005388 pw.increaseIndent();
5389 pw.print("--user <USER_ID>: Specify which user to reset.");
5390 pw.println(" Assumes the current user if not specified.");
5391 pw.decreaseIndent();
5392
Yohei Yukawacac97722017-12-15 16:52:05 -08005393 pw.decreaseIndent();
5394
5395 pw.decreaseIndent();
Yohei Yukawa926488d2017-12-11 17:24:55 -08005396 }
5397 }
5398 }
5399
5400 // ----------------------------------------------------------------------
5401 // Shell command handlers:
5402
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08005403 @BinderThread
5404 @ShellCommandResult
5405 private int getLastSwitchUserId(@NonNull ShellCommand shellCommand) {
5406 synchronized (mMethodMap) {
5407 shellCommand.getOutPrintWriter().println(mLastSwitchUserId);
5408 return ShellCommandResult.SUCCESS;
5409 }
5410 }
5411
Yohei Yukawa926488d2017-12-11 17:24:55 -08005412 /**
5413 * Handles {@code adb shell ime list}.
5414 * @param shellCommand {@link ShellCommand} object that is handling this command.
5415 * @return Exit code of the command.
5416 */
5417 @BinderThread
5418 @ShellCommandResult
5419 private int handleShellCommandListInputMethods(@NonNull ShellCommand shellCommand) {
5420 boolean all = false;
5421 boolean brief = false;
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08005422 int userIdToBeResolved = UserHandle.USER_CURRENT;
Yohei Yukawa926488d2017-12-11 17:24:55 -08005423 while (true) {
5424 final String nextOption = shellCommand.getNextOption();
5425 if (nextOption == null) {
5426 break;
5427 }
5428 switch (nextOption) {
5429 case "-a":
5430 all = true;
5431 break;
5432 case "-s":
5433 brief = true;
5434 break;
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08005435 case "-u":
5436 case "--user":
5437 userIdToBeResolved = UserHandle.parseUserArg(shellCommand.getNextArgRequired());
5438 break;
Yohei Yukawa926488d2017-12-11 17:24:55 -08005439 }
5440 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08005441 synchronized (mMethodMap) {
5442 final PrintWriter pr = shellCommand.getOutPrintWriter();
5443 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
5444 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
5445 for (int userId : userIds) {
5446 final List<InputMethodInfo> methods = all
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08005447 ? getInputMethodListLocked(userId)
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08005448 : getEnabledInputMethodListLocked(userId);
5449 if (userIds.length > 1) {
5450 pr.print("User #");
5451 pr.print(userId);
5452 pr.println(":");
5453 }
5454 for (InputMethodInfo info : methods) {
5455 if (brief) {
5456 pr.println(info.getId());
5457 } else {
5458 pr.print(info.getId());
5459 pr.println(":");
5460 info.dump(pr::println, " ");
5461 }
5462 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005463 }
5464 }
5465 return ShellCommandResult.SUCCESS;
5466 }
5467
5468 /**
5469 * Handles {@code adb shell ime enable} and {@code adb shell ime disable}.
5470 * @param shellCommand {@link ShellCommand} object that is handling this command.
5471 * @param enabled {@code true} if the command was {@code adb shell ime enable}.
5472 * @return Exit code of the command.
5473 */
5474 @BinderThread
5475 @ShellCommandResult
Yohei Yukawa926488d2017-12-11 17:24:55 -08005476 private int handleShellCommandEnableDisableInputMethod(
5477 @NonNull ShellCommand shellCommand, boolean enabled) {
Yohei Yukawa3403f2d2019-04-15 08:16:58 -07005478 final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
Yohei Yukawae1771702019-04-10 23:20:51 -07005479 final String imeId = shellCommand.getNextArgRequired();
5480 final PrintWriter out = shellCommand.getOutPrintWriter();
5481 final PrintWriter error = shellCommand.getErrPrintWriter();
Yohei Yukawa926488d2017-12-11 17:24:55 -08005482 synchronized (mMethodMap) {
Yohei Yukawae1771702019-04-10 23:20:51 -07005483 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
5484 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
5485 for (int userId : userIds) {
5486 if (!userHasDebugPriv(userId, shellCommand)) {
5487 continue;
5488 }
5489 handleShellCommandEnableDisableInputMethodInternalLocked(userId, imeId, enabled,
5490 out, error);
Tarandeep Singh87e2e512019-03-06 14:28:52 -08005491 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005492 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005493 return ShellCommandResult.SUCCESS;
5494 }
5495
5496 /**
Yohei Yukawae1771702019-04-10 23:20:51 -07005497 * A special helper method for commands that only have {@code -u} and {@code --user} options.
5498 *
5499 * <p>You cannot use this helper method if the command has other options.</p>
5500 *
Yohei Yukawa3403f2d2019-04-15 08:16:58 -07005501 * <p>CAVEAT: This method must be called only once before any other
5502 * {@link ShellCommand#getNextArg()} and {@link ShellCommand#getNextArgRequired()} for the
5503 * main arguments.</p>
5504 *
Yohei Yukawae1771702019-04-10 23:20:51 -07005505 * @param shellCommand {@link ShellCommand} from which options should be obtained.
5506 * @return User ID to be resolved. {@link UserHandle#CURRENT} if not specified.
5507 */
5508 @BinderThread
5509 @UserIdInt
5510 private static int handleOptionsForCommandsThatOnlyHaveUserOption(ShellCommand shellCommand) {
5511 while (true) {
5512 final String nextOption = shellCommand.getNextOption();
5513 if (nextOption == null) {
5514 break;
5515 }
5516 switch (nextOption) {
5517 case "-u":
5518 case "--user":
5519 return UserHandle.parseUserArg(shellCommand.getNextArgRequired());
5520 }
5521 }
5522 return UserHandle.USER_CURRENT;
5523 }
5524
5525 @BinderThread
5526 private void handleShellCommandEnableDisableInputMethodInternalLocked(
5527 @UserIdInt int userId, String imeId, boolean enabled, PrintWriter out,
5528 PrintWriter error) {
5529 boolean failedToEnableUnknownIme = false;
5530 boolean previouslyEnabled = false;
5531 if (userId == mSettings.getCurrentUserId()) {
5532 if (enabled && !mMethodMap.containsKey(imeId)) {
5533 failedToEnableUnknownIme = true;
5534 } else {
5535 previouslyEnabled = setInputMethodEnabledLocked(imeId, enabled);
5536 }
5537 } else {
5538 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
5539 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
5540 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
5541 new ArrayMap<>();
5542 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
5543 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
5544 methodMap, methodList);
5545 final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
5546 mContext.getContentResolver(), methodMap, userId, false);
5547 if (enabled) {
5548 if (!methodMap.containsKey(imeId)) {
5549 failedToEnableUnknownIme = true;
5550 } else {
5551 for (InputMethodInfo imi : settings.getEnabledInputMethodListLocked()) {
5552 if (TextUtils.equals(imi.getId(), imeId)) {
5553 previouslyEnabled = true;
5554 break;
5555 }
5556 }
5557 if (!previouslyEnabled) {
5558 settings.appendAndPutEnabledInputMethodLocked(imeId, false);
5559 }
5560 }
5561 } else {
5562 previouslyEnabled =
5563 settings.buildAndPutEnabledInputMethodsStrRemovingIdLocked(
5564 new StringBuilder(),
5565 settings.getEnabledInputMethodsAndSubtypeListLocked(), imeId);
5566 }
5567 }
5568 if (failedToEnableUnknownIme) {
5569 error.print("Unknown input method ");
5570 error.print(imeId);
5571 error.println(" cannot be enabled for user #" + userId);
5572 } else {
5573 out.print("Input method ");
5574 out.print(imeId);
5575 out.print(": ");
5576 out.print((enabled == previouslyEnabled) ? "already " : "now ");
5577 out.print(enabled ? "enabled" : "disabled");
5578 out.print(" for user #");
5579 out.println(userId);
5580 }
5581 }
5582
5583 /**
Yohei Yukawa926488d2017-12-11 17:24:55 -08005584 * Handles {@code adb shell ime set}.
5585 * @param shellCommand {@link ShellCommand} object that is handling this command.
5586 * @return Exit code of the command.
5587 */
5588 @BinderThread
5589 @ShellCommandResult
5590 private int handleShellCommandSetInputMethod(@NonNull ShellCommand shellCommand) {
Yohei Yukawa3403f2d2019-04-15 08:16:58 -07005591 final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005592 final String imeId = shellCommand.getNextArgRequired();
5593 final PrintWriter out = shellCommand.getOutPrintWriter();
5594 final PrintWriter error = shellCommand.getErrPrintWriter();
Yohei Yukawadb25df72018-12-27 08:40:41 -08005595 synchronized (mMethodMap) {
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005596 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
5597 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
5598 for (int userId : userIds) {
5599 if (!userHasDebugPriv(userId, shellCommand)) {
5600 continue;
5601 }
mincheli850892b2019-12-05 19:47:59 +08005602 boolean failedToSelectUnknownIme = !switchToInputMethod(imeId, userId);
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005603 if (failedToSelectUnknownIme) {
5604 error.print("Unknown input method ");
5605 error.print(imeId);
5606 error.print(" cannot be selected for user #");
5607 error.println(userId);
5608 } else {
5609 out.print("Input method ");
5610 out.print(imeId);
5611 out.print(" selected for user #");
Yohei Yukawa3403f2d2019-04-15 08:16:58 -07005612 out.println(userId);
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005613 }
Tarandeep Singh87e2e512019-03-06 14:28:52 -08005614 }
Yohei Yukawadb25df72018-12-27 08:40:41 -08005615 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005616 return ShellCommandResult.SUCCESS;
5617 }
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005618
5619 /**
5620 * Handles {@code adb shell ime reset-ime}.
5621 * @param shellCommand {@link ShellCommand} object that is handling this command.
5622 * @return Exit code of the command.
5623 */
5624 @BinderThread
5625 @ShellCommandResult
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005626 private int handleShellCommandResetInputMethod(@NonNull ShellCommand shellCommand) {
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005627 final PrintWriter out = shellCommand.getOutPrintWriter();
5628 final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005629 synchronized (mMethodMap) {
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005630 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
5631 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
5632 for (int userId : userIds) {
5633 if (!userHasDebugPriv(userId, shellCommand)) {
5634 continue;
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005635 }
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005636 final String nextIme;
5637 final List<InputMethodInfo> nextEnabledImes;
5638 if (userId == mSettings.getCurrentUserId()) {
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08005639 hideCurrentInputLocked(mCurFocusedWindow, 0, null,
lumarkd85e1582019-12-29 20:20:41 +08005640 SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND);
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005641 unbindCurrentMethodLocked();
5642 // Reset the current IME
5643 resetSelectedInputMethodAndSubtypeLocked(null);
5644 // Also reset the settings of the current IME
5645 mSettings.putSelectedInputMethod(null);
5646 // Disable all enabled IMEs.
5647 mSettings.getEnabledInputMethodListLocked().forEach(
5648 imi -> setInputMethodEnabledLocked(imi.getId(), false));
5649 // Re-enable with default enabled IMEs.
5650 InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList).forEach(
5651 imi -> setInputMethodEnabledLocked(imi.getId(), true));
5652 updateInputMethodsFromSettingsLocked(true /* enabledMayChange */);
5653 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
5654 mSettings.getEnabledInputMethodListLocked(),
5655 mSettings.getCurrentUserId(),
5656 mContext.getBasePackageName());
5657 nextIme = mSettings.getSelectedInputMethod();
5658 nextEnabledImes = mSettings.getEnabledInputMethodListLocked();
5659 } else {
5660 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
5661 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
5662 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
5663 new ArrayMap<>();
5664 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
5665 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
5666 methodMap, methodList);
5667 final InputMethodSettings settings = new InputMethodSettings(
5668 mContext.getResources(), mContext.getContentResolver(), methodMap,
5669 userId, false);
5670
5671 nextEnabledImes = InputMethodUtils.getDefaultEnabledImes(mContext, methodList);
5672 nextIme = InputMethodUtils.getMostApplicableDefaultIME(nextEnabledImes).getId();
5673
5674 // Reset enabled IMEs.
5675 settings.putEnabledInputMethodsStr("");
5676 nextEnabledImes.forEach(imi -> settings.appendAndPutEnabledInputMethodLocked(
5677 imi.getId(), false));
5678
5679 // Reset selected IME.
5680 settings.putSelectedInputMethod(nextIme);
5681 settings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
5682 }
5683 out.println("Reset current and enabled IMEs for user #" + userId);
5684 out.println(" Selected: " + nextIme);
5685 nextEnabledImes.forEach(ime -> out.println(" Enabled: " + ime.getId()));
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005686 }
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005687 }
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005688 return ShellCommandResult.SUCCESS;
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005689 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07005690
Tarandeep Singh87e2e512019-03-06 14:28:52 -08005691 /**
5692 * @param userId the actual user handle obtained by {@link UserHandle#getIdentifier()}
5693 * and *not* pseudo ids like {@link UserHandle#USER_ALL etc}.
5694 * @return {@code true} if userId has debugging privileges.
5695 * i.e. {@link UserManager#DISALLOW_DEBUGGING_FEATURES} is {@code false}.
5696 */
5697 private boolean userHasDebugPriv(int userId, final ShellCommand shellCommand) {
5698 if (mUserManager.hasUserRestriction(
5699 UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.of(userId))) {
5700 shellCommand.getErrPrintWriter().println("User #" + userId
5701 + " is restricted with DISALLOW_DEBUGGING_FEATURES.");
5702 return false;
5703 }
5704 return true;
5705 }
5706
Yohei Yukawac54c1172018-09-06 11:39:50 -07005707 private static final class InputMethodPrivilegedOperationsImpl
5708 extends IInputMethodPrivilegedOperations.Stub {
5709 private final InputMethodManagerService mImms;
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08005710 @NonNull
Yohei Yukawac54c1172018-09-06 11:39:50 -07005711 private final IBinder mToken;
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08005712 InputMethodPrivilegedOperationsImpl(InputMethodManagerService imms,
5713 @NonNull IBinder token) {
Yohei Yukawac54c1172018-09-06 11:39:50 -07005714 mImms = imms;
5715 mToken = token;
5716 }
5717
5718 @BinderThread
5719 @Override
5720 public void setImeWindowStatus(int vis, int backDisposition) {
5721 mImms.setImeWindowStatus(mToken, vis, backDisposition);
5722 }
5723
5724 @BinderThread
5725 @Override
5726 public void reportStartInput(IBinder startInputToken) {
5727 mImms.reportStartInput(mToken, startInputToken);
5728 }
5729
5730 @BinderThread
5731 @Override
Yohei Yukawac54c1172018-09-06 11:39:50 -07005732 public IInputContentUriToken createInputContentUriToken(Uri contentUri,
5733 String packageName) {
5734 return mImms.createInputContentUriToken(mToken, contentUri, packageName);
5735 }
5736
5737 @BinderThread
5738 @Override
5739 public void reportFullscreenMode(boolean fullscreen) {
5740 mImms.reportFullscreenMode(mToken, fullscreen);
5741 }
Yohei Yukawac7ca3682018-09-09 20:48:38 -07005742
5743 @BinderThread
5744 @Override
5745 public void setInputMethod(String id) {
5746 mImms.setInputMethod(mToken, id);
5747 }
5748
5749 @BinderThread
5750 @Override
5751 public void setInputMethodAndSubtype(String id, InputMethodSubtype subtype) {
5752 mImms.setInputMethodAndSubtype(mToken, id, subtype);
5753 }
5754
5755 @BinderThread
5756 @Override
5757 public void hideMySoftInput(int flags) {
5758 mImms.hideMySoftInput(mToken, flags);
5759 }
5760
5761 @BinderThread
5762 @Override
5763 public void showMySoftInput(int flags) {
5764 mImms.showMySoftInput(mToken, flags);
5765 }
5766
5767 @BinderThread
5768 @Override
Yohei Yukawa41b094f2018-09-09 23:58:45 -07005769 public void updateStatusIcon(String packageName, @DrawableRes int iconId) {
Yohei Yukawac7ca3682018-09-09 20:48:38 -07005770 mImms.updateStatusIcon(mToken, packageName, iconId);
5771 }
5772
5773 @BinderThread
5774 @Override
5775 public boolean switchToPreviousInputMethod() {
5776 return mImms.switchToPreviousInputMethod(mToken);
5777 }
5778
5779 @BinderThread
5780 @Override
5781 public boolean switchToNextInputMethod(boolean onlyCurrentIme) {
5782 return mImms.switchToNextInputMethod(mToken, onlyCurrentIme);
5783 }
5784
5785 @BinderThread
5786 @Override
5787 public boolean shouldOfferSwitchingToNextInputMethod() {
5788 return mImms.shouldOfferSwitchingToNextInputMethod(mToken);
5789 }
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07005790
5791 @BinderThread
5792 @Override
Yohei Yukawa9b60ba02019-01-21 00:06:27 -08005793 public void notifyUserAction() {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07005794 mImms.notifyUserAction(mToken);
5795 }
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08005796
5797 @BinderThread
5798 @Override
5799 public void reportPreRendered(EditorInfo info) {
5800 mImms.reportPreRendered(mToken, info);
5801 }
5802
5803 @BinderThread
5804 @Override
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08005805 public void applyImeVisibility(IBinder windowToken, boolean setVisible) {
5806 mImms.applyImeVisibility(mToken, windowToken, setVisible);
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08005807 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07005808 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005809}