blob: 9acb47538043c05310747c9c03d2f3ea4b260576 [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
Ming-Shin Lu48bfc312020-06-15 20:06:09 +080021import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR;
22
Yohei Yukawafa0e47e2016-04-05 09:55:56 -070023import static java.lang.annotation.RetentionPolicy.SOURCE;
24
Yohei Yukawa926488d2017-12-11 17:24:55 -080025import android.Manifest;
Phil Weaver03a65b02018-07-19 16:07:57 -070026import android.accessibilityservice.AccessibilityService;
Tarandeep Singh75a92392018-01-12 14:58:59 -080027import android.annotation.AnyThread;
Yohei Yukawad6475a62017-04-17 10:35:27 -070028import android.annotation.BinderThread;
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +090029import android.annotation.ColorInt;
Yohei Yukawa41b094f2018-09-09 23:58:45 -070030import android.annotation.DrawableRes;
Yohei Yukawafa0e47e2016-04-05 09:55:56 -070031import android.annotation.IntDef;
Yohei Yukawa930328c2017-10-18 20:19:53 -070032import android.annotation.MainThread;
Yohei Yukawa6ab1a822015-08-25 14:01:28 -070033import android.annotation.NonNull;
Yohei Yukawae13a20fa2015-09-30 19:11:32 -070034import android.annotation.Nullable;
Yohei Yukawa926488d2017-12-11 17:24:55 -080035import android.annotation.RequiresPermission;
Yohei Yukawa7b18aec2016-03-07 13:04:32 -080036import android.annotation.UserIdInt;
Sudheer Shankadc589ac2016-11-10 15:30:17 -080037import android.app.ActivityManager;
Sudheer Shankafc46e9b2016-10-21 17:55:27 -070038import android.app.ActivityManagerInternal;
Andrew Sapperstein8a3b4cb2017-04-28 14:35:31 -070039import android.app.ActivityThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.app.AlertDialog;
Yohei Yukawa6ab1a822015-08-25 14:01:28 -070041import android.app.AppGlobals;
Yohei Yukawae63b5fa2014-09-19 13:14:55 +090042import android.app.AppOpsManager;
satokf90a33e2011-07-19 11:55:52 +090043import android.app.KeyguardManager;
satok7cfc0ed2011-06-20 21:29:36 +090044import android.app.Notification;
45import android.app.NotificationManager;
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070046import android.app.PendingIntent;
satok5b927c432012-05-01 20:09:34 +090047import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.content.ComponentName;
Yohei Yukawa3933a6e2016-11-10 00:47:48 -080049import android.content.ContentProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.content.ContentResolver;
51import android.content.Context;
52import android.content.DialogInterface;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.content.DialogInterface.OnCancelListener;
Tadashi G. Takaokad130b802014-08-01 14:05:47 +090054import android.content.DialogInterface.OnClickListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.content.Intent;
satoke7c6998e2011-06-03 17:57:59 +090056import android.content.IntentFilter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import android.content.ServiceConnection;
Brandon Ballinger6da35a02009-10-21 00:38:13 -070058import android.content.pm.ApplicationInfo;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +090059import android.content.pm.IPackageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import android.content.pm.PackageManager;
Yohei Yukawad5f402b2020-05-15 10:23:32 -070061import android.content.pm.PackageManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.content.pm.ResolveInfo;
63import android.content.pm.ServiceInfo;
Amith Yamasanie861ec12010-03-24 21:39:27 -070064import android.content.res.Configuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065import android.content.res.Resources;
66import android.content.res.TypedArray;
67import android.database.ContentObserver;
Yohei Yukawab4f328a2019-05-02 08:41:27 -070068import android.graphics.Matrix;
Alan Viverette505e3ab2014-11-24 15:22:11 -080069import android.graphics.drawable.Drawable;
Yohei Yukawab4f328a2019-05-02 08:41:27 -070070import android.hardware.display.DisplayManagerInternal;
lpeter133fce02020-03-05 20:32:16 +080071import android.hardware.input.InputManagerInternal;
Joe Onorato857fd9b2011-01-27 15:08:35 -080072import android.inputmethodservice.InputMethodService;
Yohei Yukawad5f402b2020-05-15 10:23:32 -070073import android.media.AudioManagerInternal;
Michael Wright7b5a96b2014-08-09 19:28:42 -070074import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075import android.os.Binder;
Chris Wren1ce4b6d2015-06-11 10:19:43 -040076import android.os.Bundle;
Seigo Nonakae27dc2b2015-08-14 18:21:27 -070077import android.os.Debug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078import android.os.Handler;
79import android.os.IBinder;
80import android.os.IInterface;
Yohei Yukawa23cbe852016-05-17 16:42:58 -070081import android.os.LocaleList;
Yohei Yukawa0569a182018-08-28 16:09:28 -070082import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083import android.os.Parcel;
Yohei Yukawa6ab1a822015-08-25 14:01:28 -070084import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.os.RemoteException;
The Android Open Source Project4df24232009-03-05 14:34:35 -080086import android.os.ResultReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087import android.os.ServiceManager;
Yohei Yukawa926488d2017-12-11 17:24:55 -080088import android.os.ShellCallback;
89import android.os.ShellCommand;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090import android.os.SystemClock;
Tarandeep Singh75a92392018-01-12 14:58:59 -080091import android.os.SystemProperties;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +090092import android.os.UserHandle;
Amith Yamasani734983f2014-03-04 16:48:05 -080093import android.os.UserManager;
Yohei Yukawa42081402019-01-15 09:57:50 -080094import android.os.UserManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095import android.provider.Settings;
96import android.text.TextUtils;
satokf9f01002011-05-19 21:31:50 +090097import android.text.style.SuggestionSpan;
Yohei Yukawaac9311e2018-11-20 19:25:23 -080098import android.util.ArrayMap;
Christopher Tate7b9a28c2015-03-18 13:06:16 -070099import android.util.ArraySet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100import android.util.EventLog;
satokf9f01002011-05-19 21:31:50 +0900101import android.util.LruCache;
satokab751aa2010-09-14 19:17:36 +0900102import android.util.Pair;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103import android.util.PrintWriterPrinter;
104import android.util.Printer;
satoke7c6998e2011-06-03 17:57:59 +0900105import android.util.Slog;
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700106import android.util.SparseArray;
Tadashi G. Takaokad130b802014-08-01 14:05:47 +0900107import android.view.ContextThemeWrapper;
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700108import android.view.DisplayInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109import android.view.IWindowManager;
Jeff Brownc28867a2013-03-26 15:42:39 -0700110import android.view.InputChannel;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900111import android.view.LayoutInflater;
112import android.view.View;
113import android.view.ViewGroup;
Wale Ogunwale3a931692016-11-02 16:49:48 -0700114import android.view.Window;
Yohei Yukawa6e875592019-01-28 00:49:30 -0800115import android.view.WindowManager.LayoutParams;
Yohei Yukawab0c26452018-10-21 10:42:52 -0700116import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
Feng Cao7c85eb72020-02-28 11:39:56 -0800117import android.view.autofill.AutofillId;
satokab751aa2010-09-14 19:17:36 +0900118import android.view.inputmethod.EditorInfo;
Feng Cao16b2de52020-01-09 17:27:27 -0800119import android.view.inputmethod.InlineSuggestionsRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120import android.view.inputmethod.InputBinding;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800121import android.view.inputmethod.InputConnection;
Yohei Yukawa19a80a12016-03-14 22:57:37 -0700122import android.view.inputmethod.InputConnectionInspector;
Yohei Yukawa432cf602018-10-21 10:41:37 -0700123import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124import android.view.inputmethod.InputMethod;
125import android.view.inputmethod.InputMethodInfo;
126import android.view.inputmethod.InputMethodManager;
satokab751aa2010-09-14 19:17:36 +0900127import android.view.inputmethod.InputMethodSubtype;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900128import android.widget.ArrayAdapter;
satok01038492012-04-09 21:08:27 +0900129import android.widget.CompoundButton;
130import android.widget.CompoundButton.OnCheckedChangeListener;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900131import android.widget.RadioButton;
satok01038492012-04-09 21:08:27 +0900132import android.widget.Switch;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900133import android.widget.TextView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134
Yohei Yukawa0569a182018-08-28 16:09:28 -0700135import com.android.internal.annotations.GuardedBy;
136import com.android.internal.content.PackageMonitor;
137import com.android.internal.inputmethod.IInputContentUriToken;
Yohei Yukawac54c1172018-09-06 11:39:50 -0700138import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
Yohei Yukawaa468d702018-10-21 11:42:34 -0700139import com.android.internal.inputmethod.InputMethodDebug;
lumarkd85e1582019-12-29 20:20:41 +0800140import com.android.internal.inputmethod.SoftInputShowHideReason;
Yohei Yukawa35fa6d52018-10-31 11:33:32 -0700141import com.android.internal.inputmethod.StartInputFlags;
Yohei Yukawac6632df2018-10-21 11:47:16 -0700142import com.android.internal.inputmethod.StartInputReason;
Yohei Yukawa499e3f72018-10-21 20:15:11 -0700143import com.android.internal.inputmethod.UnbindReason;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700144import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
145import com.android.internal.notification.SystemNotificationChannels;
146import com.android.internal.os.HandlerCaller;
147import com.android.internal.os.SomeArgs;
148import com.android.internal.os.TransferPipe;
149import com.android.internal.util.DumpUtils;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700150import com.android.internal.util.IndentingPrintWriter;
Adam Hebc67f2e2019-11-13 14:34:56 -0800151import com.android.internal.view.IInlineSuggestionsRequestCallback;
Feng Cao16b2de52020-01-09 17:27:27 -0800152import com.android.internal.view.IInlineSuggestionsResponseCallback;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700153import com.android.internal.view.IInputContext;
154import com.android.internal.view.IInputMethod;
155import com.android.internal.view.IInputMethodClient;
156import com.android.internal.view.IInputMethodManager;
157import com.android.internal.view.IInputMethodSession;
158import com.android.internal.view.IInputSessionCallback;
Feng Cao36960ee2020-02-18 18:23:30 -0800159import com.android.internal.view.InlineSuggestionsRequestInfo;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700160import com.android.internal.view.InputBindResult;
Yohei Yukawa603f4d02018-09-11 15:04:58 -0700161import com.android.server.EventLogTags;
162import com.android.server.LocalServices;
163import com.android.server.SystemService;
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +0900164import com.android.server.inputmethod.InputMethodManagerInternal.InputMethodListListener;
Yohei Yukawae6b6e0e2018-09-12 16:42:48 -0700165import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
166import com.android.server.inputmethod.InputMethodUtils.InputMethodSettings;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700167import com.android.server.statusbar.StatusBarManagerService;
Adrian Roose99bc052017-11-20 17:55:31 +0100168import com.android.server.wm.WindowManagerInternal;
169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170import java.io.FileDescriptor;
171import java.io.IOException;
172import java.io.PrintWriter;
Yohei Yukawafa0e47e2016-04-05 09:55:56 -0700173import java.lang.annotation.Retention;
Yohei Yukawa25e08132016-06-22 16:31:41 -0700174import java.security.InvalidParameterException;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800175import java.text.SimpleDateFormat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176import java.util.ArrayList;
Yohei Yukawab8d240f2018-12-26 10:03:11 -0800177import java.util.Arrays;
satok688bd472012-02-09 20:09:17 +0900178import java.util.Collections;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800179import java.util.Date;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180import java.util.List;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800181import java.util.Locale;
Adrian Roosc22eec92020-06-12 18:48:10 +0200182import java.util.Objects;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800183import java.util.WeakHashMap;
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +0900184import java.util.concurrent.CopyOnWriteArrayList;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800185import java.util.concurrent.atomic.AtomicInteger;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186
187/**
188 * This class provides a system service that manages input methods.
189 */
190public class InputMethodManagerService extends IInputMethodManager.Stub
191 implements ServiceConnection, Handler.Callback {
192 static final boolean DEBUG = false;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700193 static final String TAG = "InputMethodManagerService";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194
Yohei Yukawa926488d2017-12-11 17:24:55 -0800195 @Retention(SOURCE)
196 @IntDef({ShellCommandResult.SUCCESS, ShellCommandResult.FAILURE})
197 private @interface ShellCommandResult {
198 int SUCCESS = 0;
199 int FAILURE = -1;
200 }
201
Seigo Nonakad4474cb2015-05-04 16:53:24 -0700202 static final int MSG_SHOW_IM_SUBTYPE_PICKER = 1;
203 static final int MSG_SHOW_IM_SUBTYPE_ENABLER = 2;
204 static final int MSG_SHOW_IM_CONFIG = 3;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800205
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 static final int MSG_UNBIND_INPUT = 1000;
207 static final int MSG_BIND_INPUT = 1010;
208 static final int MSG_SHOW_SOFT_INPUT = 1020;
209 static final int MSG_HIDE_SOFT_INPUT = 1030;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700210 static final int MSG_HIDE_CURRENT_INPUT_METHOD = 1035;
Yohei Yukawac54c1172018-09-06 11:39:50 -0700211 static final int MSG_INITIALIZE_IME = 1040;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 static final int MSG_CREATE_SESSION = 1050;
Yunfan Chenc02a5ac2020-06-16 01:52:41 +0000213 static final int MSG_REMOVE_IME_SURFACE = 1060;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 static final int MSG_START_INPUT = 2000;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800216
Yohei Yukawa33e81792015-11-17 21:14:42 -0800217 static final int MSG_UNBIND_CLIENT = 3000;
218 static final int MSG_BIND_CLIENT = 3010;
Dianne Hackborna6e41342012-05-22 16:30:34 -0700219 static final int MSG_SET_ACTIVE = 3020;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700220 static final int MSG_SET_INTERACTIVE = 3030;
Yohei Yukawa2bc66172017-02-08 11:13:25 -0800221 static final int MSG_REPORT_FULLSCREEN_MODE = 3045;
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -0800222 static final int MSG_REPORT_PRE_RENDERED = 3060;
223 static final int MSG_APPLY_IME_VISIBILITY = 3070;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800224
satok01038492012-04-09 21:08:27 +0900225 static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000;
226
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -0700227 static final int MSG_SYSTEM_UNLOCK_USER = 5000;
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +0900228 static final int MSG_DISPATCH_ON_INPUT_METHOD_LIST_UPDATED = 5010;
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -0700229
Adam Hebc67f2e2019-11-13 14:34:56 -0800230 static final int MSG_INLINE_SUGGESTIONS_REQUEST = 6000;
231
Yohei Yukawad5f402b2020-05-15 10:23:32 -0700232 static final int MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE = 7000;
233
Satoshi Kataokabcacc322013-10-21 17:57:27 -0700234 static final long TIME_TO_RECONNECT = 3 * 1000;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800235
satokf9f01002011-05-19 21:31:50 +0900236 static final int SECURE_SUGGESTION_SPANS_MAX_SIZE = 20;
237
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +0900238 private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID;
satokb6359412011-06-28 17:47:41 +0900239 private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +0900240
Yohei Yukawaa67a4592017-03-30 15:57:02 -0700241 /**
242 * Binding flags for establishing connection to the {@link InputMethodService}.
243 */
244 private static final int IME_CONNECTION_BIND_FLAGS =
245 Context.BIND_AUTO_CREATE
246 | Context.BIND_NOT_VISIBLE
247 | Context.BIND_NOT_FOREGROUND
Yohei Yukawaad78a612017-08-04 01:57:27 -0700248 | Context.BIND_IMPORTANT_BACKGROUND;
Yohei Yukawaa67a4592017-03-30 15:57:02 -0700249
250 /**
251 * Binding flags used only while the {@link InputMethodService} is showing window.
252 */
253 private static final int IME_VISIBLE_BIND_FLAGS =
254 Context.BIND_AUTO_CREATE
255 | Context.BIND_TREAT_LIKE_ACTIVITY
Yohei Yukawaad78a612017-08-04 01:57:27 -0700256 | Context.BIND_FOREGROUND_SERVICE
Amith Yamasanic45a9902019-04-05 16:29:30 -0700257 | Context.BIND_INCLUDE_CAPABILITIES
Yohei Yukawa59730962019-03-18 10:47:22 -0700258 | Context.BIND_SHOWING_UI
259 | Context.BIND_SCHEDULE_LIKE_TOP_APP;
Yohei Yukawaa67a4592017-03-30 15:57:02 -0700260
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +0900261 /**
262 * A protected broadcast intent action for internal use for {@link PendingIntent} in
263 * the notification.
264 */
265 private static final String ACTION_SHOW_INPUT_METHOD_PICKER =
Yohei Yukawa603f4d02018-09-11 15:04:58 -0700266 "com.android.server.inputmethod.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER";
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +0900267
Tarandeep Singh75a92392018-01-12 14:58:59 -0800268 /**
269 * Debug flag for overriding runtime {@link SystemProperties}.
270 */
271 @AnyThread
272 private static final class DebugFlag {
273 private static final Object LOCK = new Object();
274 private final String mKey;
Tarandeep Singh9df4ad12018-04-03 13:35:50 -0700275 private final boolean mDefaultValue;
Tarandeep Singh75a92392018-01-12 14:58:59 -0800276 @GuardedBy("LOCK")
277 private boolean mValue;
278
Tarandeep Singh1c042c52018-03-29 17:04:44 -0700279 public DebugFlag(String key, boolean defaultValue) {
Tarandeep Singh75a92392018-01-12 14:58:59 -0800280 mKey = key;
Tarandeep Singh9df4ad12018-04-03 13:35:50 -0700281 mDefaultValue = defaultValue;
Tarandeep Singh1c042c52018-03-29 17:04:44 -0700282 mValue = SystemProperties.getBoolean(key, defaultValue);
Tarandeep Singh75a92392018-01-12 14:58:59 -0800283 }
284
285 void refresh() {
286 synchronized (LOCK) {
Tarandeep Singh9df4ad12018-04-03 13:35:50 -0700287 mValue = SystemProperties.getBoolean(mKey, mDefaultValue);
Tarandeep Singh75a92392018-01-12 14:58:59 -0800288 }
289 }
290
291 boolean value() {
292 synchronized (LOCK) {
293 return mValue;
294 }
295 }
296 }
297
298 /**
299 * Debug flags that can be overridden using "adb shell setprop <key>"
300 * Note: These flags are cached. To refresh, run "adb shell ime refresh_debug_properties".
301 */
302 private static final class DebugFlags {
303 static final DebugFlag FLAG_OPTIMIZE_START_INPUT =
Tarandeep Singh1c042c52018-03-29 17:04:44 -0700304 new DebugFlag("debug.optimize_startinput", false);
Tarandeep Singheadb1392018-11-09 18:15:57 +0100305 static final DebugFlag FLAG_PRE_RENDER_IME_VIEWS =
306 new DebugFlag("persist.pre_render_ime_views", false);
Tarandeep Singh75a92392018-01-12 14:58:59 -0800307 }
308
Yohei Yukawaa7babbb2019-01-08 16:45:34 -0800309 @UserIdInt
310 private int mLastSwitchUserId;
Tarandeep Singh75a92392018-01-12 14:58:59 -0800311
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800312 final Context mContext;
Dianne Hackborn7d3a5bc2010-11-29 22:52:12 -0800313 final Resources mRes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314 final Handler mHandler;
satokd87c2592010-09-29 11:52:06 +0900315 final InputMethodSettings mSettings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 final SettingsObserver mSettingsObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317 final IWindowManager mIWindowManager;
Seigo Nonaka7309b122015-08-17 18:34:13 -0700318 final WindowManagerInternal mWindowManagerInternal;
Yohei Yukawad5f402b2020-05-15 10:23:32 -0700319 final PackageManagerInternal mPackageManagerInternal;
lpeter133fce02020-03-05 20:32:16 +0800320 final InputManagerInternal mInputManagerInternal;
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700321 private final DisplayManagerInternal mDisplayManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322 final HandlerCaller mCaller;
Dianne Hackborn119bbc32013-03-22 17:27:25 -0700323 final boolean mHasFeature;
Yohei Yukawab557d572018-12-29 21:26:26 -0800324 private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypeMap =
325 new ArrayMap<>();
Tarandeep Singheadb1392018-11-09 18:15:57 +0100326 private final boolean mIsLowRam;
satok01038492012-04-09 21:08:27 +0900327 private final HardKeyboardListener mHardKeyboardListener;
Yohei Yukawae63b5fa2014-09-19 13:14:55 +0900328 private final AppOpsManager mAppOpsManager;
Yohei Yukawaed4952a2016-02-17 07:57:25 -0800329 private final UserManager mUserManager;
Yohei Yukawa42081402019-01-15 09:57:50 -0800330 private final UserManagerInternal mUserManagerInternal;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800331
Yohei Yukawad5f402b2020-05-15 10:23:32 -0700332 /**
333 * Cache the result of {@code LocalServices.getService(AudioManagerInternal.class)}.
334 *
335 * <p>This field is used only within {@link #handleMessage(Message)} hence synchronization is
336 * not necessary.</p>
337 */
338 @Nullable
339 private AudioManagerInternal mAudioManagerInternal = null;
340
341
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 // All known input methods. mMethodMap also serves as the global
343 // lock for this class.
Yohei Yukawab0377bb2015-08-10 21:06:30 -0700344 final ArrayList<InputMethodInfo> mMethodList = new ArrayList<>();
Yohei Yukawa1dd7de62018-11-20 19:25:29 -0800345 final ArrayMap<String, InputMethodInfo> mMethodMap = new ArrayMap<>();
satokf9f01002011-05-19 21:31:50 +0900346 private final LruCache<SuggestionSpan, InputMethodInfo> mSecureSuggestionSpans =
Yohei Yukawab0377bb2015-08-10 21:06:30 -0700347 new LruCache<>(SECURE_SUGGESTION_SPANS_MAX_SIZE);
Satoshi Kataokad787f692013-10-26 04:44:21 +0900348 private final InputMethodSubtypeSwitchingController mSwitchingController;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800349
Yohei Yukawae0733062017-02-09 22:49:35 -0800350 /**
351 * Tracks how many times {@link #mMethodMap} was updated.
352 */
353 @GuardedBy("mMethodMap")
354 private int mMethodMapUpdateCount = 0;
355
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -0700356 // Used to bring IME service up to visible adjustment while it is being shown.
357 final ServiceConnection mVisibleConnection = new ServiceConnection() {
Yohei Yukawad3ef8422018-06-07 16:28:07 -0700358 @Override public void onBindingDied(ComponentName name) {
359 synchronized (mMethodMap) {
360 if (mVisibleBound) {
361 mContext.unbindService(mVisibleConnection);
362 mVisibleBound = false;
363 }
364 }
365 }
366
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -0700367 @Override public void onServiceConnected(ComponentName name, IBinder service) {
368 }
369
370 @Override public void onServiceDisconnected(ComponentName name) {
371 }
372 };
373 boolean mVisibleBound = false;
374
satok7cfc0ed2011-06-20 21:29:36 +0900375 // Ongoing notification
Dianne Hackborn661cd522011-08-22 00:26:20 -0700376 private NotificationManager mNotificationManager;
377 private KeyguardManager mKeyguardManager;
Griff Hazen6090c262016-03-25 08:11:24 -0700378 private @Nullable StatusBarManagerService mStatusBar;
Chris Wren1ce4b6d2015-06-11 10:19:43 -0400379 private Notification.Builder mImeSwitcherNotification;
Dianne Hackborn661cd522011-08-22 00:26:20 -0700380 private PendingIntent mImeSwitchPendingIntent;
satokb858c732011-07-22 19:54:34 +0900381 private boolean mShowOngoingImeSwitcherForPhones;
satok7cfc0ed2011-06-20 21:29:36 +0900382 private boolean mNotificationShown;
383
Tadashi G. Takaoka8c6d4772014-08-05 15:29:17 +0900384 static class SessionState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 final ClientState client;
386 final IInputMethod method;
Jeff Brownc28867a2013-03-26 15:42:39 -0700387
388 IInputMethodSession session;
389 InputChannel channel;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800390
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 @Override
392 public String toString() {
393 return "SessionState{uid " + client.uid + " pid " + client.pid
394 + " method " + Integer.toHexString(
395 System.identityHashCode(method))
396 + " session " + Integer.toHexString(
397 System.identityHashCode(session))
Jeff Brownc28867a2013-03-26 15:42:39 -0700398 + " channel " + channel
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 + "}";
400 }
401
402 SessionState(ClientState _client, IInputMethod _method,
Jeff Brownc28867a2013-03-26 15:42:39 -0700403 IInputMethodSession _session, InputChannel _channel) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 client = _client;
405 method = _method;
406 session = _session;
Jeff Brownc28867a2013-03-26 15:42:39 -0700407 channel = _channel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408 }
409 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800410
Yohei Yukawaa71bb252018-09-19 19:21:24 -0700411 private static final class ClientDeathRecipient implements IBinder.DeathRecipient {
412 private final InputMethodManagerService mImms;
413 private final IInputMethodClient mClient;
414
415 ClientDeathRecipient(InputMethodManagerService imms, IInputMethodClient client) {
416 mImms = imms;
417 mClient = client;
418 }
419
420 @Override
421 public void binderDied() {
422 mImms.removeClient(mClient);
423 }
424 }
425
Jeff Brownc28867a2013-03-26 15:42:39 -0700426 static final class ClientState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 final IInputMethodClient client;
428 final IInputContext inputContext;
429 final int uid;
430 final int pid;
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800431 final int selfReportedDisplayId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432 final InputBinding binding;
Yohei Yukawaa71bb252018-09-19 19:21:24 -0700433 final ClientDeathRecipient clientDeathRecipient;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800434
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 boolean sessionRequested;
Tarandeep Singheadb1392018-11-09 18:15:57 +0100436 // Determines if IMEs should be pre-rendered.
437 // DebugFlag can be flipped anytime. This flag is kept per-client to maintain behavior
438 // through the life of the current client.
439 boolean shouldPreRenderIme;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 SessionState curSession;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800441
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800442 @Override
443 public String toString() {
444 return "ClientState{" + Integer.toHexString(
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800445 System.identityHashCode(this)) + " uid=" + uid
446 + " pid=" + pid + " displayId=" + selfReportedDisplayId + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447 }
448
449 ClientState(IInputMethodClient _client, IInputContext _inputContext,
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800450 int _uid, int _pid, int _selfReportedDisplayId,
451 ClientDeathRecipient _clientDeathRecipient) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 client = _client;
453 inputContext = _inputContext;
454 uid = _uid;
455 pid = _pid;
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800456 selfReportedDisplayId = _selfReportedDisplayId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 binding = new InputBinding(null, inputContext.asBinder(), uid, pid);
Yohei Yukawaa71bb252018-09-19 19:21:24 -0700458 clientDeathRecipient = _clientDeathRecipient;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 }
460 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800461
Yohei Yukawaac9311e2018-11-20 19:25:23 -0800462 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800463
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700464 private static final class ActivityViewInfo {
465 /**
466 * {@link ClientState} where {@link android.app.ActivityView} is running.
467 */
468 private final ClientState mParentClient;
469 /**
470 * {@link Matrix} to convert screen coordinates in the embedded virtual display to
471 * screen coordinates where {@link #mParentClient} exists.
472 */
473 private final Matrix mMatrix;
474
475 ActivityViewInfo(ClientState parentClient, Matrix matrix) {
476 mParentClient = parentClient;
477 mMatrix = matrix;
478 }
479 }
480
481 /**
482 * A mapping table from virtual display IDs created for {@link android.app.ActivityView}
483 * to its parent IME client where {@link android.app.ActivityView} is running.
484 *
485 * <p>Note: this can be used only for virtual display IDs created by
486 * {@link android.app.ActivityView}.</p>
487 */
488 private SparseArray<ActivityViewInfo> mActivityViewDisplayIdToParentMap = new SparseArray<>();
489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 /**
Dianne Hackborna34f1ad2009-09-02 13:26:28 -0700491 * Set once the system is ready to run third party code.
492 */
493 boolean mSystemReady;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800494
Dianne Hackborna34f1ad2009-09-02 13:26:28 -0700495 /**
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700496 * Id obtained with {@link InputMethodInfo#getId()} for the currently selected input method.
497 * method. This is to be synchronized with the secure settings keyed with
498 * {@link Settings.Secure#DEFAULT_INPUT_METHOD}.
499 *
500 * <p>This can be transiently {@code null} when the system is re-initializing input method
501 * settings, e.g., the system locale is just changed.</p>
502 *
503 * <p>Note that {@link #mCurId} is used to track which IME is being connected to
504 * {@link InputMethodManagerService}.</p>
505 *
506 * @see #mCurId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 */
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700508 @Nullable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509 String mCurMethodId;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800510
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 /**
512 * The current binding sequence number, incremented every time there is
513 * a new bind performed.
514 */
515 int mCurSeq;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800516
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 /**
518 * The client that is currently bound to an input method.
519 */
520 ClientState mCurClient;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800521
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 /**
Yohei Yukawae39d4ed2015-11-19 03:38:49 -0800523 * The last window token that we confirmed to be focused. This is always updated upon reports
524 * from the input method client. If the window state is already changed before the report is
525 * handled, this field just keeps the last value.
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700526 */
527 IBinder mCurFocusedWindow;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800528
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700529 /**
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -0700530 * The last window token that we confirmed that IME started talking to. This is always updated
531 * upon reports from the input method. If the window state is already changed before the report
532 * is handled, this field just keeps the last value.
533 */
534 IBinder mLastImeTargetWindow;
535
536 /**
Yohei Yukawa6e875592019-01-28 00:49:30 -0800537 * {@link LayoutParams#softInputMode} of {@link #mCurFocusedWindow}.
Yohei Yukawa22a89232017-02-12 16:38:59 -0800538 *
539 * @see #mCurFocusedWindow
540 */
Yohei Yukawab0c26452018-10-21 10:42:52 -0700541 @SoftInputModeFlags
Yohei Yukawa22a89232017-02-12 16:38:59 -0800542 int mCurFocusedWindowSoftInputMode;
543
544 /**
Tarandeep Singheb570612018-01-29 16:20:32 -0800545 * The client by which {@link #mCurFocusedWindow} was reported.
Yohei Yukawae39d4ed2015-11-19 03:38:49 -0800546 */
547 ClientState mCurFocusedWindowClient;
548
549 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 * The input context last provided by the current client.
551 */
552 IInputContext mCurInputContext;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800554 /**
Yohei Yukawa19a80a12016-03-14 22:57:37 -0700555 * The missing method flags for the input context last provided by the current client.
556 *
557 * @see android.view.inputmethod.InputConnectionInspector.MissingMethodFlags
558 */
Yohei Yukawa432cf602018-10-21 10:41:37 -0700559 @MissingMethodFlags
Yohei Yukawa19a80a12016-03-14 22:57:37 -0700560 int mCurInputContextMissingMethods;
561
562 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 * The attributes last provided by the current client.
564 */
565 EditorInfo mCurAttribute;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800566
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 /**
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700568 * A special {@link Matrix} to convert virtual screen coordinates to the IME target display
569 * coordinates.
570 *
571 * <p>Used only while the IME client is running in a virtual display inside
572 * {@link android.app.ActivityView}. {@code null} otherwise.</p>
573 */
574 @Nullable
575 private Matrix mCurActivityViewToScreenMatrix = null;
576
577 /**
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700578 * Id obtained with {@link InputMethodInfo#getId()} for the input method that we are currently
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 * connected to or in the process of connecting to.
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700580 *
581 * <p>This can be {@code null} when no input method is connected.</p>
582 *
583 * @see #mCurMethodId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 */
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700585 @Nullable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 String mCurId;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800587
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 /**
satokab751aa2010-09-14 19:17:36 +0900589 * The current subtype of the current input method.
590 */
591 private InputMethodSubtype mCurrentSubtype;
592
John Spurlocke0980502013-10-25 11:59:29 -0400593 // Was the keyguard locked when this client became current?
594 private boolean mCurClientInKeyguard;
595
satokab751aa2010-09-14 19:17:36 +0900596 /**
Adrian Roosc22eec92020-06-12 18:48:10 +0200597 * {@code true} if the IME has not been mostly hidden via {@link android.view.InsetsController}
598 */
599 private boolean mCurPerceptible;
600
601 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602 * Set to true if our ServiceConnection is currently actively bound to
603 * a service (whether or not we have gotten its IBinder back yet).
604 */
605 boolean mHaveConnection;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800606
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 /**
608 * Set if the client has asked for the input method to be shown.
609 */
610 boolean mShowRequested;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 /**
613 * Set if we were explicitly told to show the input method.
614 */
615 boolean mShowExplicitlyRequested;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800616
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800617 /**
618 * Set if we were forced to be shown.
619 */
620 boolean mShowForced;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800621
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622 /**
623 * Set if we last told the input method to show itself.
624 */
625 boolean mInputShown;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800626
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800627 /**
Yohei Yukawa2bc66172017-02-08 11:13:25 -0800628 * {@code true} if the current input method is in fullscreen mode.
629 */
630 boolean mInFullscreenMode;
631
632 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 * The Intent used to connect to the current input method.
634 */
635 Intent mCurIntent;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800636
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 /**
638 * The token we have made for the currently active input method, to
639 * identify it in the future.
640 */
641 IBinder mCurToken;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800642
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 /**
lumark90120a82018-08-15 00:33:03 +0800644 * The displayId of current active input method.
645 */
646 int mCurTokenDisplayId = INVALID_DISPLAY;
647
lumark7570cac2019-03-07 22:14:38 +0800648 /**
lpeter133fce02020-03-05 20:32:16 +0800649 * The host input token of the current active input method.
650 */
651 @GuardedBy("mMethodMap")
652 @Nullable
653 private IBinder mCurHostInputToken;
654
655 /**
lumark7570cac2019-03-07 22:14:38 +0800656 * The display ID of the input method indicates the fallback display which returned by
657 * {@link #computeImeDisplayIdForTarget}.
658 */
659 private static final int FALLBACK_DISPLAY_ID = DEFAULT_DISPLAY;
660
lumarkef1965b2018-09-12 17:42:53 +0800661 final ImeDisplayValidator mImeDisplayValidator;
662
lumark90120a82018-08-15 00:33:03 +0800663 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 * If non-null, this is the input method service we are currently connected
665 * to.
666 */
667 IInputMethod mCurMethod;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800668
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800669 /**
Yohei Yukawad5f402b2020-05-15 10:23:32 -0700670 * If not {@link Process#INVALID_UID}, then the UID of {@link #mCurIntent}.
671 */
672 int mCurMethodUid = Process.INVALID_UID;
673
674 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 * Time that we last initiated a bind to the input method, to determine
676 * if we should try to disconnect and reconnect to it.
677 */
678 long mLastBindTime;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800679
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800680 /**
681 * Have we called mCurMethod.bindInput()?
682 */
683 boolean mBoundToMethod;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800684
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 /**
686 * Currently enabled session. Only touched by service thread, not
687 * protected by a lock.
688 */
689 SessionState mEnabledSession;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800690
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691 /**
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700692 * True if the device is currently interactive with user. The value is true initially.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800693 */
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700694 boolean mIsInteractive = true;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800695
Joe Onorato857fd9b2011-01-27 15:08:35 -0800696 int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
Seigo Nonakad9eb9112015-05-26 20:54:43 +0900697
698 /**
699 * A set of status bits regarding the active IME.
700 *
701 * <p>This value is a combination of following two bits:</p>
702 * <dl>
703 * <dt>{@link InputMethodService#IME_ACTIVE}</dt>
704 * <dd>
705 * If this bit is ON, connected IME is ready to accept touch/key events.
706 * </dd>
707 * <dt>{@link InputMethodService#IME_VISIBLE}</dt>
708 * <dd>
709 * If this bit is ON, some of IME view, e.g. software input, candidate view, is visible.
710 * </dd>
Tarandeep Singheadb1392018-11-09 18:15:57 +0100711 * dt>{@link InputMethodService#IME_INVISIBLE}</dt>
712 * <dd> If this bit is ON, IME is ready with views from last EditorInfo but is
713 * currently invisible.
714 * </dd>
Seigo Nonakad9eb9112015-05-26 20:54:43 +0900715 * </dl>
lumark7570cac2019-03-07 22:14:38 +0800716 * <em>Do not update this value outside of {@link #setImeWindowStatus(IBinder, int, int)} and
717 * {@link #unbindCurrentMethodLocked()}.</em>
Seigo Nonakad9eb9112015-05-26 20:54:43 +0900718 */
Joe Onorato857fd9b2011-01-27 15:08:35 -0800719 int mImeWindowVis;
720
Ming-Shin Lu48bfc312020-06-15 20:06:09 +0800721 /**
722 * Checks if the client needs to start input.
723 */
724 private boolean mCurClientNeedStartInput = false;
725
Ken Wakasa05dbb652011-08-22 15:22:43 +0900726 private AlertDialog.Builder mDialogBuilder;
727 private AlertDialog mSwitchingDialog;
Wale Ogunwale3a931692016-11-02 16:49:48 -0700728 private IBinder mSwitchingDialogToken = new Binder();
satok01038492012-04-09 21:08:27 +0900729 private View mSwitchingDialogTitleView;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900730 private InputMethodInfo[] mIms;
731 private int[] mSubtypeIds;
Yohei Yukawae985c242016-02-24 18:27:04 -0800732 private LocaleList mLastSystemLocales;
Michael Wright7b5a96b2014-08-09 19:28:42 -0700733 private boolean mShowImeWithHardKeyboard;
Anna Galusza9b278112016-01-04 11:37:37 -0800734 private boolean mAccessibilityRequestingNoSoftKeyboard;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +0900735 private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
736 private final IPackageManager mIPackageManager;
Jason Monk3e189872016-01-12 09:10:34 -0500737 private final String mSlotIme;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800738
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800739 /**
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +0900740 * Registered {@link InputMethodListListeners}.
741 * This variable can be accessed from both of MainThread and BinderThread.
742 */
743 private final CopyOnWriteArrayList<InputMethodListListener> mInputMethodListListeners =
744 new CopyOnWriteArrayList<>();
745
746 /**
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800747 * Internal state snapshot when {@link #MSG_START_INPUT} message is about to be posted to the
748 * internal message queue. Any subsequent state change inside {@link InputMethodManagerService}
749 * will not affect those tasks that are already posted.
750 *
751 * <p>Posting {@link #MSG_START_INPUT} message basically means that
752 * {@link InputMethodService#doStartInput(InputConnection, EditorInfo, boolean)} will be called
753 * back in the current IME process shortly, which will also affect what the current IME starts
754 * receiving from {@link InputMethodService#getCurrentInputConnection()}. In other words, this
755 * snapshot will be taken every time when {@link InputMethodManagerService} is initiating a new
756 * logical input session between the client application and the current IME.</p>
757 *
758 * <p>Be careful to not keep strong references to this object forever, which can prevent
759 * {@link StartInputInfo#mImeToken} and {@link StartInputInfo#mTargetWindow} from being GC-ed.
760 * </p>
761 */
762 private static class StartInputInfo {
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800763 private static final AtomicInteger sSequenceNumber = new AtomicInteger(0);
764
765 final int mSequenceNumber;
766 final long mTimestamp;
767 final long mWallTime;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800768 @UserIdInt
769 final int mImeUserId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800770 @NonNull
771 final IBinder mImeToken;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800772 final int mImeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800773 @NonNull
774 final String mImeId;
Yohei Yukawadc66e522018-10-21 10:43:14 -0700775 @StartInputReason
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800776 final int mStartInputReason;
777 final boolean mRestarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800778 @UserIdInt
779 final int mTargetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800780 final int mTargetDisplayId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800781 @Nullable
782 final IBinder mTargetWindow;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800783 @NonNull
784 final EditorInfo mEditorInfo;
Yohei Yukawab0c26452018-10-21 10:42:52 -0700785 @SoftInputModeFlags
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800786 final int mTargetWindowSoftInputMode;
787 final int mClientBindSequenceNumber;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800788
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800789 StartInputInfo(@UserIdInt int imeUserId, @NonNull IBinder imeToken, int imeDisplayId,
790 @NonNull String imeId, @StartInputReason int startInputReason, boolean restarting,
791 @UserIdInt int targetUserId, int targetDisplayId, @Nullable IBinder targetWindow,
792 @NonNull EditorInfo editorInfo, @SoftInputModeFlags int targetWindowSoftInputMode,
793 int clientBindSequenceNumber) {
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800794 mSequenceNumber = sSequenceNumber.getAndIncrement();
795 mTimestamp = SystemClock.uptimeMillis();
796 mWallTime = System.currentTimeMillis();
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800797 mImeUserId = imeUserId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800798 mImeToken = imeToken;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800799 mImeDisplayId = imeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800800 mImeId = imeId;
801 mStartInputReason = startInputReason;
802 mRestarting = restarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800803 mTargetUserId = targetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800804 mTargetDisplayId = targetDisplayId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800805 mTargetWindow = targetWindow;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800806 mEditorInfo = editorInfo;
807 mTargetWindowSoftInputMode = targetWindowSoftInputMode;
808 mClientBindSequenceNumber = clientBindSequenceNumber;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800809 }
810 }
811
Yohei Yukawab37d8bd2017-02-13 18:29:05 -0800812 @GuardedBy("mMethodMap")
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -0700813 private final WeakHashMap<IBinder, IBinder> mImeTargetWindowMap = new WeakHashMap<>();
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800814
lumarkd85e1582019-12-29 20:20:41 +0800815 private static final class SoftInputShowHideHistory {
816 private Entry[] mEntries = new Entry[16];
817 private int mNextIndex = 0;
818 private static final AtomicInteger sSequenceNumber = new AtomicInteger(0);
819
lumarkd85e1582019-12-29 20:20:41 +0800820 private static final class Entry {
Ming-Shin Lua0605a62020-04-15 23:49:40 +0800821 final int mSequenceNumber = sSequenceNumber.getAndIncrement();
Anmol Gupta29f209d2020-03-11 11:34:46 -0700822 final ClientState mClientState;
lumarkd85e1582019-12-29 20:20:41 +0800823 @SoftInputModeFlags
Anmol Gupta29f209d2020-03-11 11:34:46 -0700824 final int mFocusedWindowSoftInputMode;
lumarkd85e1582019-12-29 20:20:41 +0800825 @SoftInputShowHideReason
Anmol Gupta29f209d2020-03-11 11:34:46 -0700826 final int mReason;
lumarkd85e1582019-12-29 20:20:41 +0800827 // The timing of handling MSG_SHOW_SOFT_INPUT or MSG_HIDE_SOFT_INPUT.
Anmol Gupta29f209d2020-03-11 11:34:46 -0700828 final long mTimestamp;
829 final long mWallTime;
830 final boolean mInFullscreenMode;
831 @NonNull
832 final String mFocusedWindowName;
833 @NonNull
834 final EditorInfo mEditorInfo;
835 @NonNull
836 final String mRequestWindowName;
Ming-Shin Lud0bc1712020-05-11 09:23:37 +0800837 @Nullable
838 final String mImeControlTargetName;
839 @Nullable
840 final String mImeTargetNameFromWm;
lumarkd85e1582019-12-29 20:20:41 +0800841
Anmol Gupta29f209d2020-03-11 11:34:46 -0700842 Entry(ClientState client, EditorInfo editorInfo, String focusedWindowName,
843 @SoftInputModeFlags int softInputMode, @SoftInputShowHideReason int reason,
Ming-Shin Lud0bc1712020-05-11 09:23:37 +0800844 boolean inFullscreenMode, String requestWindowName,
845 @Nullable String imeControlTargetName, @Nullable String imeTargetName) {
lumarkd85e1582019-12-29 20:20:41 +0800846 mClientState = client;
Anmol Gupta29f209d2020-03-11 11:34:46 -0700847 mEditorInfo = editorInfo;
848 mFocusedWindowName = focusedWindowName;
lumarkd85e1582019-12-29 20:20:41 +0800849 mFocusedWindowSoftInputMode = softInputMode;
850 mReason = reason;
lumarkd85e1582019-12-29 20:20:41 +0800851 mTimestamp = SystemClock.uptimeMillis();
852 mWallTime = System.currentTimeMillis();
Anmol Gupta29f209d2020-03-11 11:34:46 -0700853 mInFullscreenMode = inFullscreenMode;
854 mRequestWindowName = requestWindowName;
Ming-Shin Lud0bc1712020-05-11 09:23:37 +0800855 mImeControlTargetName = imeControlTargetName;
856 mImeTargetNameFromWm = imeTargetName;
lumarkd85e1582019-12-29 20:20:41 +0800857 }
858 }
859
860 void addEntry(@NonNull Entry entry) {
861 final int index = mNextIndex;
862 mEntries[index] = entry;
863 mNextIndex = (mNextIndex + 1) % mEntries.length;
864 }
865
866 void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
867 final SimpleDateFormat dataFormat =
868 new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
869
870 for (int i = 0; i < mEntries.length; ++i) {
871 final Entry entry = mEntries[(i + mNextIndex) % mEntries.length];
872 if (entry == null) {
873 continue;
874 }
875 pw.print(prefix);
Ming-Shin Lua0605a62020-04-15 23:49:40 +0800876 pw.println("SoftInputShowHideHistory #" + entry.mSequenceNumber + ":");
lumarkd85e1582019-12-29 20:20:41 +0800877
878 pw.print(prefix);
879 pw.println(" time=" + dataFormat.format(new Date(entry.mWallTime))
880 + " (timestamp=" + entry.mTimestamp + ")");
881
882 pw.print(prefix);
Anmol Gupta29f209d2020-03-11 11:34:46 -0700883 pw.print(" reason=" + InputMethodDebug.softInputDisplayReasonToString(
884 entry.mReason));
885 pw.println(" inFullscreenMode=" + entry.mInFullscreenMode);
lumarkd85e1582019-12-29 20:20:41 +0800886
887 pw.print(prefix);
Anmol Gupta29f209d2020-03-11 11:34:46 -0700888 pw.println(" requestClient=" + entry.mClientState);
889
890 pw.print(prefix);
891 pw.println(" focusedWindowName=" + entry.mFocusedWindowName);
892
893 pw.print(prefix);
894 pw.println(" requestWindowName=" + entry.mRequestWindowName);
895
896 pw.print(prefix);
Ming-Shin Lud0bc1712020-05-11 09:23:37 +0800897 pw.println(" imeControlTargetName=" + entry.mImeControlTargetName);
898
899 pw.print(prefix);
900 pw.println(" imeTargetNameFromWm=" + entry.mImeTargetNameFromWm);
901
902 pw.print(prefix);
Anmol Gupta29f209d2020-03-11 11:34:46 -0700903 pw.print(" editorInfo: ");
904 pw.print(" inputType=" + entry.mEditorInfo.inputType);
905 pw.print(" privateImeOptions=" + entry.mEditorInfo.privateImeOptions);
906 pw.println(" fieldId (viewId)=" + entry.mEditorInfo.fieldId);
lumarkd85e1582019-12-29 20:20:41 +0800907
908 pw.print(prefix);
909 pw.println(" focusedWindowSoftInputMode=" + InputMethodDebug.softInputModeToString(
910 entry.mFocusedWindowSoftInputMode));
911 }
912 }
913 }
914
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800915 /**
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -0800916 * Map of generated token to windowToken that is requesting
917 * {@link InputMethodManager#showSoftInput(View, int)}.
918 * This map tracks origin of showSoftInput requests.
919 */
920 @GuardedBy("mMethodMap")
921 private final WeakHashMap<IBinder, IBinder> mShowRequestWindowMap = new WeakHashMap<>();
922
923 /**
Tarandeep Singh4fe5b652020-02-20 17:20:19 -0800924 * Map of generated token to windowToken that is requesting
925 * {@link InputMethodManager#hideSoftInputFromWindow(IBinder, int)}.
926 * This map tracks origin of hideSoftInput requests.
927 */
928 @GuardedBy("mMethodMap")
929 private final WeakHashMap<IBinder, IBinder> mHideRequestWindowMap = new WeakHashMap<>();
930
931 /**
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800932 * A ring buffer to store the history of {@link StartInputInfo}.
933 */
934 private static final class StartInputHistory {
935 /**
936 * Entry size for non low-RAM devices.
937 *
938 * <p>TODO: Consider to follow what other system services have been doing to manage
939 * constants (e.g. {@link android.provider.Settings.Global#ACTIVITY_MANAGER_CONSTANTS}).</p>
940 */
941 private final static int ENTRY_SIZE_FOR_HIGH_RAM_DEVICE = 16;
942
943 /**
944 * Entry size for non low-RAM devices.
945 *
946 * <p>TODO: Consider to follow what other system services have been doing to manage
947 * constants (e.g. {@link android.provider.Settings.Global#ACTIVITY_MANAGER_CONSTANTS}).</p>
948 */
949 private final static int ENTRY_SIZE_FOR_LOW_RAM_DEVICE = 5;
950
951 private static int getEntrySize() {
952 if (ActivityManager.isLowRamDeviceStatic()) {
953 return ENTRY_SIZE_FOR_LOW_RAM_DEVICE;
954 } else {
955 return ENTRY_SIZE_FOR_HIGH_RAM_DEVICE;
956 }
957 }
958
959 /**
960 * Backing store for the ring bugger.
961 */
962 private final Entry[] mEntries = new Entry[getEntrySize()];
963
964 /**
965 * An index of {@link #mEntries}, to which next {@link #addEntry(StartInputInfo)} should
966 * write.
967 */
968 private int mNextIndex = 0;
969
970 /**
971 * Recyclable entry to store the information in {@link StartInputInfo}.
972 */
973 private static final class Entry {
974 int mSequenceNumber;
975 long mTimestamp;
976 long mWallTime;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800977 @UserIdInt
978 int mImeUserId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800979 @NonNull
980 String mImeTokenString;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800981 int mImeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800982 @NonNull
983 String mImeId;
Yohei Yukawadc66e522018-10-21 10:43:14 -0700984 @StartInputReason
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800985 int mStartInputReason;
986 boolean mRestarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800987 @UserIdInt
988 int mTargetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800989 int mTargetDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800990 @NonNull
991 String mTargetWindowString;
992 @NonNull
993 EditorInfo mEditorInfo;
Yohei Yukawab0c26452018-10-21 10:42:52 -0700994 @SoftInputModeFlags
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800995 int mTargetWindowSoftInputMode;
996 int mClientBindSequenceNumber;
997
998 Entry(@NonNull StartInputInfo original) {
999 set(original);
1000 }
1001
1002 void set(@NonNull StartInputInfo original) {
1003 mSequenceNumber = original.mSequenceNumber;
1004 mTimestamp = original.mTimestamp;
1005 mWallTime = original.mWallTime;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -08001006 mImeUserId = original.mImeUserId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -08001007 // Intentionally convert to String so as not to keep a strong reference to a Binder
1008 // object.
1009 mImeTokenString = String.valueOf(original.mImeToken);
Yohei Yukawa557afbb2019-02-12 02:01:00 -08001010 mImeDisplayId = original.mImeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -08001011 mImeId = original.mImeId;
1012 mStartInputReason = original.mStartInputReason;
1013 mRestarting = original.mRestarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -08001014 mTargetUserId = original.mTargetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -08001015 mTargetDisplayId = original.mTargetDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -08001016 // Intentionally convert to String so as not to keep a strong reference to a Binder
1017 // object.
1018 mTargetWindowString = String.valueOf(original.mTargetWindow);
1019 mEditorInfo = original.mEditorInfo;
1020 mTargetWindowSoftInputMode = original.mTargetWindowSoftInputMode;
1021 mClientBindSequenceNumber = original.mClientBindSequenceNumber;
1022 }
1023 }
1024
1025 /**
1026 * Add a new entry and discard the oldest entry as needed.
1027 * @param info {@lin StartInputInfo} to be added.
1028 */
1029 void addEntry(@NonNull StartInputInfo info) {
1030 final int index = mNextIndex;
1031 if (mEntries[index] == null) {
1032 mEntries[index] = new Entry(info);
1033 } else {
1034 mEntries[index].set(info);
1035 }
1036 mNextIndex = (mNextIndex + 1) % mEntries.length;
1037 }
1038
1039 void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
1040 final SimpleDateFormat dataFormat =
1041 new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
1042
1043 for (int i = 0; i < mEntries.length; ++i) {
1044 final Entry entry = mEntries[(i + mNextIndex) % mEntries.length];
1045 if (entry == null) {
1046 continue;
1047 }
1048 pw.print(prefix);
1049 pw.println("StartInput #" + entry.mSequenceNumber + ":");
1050
1051 pw.print(prefix);
1052 pw.println(" time=" + dataFormat.format(new Date(entry.mWallTime))
1053 + " (timestamp=" + entry.mTimestamp + ")"
1054 + " reason="
Yohei Yukawaa468d702018-10-21 11:42:34 -07001055 + InputMethodDebug.startInputReasonToString(entry.mStartInputReason)
Yohei Yukawa357b2f62017-02-14 09:40:03 -08001056 + " restarting=" + entry.mRestarting);
1057
1058 pw.print(prefix);
Yohei Yukawa557afbb2019-02-12 02:01:00 -08001059 pw.print(" imeToken=" + entry.mImeTokenString + " [" + entry.mImeId + "]");
Yohei Yukawa7979e1a2019-02-12 02:01:10 -08001060 pw.print(" imeUserId=" + entry.mImeUserId);
Yohei Yukawa557afbb2019-02-12 02:01:00 -08001061 pw.println(" imeDisplayId=" + entry.mImeDisplayId);
Yohei Yukawa357b2f62017-02-14 09:40:03 -08001062
1063 pw.print(prefix);
1064 pw.println(" targetWin=" + entry.mTargetWindowString
1065 + " [" + entry.mEditorInfo.packageName + "]"
Yohei Yukawa7979e1a2019-02-12 02:01:10 -08001066 + " targetUserId=" + entry.mTargetUserId
Yohei Yukawa557afbb2019-02-12 02:01:00 -08001067 + " targetDisplayId=" + entry.mTargetDisplayId
Yohei Yukawa357b2f62017-02-14 09:40:03 -08001068 + " clientBindSeq=" + entry.mClientBindSequenceNumber);
1069
1070 pw.print(prefix);
Yohei Yukawaa468d702018-10-21 11:42:34 -07001071 pw.println(" softInputMode=" + InputMethodDebug.softInputModeToString(
Yohei Yukawa357b2f62017-02-14 09:40:03 -08001072 entry.mTargetWindowSoftInputMode));
1073
1074 pw.print(prefix);
1075 pw.println(" inputType=0x" + Integer.toHexString(entry.mEditorInfo.inputType)
1076 + " imeOptions=0x" + Integer.toHexString(entry.mEditorInfo.imeOptions)
1077 + " fieldId=0x" + Integer.toHexString(entry.mEditorInfo.fieldId)
1078 + " fieldName=" + entry.mEditorInfo.fieldName
1079 + " actionId=" + entry.mEditorInfo.actionId
1080 + " actionLabel=" + entry.mEditorInfo.actionLabel);
1081 }
1082 }
1083 }
1084
1085 @GuardedBy("mMethodMap")
1086 @NonNull
1087 private final StartInputHistory mStartInputHistory = new StartInputHistory();
1088
lumarkd85e1582019-12-29 20:20:41 +08001089 @GuardedBy("mMethodMap")
1090 @NonNull
1091 private final SoftInputShowHideHistory mSoftInputShowHideHistory =
1092 new SoftInputShowHideHistory();
1093
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 class SettingsObserver extends ContentObserver {
Yohei Yukawa81482972015-06-04 00:58:59 -07001095 int mUserId;
1096 boolean mRegistered = false;
Yohei Yukawa7b574cb2016-03-16 17:22:22 -07001097 @NonNull
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08001098 String mLastEnabled = "";
1099
Yohei Yukawa81482972015-06-04 00:58:59 -07001100 /**
1101 * <em>This constructor must be called within the lock.</em>
1102 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 SettingsObserver(Handler handler) {
1104 super(handler);
Yohei Yukawa81482972015-06-04 00:58:59 -07001105 }
1106
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001107 public void registerContentObserverLocked(@UserIdInt int userId) {
Yohei Yukawa81482972015-06-04 00:58:59 -07001108 if (mRegistered && mUserId == userId) {
1109 return;
1110 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001111 ContentResolver resolver = mContext.getContentResolver();
Yohei Yukawa81482972015-06-04 00:58:59 -07001112 if (mRegistered) {
1113 mContext.getContentResolver().unregisterContentObserver(this);
1114 mRegistered = false;
1115 }
1116 if (mUserId != userId) {
1117 mLastEnabled = "";
1118 mUserId = userId;
1119 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -07001121 Settings.Secure.DEFAULT_INPUT_METHOD), false, this, userId);
satokab751aa2010-09-14 19:17:36 +09001122 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -07001123 Settings.Secure.ENABLED_INPUT_METHODS), false, this, userId);
satokb6109bb2011-02-03 22:24:54 +09001124 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -07001125 Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this, userId);
Michael Wright7b5a96b2014-08-09 19:28:42 -07001126 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -07001127 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, this, userId);
Anna Galusza9b278112016-01-04 11:37:37 -08001128 resolver.registerContentObserver(Settings.Secure.getUriFor(
1129 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE), false, this, userId);
Yohei Yukawa81482972015-06-04 00:58:59 -07001130 mRegistered = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001131 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001132
Michael Wright7b5a96b2014-08-09 19:28:42 -07001133 @Override public void onChange(boolean selfChange, Uri uri) {
Anna Galusza9b278112016-01-04 11:37:37 -08001134 final Uri showImeUri = Settings.Secure.getUriFor(
1135 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
1136 final Uri accessibilityRequestingNoImeUri = Settings.Secure.getUriFor(
1137 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001138 synchronized (mMethodMap) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07001139 if (showImeUri.equals(uri)) {
1140 updateKeyboardFromSettingsLocked();
Anna Galusza9b278112016-01-04 11:37:37 -08001141 } else if (accessibilityRequestingNoImeUri.equals(uri)) {
Phil Weaver03a65b02018-07-19 16:07:57 -07001142 final int accessibilitySoftKeyboardSetting = Settings.Secure.getIntForUser(
Anna Galusza9b278112016-01-04 11:37:37 -08001143 mContext.getContentResolver(),
Phil Weaver03a65b02018-07-19 16:07:57 -07001144 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0, mUserId);
1145 mAccessibilityRequestingNoSoftKeyboard =
1146 (accessibilitySoftKeyboardSetting & AccessibilityService.SHOW_MODE_MASK)
1147 == AccessibilityService.SHOW_MODE_HIDDEN;
Anna Galusza9b278112016-01-04 11:37:37 -08001148 if (mAccessibilityRequestingNoSoftKeyboard) {
1149 final boolean showRequested = mShowRequested;
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08001150 hideCurrentInputLocked(mCurFocusedWindow, 0, null,
lumarkd85e1582019-12-29 20:20:41 +08001151 SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE);
Anna Galusza9b278112016-01-04 11:37:37 -08001152 mShowRequested = showRequested;
1153 } else if (mShowRequested) {
lumarkd85e1582019-12-29 20:20:41 +08001154 showCurrentInputLocked(mCurFocusedWindow,
1155 InputMethodManager.SHOW_IMPLICIT, null,
1156 SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE);
Anna Galusza9b278112016-01-04 11:37:37 -08001157 }
Michael Wright7b5a96b2014-08-09 19:28:42 -07001158 } else {
1159 boolean enabledChanged = false;
1160 String newEnabled = mSettings.getEnabledInputMethodsStr();
1161 if (!mLastEnabled.equals(newEnabled)) {
1162 mLastEnabled = newEnabled;
1163 enabledChanged = true;
1164 }
1165 updateInputMethodsFromSettingsLocked(enabledChanged);
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08001166 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001167 }
1168 }
Yohei Yukawa81482972015-06-04 00:58:59 -07001169
1170 @Override
1171 public String toString() {
1172 return "SettingsObserver{mUserId=" + mUserId + " mRegistered=" + mRegistered
1173 + " mLastEnabled=" + mLastEnabled + "}";
1174 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001175 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001176
Yohei Yukawa0ec08002019-03-08 10:48:26 -08001177 /**
1178 * {@link BroadcastReceiver} that is intended to listen to broadcasts sent to the system user
1179 * only.
1180 */
1181 private final class ImmsBroadcastReceiverForSystemUser extends BroadcastReceiver {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001182 @Override
1183 public void onReceive(Context context, Intent intent) {
1184 final String action = intent.getAction();
Yohei Yukawa4225c7d2019-03-08 00:06:11 -08001185 if (Intent.ACTION_USER_ADDED.equals(action)
Amith Yamasani734983f2014-03-04 16:48:05 -08001186 || Intent.ACTION_USER_REMOVED.equals(action)) {
Kenny Guy2a764942014-04-02 13:29:20 +01001187 updateCurrentProfileIds();
Amith Yamasani734983f2014-03-04 16:48:05 -08001188 return;
Yohei Yukawa79247822017-01-23 15:26:15 -08001189 } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001190 onActionLocaleChanged();
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001191 } else if (ACTION_SHOW_INPUT_METHOD_PICKER.equals(action)) {
1192 // ACTION_SHOW_INPUT_METHOD_PICKER action is a protected-broadcast and it is
1193 // guaranteed to be send only from the system, so that there is no need for extra
1194 // security check such as
1195 // {@link #canShowInputMethodPickerLocked(IInputMethodClient)}.
1196 mHandler.obtainMessage(
1197 MSG_SHOW_IM_SUBTYPE_PICKER,
lumark0b05f9e2018-11-26 15:09:06 +08001198 // TODO(b/120076400): Design and implement IME switcher for heterogeneous
1199 // navbar configuration.
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001200 InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES,
lumark0b05f9e2018-11-26 15:09:06 +08001201 DEFAULT_DISPLAY).sendToTarget();
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001202 } else {
1203 Slog.w(TAG, "Unexpected intent " + intent);
1204 }
1205 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001206 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001207
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001208 /**
Yohei Yukawa0ec08002019-03-08 10:48:26 -08001209 * {@link BroadcastReceiver} that is intended to listen to broadcasts sent to all the users.
1210 */
1211 private final class ImmsBroadcastReceiverForAllUsers extends BroadcastReceiver {
1212 @Override
1213 public void onReceive(Context context, Intent intent) {
1214 final String action = intent.getAction();
1215 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
1216 final PendingResult pendingResult = getPendingResult();
1217 if (pendingResult == null) {
1218 return;
1219 }
1220 // sender userId can be a real user ID or USER_ALL.
1221 final int senderUserId = pendingResult.getSendingUserId();
1222 if (senderUserId != UserHandle.USER_ALL) {
Tarandeep Singhcf5ff822019-07-08 14:06:27 -07001223 if (senderUserId != mSettings.getCurrentUserId()) {
Yohei Yukawa0ec08002019-03-08 10:48:26 -08001224 // A background user is trying to hide the dialog. Ignore.
1225 return;
1226 }
1227 }
1228 hideInputMethodMenu();
1229 } else {
1230 Slog.w(TAG, "Unexpected intent " + intent);
1231 }
1232 }
1233 }
1234
1235 /**
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001236 * Handles {@link Intent#ACTION_LOCALE_CHANGED}.
1237 *
1238 * <p>Note: For historical reasons, {@link Intent#ACTION_LOCALE_CHANGED} has been sent to all
1239 * the users. We should ignore this event if this is about any background user's locale.</p>
1240 *
1241 * <p>Caution: This method must not be called when system is not ready.</p>
1242 */
1243 void onActionLocaleChanged() {
1244 synchronized (mMethodMap) {
1245 final LocaleList possibleNewLocale = mRes.getConfiguration().getLocales();
1246 if (possibleNewLocale != null && possibleNewLocale.equals(mLastSystemLocales)) {
1247 return;
1248 }
1249 buildInputMethodListLocked(true);
1250 // If the locale is changed, needs to reset the default ime
1251 resetDefaultImeLocked(mContext);
1252 updateFromSettingsLocked(true);
1253 mLastSystemLocales = possibleNewLocale;
1254 }
1255 }
1256
Yohei Yukawac4e44912017-02-09 19:30:22 -08001257 final class MyPackageMonitor extends PackageMonitor {
1258 /**
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001259 * Package names that are known to contain {@link InputMethodService}.
Yohei Yukawac4e44912017-02-09 19:30:22 -08001260 *
1261 * <p>No need to include packages because of direct-boot unaware IMEs since we always rescan
1262 * all the packages when the user is unlocked, and direct-boot awareness will not be changed
1263 * dynamically unless the entire package is updated, which also always triggers package
1264 * rescanning.</p>
1265 */
1266 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001267 final private ArraySet<String> mKnownImePackageNames = new ArraySet<>();
1268
1269 /**
1270 * Packages that are appeared, disappeared, or modified for whatever reason.
1271 *
1272 * <p>Note: For now we intentionally use {@link ArrayList} instead of {@link ArraySet}
1273 * because 1) the number of elements is almost always 1 or so, and 2) we do not care
1274 * duplicate elements for our use case.</p>
1275 *
1276 * <p>This object must be accessed only from callback methods in {@link PackageMonitor},
1277 * which should be bound to {@link #getRegisteredHandler()}.</p>
1278 */
1279 private final ArrayList<String> mChangedPackages = new ArrayList<>();
1280
1281 /**
1282 * {@code true} if one or more packages that contain {@link InputMethodService} appeared.
1283 *
1284 * <p>This field must be accessed only from callback methods in {@link PackageMonitor},
1285 * which should be bound to {@link #getRegisteredHandler()}.</p>
1286 */
1287 private boolean mImePackageAppeared = false;
Yohei Yukawac4e44912017-02-09 19:30:22 -08001288
1289 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001290 void clearKnownImePackageNamesLocked() {
1291 mKnownImePackageNames.clear();
Yohei Yukawac4e44912017-02-09 19:30:22 -08001292 }
1293
1294 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001295 final void addKnownImePackageNameLocked(@NonNull String packageName) {
1296 mKnownImePackageNames.add(packageName);
Yohei Yukawac4e44912017-02-09 19:30:22 -08001297 }
1298
Yohei Yukawa278f2ab2017-02-14 19:51:33 -08001299 @GuardedBy("mMethodMap")
1300 private boolean isChangingPackagesOfCurrentUserLocked() {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001301 final int userId = getChangingUserId();
1302 final boolean retval = userId == mSettings.getCurrentUserId();
1303 if (DEBUG) {
satok81f8b7c2012-12-04 20:42:56 +09001304 if (!retval) {
1305 Slog.d(TAG, "--- ignore this call back from a background user: " + userId);
1306 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001307 }
1308 return retval;
1309 }
1310
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001311 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001312 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313 synchronized (mMethodMap) {
Yohei Yukawa278f2ab2017-02-14 19:51:33 -08001314 if (!isChangingPackagesOfCurrentUserLocked()) {
1315 return false;
1316 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001317 String curInputMethodId = mSettings.getSelectedInputMethod();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001318 final int N = mMethodList.size();
1319 if (curInputMethodId != null) {
1320 for (int i=0; i<N; i++) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001321 InputMethodInfo imi = mMethodList.get(i);
1322 if (imi.getId().equals(curInputMethodId)) {
1323 for (String pkg : packages) {
1324 if (imi.getPackageName().equals(pkg)) {
1325 if (!doit) {
1326 return true;
1327 }
satok723a27e2010-11-11 14:58:11 +09001328 resetSelectedInputMethodAndSubtypeLocked("");
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001329 chooseNewDefaultIMELocked();
1330 return true;
1331 }
1332 }
1333 }
1334 }
1335 }
1336 }
1337 return false;
1338 }
1339
1340 @Override
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001341 public void onBeginPackageChanges() {
1342 clearPackageChangeState();
1343 }
1344
1345 @Override
1346 public void onPackageAppeared(String packageName, int reason) {
1347 if (!mImePackageAppeared) {
1348 final PackageManager pm = mContext.getPackageManager();
1349 final List<ResolveInfo> services = pm.queryIntentServicesAsUser(
1350 new Intent(InputMethod.SERVICE_INTERFACE).setPackage(packageName),
Yohei Yukawa5ec1fce2018-12-17 07:56:14 -08001351 PackageManager.MATCH_DISABLED_COMPONENTS, getChangingUserId());
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001352 // No need to lock this because we access it only on getRegisteredHandler().
1353 if (!services.isEmpty()) {
1354 mImePackageAppeared = true;
1355 }
1356 }
1357 // No need to lock this because we access it only on getRegisteredHandler().
1358 mChangedPackages.add(packageName);
1359 }
1360
1361 @Override
1362 public void onPackageDisappeared(String packageName, int reason) {
1363 // No need to lock this because we access it only on getRegisteredHandler().
1364 mChangedPackages.add(packageName);
1365 }
1366
1367 @Override
1368 public void onPackageModified(String packageName) {
1369 // No need to lock this because we access it only on getRegisteredHandler().
1370 mChangedPackages.add(packageName);
1371 }
1372
1373 @Override
1374 public void onPackagesSuspended(String[] packages) {
1375 // No need to lock this because we access it only on getRegisteredHandler().
1376 for (String packageName : packages) {
1377 mChangedPackages.add(packageName);
Yohei Yukawac4e44912017-02-09 19:30:22 -08001378 }
1379 }
1380
1381 @Override
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001382 public void onPackagesUnsuspended(String[] packages) {
1383 // No need to lock this because we access it only on getRegisteredHandler().
1384 for (String packageName : packages) {
1385 mChangedPackages.add(packageName);
1386 }
1387 }
1388
1389 @Override
1390 public void onFinishPackageChanges() {
1391 onFinishPackageChangesInternal();
1392 clearPackageChangeState();
1393 }
1394
1395 private void clearPackageChangeState() {
1396 // No need to lock them because we access these fields only on getRegisteredHandler().
1397 mChangedPackages.clear();
1398 mImePackageAppeared = false;
1399 }
1400
Andreas Gampea36dc622018-02-05 17:19:22 -08001401 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001402 private boolean shouldRebuildInputMethodListLocked() {
1403 // This method is guaranteed to be called only by getRegisteredHandler().
1404
1405 // If there is any new package that contains at least one IME, then rebuilt the list
1406 // of IMEs.
1407 if (mImePackageAppeared) {
1408 return true;
1409 }
1410
1411 // Otherwise, check if mKnownImePackageNames and mChangedPackages have any intersection.
1412 // TODO: Consider to create a utility method to do the following test. List.retainAll()
1413 // is an option, but it may still do some extra operations that we do not need here.
1414 final int N = mChangedPackages.size();
1415 for (int i = 0; i < N; ++i) {
1416 final String packageName = mChangedPackages.get(i);
1417 if (mKnownImePackageNames.contains(packageName)) {
1418 return true;
1419 }
1420 }
1421 return false;
1422 }
1423
1424 private void onFinishPackageChangesInternal() {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001425 synchronized (mMethodMap) {
Yohei Yukawa278f2ab2017-02-14 19:51:33 -08001426 if (!isChangingPackagesOfCurrentUserLocked()) {
1427 return;
1428 }
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001429 if (!shouldRebuildInputMethodListLocked()) {
1430 return;
1431 }
1432
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001433 InputMethodInfo curIm = null;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001434 String curInputMethodId = mSettings.getSelectedInputMethod();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001435 final int N = mMethodList.size();
1436 if (curInputMethodId != null) {
1437 for (int i=0; i<N; i++) {
1438 InputMethodInfo imi = mMethodList.get(i);
satoke7c6998e2011-06-03 17:57:59 +09001439 final String imiId = imi.getId();
1440 if (imiId.equals(curInputMethodId)) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001441 curIm = imi;
1442 }
satoke7c6998e2011-06-03 17:57:59 +09001443
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001444 int change = isPackageDisappearing(imi.getPackageName());
satoke7c6998e2011-06-03 17:57:59 +09001445 if (isPackageModified(imi.getPackageName())) {
Yohei Yukawab557d572018-12-29 21:26:26 -08001446 mAdditionalSubtypeMap.remove(imi.getId());
1447 AdditionalSubtypeUtils.save(mAdditionalSubtypeMap, mMethodMap,
1448 mSettings.getCurrentUserId());
satoke7c6998e2011-06-03 17:57:59 +09001449 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001450 if (change == PACKAGE_TEMPORARY_CHANGE
1451 || change == PACKAGE_PERMANENT_CHANGE) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001452 Slog.i(TAG, "Input method uninstalled, disabling: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001453 + imi.getComponent());
1454 setInputMethodEnabledLocked(imi.getId(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001455 }
1456 }
1457 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001458
Yohei Yukawa94e33302016-02-12 19:37:03 -08001459 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001460
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001461 boolean changed = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001462
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001463 if (curIm != null) {
Anna Galusza9b278112016-01-04 11:37:37 -08001464 int change = isPackageDisappearing(curIm.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001465 if (change == PACKAGE_TEMPORARY_CHANGE
1466 || change == PACKAGE_PERMANENT_CHANGE) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001467 ServiceInfo si = null;
1468 try {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001469 si = mIPackageManager.getServiceInfo(
1470 curIm.getComponent(), 0, mSettings.getCurrentUserId());
1471 } catch (RemoteException ex) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001472 }
1473 if (si == null) {
1474 // Uh oh, current input method is no longer around!
1475 // Pick another one...
Joe Onorato8a9b2202010-02-26 18:56:32 -08001476 Slog.i(TAG, "Current input method removed: " + curInputMethodId);
Yohei Yukawa849443c2019-01-21 09:02:25 -08001477 updateSystemUiLocked(0 /* vis */, mBackDisposition);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001478 if (!chooseNewDefaultIMELocked()) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001479 changed = true;
1480 curIm = null;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001481 Slog.i(TAG, "Unsetting current input method");
satok723a27e2010-11-11 14:58:11 +09001482 resetSelectedInputMethodAndSubtypeLocked("");
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001483 }
1484 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001485 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001486 }
satokab751aa2010-09-14 19:17:36 +09001487
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001488 if (curIm == null) {
1489 // We currently don't have a default input method... is
1490 // one now available?
1491 changed = chooseNewDefaultIMELocked();
Yohei Yukawa54d512c2015-05-19 22:15:02 -07001492 } else if (!changed && isPackageModified(curIm.getPackageName())) {
1493 // Even if the current input method is still available, mCurrentSubtype could
1494 // be obsolete when the package is modified in practice.
1495 changed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001496 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001497
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001498 if (changed) {
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08001499 updateFromSettingsLocked(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001500 }
1501 }
1502 }
1503 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001504
Jeff Brownc28867a2013-03-26 15:42:39 -07001505 private static final class MethodCallback extends IInputSessionCallback.Stub {
Jean Chalarde0d32a62011-10-20 20:36:07 +09001506 private final InputMethodManagerService mParentIMMS;
Jeff Brownc28867a2013-03-26 15:42:39 -07001507 private final IInputMethod mMethod;
1508 private final InputChannel mChannel;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001509
Jeff Brownc28867a2013-03-26 15:42:39 -07001510 MethodCallback(InputMethodManagerService imms, IInputMethod method,
1511 InputChannel channel) {
Jean Chalarde0d32a62011-10-20 20:36:07 +09001512 mParentIMMS = imms;
Jeff Brownc28867a2013-03-26 15:42:39 -07001513 mMethod = method;
1514 mChannel = channel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001515 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001516
satoke7c6998e2011-06-03 17:57:59 +09001517 @Override
Jeff Brownc28867a2013-03-26 15:42:39 -07001518 public void sessionCreated(IInputMethodSession session) {
Dianne Hackborn6b6b3fd2014-03-24 11:27:18 -07001519 long ident = Binder.clearCallingIdentity();
1520 try {
1521 mParentIMMS.onSessionCreated(mMethod, session, mChannel);
1522 } finally {
1523 Binder.restoreCallingIdentity(ident);
1524 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001525 }
1526 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001527
satok01038492012-04-09 21:08:27 +09001528 private class HardKeyboardListener
Seigo Nonaka7309b122015-08-17 18:34:13 -07001529 implements WindowManagerInternal.OnHardKeyboardStatusChangeListener {
satok01038492012-04-09 21:08:27 +09001530 @Override
Michael Wright7b5a96b2014-08-09 19:28:42 -07001531 public void onHardKeyboardStatusChange(boolean available) {
1532 mHandler.sendMessage(mHandler.obtainMessage(MSG_HARD_KEYBOARD_SWITCH_CHANGED,
1533 available ? 1 : 0));
satok01038492012-04-09 21:08:27 +09001534 }
1535
Michael Wright7b5a96b2014-08-09 19:28:42 -07001536 public void handleHardKeyboardStatusChange(boolean available) {
satok01038492012-04-09 21:08:27 +09001537 if (DEBUG) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07001538 Slog.w(TAG, "HardKeyboardStatusChanged: available=" + available);
satok01038492012-04-09 21:08:27 +09001539 }
1540 synchronized(mMethodMap) {
1541 if (mSwitchingDialog != null && mSwitchingDialogTitleView != null
1542 && mSwitchingDialog.isShowing()) {
1543 mSwitchingDialogTitleView.findViewById(
1544 com.android.internal.R.id.hard_keyboard_section).setVisibility(
1545 available ? View.VISIBLE : View.GONE);
1546 }
1547 }
1548 }
1549 }
1550
Yohei Yukawad277d692020-02-19 17:12:17 -08001551 private static final class UserSwitchHandlerTask implements Runnable {
1552 final InputMethodManagerService mService;
1553
1554 @UserIdInt
1555 final int mToUserId;
1556
1557 @Nullable
1558 IInputMethodClient mClientToBeReset;
1559
1560 UserSwitchHandlerTask(InputMethodManagerService service, @UserIdInt int toUserId,
1561 @Nullable IInputMethodClient clientToBeReset) {
1562 mService = service;
1563 mToUserId = toUserId;
1564 mClientToBeReset = clientToBeReset;
1565 }
1566
1567 @Override
1568 public void run() {
1569 synchronized (mService.mMethodMap) {
1570 if (mService.mUserSwitchHandlerTask != this) {
1571 // This task was already canceled before it is handled here. So do nothing.
1572 return;
1573 }
1574 mService.switchUserOnHandlerLocked(mService.mUserSwitchHandlerTask.mToUserId,
1575 mClientToBeReset);
1576 mService.mUserSwitchHandlerTask = null;
1577 }
1578 }
1579 }
1580
1581 /**
1582 * When non-{@code null}, this represents pending user-switch task, which is to be executed as
1583 * a handler callback. This needs to be set and unset only within the lock.
1584 */
1585 @Nullable
1586 @GuardedBy("mMethodMap")
1587 private UserSwitchHandlerTask mUserSwitchHandlerTask;
1588
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001589 public static final class Lifecycle extends SystemService {
1590 private InputMethodManagerService mService;
1591
1592 public Lifecycle(Context context) {
1593 super(context);
1594 mService = new InputMethodManagerService(context);
1595 }
1596
1597 @Override
1598 public void onStart() {
1599 LocalServices.addService(InputMethodManagerInternal.class,
Yohei Yukawafffc0e52018-09-04 13:24:00 -07001600 new LocalServiceImpl(mService));
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001601 publishBinderService(Context.INPUT_METHOD_SERVICE, mService);
1602 }
1603
1604 @Override
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001605 public void onSwitchUser(@UserIdInt int userHandle) {
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07001606 // Called on ActivityManager thread.
Yohei Yukawad277d692020-02-19 17:12:17 -08001607 synchronized (mService.mMethodMap) {
1608 mService.scheduleSwitchUserTaskLocked(userHandle, null /* clientToBeReset */);
1609 }
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001610 }
1611
1612 @Override
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001613 public void onBootPhase(int phase) {
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07001614 // Called on ActivityManager thread.
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001615 // TODO: Dispatch this to a worker thread as needed.
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001616 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
1617 StatusBarManagerService statusBarService = (StatusBarManagerService) ServiceManager
1618 .getService(Context.STATUS_BAR_SERVICE);
1619 mService.systemRunning(statusBarService);
1620 }
1621 }
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001622
1623 @Override
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07001624 public void onUnlockUser(final @UserIdInt int userHandle) {
1625 // Called on ActivityManager thread.
1626 mService.mHandler.sendMessage(mService.mHandler.obtainMessage(MSG_SYSTEM_UNLOCK_USER,
Fyodor Kupolov0f57cce2016-09-09 10:36:30 -07001627 userHandle /* arg1 */, 0 /* arg2 */));
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001628 }
1629 }
1630
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001631 void onUnlockUser(@UserIdInt int userId) {
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001632 synchronized(mMethodMap) {
1633 final int currentUserId = mSettings.getCurrentUserId();
1634 if (DEBUG) {
1635 Slog.d(TAG, "onUnlockUser: userId=" + userId + " curUserId=" + currentUserId);
1636 }
1637 if (userId != currentUserId) {
1638 return;
1639 }
1640 mSettings.switchCurrentUser(currentUserId, !mSystemReady);
Yohei Yukawa79247822017-01-23 15:26:15 -08001641 if (mSystemReady) {
1642 // We need to rebuild IMEs.
1643 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
1644 updateInputMethodsFromSettingsLocked(true /* enabledChanged */);
1645 }
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001646 }
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001647 }
1648
Yohei Yukawad277d692020-02-19 17:12:17 -08001649 @GuardedBy("mMethodMap")
1650 void scheduleSwitchUserTaskLocked(@UserIdInt int userId,
1651 @Nullable IInputMethodClient clientToBeReset) {
1652 if (mUserSwitchHandlerTask != null) {
1653 if (mUserSwitchHandlerTask.mToUserId == userId) {
1654 mUserSwitchHandlerTask.mClientToBeReset = clientToBeReset;
1655 return;
1656 }
1657 mHandler.removeCallbacks(mUserSwitchHandlerTask);
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001658 }
Yohei Yukawad277d692020-02-19 17:12:17 -08001659 final UserSwitchHandlerTask task = new UserSwitchHandlerTask(this, userId,
1660 clientToBeReset);
1661 mUserSwitchHandlerTask = task;
1662 mHandler.post(task);
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001663 }
1664
Seigo Nonaka7309b122015-08-17 18:34:13 -07001665 public InputMethodManagerService(Context context) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001666 mIPackageManager = AppGlobals.getPackageManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001667 mContext = context;
Dianne Hackborn7d3a5bc2010-11-29 22:52:12 -08001668 mRes = context.getResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001669 mHandler = new Handler(this);
Yohei Yukawa81482972015-06-04 00:58:59 -07001670 // Note: SettingsObserver doesn't register observers in its constructor.
1671 mSettingsObserver = new SettingsObserver(mHandler);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001672 mIWindowManager = IWindowManager.Stub.asInterface(
1673 ServiceManager.getService(Context.WINDOW_SERVICE));
Seigo Nonaka7309b122015-08-17 18:34:13 -07001674 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
Yohei Yukawad5f402b2020-05-15 10:23:32 -07001675 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
lpeter133fce02020-03-05 20:32:16 +08001676 mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
Yohei Yukawab4f328a2019-05-02 08:41:27 -07001677 mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
lumark9a72d222019-03-30 18:31:45 +08001678 mImeDisplayValidator = displayId -> mWindowManagerInternal.shouldShowIme(displayId);
Mita Yuned218c72012-12-06 17:18:25 -08001679 mCaller = new HandlerCaller(context, null, new HandlerCaller.Callback() {
satoke7c6998e2011-06-03 17:57:59 +09001680 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001681 public void executeMessage(Message msg) {
1682 handleMessage(msg);
1683 }
Mita Yuned218c72012-12-06 17:18:25 -08001684 }, true /*asyncHandler*/);
Yohei Yukawad34e1482016-02-11 08:03:52 -08001685 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001686 mUserManager = mContext.getSystemService(UserManager.class);
Yohei Yukawa42081402019-01-15 09:57:50 -08001687 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
satok01038492012-04-09 21:08:27 +09001688 mHardKeyboardListener = new HardKeyboardListener();
Dianne Hackborn119bbc32013-03-22 17:27:25 -07001689 mHasFeature = context.getPackageManager().hasSystemFeature(
1690 PackageManager.FEATURE_INPUT_METHODS);
Jason Monk3e189872016-01-12 09:10:34 -05001691 mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
Tarandeep Singheadb1392018-11-09 18:15:57 +01001692 mIsLowRam = ActivityManager.isLowRamDeviceStatic();
satok7cfc0ed2011-06-20 21:29:36 +09001693
Chris Wren1ce4b6d2015-06-11 10:19:43 -04001694 Bundle extras = new Bundle();
1695 extras.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, true);
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001696 @ColorInt final int accentColor = mContext.getColor(
1697 com.android.internal.R.color.system_notification_accent_color);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05001698 mImeSwitcherNotification =
1699 new Notification.Builder(mContext, SystemNotificationChannels.VIRTUAL_KEYBOARD)
1700 .setSmallIcon(com.android.internal.R.drawable.ic_notification_ime_default)
1701 .setWhen(0)
1702 .setOngoing(true)
1703 .addExtras(extras)
1704 .setCategory(Notification.CATEGORY_SYSTEM)
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001705 .setColor(accentColor);
Daniel Sandler590d5152012-06-14 16:10:13 -04001706
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001707 Intent intent = new Intent(ACTION_SHOW_INPUT_METHOD_PICKER)
1708 .setPackage(mContext.getPackageName());
satok683e2382011-07-12 08:28:52 +09001709 mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
satokb858c732011-07-22 19:54:34 +09001710
1711 mShowOngoingImeSwitcherForPhones = false;
satok7cfc0ed2011-06-20 21:29:36 +09001712
satok7cfc0ed2011-06-20 21:29:36 +09001713 mNotificationShown = false;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001714 int userId = 0;
1715 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001716 userId = ActivityManager.getService().getCurrentUser().id;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001717 } catch (RemoteException e) {
1718 Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
1719 }
satok913a8922010-08-26 21:53:41 +09001720
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08001721 mLastSwitchUserId = userId;
1722
satokd87c2592010-09-29 11:52:06 +09001723 // mSettings should be created before buildInputMethodListLocked
satokdf31ae62011-01-15 06:19:44 +09001724 mSettings = new InputMethodSettings(
Yohei Yukawaf9277532019-01-25 02:47:32 -08001725 mRes, context.getContentResolver(), mMethodMap, userId, !mSystemReady);
Svet Ganovadc1cf42015-06-15 16:36:24 -07001726
Kenny Guy2a764942014-04-02 13:29:20 +01001727 updateCurrentProfileIds();
Yohei Yukawab557d572018-12-29 21:26:26 -08001728 AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, userId);
Yohei Yukawa79247822017-01-23 15:26:15 -08001729 mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
1730 mSettings, context);
satok5b927c432012-05-01 20:09:34 +09001731 }
1732
satok5b927c432012-05-01 20:09:34 +09001733 private void resetDefaultImeLocked(Context context) {
1734 // Do not reset the default (current) IME when it is a 3rd-party IME
Yohei Yukawafd70fe82018-04-08 12:19:56 -07001735 if (mCurMethodId != null && !mMethodMap.get(mCurMethodId).isSystem()) {
satok5b927c432012-05-01 20:09:34 +09001736 return;
1737 }
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001738 final List<InputMethodInfo> suitableImes = InputMethodUtils.getDefaultEnabledImes(
Yohei Yukawaaf5cee82017-01-23 16:17:11 -08001739 context, mSettings.getEnabledInputMethodListLocked());
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001740 if (suitableImes.isEmpty()) {
1741 Slog.i(TAG, "No default found");
1742 return;
satok5b927c432012-05-01 20:09:34 +09001743 }
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001744 final InputMethodInfo defIm = suitableImes.get(0);
Yohei Yukawad0332832017-02-01 13:59:43 -08001745 if (DEBUG) {
1746 Slog.i(TAG, "Default found, using " + defIm.getId());
1747 }
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001748 setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
satok5b927c432012-05-01 20:09:34 +09001749 }
1750
Andreas Gampea36dc622018-02-05 17:19:22 -08001751 @GuardedBy("mMethodMap")
Yohei Yukawad277d692020-02-19 17:12:17 -08001752 private void switchUserOnHandlerLocked(@UserIdInt int newUserId,
1753 IInputMethodClient clientToBeReset) {
Yohei Yukawa90bf7082015-06-03 23:50:27 -07001754 if (DEBUG) Slog.d(TAG, "Switching user stage 1/3. newUserId=" + newUserId
1755 + " currentUserId=" + mSettings.getCurrentUserId());
1756
Yohei Yukawa81482972015-06-04 00:58:59 -07001757 // ContentObserver should be registered again when the user is changed
1758 mSettingsObserver.registerContentObserverLocked(newUserId);
Yohei Yukawa68645a62016-02-17 07:54:20 -08001759
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001760 // If the system is not ready or the device is not yed unlocked by the user, then we use
1761 // copy-on-write settings.
1762 final boolean useCopyOnWriteSettings =
Yohei Yukawa42081402019-01-15 09:57:50 -08001763 !mSystemReady || !mUserManagerInternal.isUserUnlockingOrUnlocked(newUserId);
Yohei Yukawa68645a62016-02-17 07:54:20 -08001764 mSettings.switchCurrentUser(newUserId, useCopyOnWriteSettings);
Kenny Guy2a764942014-04-02 13:29:20 +01001765 updateCurrentProfileIds();
Yohei Yukawab557d572018-12-29 21:26:26 -08001766 // Additional subtypes should be reset when the user is changed
1767 AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, newUserId);
Satoshi Kataoka7f7535f2013-02-18 12:54:16 +09001768 final String defaultImiId = mSettings.getSelectedInputMethod();
Yohei Yukawa90bf7082015-06-03 23:50:27 -07001769
1770 if (DEBUG) Slog.d(TAG, "Switching user stage 2/3. newUserId=" + newUserId
1771 + " defaultImiId=" + defaultImiId);
1772
Satoshi Kataoka7c4a2a12013-02-25 15:25:43 +09001773 // For secondary users, the list of enabled IMEs may not have been updated since the
1774 // callbacks to PackageMonitor are ignored for the secondary user. Here, defaultImiId may
1775 // not be empty even if the IME has been uninstalled by the primary user.
1776 // Even in such cases, IMMS works fine because it will find the most applicable
1777 // IME for that user.
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09001778 final boolean initialUserSwitch = TextUtils.isEmpty(defaultImiId);
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001779 mLastSystemLocales = mRes.getConfiguration().getLocales();
1780
1781 // TODO: Is it really possible that switchUserLocked() happens before system ready?
1782 if (mSystemReady) {
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08001783 hideCurrentInputLocked(
1784 mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_SWITCH_USER);
1785
Yohei Yukawab7526452018-10-21 20:15:17 -07001786 resetCurrentMethodAndClient(UnbindReason.SWITCH_USER);
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001787 buildInputMethodListLocked(initialUserSwitch);
1788 if (TextUtils.isEmpty(mSettings.getSelectedInputMethod())) {
1789 // This is the first time of the user switch and
1790 // set the current ime to the proper one.
1791 resetDefaultImeLocked(mContext);
1792 }
1793 updateFromSettingsLocked(true);
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001794 }
1795
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09001796 if (initialUserSwitch) {
Yohei Yukawa094c71f2015-06-20 00:41:31 -07001797 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
1798 mSettings.getEnabledInputMethodListLocked(), newUserId,
1799 mContext.getBasePackageName());
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09001800 }
Yohei Yukawa90bf7082015-06-03 23:50:27 -07001801
1802 if (DEBUG) Slog.d(TAG, "Switching user stage 3/3. newUserId=" + newUserId
1803 + " selectedIme=" + mSettings.getSelectedInputMethod());
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08001804
1805 mLastSwitchUserId = newUserId;
Yohei Yukawad277d692020-02-19 17:12:17 -08001806
1807 if (mIsInteractive && clientToBeReset != null) {
1808 final ClientState cs = mClients.get(clientToBeReset.asBinder());
1809 if (cs == null) {
1810 // The client is already gone.
1811 return;
1812 }
1813 try {
1814 cs.client.scheduleStartInputIfNecessary(mInFullscreenMode);
1815 } catch (RemoteException e) {
1816 }
1817 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001818 }
1819
Kenny Guy2a764942014-04-02 13:29:20 +01001820 void updateCurrentProfileIds() {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -07001821 mSettings.setCurrentProfileIds(
1822 mUserManager.getProfileIdsWithDisabled(mSettings.getCurrentUserId()));
Amith Yamasani734983f2014-03-04 16:48:05 -08001823 }
1824
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001825 @Override
1826 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1827 throws RemoteException {
1828 try {
1829 return super.onTransact(code, data, reply, flags);
1830 } catch (RuntimeException e) {
1831 // The input method manager only throws security exceptions, so let's
1832 // log all others.
1833 if (!(e instanceof SecurityException)) {
Dianne Hackborn164371f2013-10-01 19:10:13 -07001834 Slog.wtf(TAG, "Input Method Manager Crash", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001835 }
1836 throw e;
1837 }
1838 }
1839
Svetoslav Ganova0027152013-06-25 14:59:53 -07001840 public void systemRunning(StatusBarManagerService statusBar) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07001841 synchronized (mMethodMap) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001842 if (DEBUG) {
1843 Slog.d(TAG, "--- systemReady");
1844 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07001845 if (!mSystemReady) {
1846 mSystemReady = true;
Yohei Yukawa79247822017-01-23 15:26:15 -08001847 mLastSystemLocales = mRes.getConfiguration().getLocales();
Yohei Yukawa68645a62016-02-17 07:54:20 -08001848 final int currentUserId = mSettings.getCurrentUserId();
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001849 mSettings.switchCurrentUser(currentUserId,
Yohei Yukawa42081402019-01-15 09:57:50 -08001850 !mUserManagerInternal.isUserUnlockingOrUnlocked(currentUserId));
Yohei Yukawad34e1482016-02-11 08:03:52 -08001851 mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
1852 mNotificationManager = mContext.getSystemService(NotificationManager.class);
Dianne Hackborn661cd522011-08-22 00:26:20 -07001853 mStatusBar = statusBar;
Griff Hazen6090c262016-03-25 08:11:24 -07001854 if (mStatusBar != null) {
1855 mStatusBar.setIconVisibility(mSlotIme, false);
1856 }
Yohei Yukawa849443c2019-01-21 09:02:25 -08001857 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
satokb858c732011-07-22 19:54:34 +09001858 mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
1859 com.android.internal.R.bool.show_ongoing_ime_switcher);
satok01038492012-04-09 21:08:27 +09001860 if (mShowOngoingImeSwitcherForPhones) {
Seigo Nonaka7309b122015-08-17 18:34:13 -07001861 mWindowManagerInternal.setOnHardKeyboardStatusChangeListener(
satok01038492012-04-09 21:08:27 +09001862 mHardKeyboardListener);
1863 }
Yohei Yukawa79247822017-01-23 15:26:15 -08001864
1865 mMyPackageMonitor.register(mContext, null, UserHandle.ALL, true);
1866 mSettingsObserver.registerContentObserverLocked(currentUserId);
1867
Yohei Yukawa0ec08002019-03-08 10:48:26 -08001868 final IntentFilter broadcastFilterForSystemUser = new IntentFilter();
1869 broadcastFilterForSystemUser.addAction(Intent.ACTION_USER_ADDED);
1870 broadcastFilterForSystemUser.addAction(Intent.ACTION_USER_REMOVED);
1871 broadcastFilterForSystemUser.addAction(Intent.ACTION_LOCALE_CHANGED);
1872 broadcastFilterForSystemUser.addAction(ACTION_SHOW_INPUT_METHOD_PICKER);
1873 mContext.registerReceiver(new ImmsBroadcastReceiverForSystemUser(),
1874 broadcastFilterForSystemUser);
1875
1876 final IntentFilter broadcastFilterForAllUsers = new IntentFilter();
1877 broadcastFilterForAllUsers.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
1878 mContext.registerReceiverAsUser(new ImmsBroadcastReceiverForAllUsers(),
1879 UserHandle.ALL, broadcastFilterForAllUsers, null, null);
Yohei Yukawa79247822017-01-23 15:26:15 -08001880
Yohei Yukawa1f9a3cb2017-10-26 15:00:59 -07001881 final String defaultImiId = mSettings.getSelectedInputMethod();
1882 final boolean imeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId);
1883 buildInputMethodListLocked(!imeSelectedOnBoot /* resetDefaultEnabledIme */);
Yohei Yukawa79247822017-01-23 15:26:15 -08001884 updateFromSettingsLocked(true);
1885 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
1886 mSettings.getEnabledInputMethodListLocked(), currentUserId,
1887 mContext.getBasePackageName());
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07001888 }
1889 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001890 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001891
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001892 // ---------------------------------------------------------------------------------------
1893 // Check whether or not this is a valid IPC. Assumes an IPC is valid when either
1894 // 1) it comes from the system process
1895 // 2) the calling process' user id is identical to the current user id IMMS thinks.
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08001896 @GuardedBy("mMethodMap")
Yohei Yukawa46d74762019-01-22 10:17:22 -08001897 private boolean calledFromValidUserLocked() {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001898 final int uid = Binder.getCallingUid();
1899 final int userId = UserHandle.getUserId(uid);
1900 if (DEBUG) {
1901 Slog.d(TAG, "--- calledFromForegroundUserOrSystemProcess ? "
1902 + "calling uid = " + uid + " system uid = " + Process.SYSTEM_UID
1903 + " calling userId = " + userId + ", foreground user id = "
Satoshi Kataoka87c29142013-07-31 23:11:54 +09001904 + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid()
1905 + InputMethodUtils.getApiCallStack());
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001906 }
Yohei Yukawaa878b952019-01-10 19:36:24 -08001907 if (uid == Process.SYSTEM_UID) {
1908 return true;
1909 }
1910 if (userId == mSettings.getCurrentUserId()) {
1911 return true;
1912 }
Satoshi Kataoka135e5fb2012-09-28 18:25:06 +09001913
1914 // Caveat: A process which has INTERACT_ACROSS_USERS_FULL gets results for the
1915 // foreground user, not for the user of that process. Accordingly InputMethodManagerService
1916 // must not manage background users' states in any functions.
1917 // Note that privacy-sensitive IPCs, such as setInputMethod, are still securely guarded
1918 // by a token.
1919 if (mContext.checkCallingOrSelfPermission(
1920 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1921 == PackageManager.PERMISSION_GRANTED) {
1922 if (DEBUG) {
1923 Slog.d(TAG, "--- Access granted because the calling process has "
1924 + "the INTERACT_ACROSS_USERS_FULL permission");
1925 }
1926 return true;
1927 }
Yohei Yukawad0332832017-02-01 13:59:43 -08001928 // TODO(b/34886274): The semantics of this verification is actually not well-defined.
Seigo Nonakae27dc2b2015-08-14 18:21:27 -07001929 Slog.w(TAG, "--- IPC called from background users. Ignore. callers="
1930 + Debug.getCallers(10));
Satoshi Kataoka135e5fb2012-09-28 18:25:06 +09001931 return false;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001932 }
1933
Yohei Yukawa22c97be2014-06-04 19:43:36 +09001934
1935 /**
1936 * Returns true iff the caller is identified to be the current input method with the token.
1937 * @param token The window token given to the input method when it was started.
1938 * @return true if and only if non-null valid token is specified.
1939 */
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08001940 @GuardedBy("mMethodMap")
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08001941 private boolean calledWithValidTokenLocked(@NonNull IBinder token) {
1942 if (token == null) {
1943 throw new InvalidParameterException("token must not be null.");
Yohei Yukawad0332832017-02-01 13:59:43 -08001944 }
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08001945 if (token != mCurToken) {
Yohei Yukawad0332832017-02-01 13:59:43 -08001946 Slog.e(TAG, "Ignoring " + Debug.getCaller() + " due to an invalid token."
1947 + " uid:" + Binder.getCallingUid() + " token:" + token);
Yohei Yukawa22c97be2014-06-04 19:43:36 +09001948 return false;
1949 }
1950 return true;
1951 }
1952
Yohei Yukawaf80087c2018-05-21 09:47:53 -07001953 @GuardedBy("mMethodMap")
1954 private boolean bindCurrentInputMethodServiceLocked(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001955 Intent service, ServiceConnection conn, int flags) {
1956 if (service == null || conn == null) {
1957 Slog.e(TAG, "--- bind failed: service = " + service + ", conn = " + conn);
1958 return false;
1959 }
Amith Yamasani27b89e62013-01-16 12:30:11 -08001960 return mContext.bindServiceAsUser(service, conn, flags,
1961 new UserHandle(mSettings.getCurrentUserId()));
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001962 }
1963
satoke7c6998e2011-06-03 17:57:59 +09001964 @Override
Yohei Yukawad20eef82019-02-05 10:45:32 -08001965 public List<InputMethodInfo> getInputMethodList(@UserIdInt int userId) {
1966 if (UserHandle.getCallingUserId() != userId) {
1967 mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
1968 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001969 synchronized (mMethodMap) {
Yohei Yukawad20eef82019-02-05 10:45:32 -08001970 final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001971 mSettings.getCurrentUserId(), null);
1972 if (resolvedUserIds.length != 1) {
1973 return Collections.emptyList();
1974 }
1975 final long ident = Binder.clearCallingIdentity();
1976 try {
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08001977 return getInputMethodListLocked(resolvedUserIds[0]);
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001978 } finally {
1979 Binder.restoreCallingIdentity(ident);
Tarandeep Singh89a6c482017-11-21 14:26:11 -08001980 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001981 }
1982 }
1983
satoke7c6998e2011-06-03 17:57:59 +09001984 @Override
Yohei Yukawa1fb13c52019-02-05 07:55:28 -08001985 public List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) {
1986 if (UserHandle.getCallingUserId() != userId) {
1987 mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
1988 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001989 synchronized (mMethodMap) {
Yohei Yukawa1fb13c52019-02-05 07:55:28 -08001990 final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001991 mSettings.getCurrentUserId(), null);
1992 if (resolvedUserIds.length != 1) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08001993 return Collections.emptyList();
1994 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001995 final long ident = Binder.clearCallingIdentity();
1996 try {
1997 return getEnabledInputMethodListLocked(resolvedUserIds[0]);
1998 } finally {
1999 Binder.restoreCallingIdentity(ident);
2000 }
2001 }
2002 }
2003
2004 @GuardedBy("mMethodMap")
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08002005 private List<InputMethodInfo> getInputMethodListLocked(@UserIdInt int userId) {
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08002006 final ArrayList<InputMethodInfo> methodList;
2007 if (userId == mSettings.getCurrentUserId()) {
2008 // Create a copy.
2009 methodList = new ArrayList<>(mMethodList);
2010 } else {
2011 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
2012 methodList = new ArrayList<>();
2013 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
2014 new ArrayMap<>();
2015 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
2016 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
2017 methodList);
2018 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08002019 return methodList;
2020 }
2021
2022 @GuardedBy("mMethodMap")
2023 private List<InputMethodInfo> getEnabledInputMethodListLocked(@UserIdInt int userId) {
2024 if (userId == mSettings.getCurrentUserId()) {
satokd87c2592010-09-29 11:52:06 +09002025 return mSettings.getEnabledInputMethodListLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002026 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08002027 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
2028 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
2029 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
2030 new ArrayMap<>();
2031 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
2032 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
2033 methodList);
2034 final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
Yohei Yukawaf9277532019-01-25 02:47:32 -08002035 mContext.getContentResolver(), methodMap, userId, true);
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08002036 return settings.getEnabledInputMethodListLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002037 }
2038
Adam Hebc67f2e2019-11-13 14:34:56 -08002039 @GuardedBy("mMethodMap")
Feng Cao16b2de52020-01-09 17:27:27 -08002040 private void onCreateInlineSuggestionsRequestLocked(@UserIdInt int userId,
Feng Cao36960ee2020-02-18 18:23:30 -08002041 InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback) {
Adam He7bc8f602019-12-12 17:00:34 -08002042 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
2043 try {
Feng Cao16b2de52020-01-09 17:27:27 -08002044 if (userId == mSettings.getCurrentUserId() && imi != null
2045 && imi.isInlineSuggestionsEnabled() && mCurMethod != null) {
Adam He7bc8f602019-12-12 17:00:34 -08002046 executeOrSendMessage(mCurMethod,
Feng Cao36960ee2020-02-18 18:23:30 -08002047 mCaller.obtainMessageOOO(MSG_INLINE_SUGGESTIONS_REQUEST, mCurMethod,
2048 requestInfo, new InlineSuggestionsRequestCallbackDecorator(callback,
lpeter133fce02020-03-05 20:32:16 +08002049 imi.getPackageName(), mCurTokenDisplayId, mCurToken,
2050 this)));
Adam He7bc8f602019-12-12 17:00:34 -08002051 } else {
2052 callback.onInlineSuggestionsUnsupported();
2053 }
2054 } catch (RemoteException e) {
2055 Slog.w(TAG, "RemoteException calling onCreateInlineSuggestionsRequest(): " + e);
Adam Hebc67f2e2019-11-13 14:34:56 -08002056 }
2057 }
2058
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09002059 /**
Feng Cao16b2de52020-01-09 17:27:27 -08002060 * The decorator which validates the host package name in the
2061 * {@link InlineSuggestionsRequest} argument to make sure it matches the IME package name.
2062 */
2063 private static final class InlineSuggestionsRequestCallbackDecorator
2064 extends IInlineSuggestionsRequestCallback.Stub {
2065 @NonNull
2066 private final IInlineSuggestionsRequestCallback mCallback;
2067 @NonNull
2068 private final String mImePackageName;
2069
Svet Ganov02fdd342020-02-20 20:48:34 -08002070 private final int mImeDisplayId;
2071
lpeter133fce02020-03-05 20:32:16 +08002072 @NonNull
2073 private final IBinder mImeToken;
2074 @NonNull
2075 private final InputMethodManagerService mImms;
2076
Feng Cao16b2de52020-01-09 17:27:27 -08002077 InlineSuggestionsRequestCallbackDecorator(
lpeter133fce02020-03-05 20:32:16 +08002078 @NonNull IInlineSuggestionsRequestCallback callback, @NonNull String imePackageName,
2079 int displayId, @NonNull IBinder imeToken, @NonNull InputMethodManagerService imms) {
Feng Cao16b2de52020-01-09 17:27:27 -08002080 mCallback = callback;
2081 mImePackageName = imePackageName;
Svet Ganov02fdd342020-02-20 20:48:34 -08002082 mImeDisplayId = displayId;
lpeter133fce02020-03-05 20:32:16 +08002083 mImeToken = imeToken;
2084 mImms = imms;
Feng Cao16b2de52020-01-09 17:27:27 -08002085 }
2086
2087 @Override
2088 public void onInlineSuggestionsUnsupported() throws RemoteException {
2089 mCallback.onInlineSuggestionsUnsupported();
2090 }
2091
2092 @Override
2093 public void onInlineSuggestionsRequest(InlineSuggestionsRequest request,
Feng Cao97ec1c42020-03-25 12:20:42 -07002094 IInlineSuggestionsResponseCallback callback)
Feng Cao7c85eb72020-02-28 11:39:56 -08002095 throws RemoteException {
Feng Cao16b2de52020-01-09 17:27:27 -08002096 if (!mImePackageName.equals(request.getHostPackageName())) {
2097 throw new SecurityException(
2098 "Host package name in the provide request=[" + request.getHostPackageName()
2099 + "] doesn't match the IME package name=[" + mImePackageName
2100 + "].");
2101 }
Svet Ganov02fdd342020-02-20 20:48:34 -08002102 request.setHostDisplayId(mImeDisplayId);
lpeter133fce02020-03-05 20:32:16 +08002103 mImms.setCurHostInputToken(mImeToken, request.getHostInputToken());
Feng Cao97ec1c42020-03-25 12:20:42 -07002104 mCallback.onInlineSuggestionsRequest(request, callback);
Feng Cao7c85eb72020-02-28 11:39:56 -08002105 }
2106
2107 @Override
Feng Cao97ec1c42020-03-25 12:20:42 -07002108 public void onInputMethodStartInput(AutofillId imeFieldId) throws RemoteException {
2109 mCallback.onInputMethodStartInput(imeFieldId);
Feng Cao7c85eb72020-02-28 11:39:56 -08002110 }
2111
2112 @Override
Feng Cao97ec1c42020-03-25 12:20:42 -07002113 public void onInputMethodShowInputRequested(boolean requestResult) throws RemoteException {
2114 mCallback.onInputMethodShowInputRequested(requestResult);
2115 }
2116
2117 @Override
2118 public void onInputMethodStartInputView() throws RemoteException {
2119 mCallback.onInputMethodStartInputView();
2120 }
2121
2122 @Override
2123 public void onInputMethodFinishInputView() throws RemoteException {
2124 mCallback.onInputMethodFinishInputView();
2125 }
2126
2127 @Override
2128 public void onInputMethodFinishInput() throws RemoteException {
2129 mCallback.onInputMethodFinishInput();
Feng Cao16b2de52020-01-09 17:27:27 -08002130 }
2131 }
2132
2133 /**
lpeter133fce02020-03-05 20:32:16 +08002134 * Sets current host input token.
2135 *
2136 * @param callerImeToken the token has been made for the current active input method
2137 * @param hostInputToken the host input token of the current active input method
2138 */
2139 void setCurHostInputToken(@NonNull IBinder callerImeToken, @Nullable IBinder hostInputToken) {
2140 synchronized (mMethodMap) {
2141 if (!calledWithValidTokenLocked(callerImeToken)) {
2142 return;
2143 }
2144 mCurHostInputToken = hostInputToken;
2145 }
2146 }
2147
2148 /**
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09002149 * @param imiId if null, returns enabled subtypes for the current imi
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09002150 * @return enabled subtypes of the specified imi
2151 */
satoke7c6998e2011-06-03 17:57:59 +09002152 @Override
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09002153 public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
satok16331c82010-12-20 23:48:46 +09002154 boolean allowsImplicitlySelectedSubtypes) {
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08002155 final int callingUserId = UserHandle.getCallingUserId();
satok67ddf9c2010-11-17 09:45:54 +09002156 synchronized (mMethodMap) {
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08002157 final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
2158 mSettings.getCurrentUserId(), null);
2159 if (resolvedUserIds.length != 1) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002160 return Collections.emptyList();
2161 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08002162 final long ident = Binder.clearCallingIdentity();
2163 try {
2164 return getEnabledInputMethodSubtypeListLocked(imiId,
2165 allowsImplicitlySelectedSubtypes, resolvedUserIds[0]);
2166 } finally {
2167 Binder.restoreCallingIdentity(ident);
2168 }
2169 }
2170 }
2171
2172 @GuardedBy("mMethodMap")
2173 private List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(String imiId,
2174 boolean allowsImplicitlySelectedSubtypes, @UserIdInt int userId) {
2175 if (userId == mSettings.getCurrentUserId()) {
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09002176 final InputMethodInfo imi;
2177 if (imiId == null && mCurMethodId != null) {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09002178 imi = mMethodMap.get(mCurMethodId);
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09002179 } else {
2180 imi = mMethodMap.get(imiId);
2181 }
2182 if (imi == null) {
Yohei Yukawab0377bb2015-08-10 21:06:30 -07002183 return Collections.emptyList();
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09002184 }
2185 return mSettings.getEnabledInputMethodSubtypeListLocked(
2186 mContext, imi, allowsImplicitlySelectedSubtypes);
satok67ddf9c2010-11-17 09:45:54 +09002187 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08002188 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
2189 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
2190 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
2191 new ArrayMap<>();
2192 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
2193 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
2194 methodList);
2195 final InputMethodInfo imi = methodMap.get(imiId);
2196 if (imi == null) {
2197 return Collections.emptyList();
2198 }
2199 final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
Yohei Yukawaf9277532019-01-25 02:47:32 -08002200 mContext.getContentResolver(), methodMap, userId, true);
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08002201 return settings.getEnabledInputMethodSubtypeListLocked(
2202 mContext, imi, allowsImplicitlySelectedSubtypes);
satok67ddf9c2010-11-17 09:45:54 +09002203 }
2204
Yohei Yukawaa71bb252018-09-19 19:21:24 -07002205 /**
2206 * Called by each application process as a preparation to start interacting with
2207 * {@link InputMethodManagerService}.
2208 *
2209 * <p>As a general principle, IPCs from the application process that take
Yohei Yukawa499e3f72018-10-21 20:15:11 -07002210 * {@link IInputMethodClient} will be rejected without this step.</p>
Yohei Yukawaa71bb252018-09-19 19:21:24 -07002211 *
2212 * @param client {@link android.os.Binder} proxy that is associated with the singleton instance
2213 * of {@link android.view.inputmethod.InputMethodManager} that runs on the client
2214 * process
2215 * @param inputContext communication channel for the dummy
2216 * {@link android.view.inputmethod.InputConnection}
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002217 * @param selfReportedDisplayId self-reported display ID to which the client is associated.
2218 * Whether the client is still allowed to access to this display
2219 * or not needs to be evaluated every time the client interacts
2220 * with the display
Yohei Yukawaa71bb252018-09-19 19:21:24 -07002221 */
2222 @Override
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002223 public void addClient(IInputMethodClient client, IInputContext inputContext,
2224 int selfReportedDisplayId) {
Yohei Yukawacb768bc2018-10-24 16:05:09 -07002225 // Here there are two scenarios where this method is called:
2226 // A. IMM is being instantiated in a different process and this is an IPC from that process
2227 // B. IMM is being instantiated in the same process but Binder.clearCallingIdentity() is
2228 // called in the caller side if necessary.
2229 // In either case the following UID/PID should be the ones where InputMethodManager is
2230 // actually running.
Yohei Yukawaa71bb252018-09-19 19:21:24 -07002231 final int callerUid = Binder.getCallingUid();
2232 final int callerPid = Binder.getCallingPid();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002233 synchronized (mMethodMap) {
Yohei Yukawaa71bb252018-09-19 19:21:24 -07002234 // TODO: Optimize this linear search.
Yohei Yukawaac9311e2018-11-20 19:25:23 -08002235 final int numClients = mClients.size();
2236 for (int i = 0; i < numClients; ++i) {
2237 final ClientState state = mClients.valueAt(i);
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002238 if (state.uid == callerUid && state.pid == callerPid
2239 && state.selfReportedDisplayId == selfReportedDisplayId) {
Yohei Yukawaa71bb252018-09-19 19:21:24 -07002240 throw new SecurityException("uid=" + callerUid + "/pid=" + callerPid
Yohei Yukawacb768bc2018-10-24 16:05:09 -07002241 + "/displayId=" + selfReportedDisplayId + " is already registered.");
Yohei Yukawaa71bb252018-09-19 19:21:24 -07002242 }
2243 }
2244 final ClientDeathRecipient deathRecipient = new ClientDeathRecipient(this, client);
2245 try {
2246 client.asBinder().linkToDeath(deathRecipient, 0);
2247 } catch (RemoteException e) {
2248 throw new IllegalStateException(e);
2249 }
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002250 // We cannot fully avoid race conditions where the client UID already lost the access to
2251 // the given self-reported display ID, even if the client is not maliciously reporting
2252 // a fake display ID. Unconditionally returning SecurityException just because the
2253 // client doesn't pass display ID verification can cause many test failures hence not an
2254 // option right now. At the same time
2255 // context.getSystemService(InputMethodManager.class)
2256 // is expected to return a valid non-null instance at any time if we do not choose to
2257 // have the client crash. Thus we do not verify the display ID at all here. Instead we
2258 // later check the display ID every time the client needs to interact with the specified
2259 // display.
2260 mClients.put(client.asBinder(), new ClientState(client, inputContext, callerUid,
2261 callerPid, selfReportedDisplayId, deathRecipient));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002262 }
2263 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002264
Yohei Yukawae24ed792018-08-28 19:10:32 -07002265 void removeClient(IInputMethodClient client) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002266 synchronized (mMethodMap) {
Jeff Brownc28867a2013-03-26 15:42:39 -07002267 ClientState cs = mClients.remove(client.asBinder());
2268 if (cs != null) {
Yohei Yukawaa71bb252018-09-19 19:21:24 -07002269 client.asBinder().unlinkToDeath(cs.clientDeathRecipient, 0);
Jeff Brownc28867a2013-03-26 15:42:39 -07002270 clearClientSessionLocked(cs);
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002271
2272 final int numItems = mActivityViewDisplayIdToParentMap.size();
2273 for (int i = numItems - 1; i >= 0; --i) {
2274 final ActivityViewInfo info = mActivityViewDisplayIdToParentMap.valueAt(i);
2275 if (info.mParentClient == cs) {
2276 mActivityViewDisplayIdToParentMap.removeAt(i);
2277 }
2278 }
2279
Yohei Yukawa072b1b52015-11-18 15:54:34 -08002280 if (mCurClient == cs) {
Tarandeep Singh93c00cea2018-02-16 14:31:17 -08002281 if (mBoundToMethod) {
2282 mBoundToMethod = false;
2283 if (mCurMethod != null) {
2284 executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
2285 MSG_UNBIND_INPUT, mCurMethod));
2286 }
2287 }
Yohei Yukawa072b1b52015-11-18 15:54:34 -08002288 mCurClient = null;
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002289 mCurActivityViewToScreenMatrix = null;
Yohei Yukawa072b1b52015-11-18 15:54:34 -08002290 }
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08002291 if (mCurFocusedWindowClient == cs) {
2292 mCurFocusedWindowClient = null;
2293 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002294 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002295 }
2296 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002297
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002298 void executeOrSendMessage(IInterface target, Message msg) {
2299 if (target.asBinder() instanceof Binder) {
2300 mCaller.sendMessage(msg);
2301 } else {
2302 handleMessage(msg);
2303 msg.recycle();
2304 }
2305 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002306
Yohei Yukawa4afd9332018-10-21 10:43:53 -07002307 void unbindCurrentClientLocked(@UnbindReason int unbindClientReason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002308 if (mCurClient != null) {
Yohei Yukawa35d3f372015-11-25 11:07:19 -08002309 if (DEBUG) Slog.v(TAG, "unbindCurrentInputLocked: client="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002310 + mCurClient.client.asBinder());
2311 if (mBoundToMethod) {
2312 mBoundToMethod = false;
2313 if (mCurMethod != null) {
2314 executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
2315 MSG_UNBIND_INPUT, mCurMethod));
2316 }
2317 }
Dianne Hackborna6e41342012-05-22 16:30:34 -07002318
Yohei Yukawa2bc66172017-02-08 11:13:25 -08002319 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
2320 MSG_SET_ACTIVE, 0, 0, mCurClient));
Yohei Yukawa33e81792015-11-17 21:14:42 -08002321 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
2322 MSG_UNBIND_CLIENT, mCurSeq, unbindClientReason, mCurClient.client));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002323 mCurClient.sessionRequested = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002324 mCurClient = null;
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002325 mCurActivityViewToScreenMatrix = null;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002326
The Android Open Source Project10592532009-03-18 17:39:46 -07002327 hideInputMethodMenuLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002328 }
2329 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002330
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002331 private int getImeShowFlags() {
2332 int flags = 0;
2333 if (mShowForced) {
2334 flags |= InputMethod.SHOW_FORCED
2335 | InputMethod.SHOW_EXPLICIT;
2336 } else if (mShowExplicitlyRequested) {
2337 flags |= InputMethod.SHOW_EXPLICIT;
2338 }
2339 return flags;
2340 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002341
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002342 private int getAppShowFlags() {
2343 int flags = 0;
2344 if (mShowForced) {
2345 flags |= InputMethodManager.SHOW_FORCED;
2346 } else if (!mShowExplicitlyRequested) {
2347 flags |= InputMethodManager.SHOW_IMPLICIT;
2348 }
2349 return flags;
2350 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002351
Andreas Gampea36dc622018-02-05 17:19:22 -08002352 @GuardedBy("mMethodMap")
Yohei Yukawa2553e482017-12-15 15:47:33 -08002353 @NonNull
Yohei Yukawadc66e522018-10-21 10:43:14 -07002354 InputBindResult attachNewInputLocked(@StartInputReason int startInputReason, boolean initial) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002355 if (!mBoundToMethod) {
2356 executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
2357 MSG_BIND_INPUT, mCurMethod, mCurClient.binding));
2358 mBoundToMethod = true;
2359 }
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08002360
2361 final Binder startInputToken = new Binder();
Yohei Yukawa7979e1a2019-02-12 02:01:10 -08002362 final StartInputInfo info = new StartInputInfo(mSettings.getCurrentUserId(), mCurToken,
2363 mCurTokenDisplayId, mCurId, startInputReason, !initial,
2364 UserHandle.getUserId(mCurClient.uid), mCurClient.selfReportedDisplayId,
2365 mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode, mCurSeq);
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002366 mImeTargetWindowMap.put(startInputToken, mCurFocusedWindow);
Yohei Yukawa357b2f62017-02-14 09:40:03 -08002367 mStartInputHistory.addEntry(info);
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08002368
Yohei Yukawa724c5bb2020-06-10 17:05:17 -07002369 // Seems that PackageManagerInternal#grantImplicitAccess() doesn't handle cross-user
2370 // implicit visibility (e.g. IME[user=10] -> App[user=0]) thus we do this only for the
2371 // same-user scenarios.
2372 // That said ignoring cross-user scenario will never affect IMEs that do not have
2373 // INTERACT_ACROSS_USERS(_FULL) permissions, which is actually almost always the case.
2374 if (mSettings.getCurrentUserId() == UserHandle.getUserId(mCurClient.uid)) {
2375 mPackageManagerInternal.grantImplicitAccess(mSettings.getCurrentUserId(),
2376 null /* intent */, UserHandle.getAppId(mCurMethodUid), mCurClient.uid, true);
2377 }
2378
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002379 final SessionState session = mCurClient.curSession;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08002380 executeOrSendMessage(session.method, mCaller.obtainMessageIIOOOO(
Yohei Yukawaf7526b52017-02-11 20:57:10 -08002381 MSG_START_INPUT, mCurInputContextMissingMethods, initial ? 0 : 1 /* restarting */,
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08002382 startInputToken, session, mCurInputContext, mCurAttribute));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002383 if (mShowRequested) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002384 if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
lumarkd85e1582019-12-29 20:20:41 +08002385 showCurrentInputLocked(mCurFocusedWindow, getAppShowFlags(), null,
2386 SoftInputShowHideReason.ATTACH_NEW_INPUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002387 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002388 return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
2389 session.session, (session.channel != null ? session.channel.dup() : null),
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002390 mCurId, mCurSeq, mCurActivityViewToScreenMatrix);
2391 }
2392
2393 @Nullable
2394 private Matrix getActivityViewToScreenMatrixLocked(int clientDisplayId, int imeDisplayId) {
2395 if (clientDisplayId == imeDisplayId) {
2396 return null;
2397 }
2398 int displayId = clientDisplayId;
2399 Matrix matrix = null;
2400 while (true) {
2401 final ActivityViewInfo info = mActivityViewDisplayIdToParentMap.get(displayId);
2402 if (info == null) {
2403 return null;
2404 }
2405 if (matrix == null) {
2406 matrix = new Matrix(info.mMatrix);
2407 } else {
2408 matrix.postConcat(info.mMatrix);
2409 }
2410 if (info.mParentClient.selfReportedDisplayId == imeDisplayId) {
2411 return matrix;
2412 }
2413 displayId = info.mParentClient.selfReportedDisplayId;
2414 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002415 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002416
Andreas Gampea36dc622018-02-05 17:19:22 -08002417 @GuardedBy("mMethodMap")
Yohei Yukawa2553e482017-12-15 15:47:33 -08002418 @NonNull
Yohei Yukawa35d3f372015-11-25 11:07:19 -08002419 InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07002420 @MissingMethodFlags int missingMethods, @NonNull EditorInfo attribute,
2421 @StartInputFlags int startInputFlags, @StartInputReason int startInputReason) {
Dianne Hackborn7663d802012-02-24 13:08:49 -08002422 // If no method is currently selected, do nothing.
2423 if (mCurMethodId == null) {
Yohei Yukawa2553e482017-12-15 15:47:33 -08002424 return InputBindResult.NO_IME;
Dianne Hackborn7663d802012-02-24 13:08:49 -08002425 }
2426
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002427 if (!mSystemReady) {
2428 // If the system is not yet ready, we shouldn't be running third
2429 // party code.
2430 return new InputBindResult(
2431 InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002432 null, null, mCurMethodId, mCurSeq, null);
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002433 }
2434
Yohei Yukawad57ba672015-06-08 16:39:46 -07002435 if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid,
2436 attribute.packageName)) {
2437 Slog.e(TAG, "Rejecting this client as it reported an invalid package name."
2438 + " uid=" + cs.uid + " package=" + attribute.packageName);
Yohei Yukawa2553e482017-12-15 15:47:33 -08002439 return InputBindResult.INVALID_PACKAGE_NAME;
Yohei Yukawa0f3ad12015-04-06 16:48:24 -07002440 }
2441
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002442 if (!mWindowManagerInternal.isUidAllowedOnDisplay(cs.selfReportedDisplayId, cs.uid)) {
2443 // Wait, the client no longer has access to the display.
2444 return InputBindResult.INVALID_DISPLAY_ID;
2445 }
lumarkef1965b2018-09-12 17:42:53 +08002446 // Compute the final shown display ID with validated cs.selfReportedDisplayId for this
2447 // session & other conditions.
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08002448 final int displayIdToShowIme = computeImeDisplayIdForTarget(cs.selfReportedDisplayId,
2449 mImeDisplayValidator);
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002450
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002451 if (mCurClient != cs) {
John Spurlocke0980502013-10-25 11:59:29 -04002452 // Was the keyguard locked when switching over to the new client?
2453 mCurClientInKeyguard = isKeyguardLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002454 // If the client is changing, we need to switch over to the new
2455 // one.
Yohei Yukawab7526452018-10-21 20:15:17 -07002456 unbindCurrentClientLocked(UnbindReason.SWITCH_CLIENT);
Yohei Yukawa35d3f372015-11-25 11:07:19 -08002457 if (DEBUG) Slog.v(TAG, "switching to client: client="
John Spurlocke0980502013-10-25 11:59:29 -04002458 + cs.client.asBinder() + " keyguard=" + mCurClientInKeyguard);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002459
2460 // If the screen is on, inform the new client it is active
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07002461 if (mIsInteractive) {
tiansiming [田思明]e102c972018-04-17 18:15:33 +08002462 executeOrSendMessage(cs.client, mCaller.obtainMessageIO(MSG_SET_ACTIVE, 1, cs));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002463 }
2464 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002465
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002466 // Bump up the sequence for this client and attach it.
2467 mCurSeq++;
2468 if (mCurSeq <= 0) mCurSeq = 1;
2469 mCurClient = cs;
2470 mCurInputContext = inputContext;
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002471 mCurActivityViewToScreenMatrix =
2472 getActivityViewToScreenMatrixLocked(cs.selfReportedDisplayId, displayIdToShowIme);
2473 if (cs.selfReportedDisplayId != displayIdToShowIme
2474 && mCurActivityViewToScreenMatrix == null) {
Yohei Yukawa3d2cc0f2019-04-25 18:32:15 -07002475 // CursorAnchorInfo API does not work as-is for cross-display scenario. Pretend that
2476 // InputConnection#requestCursorUpdates() is not implemented in the application so that
2477 // IMEs will always receive false from this API.
2478 missingMethods |= MissingMethodFlags.REQUEST_CURSOR_UPDATES;
2479 }
Yohei Yukawa19a80a12016-03-14 22:57:37 -07002480 mCurInputContextMissingMethods = missingMethods;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002481 mCurAttribute = attribute;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002482
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002483 // Check if the input method is changing.
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002484 // We expect the caller has already verified that the client is allowed to access this
2485 // display ID.
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002486 if (mCurId != null && mCurId.equals(mCurMethodId)
2487 && displayIdToShowIme == mCurTokenDisplayId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002488 if (cs.curSession != null) {
2489 // Fast case: if we are already connected to the input method,
2490 // then just return it.
Yohei Yukawa87ca8402017-02-07 00:13:14 -08002491 return attachNewInputLocked(startInputReason,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07002492 (startInputFlags & StartInputFlags.INITIAL_CONNECTION) != 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002493 }
2494 if (mHaveConnection) {
2495 if (mCurMethod != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002496 // Return to client, and we will get back with it when
2497 // we have had a session made for it.
Jeff Brownc28867a2013-03-26 15:42:39 -07002498 requestClientSessionLocked(cs);
Yohei Yukawa2553e482017-12-15 15:47:33 -08002499 return new InputBindResult(
2500 InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002501 null, null, mCurId, mCurSeq, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002502 } else if (SystemClock.uptimeMillis()
2503 < (mLastBindTime+TIME_TO_RECONNECT)) {
2504 // In this case we have connected to the service, but
2505 // don't yet have its interface. If it hasn't been too
2506 // long since we did the connection, we'll return to
2507 // the client and wait to get the service interface so
2508 // we can report back. If it has been too long, we want
2509 // to fall through so we can try a disconnect/reconnect
2510 // to see if we can get back in touch with the service.
Yohei Yukawa2553e482017-12-15 15:47:33 -08002511 return new InputBindResult(
2512 InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002513 null, null, mCurId, mCurSeq, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002514 } else {
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002515 EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
2516 mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002517 }
2518 }
2519 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002520
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002521 InputMethodInfo info = mMethodMap.get(mCurMethodId);
2522 if (info == null) {
2523 throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
2524 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002525
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002526 unbindCurrentMethodLocked();
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002527
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002528 mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE);
2529 mCurIntent.setComponent(info.getComponent());
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07002530 mCurIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
2531 com.android.internal.R.string.input_method_binding_label);
2532 mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
2533 mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002534
Yohei Yukawaf80087c2018-05-21 09:47:53 -07002535 if (bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002536 mLastBindTime = SystemClock.uptimeMillis();
2537 mHaveConnection = true;
2538 mCurId = info.getId();
2539 mCurToken = new Binder();
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002540 mCurTokenDisplayId = displayIdToShowIme;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002541 try {
lumark90120a82018-08-15 00:33:03 +08002542 if (DEBUG) {
2543 Slog.v(TAG, "Adding window token: " + mCurToken + " for display: "
2544 + mCurTokenDisplayId);
2545 }
Yohei Yukawa6e875592019-01-28 00:49:30 -08002546 mIWindowManager.addWindowToken(mCurToken, LayoutParams.TYPE_INPUT_METHOD,
2547 mCurTokenDisplayId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002548 } catch (RemoteException e) {
2549 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002550 return new InputBindResult(
2551 InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002552 null, null, mCurId, mCurSeq, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002553 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002554 mCurIntent = null;
2555 Slog.w(TAG, "Failure connecting to input method service: " + mCurIntent);
2556 return InputBindResult.IME_NOT_CONNECTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002557 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002558
lumarkef1965b2018-09-12 17:42:53 +08002559 @FunctionalInterface
2560 interface ImeDisplayValidator {
2561 boolean displayCanShowIme(int displayId);
2562 }
2563
2564 /**
2565 * Find the display where the IME should be shown.
2566 *
2567 * @param displayId the ID of the display where the IME client target is.
lumarkef1965b2018-09-12 17:42:53 +08002568 * @param checker instance of {@link ImeDisplayValidator} which is used for
2569 * checking display config to adjust the final target display.
2570 * @return The ID of the display where the IME should be shown.
2571 */
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08002572 static int computeImeDisplayIdForTarget(int displayId, @NonNull ImeDisplayValidator checker) {
lumarkef1965b2018-09-12 17:42:53 +08002573 if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) {
lumark7570cac2019-03-07 22:14:38 +08002574 return FALLBACK_DISPLAY_ID;
lumarkef1965b2018-09-12 17:42:53 +08002575 }
lumark9a72d222019-03-30 18:31:45 +08002576
2577 // Show IME window on fallback display when the display doesn't support system decorations
2578 // or the display is virtual and isn't owned by system for security concern.
lumark7570cac2019-03-07 22:14:38 +08002579 return checker.displayCanShowIme(displayId) ? displayId : FALLBACK_DISPLAY_ID;
lumarkef1965b2018-09-12 17:42:53 +08002580 }
2581
Yohei Yukawad5f402b2020-05-15 10:23:32 -07002582 @AnyThread
2583 private void scheduleNotifyImeUidToAudioService(int uid) {
2584 mCaller.removeMessages(MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE);
2585 mCaller.obtainMessageI(MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE, uid).sendToTarget();
2586 }
2587
satoke7c6998e2011-06-03 17:57:59 +09002588 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002589 public void onServiceConnected(ComponentName name, IBinder service) {
2590 synchronized (mMethodMap) {
2591 if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
2592 mCurMethod = IInputMethod.Stub.asInterface(service);
Yohei Yukawad5f402b2020-05-15 10:23:32 -07002593 final String curMethodPackage = mCurIntent.getComponent().getPackageName();
2594 final int curMethodUid = mPackageManagerInternal.getPackageUidInternal(
2595 curMethodPackage, 0 /* flags */, mSettings.getCurrentUserId());
2596 if (curMethodUid < 0) {
2597 Slog.e(TAG, "Failed to get UID for package=" + curMethodPackage);
2598 mCurMethodUid = Process.INVALID_UID;
2599 } else {
2600 mCurMethodUid = curMethodUid;
2601 }
Dianne Hackborncc278702009-09-02 23:07:23 -07002602 if (mCurToken == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002603 Slog.w(TAG, "Service connected without a token!");
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002604 unbindCurrentMethodLocked();
Dianne Hackborncc278702009-09-02 23:07:23 -07002605 return;
2606 }
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002607 if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
lumark90120a82018-08-15 00:33:03 +08002608 // Dispatch display id for InputMethodService to update context display.
2609 executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
2610 MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken));
Yohei Yukawad5f402b2020-05-15 10:23:32 -07002611 scheduleNotifyImeUidToAudioService(mCurMethodUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002612 if (mCurClient != null) {
Jeff Brownc28867a2013-03-26 15:42:39 -07002613 clearClientSessionLocked(mCurClient);
2614 requestClientSessionLocked(mCurClient);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002615 }
2616 }
2617 }
2618 }
2619
Jeff Brownc28867a2013-03-26 15:42:39 -07002620 void onSessionCreated(IInputMethod method, IInputMethodSession session,
2621 InputChannel channel) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002622 synchronized (mMethodMap) {
Yohei Yukawa32807ad2020-03-04 12:27:29 -08002623 if (mUserSwitchHandlerTask != null) {
2624 // We have a pending user-switching task so it's better to just ignore this session.
2625 channel.dispose();
2626 return;
2627 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002628 if (mCurMethod != null && method != null
2629 && mCurMethod.asBinder() == method.asBinder()) {
2630 if (mCurClient != null) {
Jeff Brownc28867a2013-03-26 15:42:39 -07002631 clearClientSessionLocked(mCurClient);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002632 mCurClient.curSession = new SessionState(mCurClient,
Jeff Brownc28867a2013-03-26 15:42:39 -07002633 method, session, channel);
Yohei Yukawa87ca8402017-02-07 00:13:14 -08002634 InputBindResult res = attachNewInputLocked(
Yohei Yukawa42194222018-10-21 20:14:40 -07002635 StartInputReason.SESSION_CREATED_BY_IME, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002636 if (res.method != null) {
2637 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
Yohei Yukawa33e81792015-11-17 21:14:42 -08002638 MSG_BIND_CLIENT, mCurClient.client, res));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002639 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002640 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002641 }
2642 }
2643 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002644
2645 // Session abandoned. Close its associated input channel.
2646 channel.dispose();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002647 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002648
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002649 void unbindCurrentMethodLocked() {
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002650 if (mVisibleBound) {
2651 mContext.unbindService(mVisibleConnection);
2652 mVisibleBound = false;
2653 }
2654
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002655 if (mHaveConnection) {
2656 mContext.unbindService(this);
2657 mHaveConnection = false;
2658 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002659
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002660 if (mCurToken != null) {
2661 try {
lumark90120a82018-08-15 00:33:03 +08002662 if (DEBUG) {
2663 Slog.v(TAG, "Removing window token: " + mCurToken + " for display: "
2664 + mCurTokenDisplayId);
2665 }
lumark90120a82018-08-15 00:33:03 +08002666 mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId);
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002667 } catch (RemoteException e) {
2668 }
lumark7570cac2019-03-07 22:14:38 +08002669 // Set IME window status as invisible when unbind current method.
2670 mImeWindowVis = 0;
2671 mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
2672 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002673 mCurToken = null;
lumark90120a82018-08-15 00:33:03 +08002674 mCurTokenDisplayId = INVALID_DISPLAY;
lpeter133fce02020-03-05 20:32:16 +08002675 mCurHostInputToken = null;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002676 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002677
The Android Open Source Project10592532009-03-18 17:39:46 -07002678 mCurId = null;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002679 clearCurMethodLocked();
Yohei Yukawabc7b5262015-11-17 17:38:41 -08002680 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002681
Yohei Yukawa4afd9332018-10-21 10:43:53 -07002682 void resetCurrentMethodAndClient(@UnbindReason int unbindClientReason) {
Yohei Yukawabc7b5262015-11-17 17:38:41 -08002683 mCurMethodId = null;
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002684 unbindCurrentMethodLocked();
Yohei Yukawa33e81792015-11-17 21:14:42 -08002685 unbindCurrentClientLocked(unbindClientReason);
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002686 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002687
2688 void requestClientSessionLocked(ClientState cs) {
2689 if (!cs.sessionRequested) {
2690 if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs);
2691 InputChannel[] channels = InputChannel.openInputChannelPair(cs.toString());
2692 cs.sessionRequested = true;
2693 executeOrSendMessage(mCurMethod, mCaller.obtainMessageOOO(
2694 MSG_CREATE_SESSION, mCurMethod, channels[1],
2695 new MethodCallback(this, mCurMethod, channels[0])));
2696 }
2697 }
2698
2699 void clearClientSessionLocked(ClientState cs) {
2700 finishSessionLocked(cs.curSession);
2701 cs.curSession = null;
2702 cs.sessionRequested = false;
2703 }
2704
2705 private void finishSessionLocked(SessionState sessionState) {
2706 if (sessionState != null) {
2707 if (sessionState.session != null) {
2708 try {
2709 sessionState.session.finishSession();
2710 } catch (RemoteException e) {
2711 Slog.w(TAG, "Session failed to close due to remote exception", e);
Yohei Yukawa849443c2019-01-21 09:02:25 -08002712 updateSystemUiLocked(0 /* vis */, mBackDisposition);
Jeff Brownc28867a2013-03-26 15:42:39 -07002713 }
2714 sessionState.session = null;
2715 }
2716 if (sessionState.channel != null) {
2717 sessionState.channel.dispose();
2718 sessionState.channel = null;
Devin Taylor0c33ed22010-02-23 13:26:46 -06002719 }
2720 }
2721 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002722
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002723 void clearCurMethodLocked() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002724 if (mCurMethod != null) {
Yohei Yukawaac9311e2018-11-20 19:25:23 -08002725 final int numClients = mClients.size();
2726 for (int i = 0; i < numClients; ++i) {
2727 clearClientSessionLocked(mClients.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002728 }
Devin Taylor0c33ed22010-02-23 13:26:46 -06002729
Jeff Brownc28867a2013-03-26 15:42:39 -07002730 finishSessionLocked(mEnabledSession);
Devin Taylor0c33ed22010-02-23 13:26:46 -06002731 mEnabledSession = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002732 mCurMethod = null;
Yohei Yukawad5f402b2020-05-15 10:23:32 -07002733 mCurMethodUid = Process.INVALID_UID;
2734 scheduleNotifyImeUidToAudioService(mCurMethodUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002735 }
Dianne Hackborn661cd522011-08-22 00:26:20 -07002736 if (mStatusBar != null) {
Jason Monk3e189872016-01-12 09:10:34 -05002737 mStatusBar.setIconVisibility(mSlotIme, false);
Dianne Hackborn661cd522011-08-22 00:26:20 -07002738 }
Yohei Yukawa2bc66172017-02-08 11:13:25 -08002739 mInFullscreenMode = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002740 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002741
satoke7c6998e2011-06-03 17:57:59 +09002742 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002743 public void onServiceDisconnected(ComponentName name) {
Yohei Yukawa817d5f72017-01-04 20:15:02 -08002744 // Note that mContext.unbindService(this) does not trigger this. Hence if we are here the
2745 // disconnection is not intended by IMMS (e.g. triggered because the current IMS crashed),
2746 // which is irregular but can eventually happen for everyone just by continuing using the
2747 // device. Thus it is important to make sure that all the internal states are properly
2748 // refreshed when this method is called back. Running
2749 // adb install -r <APK that implements the current IME>
2750 // would be a good way to trigger such a situation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002751 synchronized (mMethodMap) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002752 if (DEBUG) Slog.v(TAG, "Service disconnected: " + name
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002753 + " mCurIntent=" + mCurIntent);
2754 if (mCurMethod != null && mCurIntent != null
2755 && name.equals(mCurIntent.getComponent())) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002756 clearCurMethodLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002757 // We consider this to be a new bind attempt, since the system
2758 // should now try to restart the service for us.
2759 mLastBindTime = SystemClock.uptimeMillis();
2760 mShowRequested = mInputShown;
2761 mInputShown = false;
Yohei Yukawab7526452018-10-21 20:15:17 -07002762 unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002763 }
2764 }
2765 }
2766
Yohei Yukawaeec552e2018-09-09 20:48:41 -07002767 @BinderThread
Yohei Yukawa41b094f2018-09-09 23:58:45 -07002768 private void updateStatusIcon(@NonNull IBinder token, String packageName,
2769 @DrawableRes int iconId) {
Yohei Yukawa59377ca2017-01-31 21:32:26 -08002770 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08002771 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa59377ca2017-01-31 21:32:26 -08002772 return;
2773 }
2774 final long ident = Binder.clearCallingIdentity();
2775 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002776 if (iconId == 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002777 if (DEBUG) Slog.d(TAG, "hide the small icon for the input method");
Dianne Hackborn661cd522011-08-22 00:26:20 -07002778 if (mStatusBar != null) {
Jason Monk3e189872016-01-12 09:10:34 -05002779 mStatusBar.setIconVisibility(mSlotIme, false);
Dianne Hackborn661cd522011-08-22 00:26:20 -07002780 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002781 } else if (packageName != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002782 if (DEBUG) Slog.d(TAG, "show a small icon for the input method");
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002783 CharSequence contentDescription = null;
2784 try {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002785 // Use PackageManager to load label
2786 final PackageManager packageManager = mContext.getPackageManager();
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002787 contentDescription = packageManager.getApplicationLabel(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002788 mIPackageManager.getApplicationInfo(packageName, 0,
2789 mSettings.getCurrentUserId()));
2790 } catch (RemoteException e) {
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002791 /* ignore */
2792 }
Dianne Hackborn661cd522011-08-22 00:26:20 -07002793 if (mStatusBar != null) {
Jason Monk3e189872016-01-12 09:10:34 -05002794 mStatusBar.setIcon(mSlotIme, packageName, iconId, 0,
Dianne Hackborn661cd522011-08-22 00:26:20 -07002795 contentDescription != null
2796 ? contentDescription.toString() : null);
Jason Monk3e189872016-01-12 09:10:34 -05002797 mStatusBar.setIconVisibility(mSlotIme, true);
Dianne Hackborn661cd522011-08-22 00:26:20 -07002798 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002799 }
Yohei Yukawa59377ca2017-01-31 21:32:26 -08002800 } finally {
2801 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002802 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002803 }
2804 }
2805
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002806 private boolean shouldShowImeSwitcherLocked(int visibility) {
satok7cfc0ed2011-06-20 21:29:36 +09002807 if (!mShowOngoingImeSwitcherForPhones) return false;
Jason Monk807ef762014-05-08 15:47:46 -04002808 if (mSwitchingDialog != null) return false;
Yohei Yukawad2bc3092017-07-31 15:37:14 -07002809 if (mWindowManagerInternal.isKeyguardShowingAndNotOccluded()
2810 && mKeyguardManager != null && mKeyguardManager.isKeyguardSecure()) return false;
Tarandeep Singheadb1392018-11-09 18:15:57 +01002811 if ((visibility & InputMethodService.IME_ACTIVE) == 0
2812 || (visibility & InputMethodService.IME_INVISIBLE) != 0) {
2813 return false;
2814 }
Seigo Nonaka7309b122015-08-17 18:34:13 -07002815 if (mWindowManagerInternal.isHardKeyboardAvailable()) {
Yohei Yukawaaf023f22019-06-21 16:38:22 -07002816 // When physical keyboard is attached, we show the ime switcher (or notification if
2817 // NavBar is not available) because SHOW_IME_WITH_HARD_KEYBOARD settings currently
2818 // exists in the IME switcher dialog. Might be OK to remove this condition once
2819 // SHOW_IME_WITH_HARD_KEYBOARD settings finds a good place to live.
2820 return true;
Yohei Yukawa89398382016-03-29 11:37:04 -07002821 } else if ((visibility & InputMethodService.IME_VISIBLE) == 0) {
2822 return false;
Yohei Yukawac6c7cd22015-05-12 15:00:33 -07002823 }
Yohei Yukawac6c7cd22015-05-12 15:00:33 -07002824
2825 List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked();
2826 final int N = imis.size();
2827 if (N > 2) return true;
2828 if (N < 1) return false;
2829 int nonAuxCount = 0;
2830 int auxCount = 0;
2831 InputMethodSubtype nonAuxSubtype = null;
2832 InputMethodSubtype auxSubtype = null;
2833 for(int i = 0; i < N; ++i) {
2834 final InputMethodInfo imi = imis.get(i);
2835 final List<InputMethodSubtype> subtypes =
2836 mSettings.getEnabledInputMethodSubtypeListLocked(mContext, imi, true);
2837 final int subtypeCount = subtypes.size();
2838 if (subtypeCount == 0) {
2839 ++nonAuxCount;
2840 } else {
2841 for (int j = 0; j < subtypeCount; ++j) {
2842 final InputMethodSubtype subtype = subtypes.get(j);
2843 if (!subtype.isAuxiliary()) {
2844 ++nonAuxCount;
2845 nonAuxSubtype = subtype;
2846 } else {
2847 ++auxCount;
2848 auxSubtype = subtype;
satok7cfc0ed2011-06-20 21:29:36 +09002849 }
2850 }
satok7cfc0ed2011-06-20 21:29:36 +09002851 }
2852 }
Yohei Yukawac6c7cd22015-05-12 15:00:33 -07002853 if (nonAuxCount > 1 || auxCount > 1) {
2854 return true;
2855 } else if (nonAuxCount == 1 && auxCount == 1) {
2856 if (nonAuxSubtype != null && auxSubtype != null
2857 && (nonAuxSubtype.getLocale().equals(auxSubtype.getLocale())
2858 || auxSubtype.overridesImplicitlyEnabledSubtype()
2859 || nonAuxSubtype.overridesImplicitlyEnabledSubtype())
2860 && nonAuxSubtype.containsExtraValueKey(TAG_TRY_SUPPRESSING_IME_SWITCHER)) {
2861 return false;
2862 }
2863 return true;
2864 }
2865 return false;
satok7cfc0ed2011-06-20 21:29:36 +09002866 }
2867
John Spurlocke0980502013-10-25 11:59:29 -04002868 private boolean isKeyguardLocked() {
2869 return mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
2870 }
2871
Yohei Yukawad6475a62017-04-17 10:35:27 -07002872 @BinderThread
satokdbf29502011-08-25 15:28:23 +09002873 @SuppressWarnings("deprecation")
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08002874 private void setImeWindowStatus(@NonNull IBinder token, int vis, int backDisposition) {
lumark7570cac2019-03-07 22:14:38 +08002875 final int topFocusedDisplayId = mWindowManagerInternal.getTopFocusedDisplayId();
2876
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002877 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08002878 if (!calledWithValidTokenLocked(token)) {
2879 return;
2880 }
lumark7570cac2019-03-07 22:14:38 +08002881 // Skip update IME status when current token display is not same as focused display.
2882 // Note that we still need to update IME status when focusing external display
2883 // that does not support system decoration and fallback to show IME on default
2884 // display since it is intentional behavior.
2885 if (mCurTokenDisplayId != topFocusedDisplayId
2886 && mCurTokenDisplayId != FALLBACK_DISPLAY_ID) {
2887 return;
2888 }
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002889 mImeWindowVis = vis;
2890 mBackDisposition = backDisposition;
Yohei Yukawa849443c2019-01-21 09:02:25 -08002891 updateSystemUiLocked(vis, backDisposition);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002892 }
Yohei Yukawad6475a62017-04-17 10:35:27 -07002893
2894 final boolean dismissImeOnBackKeyPressed;
2895 switch (backDisposition) {
2896 case InputMethodService.BACK_DISPOSITION_WILL_DISMISS:
2897 dismissImeOnBackKeyPressed = true;
2898 break;
2899 case InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS:
2900 dismissImeOnBackKeyPressed = false;
2901 break;
2902 default:
2903 case InputMethodService.BACK_DISPOSITION_DEFAULT:
2904 dismissImeOnBackKeyPressed = ((vis & InputMethodService.IME_VISIBLE) != 0);
2905 break;
2906 }
Yohei Yukawaee2a7ed2017-02-15 21:38:57 -08002907 mWindowManagerInternal.updateInputMethodWindowStatus(token,
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002908 (vis & InputMethodService.IME_VISIBLE) != 0, dismissImeOnBackKeyPressed);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002909 }
2910
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002911 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08002912 private void reportStartInput(@NonNull IBinder token, IBinder startInputToken) {
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002913 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08002914 if (!calledWithValidTokenLocked(token)) {
2915 return;
2916 }
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002917 final IBinder targetWindow = mImeTargetWindowMap.get(startInputToken);
2918 if (targetWindow != null && mLastImeTargetWindow != targetWindow) {
2919 mWindowManagerInternal.updateInputMethodTargetWindow(token, targetWindow);
2920 }
2921 mLastImeTargetWindow = targetWindow;
2922 }
2923 }
2924
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002925 // Caution! This method is called in this class. Handle multi-user carefully
Yohei Yukawa849443c2019-01-21 09:02:25 -08002926 private void updateSystemUiLocked(int vis, int backDisposition) {
2927 if (mCurToken == null) {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002928 return;
2929 }
Tarandeep Singheadb1392018-11-09 18:15:57 +01002930 if (DEBUG) {
2931 Slog.d(TAG, "IME window vis: " + vis
2932 + " active: " + (vis & InputMethodService.IME_ACTIVE)
lumark7570cac2019-03-07 22:14:38 +08002933 + " inv: " + (vis & InputMethodService.IME_INVISIBLE)
2934 + " displayId: " + mCurTokenDisplayId);
Tarandeep Singheadb1392018-11-09 18:15:57 +01002935 }
2936
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002937 // TODO: Move this clearing calling identity block to setImeWindowStatus after making sure
2938 // all updateSystemUi happens on system previlege.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002939 final long ident = Binder.clearCallingIdentity();
satok06487a52010-10-29 11:37:18 +09002940 try {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002941 // apply policy for binder calls
2942 if (vis != 0 && isKeyguardLocked() && !mCurClientInKeyguard) {
2943 vis = 0;
satok06487a52010-10-29 11:37:18 +09002944 }
Adrian Roosc22eec92020-06-12 18:48:10 +02002945 if (!mCurPerceptible) {
2946 vis = 0;
2947 }
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002948 // mImeWindowVis should be updated before calling shouldShowImeSwitcherLocked().
2949 final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis);
2950 if (mStatusBar != null) {
lumark7570cac2019-03-07 22:14:38 +08002951 mStatusBar.setImeWindowStatus(mCurTokenDisplayId, mCurToken, vis, backDisposition,
Tarandeep Singh07b318b2019-07-17 11:12:04 -07002952 needsToShowImeSwitcher, false /*isMultiClientImeEnabled*/);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002953 }
2954 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
2955 if (imi != null && needsToShowImeSwitcher) {
2956 // Used to load label
2957 final CharSequence title = mRes.getText(
2958 com.android.internal.R.string.select_input_method);
2959 final CharSequence summary = InputMethodUtils.getImeAndSubtypeDisplayName(
2960 mContext, imi, mCurrentSubtype);
Chris Wren1ce4b6d2015-06-11 10:19:43 -04002961 mImeSwitcherNotification.setContentTitle(title)
2962 .setContentText(summary)
2963 .setContentIntent(mImeSwitchPendingIntent);
Seigo Nonaka7309b122015-08-17 18:34:13 -07002964 try {
Charles Chenea6e7f02018-11-19 21:37:45 +08002965 // TODO(b/120076400): Figure out what is the best behavior
Seigo Nonaka7309b122015-08-17 18:34:13 -07002966 if ((mNotificationManager != null)
Charles Chenea6e7f02018-11-19 21:37:45 +08002967 && !mIWindowManager.hasNavigationBar(DEFAULT_DISPLAY)) {
Seigo Nonaka7309b122015-08-17 18:34:13 -07002968 if (DEBUG) {
2969 Slog.d(TAG, "--- show notification: label = " + summary);
2970 }
2971 mNotificationManager.notifyAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04002972 SystemMessage.NOTE_SELECT_INPUT_METHOD,
Seigo Nonaka7309b122015-08-17 18:34:13 -07002973 mImeSwitcherNotification.build(), UserHandle.ALL);
2974 mNotificationShown = true;
Dianne Hackborn661cd522011-08-22 00:26:20 -07002975 }
Seigo Nonaka7309b122015-08-17 18:34:13 -07002976 } catch (RemoteException e) {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002977 }
2978 } else {
2979 if (mNotificationShown && mNotificationManager != null) {
2980 if (DEBUG) {
2981 Slog.d(TAG, "--- hide notification");
satok7cfc0ed2011-06-20 21:29:36 +09002982 }
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002983 mNotificationManager.cancelAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04002984 SystemMessage.NOTE_SELECT_INPUT_METHOD, UserHandle.ALL);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002985 mNotificationShown = false;
satok7cfc0ed2011-06-20 21:29:36 +09002986 }
satok06487a52010-10-29 11:37:18 +09002987 }
2988 } finally {
2989 Binder.restoreCallingIdentity(ident);
2990 }
2991 }
2992
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002993 void updateFromSettingsLocked(boolean enabledMayChange) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07002994 updateInputMethodsFromSettingsLocked(enabledMayChange);
2995 updateKeyboardFromSettingsLocked();
2996 }
2997
2998 void updateInputMethodsFromSettingsLocked(boolean enabledMayChange) {
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002999 if (enabledMayChange) {
3000 List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
3001 for (int i=0; i<enabled.size(); i++) {
3002 // We allow the user to select "disabled until used" apps, so if they
3003 // are enabling one of those here we now need to make it enabled.
3004 InputMethodInfo imm = enabled.get(i);
3005 try {
3006 ApplicationInfo ai = mIPackageManager.getApplicationInfo(imm.getPackageName(),
3007 PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
3008 mSettings.getCurrentUserId());
Satoshi Kataoka7987a312013-04-17 18:59:33 +09003009 if (ai != null && ai.enabledSetting
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08003010 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09003011 if (DEBUG) {
3012 Slog.d(TAG, "Update state(" + imm.getId()
3013 + "): DISABLED_UNTIL_USED -> DEFAULT");
3014 }
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08003015 mIPackageManager.setApplicationEnabledSetting(imm.getPackageName(),
3016 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
Dianne Hackborn3fa3c28a2013-03-26 16:15:41 -07003017 PackageManager.DONT_KILL_APP, mSettings.getCurrentUserId(),
3018 mContext.getBasePackageName());
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08003019 }
3020 } catch (RemoteException e) {
3021 }
3022 }
3023 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07003024 // We are assuming that whoever is changing DEFAULT_INPUT_METHOD and
3025 // ENABLED_INPUT_METHODS is taking care of keeping them correctly in
3026 // sync, so we will never have a DEFAULT_INPUT_METHOD that is not
3027 // enabled.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003028 String id = mSettings.getSelectedInputMethod();
satok03eb319a2010-11-11 18:17:42 +09003029 // There is no input method selected, try to choose new applicable input method.
3030 if (TextUtils.isEmpty(id) && chooseNewDefaultIMELocked()) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003031 id = mSettings.getSelectedInputMethod();
satok03eb319a2010-11-11 18:17:42 +09003032 }
3033 if (!TextUtils.isEmpty(id)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003034 try {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003035 setInputMethodLocked(id, mSettings.getSelectedInputMethodSubtypeId(id));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003036 } catch (IllegalArgumentException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003037 Slog.w(TAG, "Unknown input method from prefs: " + id, e);
Yohei Yukawab7526452018-10-21 20:15:17 -07003038 resetCurrentMethodAndClient(UnbindReason.SWITCH_IME_FAILED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003039 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07003040 } else {
3041 // There is no longer an input method set, so stop any current one.
Yohei Yukawab7526452018-10-21 20:15:17 -07003042 resetCurrentMethodAndClient(UnbindReason.NO_IME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003043 }
Yohei Yukawa3d46bab2014-05-30 18:10:18 +09003044 // Here is not the perfect place to reset the switching controller. Ideally
3045 // mSwitchingController and mSettings should be able to share the same state.
3046 // TODO: Make sure that mSwitchingController and mSettings are sharing the
3047 // the same enabled IMEs list.
3048 mSwitchingController.resetCircularListLocked(mContext);
Michael Wright7b5a96b2014-08-09 19:28:42 -07003049
3050 }
3051
3052 public void updateKeyboardFromSettingsLocked() {
3053 mShowImeWithHardKeyboard = mSettings.isShowImeWithHardKeyboardEnabled();
3054 if (mSwitchingDialog != null
3055 && mSwitchingDialogTitleView != null
3056 && mSwitchingDialog.isShowing()) {
3057 final Switch hardKeySwitch = (Switch)mSwitchingDialogTitleView.findViewById(
3058 com.android.internal.R.id.hard_keyboard_switch);
3059 hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
3060 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003061 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003062
satokab751aa2010-09-14 19:17:36 +09003063 /* package */ void setInputMethodLocked(String id, int subtypeId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003064 InputMethodInfo info = mMethodMap.get(id);
3065 if (info == null) {
satok913a8922010-08-26 21:53:41 +09003066 throw new IllegalArgumentException("Unknown id: " + id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003067 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003068
satokd81e9502012-05-21 12:58:45 +09003069 // See if we need to notify a subtype change within the same IME.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003070 if (id.equals(mCurMethodId)) {
satokd81e9502012-05-21 12:58:45 +09003071 final int subtypeCount = info.getSubtypeCount();
3072 if (subtypeCount <= 0) {
3073 return;
satokcd7cd292010-11-20 15:46:23 +09003074 }
satokd81e9502012-05-21 12:58:45 +09003075 final InputMethodSubtype oldSubtype = mCurrentSubtype;
3076 final InputMethodSubtype newSubtype;
3077 if (subtypeId >= 0 && subtypeId < subtypeCount) {
3078 newSubtype = info.getSubtypeAt(subtypeId);
3079 } else {
3080 // If subtype is null, try to find the most applicable one from
3081 // getCurrentInputMethodSubtype.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003082 newSubtype = getCurrentInputMethodSubtypeLocked();
satokd81e9502012-05-21 12:58:45 +09003083 }
3084 if (newSubtype == null || oldSubtype == null) {
3085 Slog.w(TAG, "Illegal subtype state: old subtype = " + oldSubtype
3086 + ", new subtype = " + newSubtype);
3087 return;
3088 }
3089 if (newSubtype != oldSubtype) {
3090 setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true);
3091 if (mCurMethod != null) {
3092 try {
Yohei Yukawa849443c2019-01-21 09:02:25 -08003093 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
satokd81e9502012-05-21 12:58:45 +09003094 mCurMethod.changeInputMethodSubtype(newSubtype);
3095 } catch (RemoteException e) {
3096 Slog.w(TAG, "Failed to call changeInputMethodSubtype");
satokab751aa2010-09-14 19:17:36 +09003097 }
3098 }
3099 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003100 return;
3101 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003102
satokd81e9502012-05-21 12:58:45 +09003103 // Changing to a different IME.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003104 final long ident = Binder.clearCallingIdentity();
3105 try {
satokab751aa2010-09-14 19:17:36 +09003106 // Set a subtype to this input method.
3107 // subtypeId the name of a subtype which will be set.
satok723a27e2010-11-11 14:58:11 +09003108 setSelectedInputMethodAndSubtypeLocked(info, subtypeId, false);
3109 // mCurMethodId should be updated after setSelectedInputMethodAndSubtypeLocked()
3110 // because mCurMethodId is stored as a history in
3111 // setSelectedInputMethodAndSubtypeLocked().
3112 mCurMethodId = id;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003113
Sudheer Shankafc46e9b2016-10-21 17:55:27 -07003114 if (LocalServices.getService(ActivityManagerInternal.class).isSystemReady()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003115 Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08003116 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003117 intent.putExtra("input_method_id", id);
Amith Yamasanicd757062012-10-19 18:23:52 -07003118 mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003119 }
Yohei Yukawab7526452018-10-21 20:15:17 -07003120 unbindCurrentClientLocked(UnbindReason.SWITCH_IME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003121 } finally {
3122 Binder.restoreCallingIdentity(ident);
3123 }
3124 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003125
satok42c5a162011-05-26 16:46:14 +09003126 @Override
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08003127 public boolean showSoftInput(IInputMethodClient client, IBinder windowToken, int flags,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003128 ResultReceiver resultReceiver) {
Dianne Hackborncef65ee2010-09-30 18:27:22 -07003129 int uid = Binder.getCallingUid();
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003130 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003131 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003132 return false;
3133 }
3134 final long ident = Binder.clearCallingIdentity();
3135 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003136 if (mCurClient == null || client == null
3137 || mCurClient.client.asBinder() != client.asBinder()) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07003138 // We need to check if this is the current client with
3139 // focus in the window manager, to allow this call to
3140 // be made before input is started in it.
Yohei Yukawa41f89c32018-09-19 14:30:04 -07003141 final ClientState cs = mClients.get(client.asBinder());
3142 if (cs == null) {
3143 throw new IllegalArgumentException("unknown client " + client.asBinder());
3144 }
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08003145 if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
3146 cs.selfReportedDisplayId)) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07003147 Slog.w(TAG, "Ignoring showSoftInput of uid " + uid + ": " + client);
The Android Open Source Project4df24232009-03-05 14:34:35 -08003148 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003149 }
3150 }
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07003151 if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
lumarkd85e1582019-12-29 20:20:41 +08003152 return showCurrentInputLocked(windowToken, flags, resultReceiver,
3153 SoftInputShowHideReason.SHOW_SOFT_INPUT);
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003154 } finally {
3155 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003156 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003157 }
3158 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003159
Adrian Roosc22eec92020-06-12 18:48:10 +02003160 @BinderThread
3161 @Override
3162 public void reportPerceptible(IBinder windowToken, boolean perceptible) {
3163 Objects.requireNonNull(windowToken, "windowToken must not be null");
3164 int uid = Binder.getCallingUid();
3165 synchronized (mMethodMap) {
3166 if (!calledFromValidUserLocked()) {
3167 return;
3168 }
3169 final long ident = Binder.clearCallingIdentity();
3170 try {
3171 if (mCurFocusedWindow == windowToken
3172 && mCurPerceptible != perceptible) {
3173 mCurPerceptible = perceptible;
3174 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
3175 }
3176 } finally {
3177 Binder.restoreCallingIdentity(ident);
3178 }
3179 }
3180 }
3181
Andreas Gamped6d42062018-07-20 13:08:21 -07003182 @GuardedBy("mMethodMap")
lumarkd85e1582019-12-29 20:20:41 +08003183 boolean showCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver,
3184 @SoftInputShowHideReason int reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003185 mShowRequested = true;
Anna Galusza9b278112016-01-04 11:37:37 -08003186 if (mAccessibilityRequestingNoSoftKeyboard) {
3187 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003188 }
Anna Galusza9b278112016-01-04 11:37:37 -08003189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003190 if ((flags&InputMethodManager.SHOW_FORCED) != 0) {
3191 mShowExplicitlyRequested = true;
3192 mShowForced = true;
Anna Galusza9b278112016-01-04 11:37:37 -08003193 } else if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
3194 mShowExplicitlyRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003195 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003196
Dianne Hackborncc278702009-09-02 23:07:23 -07003197 if (!mSystemReady) {
3198 return false;
3199 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003200
The Android Open Source Project4df24232009-03-05 14:34:35 -08003201 boolean res = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003202 if (mCurMethod != null) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07003203 if (DEBUG) Slog.d(TAG, "showCurrentInputLocked: mCurToken=" + mCurToken);
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08003204 // create a dummy token for IMS so that IMS cannot inject windows into client app.
3205 Binder showInputToken = new Binder();
3206 mShowRequestWindowMap.put(showInputToken, windowToken);
lumarkd85e1582019-12-29 20:20:41 +08003207 executeOrSendMessage(mCurMethod, mCaller.obtainMessageIIOOO(
3208 MSG_SHOW_SOFT_INPUT, getImeShowFlags(), reason, mCurMethod, resultReceiver,
3209 showInputToken));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003210 mInputShown = true;
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07003211 if (mHaveConnection && !mVisibleBound) {
Yohei Yukawaf80087c2018-05-21 09:47:53 -07003212 bindCurrentInputMethodServiceLocked(
Yohei Yukawaa67a4592017-03-30 15:57:02 -07003213 mCurIntent, mVisibleConnection, IME_VISIBLE_BIND_FLAGS);
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07003214 mVisibleBound = true;
3215 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08003216 res = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003217 } else if (mHaveConnection && SystemClock.uptimeMillis()
satok59b424c2011-09-30 17:21:46 +09003218 >= (mLastBindTime+TIME_TO_RECONNECT)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003219 // The client has asked to have the input method shown, but
3220 // we have been sitting here too long with a connection to the
3221 // service and no interface received, so let's disconnect/connect
3222 // to try to prod things along.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003223 EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, mCurMethodId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003224 SystemClock.uptimeMillis()-mLastBindTime,1);
satok59b424c2011-09-30 17:21:46 +09003225 Slog.w(TAG, "Force disconnect/connect to the IME in showCurrentInputLocked()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003226 mContext.unbindService(this);
Yohei Yukawaf80087c2018-05-21 09:47:53 -07003227 bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003228 } else {
3229 if (DEBUG) {
3230 Slog.d(TAG, "Can't show input: connection = " + mHaveConnection + ", time = "
3231 + ((mLastBindTime+TIME_TO_RECONNECT) - SystemClock.uptimeMillis()));
3232 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003233 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003234
The Android Open Source Project4df24232009-03-05 14:34:35 -08003235 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003236 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003237
satok42c5a162011-05-26 16:46:14 +09003238 @Override
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08003239 public boolean hideSoftInput(IInputMethodClient client, IBinder windowToken, int flags,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003240 ResultReceiver resultReceiver) {
Dianne Hackborncef65ee2010-09-30 18:27:22 -07003241 int uid = Binder.getCallingUid();
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003242 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003243 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003244 return false;
3245 }
3246 final long ident = Binder.clearCallingIdentity();
3247 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003248 if (mCurClient == null || client == null
3249 || mCurClient.client.asBinder() != client.asBinder()) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07003250 // We need to check if this is the current client with
3251 // focus in the window manager, to allow this call to
3252 // be made before input is started in it.
Yohei Yukawa41f89c32018-09-19 14:30:04 -07003253 final ClientState cs = mClients.get(client.asBinder());
3254 if (cs == null) {
3255 throw new IllegalArgumentException("unknown client " + client.asBinder());
3256 }
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08003257 if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
3258 cs.selfReportedDisplayId)) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07003259 if (DEBUG) {
3260 Slog.w(TAG, "Ignoring hideSoftInput of uid " + uid + ": " + client);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003261 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08003262 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003263 }
3264 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003265
Joe Onorato8a9b2202010-02-26 18:56:32 -08003266 if (DEBUG) Slog.v(TAG, "Client requesting input be hidden");
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08003267 return hideCurrentInputLocked(windowToken, flags, resultReceiver,
lumarkd85e1582019-12-29 20:20:41 +08003268 SoftInputShowHideReason.HIDE_SOFT_INPUT);
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003269 } finally {
3270 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003271 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003272 }
3273 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003274
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08003275 boolean hideCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver,
lumarkd85e1582019-12-29 20:20:41 +08003276 @SoftInputShowHideReason int reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003277 if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
3278 && (mShowExplicitlyRequested || mShowForced)) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07003279 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 -08003280 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003281 }
3282 if (mShowForced && (flags&InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07003283 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 -08003284 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003285 }
Seigo Nonakaec928652015-06-10 15:31:20 +09003286
3287 // There is a chance that IMM#hideSoftInput() is called in a transient state where
3288 // IMMS#InputShown is already updated to be true whereas IMMS#mImeWindowVis is still waiting
3289 // to be updated with the new value sent from IME process. Even in such a transient state
3290 // historically we have accepted an incoming call of IMM#hideSoftInput() from the
3291 // application process as a valid request, and have even promised such a behavior with CTS
3292 // since Android Eclair. That's why we need to accept IMM#hideSoftInput() even when only
3293 // IMMS#InputShown indicates that the software keyboard is shown.
3294 // TODO: Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested.
3295 final boolean shouldHideSoftInput = (mCurMethod != null) && (mInputShown ||
3296 (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0);
The Android Open Source Project4df24232009-03-05 14:34:35 -08003297 boolean res;
Seigo Nonakaec928652015-06-10 15:31:20 +09003298 if (shouldHideSoftInput) {
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08003299 final Binder hideInputToken = new Binder();
3300 mHideRequestWindowMap.put(hideInputToken, windowToken);
Seigo Nonakaec928652015-06-10 15:31:20 +09003301 // The IME will report its visible state again after the following message finally
3302 // delivered to the IME process as an IPC. Hence the inconsistency between
3303 // IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in
3304 // the final state.
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08003305 executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOOO(MSG_HIDE_SOFT_INPUT,
3306 reason, mCurMethod, resultReceiver, hideInputToken));
The Android Open Source Project4df24232009-03-05 14:34:35 -08003307 res = true;
3308 } else {
3309 res = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003310 }
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07003311 if (mHaveConnection && mVisibleBound) {
3312 mContext.unbindService(mVisibleConnection);
3313 mVisibleBound = false;
3314 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003315 mInputShown = false;
3316 mShowRequested = false;
3317 mShowExplicitlyRequested = false;
3318 mShowForced = false;
The Android Open Source Project4df24232009-03-05 14:34:35 -08003319 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003320 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003321
Yohei Yukawa2553e482017-12-15 15:47:33 -08003322 @NonNull
satok42c5a162011-05-26 16:46:14 +09003323 @Override
Yohei Yukawa05c25f82016-02-22 12:41:17 -08003324 public InputBindResult startInputOrWindowGainedFocus(
Yohei Yukawadc66e522018-10-21 10:43:14 -07003325 @StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07003326 @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
3327 int windowFlags, @Nullable EditorInfo attribute, IInputContext inputContext,
Yohei Yukawadc66e522018-10-21 10:43:14 -07003328 @MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion) {
Yohei Yukawa80498d52018-06-21 16:24:36 -07003329 if (windowToken == null) {
3330 Slog.e(TAG, "windowToken cannot be null.");
3331 return InputBindResult.NULL;
Yohei Yukawa05c25f82016-02-22 12:41:17 -08003332 }
Yohei Yukawa0f5eade2019-01-18 08:48:07 -08003333 final int callingUserId = UserHandle.getCallingUserId();
3334 final int userId;
Yohei Yukawa716897c2019-01-22 00:00:53 -08003335 if (attribute != null && attribute.targetInputMethodUser != null
Yohei Yukawa0f5eade2019-01-18 08:48:07 -08003336 && attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
3337 mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
Yohei Yukawa670abea2019-01-28 00:00:50 -08003338 "Using EditorInfo.targetInputMethodUser requires INTERACT_ACROSS_USERS_FULL.");
Yohei Yukawa0f5eade2019-01-18 08:48:07 -08003339 userId = attribute.targetInputMethodUser.getIdentifier();
3340 if (!mUserManagerInternal.isUserRunning(userId)) {
3341 // There is a chance that we hit here because of race condition. Let's just return
3342 // an error code instead of crashing the caller process, which at least has
3343 // INTERACT_ACROSS_USERS_FULL permission thus is likely to be an important process.
3344 Slog.e(TAG, "User #" + userId + " is not running.");
3345 return InputBindResult.INVALID_USER;
3346 }
3347 } else {
3348 userId = callingUserId;
3349 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003350 final InputBindResult result;
3351 synchronized (mMethodMap) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003352 final long ident = Binder.clearCallingIdentity();
3353 try {
3354 result = startInputOrWindowGainedFocusInternalLocked(startInputReason, client,
3355 windowToken, startInputFlags, softInputMode, windowFlags, attribute,
3356 inputContext, missingMethods, unverifiedTargetSdkVersion, userId);
3357 } finally {
3358 Binder.restoreCallingIdentity(ident);
3359 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003360 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08003361 if (result == null) {
3362 // This must never happen, but just in case.
3363 Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
Yohei Yukawaa468d702018-10-21 11:42:34 -07003364 + InputMethodDebug.startInputReasonToString(startInputReason)
Yohei Yukawa2553e482017-12-15 15:47:33 -08003365 + " windowFlags=#" + Integer.toHexString(windowFlags)
3366 + " editorInfo=" + attribute);
3367 return InputBindResult.NULL;
3368 }
3369 return result;
Yohei Yukawa05c25f82016-02-22 12:41:17 -08003370 }
3371
Yohei Yukawa2553e482017-12-15 15:47:33 -08003372 @NonNull
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003373 private InputBindResult startInputOrWindowGainedFocusInternalLocked(
Yohei Yukawadc66e522018-10-21 10:43:14 -07003374 @StartInputReason int startInputReason, IInputMethodClient client,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07003375 @NonNull IBinder windowToken, @StartInputFlags int startInputFlags,
3376 @SoftInputModeFlags int softInputMode, int windowFlags, EditorInfo attribute,
3377 IInputContext inputContext, @MissingMethodFlags int missingMethods,
Yohei Yukawa4391c202019-01-28 00:49:10 -08003378 int unverifiedTargetSdkVersion, @UserIdInt int userId) {
Yohei Yukawa67464522019-01-28 00:50:09 -08003379 if (DEBUG) {
3380 Slog.v(TAG, "startInputOrWindowGainedFocusInternalLocked: reason="
3381 + InputMethodDebug.startInputReasonToString(startInputReason)
3382 + " client=" + client.asBinder()
3383 + " inputContext=" + inputContext
3384 + " missingMethods="
3385 + InputConnectionInspector.getMissingMethodFlagsAsString(missingMethods)
3386 + " attribute=" + attribute
3387 + " startInputFlags="
3388 + InputMethodDebug.startInputFlagsToString(startInputFlags)
3389 + " softInputMode=" + InputMethodDebug.softInputModeToString(softInputMode)
3390 + " windowFlags=#" + Integer.toHexString(windowFlags)
3391 + " unverifiedTargetSdkVersion=" + unverifiedTargetSdkVersion);
3392 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003393
Yohei Yukawa67464522019-01-28 00:50:09 -08003394 final int windowDisplayId = mWindowManagerInternal.getDisplayIdForWindow(windowToken);
3395
3396 final ClientState cs = mClients.get(client.asBinder());
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003397 if (cs == null) {
Yohei Yukawa67464522019-01-28 00:50:09 -08003398 throw new IllegalArgumentException("unknown client " + client.asBinder());
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003399 }
3400 if (cs.selfReportedDisplayId != windowDisplayId) {
3401 Slog.e(TAG, "startInputOrWindowGainedFocusInternal: display ID mismatch."
3402 + " from client:" + cs.selfReportedDisplayId
3403 + " from window:" + windowDisplayId);
3404 return InputBindResult.DISPLAY_ID_MISMATCH;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003405 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08003406
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003407 if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
3408 cs.selfReportedDisplayId)) {
3409 // Check with the window manager to make sure this client actually
3410 // has a window with focus. If not, reject. This is thread safe
3411 // because if the focus changes some time before or after, the
3412 // next client receiving focus that has any interest in input will
3413 // be calling through here after that change happens.
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003414 if (DEBUG) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003415 Slog.w(TAG, "Focus gain on non-focused client " + cs.client
3416 + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003417 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003418 return InputBindResult.NOT_IME_TARGET_WINDOW;
3419 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003420
Yohei Yukawad277d692020-02-19 17:12:17 -08003421 if (mUserSwitchHandlerTask != null) {
3422 // There is already an on-going pending user switch task.
3423 final int nextUserId = mUserSwitchHandlerTask.mToUserId;
3424 if (userId == nextUserId) {
3425 scheduleSwitchUserTaskLocked(userId, cs.client);
3426 return InputBindResult.USER_SWITCHING;
3427 }
3428 for (int profileId : mUserManager.getProfileIdsWithDisabled(nextUserId)) {
3429 if (profileId == userId) {
3430 scheduleSwitchUserTaskLocked(userId, cs.client);
3431 return InputBindResult.USER_SWITCHING;
3432 }
3433 }
3434 return InputBindResult.INVALID_USER;
3435 }
3436
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003437 // cross-profile access is always allowed here to allow profile-switching.
3438 if (!mSettings.isCurrentProfile(userId)) {
3439 Slog.w(TAG, "A background user is requesting window. Hiding IME.");
3440 Slog.w(TAG, "If you need to impersonate a foreground user/profile from"
3441 + " a background user, use EditorInfo.targetInputMethodUser with"
3442 + " INTERACT_ACROSS_USERS_FULL permission.");
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08003443 hideCurrentInputLocked(
3444 mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_INVALID_USER);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003445 return InputBindResult.INVALID_USER;
3446 }
3447
Tarandeep Singhcf5ff822019-07-08 14:06:27 -07003448 if (userId != mSettings.getCurrentUserId()) {
Yohei Yukawad277d692020-02-19 17:12:17 -08003449 scheduleSwitchUserTaskLocked(userId, cs.client);
3450 return InputBindResult.USER_SWITCHING;
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003451 }
Yohei Yukawad277d692020-02-19 17:12:17 -08003452
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003453 // Master feature flag that overrides other conditions and forces IME preRendering.
3454 if (DEBUG) {
3455 Slog.v(TAG, "IME PreRendering MASTER flag: "
Yohei Yukawa67464522019-01-28 00:50:09 -08003456 + DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() + ", LowRam: " + mIsLowRam);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003457 }
3458 // pre-rendering not supported on low-ram devices.
3459 cs.shouldPreRenderIme = DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() && !mIsLowRam;
3460
3461 if (mCurFocusedWindow == windowToken) {
3462 if (DEBUG) {
3463 Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
3464 + " attribute=" + attribute + ", token = " + windowToken);
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003465 }
Ming-Shin Lu48bfc312020-06-15 20:06:09 +08003466 // Needs to start input when the same window focus gain but not with the same editor,
3467 // or when the current client needs to start input (e.g. when focusing the same
3468 // window after device turned screen on).
3469 if (attribute != null && (startInputReason != WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR
3470 || mCurClientNeedStartInput)) {
3471 if (mIsInteractive) {
3472 mCurClientNeedStartInput = false;
3473 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003474 return startInputUncheckedLocked(cs, inputContext, missingMethods,
3475 attribute, startInputFlags, startInputReason);
3476 }
Ming-Shin Lu48bfc312020-06-15 20:06:09 +08003477
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003478 return new InputBindResult(
3479 InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07003480 null, null, null, -1, null);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003481 }
3482 mCurFocusedWindow = windowToken;
3483 mCurFocusedWindowSoftInputMode = softInputMode;
3484 mCurFocusedWindowClient = cs;
Adrian Roosc22eec92020-06-12 18:48:10 +02003485 mCurPerceptible = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003486
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003487 // Should we auto-show the IME even if the caller has not
3488 // specified what should be done with it?
3489 // We only do this automatically if the window can resize
3490 // to accommodate the IME (so what the user sees will give
3491 // them good context without input information being obscured
3492 // by the IME) or if running on a large screen where there
3493 // is more room for the target window + IME.
3494 final boolean doAutoShow =
Yohei Yukawa6e875592019-01-28 00:49:30 -08003495 (softInputMode & LayoutParams.SOFT_INPUT_MASK_ADJUST)
3496 == LayoutParams.SOFT_INPUT_ADJUST_RESIZE
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003497 || mRes.getConfiguration().isLayoutSizeAtLeast(
3498 Configuration.SCREENLAYOUT_SIZE_LARGE);
Yohei Yukawa67464522019-01-28 00:50:09 -08003499 final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003500
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003501 // We want to start input before showing the IME, but after closing
3502 // it. We want to do this after closing it to help the IME disappear
3503 // more quickly (not get stuck behind it initializing itself for the
3504 // new focused input, even if its window wants to hide the IME).
3505 boolean didStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003506
Yohei Yukawa67464522019-01-28 00:50:09 -08003507 InputBindResult res = null;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003508 switch (softInputMode & LayoutParams.SOFT_INPUT_MASK_STATE) {
3509 case LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003510 if (!isTextEditor || !doAutoShow) {
Yohei Yukawa6e875592019-01-28 00:49:30 -08003511 if (LayoutParams.mayUseInputMethod(windowFlags)) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003512 // There is no focus view, and this window will
3513 // be behind any soft input window, so hide the
3514 // soft input window if it is shown.
3515 if (DEBUG) Slog.v(TAG, "Unspecified window will hide input");
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08003516 hideCurrentInputLocked(
3517 mCurFocusedWindow, InputMethodManager.HIDE_NOT_ALWAYS, null,
lumarkd85e1582019-12-29 20:20:41 +08003518 SoftInputShowHideReason.HIDE_UNSPECIFIED_WINDOW);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003519
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003520 // If focused display changed, we should unbind current method
3521 // to make app window in previous display relayout after Ime
3522 // window token removed.
3523 // Note that we can trust client's display ID as long as it matches
3524 // to the display ID obtained from the window.
3525 if (cs.selfReportedDisplayId != mCurTokenDisplayId) {
3526 unbindCurrentMethodLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003527 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003528 }
Yohei Yukawa6e875592019-01-28 00:49:30 -08003529 } else if (isTextEditor && doAutoShow
3530 && (softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003531 // There is a focus view, and we are navigating forward
3532 // into the window, so show the input window for the user.
3533 // We only do this automatically if the window can resize
3534 // to accommodate the IME (so what the user sees will give
3535 // them good context without input information being obscured
3536 // by the IME) or if running on a large screen where there
3537 // is more room for the target window + IME.
3538 if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
3539 if (attribute != null) {
3540 res = startInputUncheckedLocked(cs, inputContext, missingMethods,
3541 attribute, startInputFlags, startInputReason);
3542 didStart = true;
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003543 }
lumarkd85e1582019-12-29 20:20:41 +08003544 showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
3545 SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003546 }
3547 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003548 case LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003549 // Do nothing.
3550 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003551 case LayoutParams.SOFT_INPUT_STATE_HIDDEN:
3552 if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003553 if (DEBUG) Slog.v(TAG, "Window asks to hide input going forward");
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08003554 hideCurrentInputLocked(mCurFocusedWindow, 0, null,
lumarkd85e1582019-12-29 20:20:41 +08003555 SoftInputShowHideReason.HIDE_STATE_HIDDEN_FORWARD_NAV);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003556 }
3557 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003558 case LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003559 if (DEBUG) Slog.v(TAG, "Window asks to hide input");
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08003560 hideCurrentInputLocked(mCurFocusedWindow, 0, null,
lumarkd85e1582019-12-29 20:20:41 +08003561 SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003562 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003563 case LayoutParams.SOFT_INPUT_STATE_VISIBLE:
3564 if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003565 if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003566 if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
3567 unverifiedTargetSdkVersion, startInputFlags)) {
3568 if (attribute != null) {
Yohei Yukawa67464522019-01-28 00:50:09 -08003569 res = startInputUncheckedLocked(cs, inputContext, missingMethods,
3570 attribute, startInputFlags, startInputReason);
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003571 didStart = true;
3572 }
lumarkd85e1582019-12-29 20:20:41 +08003573 showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
3574 SoftInputShowHideReason.SHOW_STATE_VISIBLE_FORWARD_NAV);
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003575 } else {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003576 Slog.e(TAG, "SOFT_INPUT_STATE_VISIBLE is ignored because"
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003577 + " there is no focused view that also returns true from"
3578 + " View#onCheckIsTextEditor()");
3579 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003580 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003581 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003582 case LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003583 if (DEBUG) Slog.v(TAG, "Window asks to always show input");
3584 if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
3585 unverifiedTargetSdkVersion, startInputFlags)) {
3586 if (attribute != null) {
3587 res = startInputUncheckedLocked(cs, inputContext, missingMethods,
3588 attribute, startInputFlags, startInputReason);
3589 didStart = true;
3590 }
lumarkd85e1582019-12-29 20:20:41 +08003591 showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
3592 SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003593 } else {
3594 Slog.e(TAG, "SOFT_INPUT_STATE_ALWAYS_VISIBLE is ignored because"
3595 + " there is no focused view that also returns true from"
3596 + " View#onCheckIsTextEditor()");
3597 }
3598 break;
3599 }
3600
3601 if (!didStart) {
3602 if (attribute != null) {
3603 if (!DebugFlags.FLAG_OPTIMIZE_START_INPUT.value()
3604 || (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0) {
Yohei Yukawa67464522019-01-28 00:50:09 -08003605 res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003606 startInputFlags, startInputReason);
3607 } else {
3608 res = InputBindResult.NO_EDITOR;
3609 }
3610 } else {
3611 res = InputBindResult.NULL_EDITOR_INFO;
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003612 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003613 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08003614 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003615 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003616
Guliz Tuncay6908c152017-06-02 16:06:10 -07003617 private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08003618 // TODO(yukawa): multi-display support.
Guliz Tuncay6908c152017-06-02 16:06:10 -07003619 final int uid = Binder.getCallingUid();
lumark0b05f9e2018-11-26 15:09:06 +08003620 if (mCurFocusedWindowClient != null && client != null
Tarandeep Singheb570612018-01-29 16:20:32 -08003621 && mCurFocusedWindowClient.client.asBinder() == client.asBinder()) {
Guliz Tuncay6908c152017-06-02 16:06:10 -07003622 return true;
3623 } else if (mCurIntent != null && InputMethodUtils.checkIfPackageBelongsToUid(
3624 mAppOpsManager,
3625 uid,
3626 mCurIntent.getComponent().getPackageName())) {
3627 return true;
Guliz Tuncay6908c152017-06-02 16:06:10 -07003628 }
Guliz Tuncay6908c152017-06-02 16:06:10 -07003629 return false;
3630 }
3631
satok42c5a162011-05-26 16:46:14 +09003632 @Override
Seigo Nonaka14e13912015-05-06 21:04:13 -07003633 public void showInputMethodPickerFromClient(
3634 IInputMethodClient client, int auxiliarySubtypeMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003635 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003636 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003637 return;
3638 }
Guliz Tuncay6908c152017-06-02 16:06:10 -07003639 if(!canShowInputMethodPickerLocked(client)) {
satok47a44912010-10-06 16:03:58 +09003640 Slog.w(TAG, "Ignoring showInputMethodPickerFromClient of uid "
Dianne Hackborncef65ee2010-09-30 18:27:22 -07003641 + Binder.getCallingUid() + ": " + client);
Guliz Tuncay6908c152017-06-02 16:06:10 -07003642 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003643 }
3644
satok440aab52010-11-25 09:43:11 +09003645 // Always call subtype picker, because subtype picker is a superset of input method
3646 // picker.
lumark0b05f9e2018-11-26 15:09:06 +08003647 mHandler.sendMessage(mCaller.obtainMessageII(
3648 MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode,
3649 (mCurClient != null) ? mCurClient.selfReportedDisplayId : DEFAULT_DISPLAY));
satokab751aa2010-09-14 19:17:36 +09003650 }
3651 }
3652
lumark0b05f9e2018-11-26 15:09:06 +08003653 @Override
3654 public void showInputMethodPickerFromSystem(IInputMethodClient client, int auxiliarySubtypeMode,
3655 int displayId) {
3656 if (mContext.checkCallingPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
3657 != PackageManager.PERMISSION_GRANTED) {
3658 throw new SecurityException(
3659 "showInputMethodPickerFromSystem requires WRITE_SECURE_SETTINGS permission");
3660 }
3661 // Always call subtype picker, because subtype picker is a superset of input method
3662 // picker.
3663 mHandler.sendMessage(mCaller.obtainMessageII(
3664 MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode, displayId));
3665 }
3666
Tarandeep Singheb570612018-01-29 16:20:32 -08003667 public boolean isInputMethodPickerShownForTest() {
3668 synchronized(mMethodMap) {
3669 if (mSwitchingDialog == null) {
3670 return false;
3671 }
3672 return mSwitchingDialog.isShowing();
3673 }
3674 }
3675
Yohei Yukawa0c1ebff2018-12-27 14:06:28 -08003676 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003677 private void setInputMethod(@NonNull IBinder token, String id) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003678 synchronized (mMethodMap) {
Yohei Yukawa0c1ebff2018-12-27 14:06:28 -08003679 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003680 return;
3681 }
3682 setInputMethodWithSubtypeIdLocked(token, id, NOT_A_SUBTYPE_ID);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003683 }
satok28203512010-11-24 11:06:49 +09003684 }
3685
Yohei Yukawa4773ee12018-12-24 21:13:53 -08003686 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003687 private void setInputMethodAndSubtype(@NonNull IBinder token, String id,
3688 InputMethodSubtype subtype) {
satok28203512010-11-24 11:06:49 +09003689 synchronized (mMethodMap) {
Yohei Yukawa4773ee12018-12-24 21:13:53 -08003690 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003691 return;
3692 }
satok28203512010-11-24 11:06:49 +09003693 if (subtype != null) {
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003694 setInputMethodWithSubtypeIdLocked(token, id,
3695 InputMethodUtils.getSubtypeIdFromHashCode(mMethodMap.get(id),
3696 subtype.hashCode()));
satok28203512010-11-24 11:06:49 +09003697 } else {
3698 setInputMethod(token, id);
3699 }
3700 }
satokab751aa2010-09-14 19:17:36 +09003701 }
3702
satok42c5a162011-05-26 16:46:14 +09003703 @Override
satokb416a712010-11-25 20:42:14 +09003704 public void showInputMethodAndSubtypeEnablerFromClient(
satok217f5482010-12-15 05:19:19 +09003705 IInputMethodClient client, String inputMethodId) {
satokb416a712010-11-25 20:42:14 +09003706 synchronized (mMethodMap) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003707 // TODO(yukawa): Should we verify the display ID?
Yohei Yukawa46d74762019-01-22 10:17:22 -08003708 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003709 return;
3710 }
satok7fee71f2010-12-17 18:54:26 +09003711 executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
3712 MSG_SHOW_IM_SUBTYPE_ENABLER, inputMethodId));
satokb416a712010-11-25 20:42:14 +09003713 }
3714 }
3715
Yohei Yukawa0c499082018-12-09 18:52:02 -08003716 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003717 private boolean switchToPreviousInputMethod(@NonNull IBinder token) {
satok735cf382010-11-11 20:40:09 +09003718 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003719 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa0c499082018-12-09 18:52:02 -08003720 return false;
3721 }
satokc445bcd2011-01-25 18:57:24 +09003722 final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
satok4fc87d62011-05-20 16:13:43 +09003723 final InputMethodInfo lastImi;
satok208d5632011-05-20 22:13:38 +09003724 if (lastIme != null) {
satok4fc87d62011-05-20 16:13:43 +09003725 lastImi = mMethodMap.get(lastIme.first);
3726 } else {
3727 lastImi = null;
satok735cf382010-11-11 20:40:09 +09003728 }
satok4fc87d62011-05-20 16:13:43 +09003729 String targetLastImiId = null;
3730 int subtypeId = NOT_A_SUBTYPE_ID;
3731 if (lastIme != null && lastImi != null) {
3732 final boolean imiIdIsSame = lastImi.getId().equals(mCurMethodId);
Narayan Kamatha09b4d22016-04-15 18:32:45 +01003733 final int lastSubtypeHash = Integer.parseInt(lastIme.second);
satok4fc87d62011-05-20 16:13:43 +09003734 final int currentSubtypeHash = mCurrentSubtype == null ? NOT_A_SUBTYPE_ID
3735 : mCurrentSubtype.hashCode();
3736 // If the last IME is the same as the current IME and the last subtype is not
3737 // defined, there is no need to switch to the last IME.
3738 if (!imiIdIsSame || lastSubtypeHash != currentSubtypeHash) {
3739 targetLastImiId = lastIme.first;
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003740 subtypeId = InputMethodUtils.getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
satok4fc87d62011-05-20 16:13:43 +09003741 }
3742 }
3743
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003744 if (TextUtils.isEmpty(targetLastImiId)
3745 && !InputMethodUtils.canAddToLastInputMethod(mCurrentSubtype)) {
satok4fc87d62011-05-20 16:13:43 +09003746 // This is a safety net. If the currentSubtype can't be added to the history
3747 // and the framework couldn't find the last ime, we will make the last ime be
3748 // the most applicable enabled keyboard subtype of the system imes.
3749 final List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
3750 if (enabled != null) {
3751 final int N = enabled.size();
3752 final String locale = mCurrentSubtype == null
3753 ? mRes.getConfiguration().locale.toString()
3754 : mCurrentSubtype.getLocale();
3755 for (int i = 0; i < N; ++i) {
3756 final InputMethodInfo imi = enabled.get(i);
Yohei Yukawafd70fe82018-04-08 12:19:56 -07003757 if (imi.getSubtypeCount() > 0 && imi.isSystem()) {
satok4fc87d62011-05-20 16:13:43 +09003758 InputMethodSubtype keyboardSubtype =
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003759 InputMethodUtils.findLastResortApplicableSubtypeLocked(mRes,
3760 InputMethodUtils.getSubtypes(imi),
3761 InputMethodUtils.SUBTYPE_MODE_KEYBOARD, locale, true);
satok4fc87d62011-05-20 16:13:43 +09003762 if (keyboardSubtype != null) {
3763 targetLastImiId = imi.getId();
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003764 subtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
satok4fc87d62011-05-20 16:13:43 +09003765 imi, keyboardSubtype.hashCode());
3766 if(keyboardSubtype.getLocale().equals(locale)) {
3767 break;
3768 }
3769 }
3770 }
3771 }
3772 }
3773 }
3774
3775 if (!TextUtils.isEmpty(targetLastImiId)) {
3776 if (DEBUG) {
3777 Slog.d(TAG, "Switch to: " + lastImi.getId() + ", " + lastIme.second
3778 + ", from: " + mCurMethodId + ", " + subtypeId);
3779 }
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003780 setInputMethodWithSubtypeIdLocked(token, targetLastImiId, subtypeId);
satok4fc87d62011-05-20 16:13:43 +09003781 return true;
3782 } else {
3783 return false;
3784 }
satok735cf382010-11-11 20:40:09 +09003785 }
3786 }
3787
Yohei Yukawa70f17e72018-12-09 18:51:38 -08003788 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003789 private boolean switchToNextInputMethod(@NonNull IBinder token, boolean onlyCurrentIme) {
satok688bd472012-02-09 20:09:17 +09003790 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003791 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawaa0755742014-06-04 20:28:18 +09003792 return false;
3793 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003794 final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
Yohei Yukawa136b6ce2018-05-02 10:55:35 -07003795 onlyCurrentIme, mMethodMap.get(mCurMethodId), mCurrentSubtype);
satok688bd472012-02-09 20:09:17 +09003796 if (nextSubtype == null) {
3797 return false;
3798 }
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003799 setInputMethodWithSubtypeIdLocked(token, nextSubtype.mImi.getId(),
3800 nextSubtype.mSubtypeId);
satok688bd472012-02-09 20:09:17 +09003801 return true;
3802 }
3803 }
3804
Yohei Yukawaeec552e2018-09-09 20:48:41 -07003805 @BinderThread
3806 private boolean shouldOfferSwitchingToNextInputMethod(@NonNull IBinder token) {
Satoshi Kataoka2b10b522013-08-21 20:39:12 +09003807 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003808 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawaa0755742014-06-04 20:28:18 +09003809 return false;
3810 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003811 final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
Yohei Yukawa136b6ce2018-05-02 10:55:35 -07003812 false /* onlyCurrentIme */, mMethodMap.get(mCurMethodId), mCurrentSubtype);
Satoshi Kataoka2b10b522013-08-21 20:39:12 +09003813 if (nextSubtype == null) {
3814 return false;
3815 }
3816 return true;
3817 }
3818 }
3819
3820 @Override
satok68f1b782011-04-11 14:26:04 +09003821 public InputMethodSubtype getLastInputMethodSubtype() {
3822 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003823 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003824 return null;
3825 }
satok68f1b782011-04-11 14:26:04 +09003826 final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
3827 // TODO: Handle the case of the last IME with no subtypes
3828 if (lastIme == null || TextUtils.isEmpty(lastIme.first)
3829 || TextUtils.isEmpty(lastIme.second)) return null;
3830 final InputMethodInfo lastImi = mMethodMap.get(lastIme.first);
3831 if (lastImi == null) return null;
3832 try {
Narayan Kamatha09b4d22016-04-15 18:32:45 +01003833 final int lastSubtypeHash = Integer.parseInt(lastIme.second);
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003834 final int lastSubtypeId =
3835 InputMethodUtils.getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
satok0e7d7d62011-07-05 13:28:06 +09003836 if (lastSubtypeId < 0 || lastSubtypeId >= lastImi.getSubtypeCount()) {
3837 return null;
3838 }
3839 return lastImi.getSubtypeAt(lastSubtypeId);
satok68f1b782011-04-11 14:26:04 +09003840 } catch (NumberFormatException e) {
3841 return null;
3842 }
3843 }
3844 }
3845
satoke7c6998e2011-06-03 17:57:59 +09003846 @Override
satokee5e77c2011-09-02 18:50:15 +09003847 public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
satok91e88122011-07-18 11:11:42 +09003848 // By this IPC call, only a process which shares the same uid with the IME can add
3849 // additional input method subtypes to the IME.
Yohei Yukawa70f5c482016-01-04 19:42:36 -08003850 if (TextUtils.isEmpty(imiId) || subtypes == null) return;
Yohei Yukawab557d572018-12-29 21:26:26 -08003851 final ArrayList<InputMethodSubtype> toBeAdded = new ArrayList<>();
3852 for (InputMethodSubtype subtype : subtypes) {
3853 if (!toBeAdded.contains(subtype)) {
3854 toBeAdded.add(subtype);
3855 } else {
3856 Slog.w(TAG, "Duplicated subtype definition found: "
3857 + subtype.getLocale() + ", " + subtype.getMode());
3858 }
3859 }
satoke7c6998e2011-06-03 17:57:59 +09003860 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003861 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003862 return;
3863 }
Yohei Yukawa79247822017-01-23 15:26:15 -08003864 if (!mSystemReady) {
3865 return;
3866 }
satok91e88122011-07-18 11:11:42 +09003867 final InputMethodInfo imi = mMethodMap.get(imiId);
satokee5e77c2011-09-02 18:50:15 +09003868 if (imi == null) return;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003869 final String[] packageInfos;
3870 try {
3871 packageInfos = mIPackageManager.getPackagesForUid(Binder.getCallingUid());
3872 } catch (RemoteException e) {
3873 Slog.e(TAG, "Failed to get package infos");
3874 return;
3875 }
satok91e88122011-07-18 11:11:42 +09003876 if (packageInfos != null) {
3877 final int packageNum = packageInfos.length;
3878 for (int i = 0; i < packageNum; ++i) {
3879 if (packageInfos[i].equals(imi.getPackageName())) {
Yohei Yukawa7b1c8d72018-12-19 11:21:04 -08003880 if (subtypes.length > 0) {
Yohei Yukawab557d572018-12-29 21:26:26 -08003881 mAdditionalSubtypeMap.put(imi.getId(), toBeAdded);
Yohei Yukawa7b1c8d72018-12-19 11:21:04 -08003882 } else {
Yohei Yukawab557d572018-12-29 21:26:26 -08003883 mAdditionalSubtypeMap.remove(imi.getId());
Yohei Yukawa7b1c8d72018-12-19 11:21:04 -08003884 }
Yohei Yukawab557d572018-12-29 21:26:26 -08003885 AdditionalSubtypeUtils.save(mAdditionalSubtypeMap, mMethodMap,
3886 mSettings.getCurrentUserId());
satokc5933802011-08-31 21:26:04 +09003887 final long ident = Binder.clearCallingIdentity();
3888 try {
Yohei Yukawa94e33302016-02-12 19:37:03 -08003889 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
satokc5933802011-08-31 21:26:04 +09003890 } finally {
3891 Binder.restoreCallingIdentity(ident);
3892 }
satokee5e77c2011-09-02 18:50:15 +09003893 return;
satok91e88122011-07-18 11:11:42 +09003894 }
3895 }
3896 }
satoke7c6998e2011-06-03 17:57:59 +09003897 }
satokee5e77c2011-09-02 18:50:15 +09003898 return;
satoke7c6998e2011-06-03 17:57:59 +09003899 }
3900
Yohei Yukawab985e6e2018-09-05 17:07:52 -07003901 /**
Artur Satayev192ca302020-01-22 21:38:23 +00003902 * This is kept due to {@code @UnsupportedAppUsage} in
Yohei Yukawab985e6e2018-09-05 17:07:52 -07003903 * {@link InputMethodManager#getInputMethodWindowVisibleHeight()} and a dependency in
3904 * {@link InputMethodService#onCreate()}.
3905 *
3906 * <p>TODO(Bug 113914148): Check if we can remove this.</p>
3907 * @return {@link WindowManagerInternal#getInputMethodWindowVisibleHeight()}
3908 */
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09003909 @Override
3910 public int getInputMethodWindowVisibleHeight() {
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08003911 // TODO(yukawa): Should we verify the display ID?
lumark90120a82018-08-15 00:33:03 +08003912 return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId);
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09003913 }
3914
Yohei Yukawab4f328a2019-05-02 08:41:27 -07003915 @Override
3916 public void reportActivityView(IInputMethodClient parentClient, int childDisplayId,
3917 float[] matrixValues) {
3918 final DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(childDisplayId);
3919 if (displayInfo == null) {
3920 throw new IllegalArgumentException(
3921 "Cannot find display for non-existent displayId: " + childDisplayId);
3922 }
3923 final int callingUid = Binder.getCallingUid();
3924 if (callingUid != displayInfo.ownerUid) {
3925 throw new SecurityException("The caller doesn't own the display.");
3926 }
3927
3928 synchronized (mMethodMap) {
3929 final ClientState cs = mClients.get(parentClient.asBinder());
3930 if (cs == null) {
3931 return;
3932 }
3933
3934 // null matrixValues means that the entry needs to be removed.
3935 if (matrixValues == null) {
3936 final ActivityViewInfo info = mActivityViewDisplayIdToParentMap.get(childDisplayId);
3937 if (info == null) {
3938 return;
3939 }
3940 if (info.mParentClient != cs) {
3941 throw new SecurityException("Only the owner client can clear"
3942 + " ActivityViewGeometry for display #" + childDisplayId);
3943 }
3944 mActivityViewDisplayIdToParentMap.remove(childDisplayId);
3945 return;
3946 }
3947
3948 ActivityViewInfo info = mActivityViewDisplayIdToParentMap.get(childDisplayId);
3949 if (info != null && info.mParentClient != cs) {
3950 throw new InvalidParameterException("Display #" + childDisplayId
3951 + " is already registered by " + info.mParentClient);
3952 }
3953 if (info == null) {
3954 if (!mWindowManagerInternal.isUidAllowedOnDisplay(childDisplayId, cs.uid)) {
3955 throw new SecurityException(cs + " cannot access to display #"
3956 + childDisplayId);
3957 }
3958 info = new ActivityViewInfo(cs, new Matrix());
3959 mActivityViewDisplayIdToParentMap.put(childDisplayId, info);
3960 }
3961 info.mMatrix.setValues(matrixValues);
3962
3963 if (mCurClient == null || mCurClient.curSession == null) {
3964 return;
3965 }
3966
3967 Matrix matrix = null;
3968 int displayId = mCurClient.selfReportedDisplayId;
3969 boolean needToNotify = false;
3970 while (true) {
3971 needToNotify |= (displayId == childDisplayId);
3972 final ActivityViewInfo next = mActivityViewDisplayIdToParentMap.get(displayId);
3973 if (next == null) {
3974 break;
3975 }
3976 if (matrix == null) {
3977 matrix = new Matrix(next.mMatrix);
3978 } else {
3979 matrix.postConcat(next.mMatrix);
3980 }
3981 if (next.mParentClient.selfReportedDisplayId == mCurTokenDisplayId) {
3982 if (needToNotify) {
3983 final float[] values = new float[9];
3984 matrix.getValues(values);
3985 try {
3986 mCurClient.client.updateActivityViewToScreenMatrix(mCurSeq, values);
3987 } catch (RemoteException e) {
3988 }
3989 }
3990 break;
3991 }
3992 displayId = info.mParentClient.selfReportedDisplayId;
3993 }
3994 }
3995 }
3996
Yunfan Chenc02a5ac2020-06-16 01:52:41 +00003997 @Override
3998 public void removeImeSurface() {
3999 mContext.enforceCallingPermission(Manifest.permission.INTERNAL_SYSTEM_WINDOW, null);
4000 mHandler.sendMessage(mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE));
4001 }
4002
Yohei Yukawac54c1172018-09-06 11:39:50 -07004003 @BinderThread
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07004004 private void notifyUserAction(@NonNull IBinder token) {
Satoshi Kataokad7443c82013-10-15 17:45:43 +09004005 if (DEBUG) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07004006 Slog.d(TAG, "Got the notification of a user action.");
Satoshi Kataokad7443c82013-10-15 17:45:43 +09004007 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09004008 synchronized (mMethodMap) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07004009 if (mCurToken != token) {
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09004010 if (DEBUG) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07004011 Slog.d(TAG, "Ignoring the user action notification from IMEs that are no longer"
4012 + " active.");
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09004013 }
4014 return;
4015 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09004016 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
4017 if (imi != null) {
Yohei Yukawa02970512014-06-05 16:16:18 +09004018 mSwitchingController.onUserActionLocked(imi, mCurrentSubtype);
Yohei Yukawa5a647b692014-05-22 12:49:00 +09004019 }
Satoshi Kataokad7443c82013-10-15 17:45:43 +09004020 }
4021 }
4022
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08004023 @BinderThread
4024 private void reportPreRendered(IBinder token, EditorInfo info) {
4025 synchronized (mMethodMap) {
4026 if (!calledWithValidTokenLocked(token)) {
4027 return;
4028 }
4029 if (mCurClient != null && mCurClient.client != null) {
4030 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
4031 MSG_REPORT_PRE_RENDERED, info, mCurClient));
4032 }
4033 }
4034 }
4035
4036 @BinderThread
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08004037 private void applyImeVisibility(IBinder token, IBinder windowToken, boolean setVisible) {
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08004038 synchronized (mMethodMap) {
4039 if (!calledWithValidTokenLocked(token)) {
4040 return;
4041 }
Tarandeep Singh500a38f2019-09-26 13:36:40 -07004042 if (!setVisible) {
Taran Singhd7fc5862019-10-10 14:45:17 +02004043 if (mCurClient != null) {
4044 // IMMS only knows of focused window, not the actual IME target.
4045 // e.g. it isn't aware of any window that has both
4046 // NOT_FOCUSABLE, ALT_FOCUSABLE_IM flags set and can the IME target.
4047 // Send it to window manager to hide IME from IME target window.
4048 // TODO(b/139861270): send to mCurClient.client once IMMS is aware of
4049 // actual IME target.
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08004050 mWindowManagerInternal.hideIme(mHideRequestWindowMap.get(windowToken));
Tarandeep Singh500a38f2019-09-26 13:36:40 -07004051 }
4052 } else {
4053 // Send to window manager to show IME after IME layout finishes.
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08004054 mWindowManagerInternal.showImePostLayout(mShowRequestWindowMap.get(windowToken));
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08004055 }
4056 }
4057 }
4058
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09004059 private void setInputMethodWithSubtypeIdLocked(IBinder token, String id, int subtypeId) {
4060 if (token == null) {
4061 if (mContext.checkCallingOrSelfPermission(
4062 android.Manifest.permission.WRITE_SECURE_SETTINGS)
4063 != PackageManager.PERMISSION_GRANTED) {
4064 throw new SecurityException(
4065 "Using null token requires permission "
4066 + android.Manifest.permission.WRITE_SECURE_SETTINGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004067 }
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09004068 } else if (mCurToken != token) {
4069 Slog.w(TAG, "Ignoring setInputMethod of uid " + Binder.getCallingUid()
4070 + " token: " + token);
4071 return;
4072 }
4073
4074 final long ident = Binder.clearCallingIdentity();
4075 try {
4076 setInputMethodLocked(id, subtypeId);
4077 } finally {
4078 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004079 }
4080 }
4081
Yohei Yukawaeec552e2018-09-09 20:48:41 -07004082 @BinderThread
4083 private void hideMySoftInput(@NonNull IBinder token, int flags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004084 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08004085 if (!calledWithValidTokenLocked(token)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004086 return;
4087 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004088 long ident = Binder.clearCallingIdentity();
4089 try {
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08004090 hideCurrentInputLocked(
4091 mLastImeTargetWindow, flags, null,
4092 SoftInputShowHideReason.HIDE_MY_SOFT_INPUT);
4093
The Android Open Source Project4df24232009-03-05 14:34:35 -08004094 } finally {
4095 Binder.restoreCallingIdentity(ident);
4096 }
4097 }
4098 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004099
Yohei Yukawaeec552e2018-09-09 20:48:41 -07004100 @BinderThread
4101 private void showMySoftInput(@NonNull IBinder token, int flags) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08004102 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08004103 if (!calledWithValidTokenLocked(token)) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08004104 return;
4105 }
4106 long ident = Binder.clearCallingIdentity();
4107 try {
lumarkd85e1582019-12-29 20:20:41 +08004108 showCurrentInputLocked(mLastImeTargetWindow, flags, null,
4109 SoftInputShowHideReason.SHOW_MY_SOFT_INPUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004110 } finally {
4111 Binder.restoreCallingIdentity(ident);
4112 }
4113 }
4114 }
4115
4116 void setEnabledSessionInMainThread(SessionState session) {
4117 if (mEnabledSession != session) {
Yohei Yukawa9d91b432014-05-19 16:03:24 +09004118 if (mEnabledSession != null && mEnabledSession.session != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004119 try {
Joe Onorato8a9b2202010-02-26 18:56:32 -08004120 if (DEBUG) Slog.v(TAG, "Disabling: " + mEnabledSession);
Yohei Yukawa9d91b432014-05-19 16:03:24 +09004121 mEnabledSession.method.setSessionEnabled(mEnabledSession.session, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004122 } catch (RemoteException e) {
4123 }
4124 }
4125 mEnabledSession = session;
Yohei Yukawa9d91b432014-05-19 16:03:24 +09004126 if (mEnabledSession != null && mEnabledSession.session != null) {
4127 try {
4128 if (DEBUG) Slog.v(TAG, "Enabling: " + mEnabledSession);
4129 mEnabledSession.method.setSessionEnabled(mEnabledSession.session, true);
4130 } catch (RemoteException e) {
4131 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004132 }
4133 }
4134 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004135
Yohei Yukawa930328c2017-10-18 20:19:53 -07004136 @MainThread
satok42c5a162011-05-26 16:46:14 +09004137 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004138 public boolean handleMessage(Message msg) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004139 SomeArgs args;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004140 switch (msg.what) {
satokab751aa2010-09-14 19:17:36 +09004141 case MSG_SHOW_IM_SUBTYPE_PICKER:
Seigo Nonaka14e13912015-05-06 21:04:13 -07004142 final boolean showAuxSubtypes;
lumark0b05f9e2018-11-26 15:09:06 +08004143 final int displayId = msg.arg2;
Seigo Nonaka14e13912015-05-06 21:04:13 -07004144 switch (msg.arg1) {
4145 case InputMethodManager.SHOW_IM_PICKER_MODE_AUTO:
4146 // This is undocumented so far, but IMM#showInputMethodPicker() has been
4147 // implemented so that auxiliary subtypes will be excluded when the soft
4148 // keyboard is invisible.
4149 showAuxSubtypes = mInputShown;
4150 break;
4151 case InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES:
4152 showAuxSubtypes = true;
4153 break;
4154 case InputMethodManager.SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES:
4155 showAuxSubtypes = false;
4156 break;
4157 default:
4158 Slog.e(TAG, "Unknown subtype picker mode = " + msg.arg1);
4159 return false;
4160 }
lumark0b05f9e2018-11-26 15:09:06 +08004161 showInputMethodMenu(showAuxSubtypes, displayId);
satokab751aa2010-09-14 19:17:36 +09004162 return true;
4163
satok47a44912010-10-06 16:03:58 +09004164 case MSG_SHOW_IM_SUBTYPE_ENABLER:
Yohei Yukawa41f34272015-12-14 15:41:52 -08004165 showInputMethodAndSubtypeEnabler((String)msg.obj);
satok217f5482010-12-15 05:19:19 +09004166 return true;
4167
4168 case MSG_SHOW_IM_CONFIG:
4169 showConfigureInputMethods();
satok47a44912010-10-06 16:03:58 +09004170 return true;
4171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004172 // ---------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004173
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004174 case MSG_UNBIND_INPUT:
4175 try {
4176 ((IInputMethod)msg.obj).unbindInput();
4177 } catch (RemoteException e) {
4178 // There is nothing interesting about the method dying.
4179 }
4180 return true;
4181 case MSG_BIND_INPUT:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004182 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004183 try {
4184 ((IInputMethod)args.arg1).bindInput((InputBinding)args.arg2);
4185 } catch (RemoteException e) {
4186 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004187 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004188 return true;
4189 case MSG_SHOW_SOFT_INPUT:
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08004190 args = (SomeArgs) msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004191 try {
lumarkd85e1582019-12-29 20:20:41 +08004192 final @SoftInputShowHideReason int reason = msg.arg2;
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07004193 if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".showSoftInput("
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08004194 + args.arg3 + ", " + msg.arg1 + ", " + args.arg2 + ") for reason: "
lumarkd85e1582019-12-29 20:20:41 +08004195 + InputMethodDebug.softInputDisplayReasonToString(reason));
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08004196 ((IInputMethod) args.arg1).showSoftInput(
4197 (IBinder) args.arg3, msg.arg1, (ResultReceiver) args.arg2);
Anmol Gupta29f209d2020-03-11 11:34:46 -07004198 mSoftInputShowHideHistory.addEntry(new SoftInputShowHideHistory.Entry(
4199 mCurClient, mCurAttribute,
4200 mWindowManagerInternal.getWindowName(mCurFocusedWindow),
4201 mCurFocusedWindowSoftInputMode, reason, mInFullscreenMode,
4202 mWindowManagerInternal.getWindowName(
Ming-Shin Lud0bc1712020-05-11 09:23:37 +08004203 mShowRequestWindowMap.get(args.arg3)),
4204 mWindowManagerInternal.getImeControlTargetNameForLogging(
4205 mCurTokenDisplayId),
4206 mWindowManagerInternal.getImeTargetNameForLogging(
4207 mCurTokenDisplayId)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004208 } catch (RemoteException e) {
4209 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004210 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004211 return true;
4212 case MSG_HIDE_SOFT_INPUT:
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08004213 args = (SomeArgs) msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004214 try {
lumarkd85e1582019-12-29 20:20:41 +08004215 final @SoftInputShowHideReason int reason = msg.arg1;
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07004216 if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".hideSoftInput(0, "
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08004217 + args.arg3 + ", " + args.arg2 + ") for reason: "
lumarkd85e1582019-12-29 20:20:41 +08004218 + InputMethodDebug.softInputDisplayReasonToString(reason));
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08004219 ((IInputMethod)args.arg1).hideSoftInput(
4220 (IBinder) args.arg3, 0, (ResultReceiver)args.arg2);
Anmol Gupta29f209d2020-03-11 11:34:46 -07004221 mSoftInputShowHideHistory.addEntry(new SoftInputShowHideHistory.Entry(
4222 mCurClient, mCurAttribute,
4223 mWindowManagerInternal.getWindowName(mCurFocusedWindow),
4224 mCurFocusedWindowSoftInputMode, reason, mInFullscreenMode,
4225 mWindowManagerInternal.getWindowName(
Ming-Shin Lud0bc1712020-05-11 09:23:37 +08004226 mHideRequestWindowMap.get(args.arg3)),
4227 mWindowManagerInternal.getImeControlTargetNameForLogging(
4228 mCurTokenDisplayId),
4229 mWindowManagerInternal.getImeTargetNameForLogging(
4230 mCurTokenDisplayId)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004231 } catch (RemoteException e) {
4232 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004233 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004234 return true;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -07004235 case MSG_HIDE_CURRENT_INPUT_METHOD:
4236 synchronized (mMethodMap) {
lumarkd85e1582019-12-29 20:20:41 +08004237 final @SoftInputShowHideReason int reason = (int) msg.obj;
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08004238 hideCurrentInputLocked(mCurFocusedWindow, 0, null, reason);
4239
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -07004240 }
4241 return true;
Yohei Yukawac54c1172018-09-06 11:39:50 -07004242 case MSG_INITIALIZE_IME:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004243 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004244 try {
lumark90120a82018-08-15 00:33:03 +08004245 if (DEBUG) {
4246 Slog.v(TAG, "Sending attach of token: " + args.arg2 + " for display: "
4247 + msg.arg1);
4248 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07004249 final IBinder token = (IBinder) args.arg2;
lumark90120a82018-08-15 00:33:03 +08004250 ((IInputMethod) args.arg1).initializeInternal(token, msg.arg1,
Yohei Yukawac54c1172018-09-06 11:39:50 -07004251 new InputMethodPrivilegedOperationsImpl(this, token));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004252 } catch (RemoteException e) {
4253 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004254 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004255 return true;
Jeff Brownc28867a2013-03-26 15:42:39 -07004256 case MSG_CREATE_SESSION: {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004257 args = (SomeArgs)msg.obj;
Jeff Brown1951ce82013-04-04 22:45:12 -07004258 IInputMethod method = (IInputMethod)args.arg1;
Jeff Brownc28867a2013-03-26 15:42:39 -07004259 InputChannel channel = (InputChannel)args.arg2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004260 try {
Jeff Brown1951ce82013-04-04 22:45:12 -07004261 method.createSession(channel, (IInputSessionCallback)args.arg3);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004262 } catch (RemoteException e) {
Jeff Brownc28867a2013-03-26 15:42:39 -07004263 } finally {
Jeff Brown1951ce82013-04-04 22:45:12 -07004264 // Dispose the channel if the input method is not local to this process
4265 // because the remote proxy will get its own copy when unparceled.
4266 if (channel != null && Binder.isProxy(method)) {
Jeff Brownc28867a2013-03-26 15:42:39 -07004267 channel.dispose();
4268 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004269 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004270 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004271 return true;
Jeff Brownc28867a2013-03-26 15:42:39 -07004272 }
Yunfan Chenc02a5ac2020-06-16 01:52:41 +00004273 case MSG_REMOVE_IME_SURFACE: {
4274 try {
4275 if (mEnabledSession != null && mEnabledSession.session != null) {
4276 mEnabledSession.session.removeImeSurface();
4277 }
4278 } catch (RemoteException e) {
4279 }
4280 return true;
4281 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004282 // ---------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004283
Yohei Yukawa19a80a12016-03-14 22:57:37 -07004284 case MSG_START_INPUT: {
Yohei Yukawaf7526b52017-02-11 20:57:10 -08004285 final int missingMethods = msg.arg1;
4286 final boolean restarting = msg.arg2 != 0;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07004287 args = (SomeArgs) msg.obj;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08004288 final IBinder startInputToken = (IBinder) args.arg1;
4289 final SessionState session = (SessionState) args.arg2;
4290 final IInputContext inputContext = (IInputContext) args.arg3;
4291 final EditorInfo editorInfo = (EditorInfo) args.arg4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004292 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004293 setEnabledSessionInMainThread(session);
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08004294 session.method.startInput(startInputToken, inputContext, missingMethods,
Tarandeep Singheadb1392018-11-09 18:15:57 +01004295 editorInfo, restarting, session.client.shouldPreRenderIme);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004296 } catch (RemoteException e) {
4297 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004298 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004299 return true;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07004300 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004301
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004302 // ---------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004303
Yohei Yukawa33e81792015-11-17 21:14:42 -08004304 case MSG_UNBIND_CLIENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004305 try {
Yohei Yukawa33e81792015-11-17 21:14:42 -08004306 ((IInputMethodClient)msg.obj).onUnbindMethod(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004307 } catch (RemoteException e) {
4308 // There is nothing interesting about the last client dying.
4309 }
4310 return true;
Yohei Yukawa33e81792015-11-17 21:14:42 -08004311 case MSG_BIND_CLIENT: {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004312 args = (SomeArgs)msg.obj;
Jeff Brown1951ce82013-04-04 22:45:12 -07004313 IInputMethodClient client = (IInputMethodClient)args.arg1;
4314 InputBindResult res = (InputBindResult)args.arg2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004315 try {
Jeff Brown1951ce82013-04-04 22:45:12 -07004316 client.onBindMethod(res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004317 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08004318 Slog.w(TAG, "Client died receiving input method " + args.arg2);
Jeff Brown1951ce82013-04-04 22:45:12 -07004319 } finally {
4320 // Dispose the channel if the input method is not local to this process
4321 // because the remote proxy will get its own copy when unparceled.
4322 if (res.channel != null && Binder.isProxy(client)) {
4323 res.channel.dispose();
4324 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004325 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07004326 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004327 return true;
Jeff Brown1951ce82013-04-04 22:45:12 -07004328 }
Dianne Hackborna6e41342012-05-22 16:30:34 -07004329 case MSG_SET_ACTIVE:
4330 try {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08004331 ((ClientState)msg.obj).client.setActive(msg.arg1 != 0, msg.arg2 != 0);
Dianne Hackborna6e41342012-05-22 16:30:34 -07004332 } catch (RemoteException e) {
4333 Slog.w(TAG, "Got RemoteException sending setActive(false) notification to pid "
4334 + ((ClientState)msg.obj).pid + " uid "
4335 + ((ClientState)msg.obj).uid);
4336 }
4337 return true;
Ming-Shin Lu2c6e80b2020-05-13 00:12:26 +08004338 case MSG_SET_INTERACTIVE:
4339 handleSetInteractive(msg.arg1 != 0);
4340 return true;
Yohei Yukawa2bc66172017-02-08 11:13:25 -08004341 case MSG_REPORT_FULLSCREEN_MODE: {
4342 final boolean fullscreen = msg.arg1 != 0;
4343 final ClientState clientState = (ClientState)msg.obj;
4344 try {
4345 clientState.client.reportFullscreenMode(fullscreen);
4346 } catch (RemoteException e) {
4347 Slog.w(TAG, "Got RemoteException sending "
4348 + "reportFullscreen(" + fullscreen + ") notification to pid="
4349 + clientState.pid + " uid=" + clientState.uid);
4350 }
4351 return true;
4352 }
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08004353 case MSG_REPORT_PRE_RENDERED: {
4354 args = (SomeArgs) msg.obj;
4355 final EditorInfo info = (EditorInfo) args.arg1;
4356 final ClientState clientState = (ClientState) args.arg2;
4357 try {
4358 clientState.client.reportPreRendered(info);
4359 } catch (RemoteException e) {
4360 Slog.w(TAG, "Got RemoteException sending "
4361 + "reportPreRendered(" + info + ") notification to pid="
4362 + clientState.pid + " uid=" + clientState.uid);
4363 }
4364 args.recycle();
4365 return true;
4366 }
4367 case MSG_APPLY_IME_VISIBILITY: {
4368 final boolean setVisible = msg.arg1 != 0;
4369 final ClientState clientState = (ClientState) msg.obj;
4370 try {
4371 clientState.client.applyImeVisibility(setVisible);
4372 } catch (RemoteException e) {
4373 Slog.w(TAG, "Got RemoteException sending "
4374 + "applyImeVisibility(" + setVisible + ") notification to pid="
4375 + clientState.pid + " uid=" + clientState.uid);
4376 }
4377 return true;
4378 }
satok01038492012-04-09 21:08:27 +09004379
4380 // --------------------------------------------------------------
4381 case MSG_HARD_KEYBOARD_SWITCH_CHANGED:
Michael Wright7b5a96b2014-08-09 19:28:42 -07004382 mHardKeyboardListener.handleHardKeyboardStatusChange(msg.arg1 == 1);
satok01038492012-04-09 21:08:27 +09004383 return true;
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +09004384 case MSG_SYSTEM_UNLOCK_USER: {
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07004385 final int userId = msg.arg1;
4386 onUnlockUser(userId);
4387 return true;
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +09004388 }
4389 case MSG_DISPATCH_ON_INPUT_METHOD_LIST_UPDATED: {
4390 final int userId = msg.arg1;
4391 final List<InputMethodInfo> imes = (List<InputMethodInfo>) msg.obj;
4392 mInputMethodListListeners.forEach(
4393 listener -> listener.onInputMethodListUpdated(imes, userId));
4394 return true;
4395 }
Adam Hebc67f2e2019-11-13 14:34:56 -08004396
4397 // ---------------------------------------------------------------
Yohei Yukawa6e9768e2020-05-14 18:14:24 -07004398 case MSG_INLINE_SUGGESTIONS_REQUEST: {
Adam Hebc67f2e2019-11-13 14:34:56 -08004399 args = (SomeArgs) msg.obj;
Feng Cao36960ee2020-02-18 18:23:30 -08004400 final InlineSuggestionsRequestInfo requestInfo =
4401 (InlineSuggestionsRequestInfo) args.arg2;
Adam Hebc67f2e2019-11-13 14:34:56 -08004402 final IInlineSuggestionsRequestCallback callback =
Feng Cao36960ee2020-02-18 18:23:30 -08004403 (IInlineSuggestionsRequestCallback) args.arg3;
Adam Hebc67f2e2019-11-13 14:34:56 -08004404 try {
Feng Cao36960ee2020-02-18 18:23:30 -08004405 ((IInputMethod) args.arg1).onCreateInlineSuggestionsRequest(requestInfo,
4406 callback);
Adam Hebc67f2e2019-11-13 14:34:56 -08004407 } catch (RemoteException e) {
4408 Slog.w(TAG, "RemoteException calling onCreateInlineSuggestionsRequest(): " + e);
4409 }
Yohei Yukawa6e9768e2020-05-14 18:14:24 -07004410 args.recycle();
Adam Hebc67f2e2019-11-13 14:34:56 -08004411 return true;
Yohei Yukawa6e9768e2020-05-14 18:14:24 -07004412 }
Yohei Yukawad5f402b2020-05-15 10:23:32 -07004413
4414 // ---------------------------------------------------------------
4415 case MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE: {
4416 if (mAudioManagerInternal == null) {
4417 mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
4418 }
4419 if (mAudioManagerInternal != null) {
4420 mAudioManagerInternal.setInputMethodServiceUid(msg.arg1 /* uid */);
4421 }
4422 return true;
4423 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004424 }
4425 return false;
4426 }
4427
Ming-Shin Lu2c6e80b2020-05-13 00:12:26 +08004428 private void handleSetInteractive(final boolean interactive) {
4429 synchronized (mMethodMap) {
4430 mIsInteractive = interactive;
Ming-Shin Lu48bfc312020-06-15 20:06:09 +08004431 if (!interactive) {
4432 mCurClientNeedStartInput = true;
4433 }
Ming-Shin Lu2c6e80b2020-05-13 00:12:26 +08004434 updateSystemUiLocked(interactive ? mImeWindowVis : 0, mBackDisposition);
4435
4436 // Inform the current client of the change in active status
4437 if (mCurClient != null && mCurClient.client != null) {
4438 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
4439 MSG_SET_ACTIVE, mIsInteractive ? 1 : 0, mInFullscreenMode ? 1 : 0,
4440 mCurClient));
4441 }
4442 }
4443 }
4444
satokdc9ddae2011-10-06 12:22:36 +09004445 private boolean chooseNewDefaultIMELocked() {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004446 final InputMethodInfo imi = InputMethodUtils.getMostApplicableDefaultIME(
4447 mSettings.getEnabledInputMethodListLocked());
satokdc9ddae2011-10-06 12:22:36 +09004448 if (imi != null) {
satok03eb319a2010-11-11 18:17:42 +09004449 if (DEBUG) {
4450 Slog.d(TAG, "New default IME was selected: " + imi.getId());
4451 }
satok723a27e2010-11-11 14:58:11 +09004452 resetSelectedInputMethodAndSubtypeLocked(imi.getId());
Brandon Ballinger6da35a02009-10-21 00:38:13 -07004453 return true;
4454 }
4455
4456 return false;
4457 }
4458
Yohei Yukawa05139322018-12-25 10:34:14 -08004459 static void queryInputMethodServicesInternal(Context context,
4460 @UserIdInt int userId, ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap,
4461 ArrayMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList) {
4462 methodList.clear();
4463 methodMap.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004464
Yohei Yukawaed4952a2016-02-17 07:57:25 -08004465 // Note: We do not specify PackageManager.MATCH_ENCRYPTION_* flags here because the default
4466 // behavior of PackageManager is exactly what we want. It by default picks up appropriate
4467 // services depending on the unlock state for the specified user.
Yohei Yukawa05139322018-12-25 10:34:14 -08004468 final List<ResolveInfo> services = context.getPackageManager().queryIntentServicesAsUser(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004469 new Intent(InputMethod.SERVICE_INTERFACE),
Yohei Yukawa5ec1fce2018-12-17 07:56:14 -08004470 PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS,
Yohei Yukawa05139322018-12-25 10:34:14 -08004471 userId);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004472
Yohei Yukawa05139322018-12-25 10:34:14 -08004473 methodList.ensureCapacity(services.size());
4474 methodMap.ensureCapacity(services.size());
4475
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004476 for (int i = 0; i < services.size(); ++i) {
4477 ResolveInfo ri = services.get(i);
4478 ServiceInfo si = ri.serviceInfo;
Yohei Yukawaddad4b92017-02-02 01:46:13 -08004479 final String imeId = InputMethodInfo.computeId(ri);
4480 if (!android.Manifest.permission.BIND_INPUT_METHOD.equals(si.permission)) {
4481 Slog.w(TAG, "Skipping input method " + imeId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004482 + ": it does not require the permission "
4483 + android.Manifest.permission.BIND_INPUT_METHOD);
4484 continue;
4485 }
4486
Yohei Yukawaddad4b92017-02-02 01:46:13 -08004487 if (DEBUG) Slog.d(TAG, "Checking " + imeId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004488
4489 try {
Yohei Yukawa05139322018-12-25 10:34:14 -08004490 final InputMethodInfo imi = new InputMethodInfo(context, ri,
4491 additionalSubtypeMap.get(imeId));
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08004492 if (imi.isVrOnly()) {
4493 continue; // Skip VR-only IME, which isn't supported for now.
4494 }
Yohei Yukawa05139322018-12-25 10:34:14 -08004495 methodList.add(imi);
4496 methodMap.put(imi.getId(), imi);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004497 if (DEBUG) {
Yohei Yukawa05139322018-12-25 10:34:14 -08004498 Slog.d(TAG, "Found an input method " + imi);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004499 }
Tadashi G. Takaoka3c23d5b2016-09-16 11:41:07 +09004500 } catch (Exception e) {
Yohei Yukawaddad4b92017-02-02 01:46:13 -08004501 Slog.wtf(TAG, "Unable to load input method " + imeId, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004502 }
4503 }
Yohei Yukawa05139322018-12-25 10:34:14 -08004504 }
4505
4506 @GuardedBy("mMethodMap")
4507 void buildInputMethodListLocked(boolean resetDefaultEnabledIme) {
4508 if (DEBUG) {
4509 Slog.d(TAG, "--- re-buildInputMethodList reset = " + resetDefaultEnabledIme
4510 + " \n ------ caller=" + Debug.getCallers(10));
4511 }
4512 if (!mSystemReady) {
4513 Slog.e(TAG, "buildInputMethodListLocked is not allowed until system is ready");
4514 return;
4515 }
4516 mMethodMapUpdateCount++;
4517 mMyPackageMonitor.clearKnownImePackageNamesLocked();
4518
4519 queryInputMethodServicesInternal(mContext, mSettings.getCurrentUserId(),
Yohei Yukawab557d572018-12-29 21:26:26 -08004520 mAdditionalSubtypeMap, mMethodMap, mMethodList);
Brandon Ballinger6da35a02009-10-21 00:38:13 -07004521
Yohei Yukawac4e44912017-02-09 19:30:22 -08004522 // Construct the set of possible IME packages for onPackageChanged() to avoid false
4523 // negatives when the package state remains to be the same but only the component state is
4524 // changed.
4525 {
4526 // Here we intentionally use PackageManager.MATCH_DISABLED_COMPONENTS since the purpose
4527 // of this query is to avoid false negatives. PackageManager.MATCH_ALL could be more
4528 // conservative, but it seems we cannot use it for now (Issue 35176630).
Yohei Yukawa05139322018-12-25 10:34:14 -08004529 final List<ResolveInfo> allInputMethodServices =
4530 mContext.getPackageManager().queryIntentServicesAsUser(
4531 new Intent(InputMethod.SERVICE_INTERFACE),
4532 PackageManager.MATCH_DISABLED_COMPONENTS, mSettings.getCurrentUserId());
Yohei Yukawac4e44912017-02-09 19:30:22 -08004533 final int N = allInputMethodServices.size();
4534 for (int i = 0; i < N; ++i) {
4535 final ServiceInfo si = allInputMethodServices.get(i).serviceInfo;
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08004536 if (android.Manifest.permission.BIND_INPUT_METHOD.equals(si.permission)) {
4537 mMyPackageMonitor.addKnownImePackageNameLocked(si.packageName);
Yohei Yukawac4e44912017-02-09 19:30:22 -08004538 }
Yohei Yukawac4e44912017-02-09 19:30:22 -08004539 }
4540 }
4541
Yohei Yukawa9c372192018-03-20 22:54:56 -07004542 boolean reenableMinimumNonAuxSystemImes = false;
Yohei Yukawa859df052016-02-17 07:56:46 -08004543 // TODO: The following code should find better place to live.
4544 if (!resetDefaultEnabledIme) {
4545 boolean enabledImeFound = false;
Yohei Yukawa9c372192018-03-20 22:54:56 -07004546 boolean enabledNonAuxImeFound = false;
Yohei Yukawa859df052016-02-17 07:56:46 -08004547 final List<InputMethodInfo> enabledImes = mSettings.getEnabledInputMethodListLocked();
4548 final int N = enabledImes.size();
4549 for (int i = 0; i < N; ++i) {
4550 final InputMethodInfo imi = enabledImes.get(i);
4551 if (mMethodList.contains(imi)) {
4552 enabledImeFound = true;
Yohei Yukawa9c372192018-03-20 22:54:56 -07004553 if (!imi.isAuxiliaryIme()) {
4554 enabledNonAuxImeFound = true;
4555 break;
4556 }
Yohei Yukawa859df052016-02-17 07:56:46 -08004557 }
4558 }
4559 if (!enabledImeFound) {
Yohei Yukawad0332832017-02-01 13:59:43 -08004560 if (DEBUG) {
4561 Slog.i(TAG, "All the enabled IMEs are gone. Reset default enabled IMEs.");
4562 }
Yohei Yukawa859df052016-02-17 07:56:46 -08004563 resetDefaultEnabledIme = true;
4564 resetSelectedInputMethodAndSubtypeLocked("");
Yohei Yukawa9c372192018-03-20 22:54:56 -07004565 } else if (!enabledNonAuxImeFound) {
4566 if (DEBUG) {
4567 Slog.i(TAG, "All the enabled non-Aux IMEs are gone. Do partial reset.");
4568 }
4569 reenableMinimumNonAuxSystemImes = true;
Yohei Yukawa859df052016-02-17 07:56:46 -08004570 }
4571 }
4572
Yohei Yukawa9c372192018-03-20 22:54:56 -07004573 if (resetDefaultEnabledIme || reenableMinimumNonAuxSystemImes) {
Satoshi Kataokaf1367b72013-01-25 17:20:12 +09004574 final ArrayList<InputMethodInfo> defaultEnabledIme =
Yohei Yukawa9c372192018-03-20 22:54:56 -07004575 InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList,
4576 reenableMinimumNonAuxSystemImes);
Yohei Yukawa68645a62016-02-17 07:54:20 -08004577 final int N = defaultEnabledIme.size();
4578 for (int i = 0; i < N; ++i) {
Satoshi Kataokaf1367b72013-01-25 17:20:12 +09004579 final InputMethodInfo imi = defaultEnabledIme.get(i);
4580 if (DEBUG) {
4581 Slog.d(TAG, "--- enable ime = " + imi);
4582 }
4583 setInputMethodEnabledLocked(imi.getId(), true);
4584 }
4585 }
4586
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004587 final String defaultImiId = mSettings.getSelectedInputMethod();
satok0a1bcf42012-05-16 19:26:31 +09004588 if (!TextUtils.isEmpty(defaultImiId)) {
Yohei Yukawa94e33302016-02-12 19:37:03 -08004589 if (!mMethodMap.containsKey(defaultImiId)) {
satok0a1bcf42012-05-16 19:26:31 +09004590 Slog.w(TAG, "Default IME is uninstalled. Choose new default IME.");
4591 if (chooseNewDefaultIMELocked()) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07004592 updateInputMethodsFromSettingsLocked(true);
satok0a1bcf42012-05-16 19:26:31 +09004593 }
4594 } else {
4595 // Double check that the default IME is certainly enabled.
4596 setInputMethodEnabledLocked(defaultImiId, true);
Brandon Ballinger6da35a02009-10-21 00:38:13 -07004597 }
4598 }
Yohei Yukawa3d46bab2014-05-30 18:10:18 +09004599 // Here is not the perfect place to reset the switching controller. Ideally
4600 // mSwitchingController and mSettings should be able to share the same state.
4601 // TODO: Make sure that mSwitchingController and mSettings are sharing the
4602 // the same enabled IMEs list.
Yohei Yukawac834a252014-05-21 22:42:32 +09004603 mSwitchingController.resetCircularListLocked(mContext);
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +09004604
4605 // Notify InputMethodListListeners of the new installed InputMethods.
4606 final List<InputMethodInfo> inputMethodList = new ArrayList<>(mMethodList);
4607 mHandler.obtainMessage(MSG_DISPATCH_ON_INPUT_METHOD_LIST_UPDATED,
4608 mSettings.getCurrentUserId(), 0 /* unused */, inputMethodList).sendToTarget();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004609 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004610
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004611 // ----------------------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004612
satok217f5482010-12-15 05:19:19 +09004613 private void showInputMethodAndSubtypeEnabler(String inputMethodId) {
Tadashi G. Takaokaf49688f2011-01-20 17:56:13 +09004614 Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS);
satok47a44912010-10-06 16:03:58 +09004615 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
satok86417ea2010-10-27 14:11:03 +09004616 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
4617 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
satok7fee71f2010-12-17 18:54:26 +09004618 if (!TextUtils.isEmpty(inputMethodId)) {
Tadashi G. Takaoka25480202011-01-20 23:13:02 +09004619 intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, inputMethodId);
satok7fee71f2010-12-17 18:54:26 +09004620 }
Yohei Yukawa41f34272015-12-14 15:41:52 -08004621 final int userId;
4622 synchronized (mMethodMap) {
4623 userId = mSettings.getCurrentUserId();
4624 }
4625 mContext.startActivityAsUser(intent, null, UserHandle.of(userId));
satok217f5482010-12-15 05:19:19 +09004626 }
4627
4628 private void showConfigureInputMethods() {
4629 Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS);
4630 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
4631 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
4632 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
Satoshi Kataoka3ba439d2012-10-05 18:30:13 +09004633 mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
satok47a44912010-10-06 16:03:58 +09004634 }
4635
satok2c93efc2012-04-02 19:33:47 +09004636 private boolean isScreenLocked() {
4637 return mKeyguardManager != null
4638 && mKeyguardManager.isKeyguardLocked() && mKeyguardManager.isKeyguardSecure();
4639 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004640
lumark0b05f9e2018-11-26 15:09:06 +08004641 private void showInputMethodMenu(boolean showAuxSubtypes, int displayId) {
Seigo Nonaka14e13912015-05-06 21:04:13 -07004642 if (DEBUG) Slog.v(TAG, "Show switching menu. showAuxSubtypes=" + showAuxSubtypes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004643
satok2c93efc2012-04-02 19:33:47 +09004644 final boolean isScreenLocked = isScreenLocked();
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004645
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004646 final String lastInputMethodId = mSettings.getSelectedInputMethod();
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004647 int lastInputMethodSubtypeId = mSettings.getSelectedInputMethodSubtypeId(lastInputMethodId);
Joe Onorato8a9b2202010-02-26 18:56:32 -08004648 if (DEBUG) Slog.v(TAG, "Current IME: " + lastInputMethodId);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004649
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004650 synchronized (mMethodMap) {
Yohei Yukawacf3bbff2018-11-20 17:24:20 -08004651 final List<ImeSubtypeListItem> imList =
4652 mSwitchingController.getSortedInputMethodAndSubtypeListLocked(
4653 showAuxSubtypes, isScreenLocked);
4654 if (imList.isEmpty()) {
satok7f35c8c2010-10-07 21:13:11 +09004655 return;
4656 }
4657
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004658 hideInputMethodMenuLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004659
satokc3690562012-01-10 20:14:43 +09004660 if (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004661 final InputMethodSubtype currentSubtype = getCurrentInputMethodSubtypeLocked();
satokc3690562012-01-10 20:14:43 +09004662 if (currentSubtype != null) {
4663 final InputMethodInfo currentImi = mMethodMap.get(mCurMethodId);
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004664 lastInputMethodSubtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
4665 currentImi, currentSubtype.hashCode());
satokc3690562012-01-10 20:14:43 +09004666 }
4667 }
4668
Ken Wakasa761eb372011-03-04 19:06:18 +09004669 final int N = imList.size();
satokab751aa2010-09-14 19:17:36 +09004670 mIms = new InputMethodInfo[N];
4671 mSubtypeIds = new int[N];
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004672 int checkedItem = 0;
4673 for (int i = 0; i < N; ++i) {
Ken Wakasa05dbb652011-08-22 15:22:43 +09004674 final ImeSubtypeListItem item = imList.get(i);
4675 mIms[i] = item.mImi;
4676 mSubtypeIds[i] = item.mSubtypeId;
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004677 if (mIms[i].getId().equals(lastInputMethodId)) {
satokab751aa2010-09-14 19:17:36 +09004678 int subtypeId = mSubtypeIds[i];
4679 if ((subtypeId == NOT_A_SUBTYPE_ID)
4680 || (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID && subtypeId == 0)
4681 || (subtypeId == lastInputMethodSubtypeId)) {
4682 checkedItem = i;
4683 }
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004684 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004685 }
Alan Viverette505e3ab2014-11-24 15:22:11 -08004686
lumark0b05f9e2018-11-26 15:09:06 +08004687 final ActivityThread currentThread = ActivityThread.currentActivityThread();
Andrew Sapperstein8a3b4cb2017-04-28 14:35:31 -07004688 final Context settingsContext = new ContextThemeWrapper(
lumark0b05f9e2018-11-26 15:09:06 +08004689 displayId == DEFAULT_DISPLAY ? currentThread.getSystemUiContext()
4690 : currentThread.createSystemUiContext(displayId),
Alan Viverette505e3ab2014-11-24 15:22:11 -08004691 com.android.internal.R.style.Theme_DeviceDefault_Settings);
4692
4693 mDialogBuilder = new AlertDialog.Builder(settingsContext);
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004694 mDialogBuilder.setOnCancelListener(new OnCancelListener() {
4695 @Override
4696 public void onCancel(DialogInterface dialog) {
4697 hideInputMethodMenu();
4698 }
4699 });
Alan Viverette505e3ab2014-11-24 15:22:11 -08004700
4701 final Context dialogContext = mDialogBuilder.getContext();
4702 final TypedArray a = dialogContext.obtainStyledAttributes(null,
4703 com.android.internal.R.styleable.DialogPreference,
4704 com.android.internal.R.attr.alertDialogStyle, 0);
4705 final Drawable dialogIcon = a.getDrawable(
4706 com.android.internal.R.styleable.DialogPreference_dialogIcon);
4707 a.recycle();
4708
4709 mDialogBuilder.setIcon(dialogIcon);
4710
Yohei Yukawad34e1482016-02-11 08:03:52 -08004711 final LayoutInflater inflater = dialogContext.getSystemService(LayoutInflater.class);
satok01038492012-04-09 21:08:27 +09004712 final View tv = inflater.inflate(
4713 com.android.internal.R.layout.input_method_switch_dialog_title, null);
4714 mDialogBuilder.setCustomTitle(tv);
4715
4716 // Setup layout for a toggle switch of the hardware keyboard
4717 mSwitchingDialogTitleView = tv;
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004718 mSwitchingDialogTitleView
4719 .findViewById(com.android.internal.R.id.hard_keyboard_section)
Seigo Nonaka7309b122015-08-17 18:34:13 -07004720 .setVisibility(mWindowManagerInternal.isHardKeyboardAvailable()
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004721 ? View.VISIBLE : View.GONE);
Alan Viverette505e3ab2014-11-24 15:22:11 -08004722 final Switch hardKeySwitch = (Switch) mSwitchingDialogTitleView.findViewById(
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004723 com.android.internal.R.id.hard_keyboard_switch);
Michael Wright7b5a96b2014-08-09 19:28:42 -07004724 hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004725 hardKeySwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
4726 @Override
4727 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07004728 mSettings.setShowImeWithHardKeyboard(isChecked);
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004729 // Ensure that the input method dialog is dismissed when changing
4730 // the hardware keyboard state.
4731 hideInputMethodMenu();
4732 }
4733 });
4734
Alan Viverette505e3ab2014-11-24 15:22:11 -08004735 final ImeSubtypeListAdapter adapter = new ImeSubtypeListAdapter(dialogContext,
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004736 com.android.internal.R.layout.input_method_switch_item, imList, checkedItem);
4737 final OnClickListener choiceListener = new OnClickListener() {
4738 @Override
4739 public void onClick(final DialogInterface dialog, final int which) {
4740 synchronized (mMethodMap) {
4741 if (mIms == null || mIms.length <= which || mSubtypeIds == null
4742 || mSubtypeIds.length <= which) {
4743 return;
satok01038492012-04-09 21:08:27 +09004744 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004745 final InputMethodInfo im = mIms[which];
4746 int subtypeId = mSubtypeIds[which];
4747 adapter.mCheckedItem = which;
4748 adapter.notifyDataSetChanged();
4749 hideInputMethodMenu();
4750 if (im != null) {
4751 if (subtypeId < 0 || subtypeId >= im.getSubtypeCount()) {
4752 subtypeId = NOT_A_SUBTYPE_ID;
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08004753 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004754 setInputMethodLocked(im.getId(), subtypeId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004755 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004756 }
4757 }
4758 };
4759 mDialogBuilder.setSingleChoiceItems(adapter, checkedItem, choiceListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004760
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004761 mSwitchingDialog = mDialogBuilder.create();
Dianne Hackborne3a7f622011-03-03 21:48:24 -08004762 mSwitchingDialog.setCanceledOnTouchOutside(true);
Wale Ogunwale3a931692016-11-02 16:49:48 -07004763 final Window w = mSwitchingDialog.getWindow();
Yohei Yukawa6e875592019-01-28 00:49:30 -08004764 final LayoutParams attrs = w.getAttributes();
4765 w.setType(LayoutParams.TYPE_INPUT_METHOD_DIALOG);
Wale Ogunwale3a931692016-11-02 16:49:48 -07004766 // Use an alternate token for the dialog for that window manager can group the token
4767 // with other IME windows based on type vs. grouping based on whichever token happens
4768 // to get selected by the system later on.
4769 attrs.token = mSwitchingDialogToken;
Roshan Piusa3f89c62019-10-11 08:50:53 -07004770 attrs.privateFlags |= LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
Wale Ogunwale3a931692016-11-02 16:49:48 -07004771 attrs.setTitle("Select input method");
4772 w.setAttributes(attrs);
Yohei Yukawa849443c2019-01-21 09:02:25 -08004773 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004774 mSwitchingDialog.show();
4775 }
4776 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004777
Ken Wakasa05dbb652011-08-22 15:22:43 +09004778 private static class ImeSubtypeListAdapter extends ArrayAdapter<ImeSubtypeListItem> {
4779 private final LayoutInflater mInflater;
4780 private final int mTextViewResourceId;
4781 private final List<ImeSubtypeListItem> mItemsList;
Satoshi Kataokad2142962012-11-12 18:43:06 +09004782 public int mCheckedItem;
Ken Wakasa05dbb652011-08-22 15:22:43 +09004783 public ImeSubtypeListAdapter(Context context, int textViewResourceId,
4784 List<ImeSubtypeListItem> itemsList, int checkedItem) {
4785 super(context, textViewResourceId, itemsList);
Alan Viverette505e3ab2014-11-24 15:22:11 -08004786
Ken Wakasa05dbb652011-08-22 15:22:43 +09004787 mTextViewResourceId = textViewResourceId;
4788 mItemsList = itemsList;
4789 mCheckedItem = checkedItem;
Yohei Yukawad34e1482016-02-11 08:03:52 -08004790 mInflater = context.getSystemService(LayoutInflater.class);
Ken Wakasa05dbb652011-08-22 15:22:43 +09004791 }
4792
4793 @Override
4794 public View getView(int position, View convertView, ViewGroup parent) {
4795 final View view = convertView != null ? convertView
4796 : mInflater.inflate(mTextViewResourceId, null);
4797 if (position < 0 || position >= mItemsList.size()) return view;
4798 final ImeSubtypeListItem item = mItemsList.get(position);
4799 final CharSequence imeName = item.mImeName;
4800 final CharSequence subtypeName = item.mSubtypeName;
4801 final TextView firstTextView = (TextView)view.findViewById(android.R.id.text1);
4802 final TextView secondTextView = (TextView)view.findViewById(android.R.id.text2);
4803 if (TextUtils.isEmpty(subtypeName)) {
4804 firstTextView.setText(imeName);
4805 secondTextView.setVisibility(View.GONE);
4806 } else {
4807 firstTextView.setText(subtypeName);
4808 secondTextView.setText(imeName);
4809 secondTextView.setVisibility(View.VISIBLE);
4810 }
4811 final RadioButton radioButton =
4812 (RadioButton)view.findViewById(com.android.internal.R.id.radio);
4813 radioButton.setChecked(position == mCheckedItem);
4814 return view;
4815 }
4816 }
4817
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004818 void hideInputMethodMenu() {
The Android Open Source Project10592532009-03-18 17:39:46 -07004819 synchronized (mMethodMap) {
4820 hideInputMethodMenuLocked();
4821 }
4822 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004823
The Android Open Source Project10592532009-03-18 17:39:46 -07004824 void hideInputMethodMenuLocked() {
Joe Onorato8a9b2202010-02-26 18:56:32 -08004825 if (DEBUG) Slog.v(TAG, "Hide switching menu");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004826
The Android Open Source Project10592532009-03-18 17:39:46 -07004827 if (mSwitchingDialog != null) {
4828 mSwitchingDialog.dismiss();
4829 mSwitchingDialog = null;
Yohei Yukawa1fc7a1d2018-04-18 17:31:27 -07004830 mSwitchingDialogTitleView = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004831 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004832
Yohei Yukawa849443c2019-01-21 09:02:25 -08004833 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
The Android Open Source Project10592532009-03-18 17:39:46 -07004834 mDialogBuilder = null;
The Android Open Source Project10592532009-03-18 17:39:46 -07004835 mIms = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004836 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004837
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004838 // ----------------------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004839
Yohei Yukawa3d3abd22019-04-09 23:20:12 -07004840 /**
4841 * Enable or disable the given IME by updating {@link Settings.Secure#ENABLED_INPUT_METHODS}.
4842 *
4843 * @param id ID of the IME is to be manipulated. It is OK to pass IME ID that is currently not
4844 * recognized by the system.
4845 * @param enabled {@code true} if {@code id} needs to be enabled.
4846 * @return {@code true} if the IME was previously enabled. {@code false} otherwise.
4847 */
4848 private boolean setInputMethodEnabledLocked(String id, boolean enabled) {
satokd87c2592010-09-29 11:52:06 +09004849 List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings
4850 .getEnabledInputMethodsAndSubtypeListLocked();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004851
satokd87c2592010-09-29 11:52:06 +09004852 if (enabled) {
4853 for (Pair<String, ArrayList<String>> pair: enabledInputMethodsList) {
4854 if (pair.first.equals(id)) {
4855 // We are enabling this input method, but it is already enabled.
4856 // Nothing to do. The previous state was enabled.
4857 return true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004858 }
4859 }
satokd87c2592010-09-29 11:52:06 +09004860 mSettings.appendAndPutEnabledInputMethodLocked(id, false);
4861 // Previous state was disabled.
4862 return false;
4863 } else {
4864 StringBuilder builder = new StringBuilder();
4865 if (mSettings.buildAndPutEnabledInputMethodsStrRemovingIdLocked(
4866 builder, enabledInputMethodsList, id)) {
4867 // Disabled input method is currently selected, switch to another one.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004868 final String selId = mSettings.getSelectedInputMethod();
satok03eb319a2010-11-11 18:17:42 +09004869 if (id.equals(selId) && !chooseNewDefaultIMELocked()) {
4870 Slog.i(TAG, "Can't find new IME, unsetting the current input method.");
4871 resetSelectedInputMethodAndSubtypeLocked("");
satokd87c2592010-09-29 11:52:06 +09004872 }
4873 // Previous state was enabled.
4874 return true;
4875 } else {
4876 // We are disabling the input method but it is already disabled.
4877 // Nothing to do. The previous state was disabled.
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004878 return false;
4879 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004880 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004881 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08004882
satok723a27e2010-11-11 14:58:11 +09004883 private void setSelectedInputMethodAndSubtypeLocked(InputMethodInfo imi, int subtypeId,
4884 boolean setSubtypeOnly) {
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08004885 mSettings.saveCurrentInputMethodAndSubtypeToHistory(mCurMethodId, mCurrentSubtype);
Tarandeep Singh89a6c482017-11-21 14:26:11 -08004886
satok723a27e2010-11-11 14:58:11 +09004887 // Set Subtype here
4888 if (imi == null || subtypeId < 0) {
4889 mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
Tadashi G. Takaoka0ba75bb2010-11-09 12:19:32 -08004890 mCurrentSubtype = null;
satok723a27e2010-11-11 14:58:11 +09004891 } else {
Ken Wakasa586f0512011-01-20 22:31:01 +09004892 if (subtypeId < imi.getSubtypeCount()) {
4893 InputMethodSubtype subtype = imi.getSubtypeAt(subtypeId);
4894 mSettings.putSelectedSubtype(subtype.hashCode());
4895 mCurrentSubtype = subtype;
satok723a27e2010-11-11 14:58:11 +09004896 } else {
4897 mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
satokd81e9502012-05-21 12:58:45 +09004898 // If the subtype is not specified, choose the most applicable one
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004899 mCurrentSubtype = getCurrentInputMethodSubtypeLocked();
satok723a27e2010-11-11 14:58:11 +09004900 }
satokab751aa2010-09-14 19:17:36 +09004901 }
satok723a27e2010-11-11 14:58:11 +09004902
Yohei Yukawa68645a62016-02-17 07:54:20 -08004903 if (!setSubtypeOnly) {
satok723a27e2010-11-11 14:58:11 +09004904 // Set InputMethod here
4905 mSettings.putSelectedInputMethod(imi != null ? imi.getId() : "");
4906 }
4907 }
4908
4909 private void resetSelectedInputMethodAndSubtypeLocked(String newDefaultIme) {
4910 InputMethodInfo imi = mMethodMap.get(newDefaultIme);
4911 int lastSubtypeId = NOT_A_SUBTYPE_ID;
4912 // newDefaultIme is empty when there is no candidate for the selected IME.
4913 if (imi != null && !TextUtils.isEmpty(newDefaultIme)) {
4914 String subtypeHashCode = mSettings.getLastSubtypeForInputMethodLocked(newDefaultIme);
4915 if (subtypeHashCode != null) {
4916 try {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004917 lastSubtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
Narayan Kamatha09b4d22016-04-15 18:32:45 +01004918 imi, Integer.parseInt(subtypeHashCode));
satok723a27e2010-11-11 14:58:11 +09004919 } catch (NumberFormatException e) {
4920 Slog.w(TAG, "HashCode for subtype looks broken: " + subtypeHashCode, e);
4921 }
4922 }
4923 }
4924 setSelectedInputMethodAndSubtypeLocked(imi, lastSubtypeId, false);
satokab751aa2010-09-14 19:17:36 +09004925 }
4926
satokab751aa2010-09-14 19:17:36 +09004927 /**
4928 * @return Return the current subtype of this input method.
4929 */
satok42c5a162011-05-26 16:46:14 +09004930 @Override
satokab751aa2010-09-14 19:17:36 +09004931 public InputMethodSubtype getCurrentInputMethodSubtype() {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004932 synchronized (mMethodMap) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08004933 // TODO: Make this work even for non-current users?
Yohei Yukawa46d74762019-01-22 10:17:22 -08004934 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08004935 return null;
4936 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004937 return getCurrentInputMethodSubtypeLocked();
4938 }
4939 }
4940
4941 private InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
satokfdf419e2012-05-08 16:52:08 +09004942 if (mCurMethodId == null) {
4943 return null;
4944 }
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004945 final boolean subtypeIsSelected = mSettings.isSubtypeSelected();
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004946 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
4947 if (imi == null || imi.getSubtypeCount() == 0) {
4948 return null;
satok4e4569d2010-11-19 18:45:53 +09004949 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004950 if (!subtypeIsSelected || mCurrentSubtype == null
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004951 || !InputMethodUtils.isValidSubtypeId(imi, mCurrentSubtype.hashCode())) {
4952 int subtypeId = mSettings.getSelectedInputMethodSubtypeId(mCurMethodId);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004953 if (subtypeId == NOT_A_SUBTYPE_ID) {
4954 // If there are no selected subtypes, the framework will try to find
4955 // the most applicable subtype from explicitly or implicitly enabled
4956 // subtypes.
4957 List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypes =
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004958 mSettings.getEnabledInputMethodSubtypeListLocked(mContext, imi, true);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004959 // If there is only one explicitly or implicitly enabled subtype,
4960 // just returns it.
4961 if (explicitlyOrImplicitlyEnabledSubtypes.size() == 1) {
4962 mCurrentSubtype = explicitlyOrImplicitlyEnabledSubtypes.get(0);
4963 } else if (explicitlyOrImplicitlyEnabledSubtypes.size() > 1) {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004964 mCurrentSubtype = InputMethodUtils.findLastResortApplicableSubtypeLocked(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004965 mRes, explicitlyOrImplicitlyEnabledSubtypes,
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004966 InputMethodUtils.SUBTYPE_MODE_KEYBOARD, null, true);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004967 if (mCurrentSubtype == null) {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004968 mCurrentSubtype = InputMethodUtils.findLastResortApplicableSubtypeLocked(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004969 mRes, explicitlyOrImplicitlyEnabledSubtypes, null, null,
4970 true);
satok4e4569d2010-11-19 18:45:53 +09004971 }
satok3ef8b292010-11-23 06:06:29 +09004972 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004973 } else {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004974 mCurrentSubtype = InputMethodUtils.getSubtypes(imi).get(subtypeId);
satok8fbb1e82010-11-02 23:15:58 +09004975 }
4976 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004977 return mCurrentSubtype;
satokab751aa2010-09-14 19:17:36 +09004978 }
4979
Yohei Yukawaa878b952019-01-10 19:36:24 -08004980 private List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
4981 synchronized (mMethodMap) {
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08004982 return getInputMethodListLocked(userId);
Yohei Yukawaa878b952019-01-10 19:36:24 -08004983 }
4984 }
4985
4986 private List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
4987 synchronized (mMethodMap) {
4988 return getEnabledInputMethodListLocked(userId);
4989 }
4990 }
4991
Feng Cao16b2de52020-01-09 17:27:27 -08004992 private void onCreateInlineSuggestionsRequest(@UserIdInt int userId,
Feng Cao36960ee2020-02-18 18:23:30 -08004993 InlineSuggestionsRequestInfo requestInfo,
Feng Cao16b2de52020-01-09 17:27:27 -08004994 IInlineSuggestionsRequestCallback callback) {
Adam Hebc67f2e2019-11-13 14:34:56 -08004995 synchronized (mMethodMap) {
Feng Cao36960ee2020-02-18 18:23:30 -08004996 onCreateInlineSuggestionsRequestLocked(userId, requestInfo, callback);
Adam Hebc67f2e2019-11-13 14:34:56 -08004997 }
4998 }
4999
mincheli850892b2019-12-05 19:47:59 +08005000 private boolean switchToInputMethod(String imeId, @UserIdInt int userId) {
5001 synchronized (mMethodMap) {
5002 if (userId == mSettings.getCurrentUserId()) {
5003 if (!mMethodMap.containsKey(imeId)
5004 || !mSettings.getEnabledInputMethodListLocked()
5005 .contains(mMethodMap.get(imeId))) {
5006 return false; // IME is not is found or not enabled.
5007 }
5008 setInputMethodLocked(imeId, NOT_A_SUBTYPE_ID);
5009 return true;
5010 }
5011 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
5012 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
5013 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
5014 new ArrayMap<>();
5015 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
5016 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
5017 methodMap, methodList);
5018 final InputMethodSettings settings = new InputMethodSettings(
5019 mContext.getResources(), mContext.getContentResolver(), methodMap,
5020 userId, false);
5021 if (!methodMap.containsKey(imeId)
5022 || !settings.getEnabledInputMethodListLocked()
5023 .contains(methodMap.get(imeId))) {
5024 return false; // IME is not is found or not enabled.
5025 }
5026 settings.putSelectedInputMethod(imeId);
5027 settings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
5028 return true;
5029 }
5030 }
5031
lpeter133fce02020-03-05 20:32:16 +08005032 private boolean transferTouchFocusToImeWindow(@NonNull IBinder sourceInputToken,
5033 int displayId) {
5034 //TODO(b/150843766): Check if Input Token is valid.
5035 final IBinder curHostInputToken;
5036 synchronized (mMethodMap) {
5037 if (displayId != mCurTokenDisplayId || mCurHostInputToken == null) {
5038 return false;
5039 }
5040 curHostInputToken = mCurHostInputToken;
5041 }
5042 return mInputManagerInternal.transferTouchFocus(sourceInputToken, curHostInputToken);
5043 }
5044
Adrian Roosc22eec92020-06-12 18:48:10 +02005045 private void reportImeControl(@Nullable IBinder windowToken) {
5046 synchronized (mMethodMap) {
5047 if (mCurFocusedWindow != windowToken) {
5048 // mCurPerceptible was set by the focused window, but it is no longer in control,
5049 // so we reset mCurPerceptible.
5050 mCurPerceptible = true;
5051 }
5052 }
5053 }
5054
Yohei Yukawae24ed792018-08-28 19:10:32 -07005055 private static final class LocalServiceImpl extends InputMethodManagerInternal {
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07005056 @NonNull
Yohei Yukawafffc0e52018-09-04 13:24:00 -07005057 private final InputMethodManagerService mService;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07005058
Yohei Yukawafffc0e52018-09-04 13:24:00 -07005059 LocalServiceImpl(@NonNull InputMethodManagerService service) {
5060 mService = service;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07005061 }
5062
5063 @Override
Ming-Shin Lu2c6e80b2020-05-13 00:12:26 +08005064 public void setInteractive(boolean interactive) {
5065 // Do everything in handler so as not to block the caller.
5066 mService.mHandler.obtainMessage(MSG_SET_INTERACTIVE, interactive ? 1 : 0, 0)
5067 .sendToTarget();
5068 }
5069
5070 @Override
lumarkd85e1582019-12-29 20:20:41 +08005071 public void hideCurrentInputMethod(@SoftInputShowHideReason int reason) {
Yohei Yukawaf16abb72018-09-05 11:28:42 -07005072 mService.mHandler.removeMessages(MSG_HIDE_CURRENT_INPUT_METHOD);
lumarkd85e1582019-12-29 20:20:41 +08005073 mService.mHandler.obtainMessage(MSG_HIDE_CURRENT_INPUT_METHOD, reason).sendToTarget();
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -07005074 }
Tarandeep Singh89a6c482017-11-21 14:26:11 -08005075
5076 @Override
Yohei Yukawaa878b952019-01-10 19:36:24 -08005077 public List<InputMethodInfo> getInputMethodListAsUser(int userId) {
5078 return mService.getInputMethodListAsUser(userId);
5079 }
5080
5081 @Override
5082 public List<InputMethodInfo> getEnabledInputMethodListAsUser(int userId) {
5083 return mService.getEnabledInputMethodListAsUser(userId);
5084 }
Adam Hebc67f2e2019-11-13 14:34:56 -08005085
5086 @Override
Feng Cao36960ee2020-02-18 18:23:30 -08005087 public void onCreateInlineSuggestionsRequest(int userId,
5088 InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback cb) {
5089 mService.onCreateInlineSuggestionsRequest(userId, requestInfo, cb);
Adam Hebc67f2e2019-11-13 14:34:56 -08005090 }
mincheli850892b2019-12-05 19:47:59 +08005091
5092 @Override
5093 public boolean switchToInputMethod(String imeId, int userId) {
5094 return mService.switchToInputMethod(imeId, userId);
5095 }
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +09005096
5097 @Override
5098 public void registerInputMethodListListener(InputMethodListListener listener) {
5099 mService.mInputMethodListListeners.addIfAbsent(listener);
5100 }
lpeter133fce02020-03-05 20:32:16 +08005101
5102 @Override
5103 public boolean transferTouchFocusToImeWindow(@NonNull IBinder sourceInputToken,
5104 int displayId) {
5105 return mService.transferTouchFocusToImeWindow(sourceInputToken, displayId);
5106 }
Adrian Roosc22eec92020-06-12 18:48:10 +02005107
5108 @Override
5109 public void reportImeControl(@Nullable IBinder windowToken) {
5110 mService.reportImeControl(windowToken);
5111 }
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07005112 }
5113
Yohei Yukawac54c1172018-09-06 11:39:50 -07005114 @BinderThread
5115 private IInputContentUriToken createInputContentUriToken(@Nullable IBinder token,
Yohei Yukawa25e08132016-06-22 16:31:41 -07005116 @Nullable Uri contentUri, @Nullable String packageName) {
Yohei Yukawa25e08132016-06-22 16:31:41 -07005117 if (token == null) {
5118 throw new NullPointerException("token");
5119 }
5120 if (packageName == null) {
5121 throw new NullPointerException("packageName");
5122 }
5123 if (contentUri == null) {
5124 throw new NullPointerException("contentUri");
5125 }
5126 final String contentUriScheme = contentUri.getScheme();
5127 if (!"content".equals(contentUriScheme)) {
5128 throw new InvalidParameterException("contentUri must have content scheme");
5129 }
5130
5131 synchronized (mMethodMap) {
5132 final int uid = Binder.getCallingUid();
5133 if (mCurMethodId == null) {
5134 return null;
5135 }
5136 if (mCurToken != token) {
5137 Slog.e(TAG, "Ignoring createInputContentUriToken mCurToken=" + mCurToken
5138 + " token=" + token);
5139 return null;
5140 }
5141 // We cannot simply distinguish a bad IME that reports an arbitrary package name from
5142 // an unfortunate IME whose internal state is already obsolete due to the asynchronous
5143 // nature of our system. Let's compare it with our internal record.
5144 if (!TextUtils.equals(mCurAttribute.packageName, packageName)) {
5145 Slog.e(TAG, "Ignoring createInputContentUriToken mCurAttribute.packageName="
5146 + mCurAttribute.packageName + " packageName=" + packageName);
5147 return null;
5148 }
Yohei Yukawa3933a6e2016-11-10 00:47:48 -08005149 // This user ID can never bee spoofed.
Yohei Yukawa25e08132016-06-22 16:31:41 -07005150 final int imeUserId = UserHandle.getUserId(uid);
Yohei Yukawa3933a6e2016-11-10 00:47:48 -08005151 // This user ID can never bee spoofed.
Yohei Yukawa25e08132016-06-22 16:31:41 -07005152 final int appUserId = UserHandle.getUserId(mCurClient.uid);
Yohei Yukawa3933a6e2016-11-10 00:47:48 -08005153 // This user ID may be invalid if "contentUri" embedded an invalid user ID.
5154 final int contentUriOwnerUserId = ContentProvider.getUserIdFromUri(contentUri,
5155 imeUserId);
5156 final Uri contentUriWithoutUserId = ContentProvider.getUriWithoutUserId(contentUri);
5157 // Note: InputContentUriTokenHandler.take() checks whether the IME (specified by "uid")
5158 // actually has the right to grant a read permission for "contentUriWithoutUserId" that
5159 // is claimed to belong to "contentUriOwnerUserId". For example, specifying random
5160 // content URI and/or contentUriOwnerUserId just results in a SecurityException thrown
5161 // from InputContentUriTokenHandler.take() and can never be allowed beyond what is
5162 // actually allowed to "uid", which is guaranteed to be the IME's one.
5163 return new InputContentUriTokenHandler(contentUriWithoutUserId, uid,
5164 packageName, contentUriOwnerUserId, appUserId);
Yohei Yukawa25e08132016-06-22 16:31:41 -07005165 }
5166 }
5167
Yohei Yukawac54c1172018-09-06 11:39:50 -07005168 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08005169 private void reportFullscreenMode(@NonNull IBinder token, boolean fullscreen) {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08005170 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08005171 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08005172 return;
5173 }
5174 if (mCurClient != null && mCurClient.client != null) {
5175 mInFullscreenMode = fullscreen;
5176 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
5177 MSG_REPORT_FULLSCREEN_MODE, fullscreen ? 1 : 0, mCurClient));
5178 }
5179 }
5180 }
5181
5182 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005183 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06005184 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005185
5186 IInputMethod method;
5187 ClientState client;
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08005188 ClientState focusedWindowClient;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005190 final Printer p = new PrintWriterPrinter(pw);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005191
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005192 synchronized (mMethodMap) {
5193 p.println("Current Input Method Manager state:");
5194 int N = mMethodList.size();
Yohei Yukawa5ec1fce2018-12-17 07:56:14 -08005195 p.println(" Input Methods: mMethodMapUpdateCount=" + mMethodMapUpdateCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005196 for (int i=0; i<N; i++) {
5197 InputMethodInfo info = mMethodList.get(i);
5198 p.println(" InputMethod #" + i + ":");
5199 info.dump(p, " ");
5200 }
5201 p.println(" Clients:");
Yohei Yukawaac9311e2018-11-20 19:25:23 -08005202 final int numClients = mClients.size();
5203 for (int i = 0; i < numClients; ++i) {
5204 final ClientState ci = mClients.valueAt(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005205 p.println(" Client " + ci + ":");
5206 p.println(" client=" + ci.client);
5207 p.println(" inputContext=" + ci.inputContext);
5208 p.println(" sessionRequested=" + ci.sessionRequested);
5209 p.println(" curSession=" + ci.curSession);
5210 }
The Android Open Source Project10592532009-03-18 17:39:46 -07005211 p.println(" mCurMethodId=" + mCurMethodId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005212 client = mCurClient;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07005213 p.println(" mCurClient=" + client + " mCurSeq=" + mCurSeq);
Adrian Roosc22eec92020-06-12 18:48:10 +02005214 p.println(" mCurPerceptible=" + mCurPerceptible);
Yohei Yukawa22a89232017-02-12 16:38:59 -08005215 p.println(" mCurFocusedWindow=" + mCurFocusedWindow
5216 + " softInputMode=" +
Yohei Yukawaa468d702018-10-21 11:42:34 -07005217 InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode)
Yohei Yukawa22a89232017-02-12 16:38:59 -08005218 + " client=" + mCurFocusedWindowClient);
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08005219 focusedWindowClient = mCurFocusedWindowClient;
Yohei Yukawad3ef8422018-06-07 16:28:07 -07005220 p.println(" mCurId=" + mCurId + " mHaveConnection=" + mHaveConnection
5221 + " mBoundToMethod=" + mBoundToMethod + " mVisibleBound=" + mVisibleBound);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005222 p.println(" mCurToken=" + mCurToken);
lumark90120a82018-08-15 00:33:03 +08005223 p.println(" mCurTokenDisplayId=" + mCurTokenDisplayId);
lpeter133fce02020-03-05 20:32:16 +08005224 p.println(" mCurHostInputToken=" + mCurHostInputToken);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005225 p.println(" mCurIntent=" + mCurIntent);
5226 method = mCurMethod;
5227 p.println(" mCurMethod=" + mCurMethod);
5228 p.println(" mEnabledSession=" + mEnabledSession);
5229 p.println(" mShowRequested=" + mShowRequested
5230 + " mShowExplicitlyRequested=" + mShowExplicitlyRequested
5231 + " mShowForced=" + mShowForced
5232 + " mInputShown=" + mInputShown);
Yohei Yukawa2bc66172017-02-08 11:13:25 -08005233 p.println(" mInFullscreenMode=" + mInFullscreenMode);
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07005234 p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
Yohei Yukawa81482972015-06-04 00:58:59 -07005235 p.println(" mSettingsObserver=" + mSettingsObserver);
Yohei Yukawad7248862015-06-03 23:56:12 -07005236 p.println(" mSwitchingController:");
5237 mSwitchingController.dump(p);
Yohei Yukawa68645a62016-02-17 07:54:20 -08005238 p.println(" mSettings:");
5239 mSettings.dumpLocked(p, " ");
Yohei Yukawa357b2f62017-02-14 09:40:03 -08005240
5241 p.println(" mStartInputHistory:");
5242 mStartInputHistory.dump(pw, " ");
lumarkd85e1582019-12-29 20:20:41 +08005243
5244 p.println(" mSoftInputShowHideHistory:");
5245 mSoftInputShowHideHistory.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005246 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005247
Jeff Brownb88102f2010-09-08 11:49:43 -07005248 p.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005249 if (client != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005250 pw.flush();
5251 try {
Jeff Sharkey850c83e2016-11-09 12:25:44 -07005252 TransferPipe.dumpAsync(client.client.asBinder(), fd, args);
5253 } catch (IOException | RemoteException e) {
5254 p.println("Failed to dump input method client: " + e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005255 }
Jeff Brownb88102f2010-09-08 11:49:43 -07005256 } else {
5257 p.println("No input method client.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005258 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005259
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08005260 if (focusedWindowClient != null && client != focusedWindowClient) {
5261 p.println(" ");
5262 p.println("Warning: Current input method client doesn't match the last focused. "
5263 + "window.");
5264 p.println("Dumping input method client in the last focused window just in case.");
5265 p.println(" ");
5266 pw.flush();
5267 try {
Jeff Sharkey850c83e2016-11-09 12:25:44 -07005268 TransferPipe.dumpAsync(focusedWindowClient.client.asBinder(), fd, args);
5269 } catch (IOException | RemoteException e) {
5270 p.println("Failed to dump input method client in focused window: " + e);
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08005271 }
5272 }
5273
Jeff Brownb88102f2010-09-08 11:49:43 -07005274 p.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005275 if (method != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005276 pw.flush();
5277 try {
Jeff Sharkey850c83e2016-11-09 12:25:44 -07005278 TransferPipe.dumpAsync(method.asBinder(), fd, args);
5279 } catch (IOException | RemoteException e) {
5280 p.println("Failed to dump input method service: " + e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005281 }
Jeff Brownb88102f2010-09-08 11:49:43 -07005282 } else {
5283 p.println("No input method service.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005284 }
5285 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005286
5287 @BinderThread
5288 @Override
5289 public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
5290 @Nullable FileDescriptor err,
5291 @NonNull String[] args, @Nullable ShellCallback callback,
5292 @NonNull ResultReceiver resultReceiver) throws RemoteException {
Yohei Yukawab8d240f2018-12-26 10:03:11 -08005293 final int callingUid = Binder.getCallingUid();
5294 // Reject any incoming calls from non-shell users, including ones from the system user.
5295 if (callingUid != Process.ROOT_UID && callingUid != Process.SHELL_UID) {
5296 // Note that Binder#onTransact() will automatically close "in", "out", and "err" when
5297 // returned from this method, hence there is no need to close those FDs.
5298 // "resultReceiver" is the only thing that needs to be taken care of here.
5299 if (resultReceiver != null) {
5300 resultReceiver.send(ShellCommandResult.FAILURE, null);
5301 }
5302 final String errorMsg = "InputMethodManagerService does not support shell commands from"
5303 + " non-shell users. callingUid=" + callingUid
5304 + " args=" + Arrays.toString(args);
5305 if (Process.isCoreUid(callingUid)) {
5306 // Let's not crash the calling process if the caller is one of core components.
5307 Slog.e(TAG, errorMsg);
5308 return;
5309 }
5310 throw new SecurityException(errorMsg);
5311 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005312 new ShellCommandImpl(this).exec(
5313 this, in, out, err, args, callback, resultReceiver);
5314 }
5315
5316 private static final class ShellCommandImpl extends ShellCommand {
5317 @NonNull
5318 final InputMethodManagerService mService;
5319
5320 ShellCommandImpl(InputMethodManagerService service) {
5321 mService = service;
5322 }
5323
Yohei Yukawadb25df72018-12-27 08:40:41 -08005324 @RequiresPermission(allOf = {
Yohei Yukawa8a2b96b2018-12-28 17:23:29 -08005325 Manifest.permission.DUMP,
5326 Manifest.permission.INTERACT_ACROSS_USERS_FULL,
Yohei Yukawadb25df72018-12-27 08:40:41 -08005327 Manifest.permission.WRITE_SECURE_SETTINGS,
Yohei Yukawa8a2b96b2018-12-28 17:23:29 -08005328 })
Yohei Yukawa926488d2017-12-11 17:24:55 -08005329 @BinderThread
5330 @ShellCommandResult
5331 @Override
5332 public int onCommand(@Nullable String cmd) {
Yohei Yukawadb25df72018-12-27 08:40:41 -08005333 // For shell command, require all the permissions here in favor of code simplicity.
Yohei Yukawa8a2b96b2018-12-28 17:23:29 -08005334 Arrays.asList(
5335 Manifest.permission.DUMP,
5336 Manifest.permission.INTERACT_ACROSS_USERS_FULL,
5337 Manifest.permission.WRITE_SECURE_SETTINGS
5338 ).forEach(permission -> mService.mContext.enforceCallingPermission(permission, null));
Yohei Yukawadb25df72018-12-27 08:40:41 -08005339
5340 final long identity = Binder.clearCallingIdentity();
5341 try {
5342 return onCommandWithSystemIdentity(cmd);
5343 } finally {
5344 Binder.restoreCallingIdentity(identity);
5345 }
5346 }
5347
5348 @BinderThread
5349 @ShellCommandResult
5350 private int onCommandWithSystemIdentity(@Nullable String cmd) {
Yohei Yukawadfdab732018-02-21 07:16:30 +09005351 if ("refresh_debug_properties".equals(cmd)) {
5352 return refreshDebugProperties();
5353 }
5354
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08005355 if ("get-last-switch-user-id".equals(cmd)) {
5356 return mService.getLastSwitchUserId(this);
5357 }
5358
Yohei Yukawacac97722017-12-15 16:52:05 -08005359 // For existing "adb shell ime <command>".
5360 if ("ime".equals(cmd)) {
5361 final String imeCommand = getNextArg();
5362 if (imeCommand == null || "help".equals(imeCommand) || "-h".equals(imeCommand)) {
5363 onImeCommandHelp();
5364 return ShellCommandResult.SUCCESS;
5365 }
5366 switch (imeCommand) {
5367 case "list":
5368 return mService.handleShellCommandListInputMethods(this);
5369 case "enable":
5370 return mService.handleShellCommandEnableDisableInputMethod(this, true);
5371 case "disable":
5372 return mService.handleShellCommandEnableDisableInputMethod(this, false);
5373 case "set":
5374 return mService.handleShellCommandSetInputMethod(this);
5375 case "reset":
5376 return mService.handleShellCommandResetInputMethod(this);
5377 default:
5378 getOutPrintWriter().println("Unknown command: " + imeCommand);
5379 return ShellCommandResult.FAILURE;
5380 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005381 }
Yohei Yukawacac97722017-12-15 16:52:05 -08005382
5383 return handleDefaultCommands(cmd);
Yohei Yukawa926488d2017-12-11 17:24:55 -08005384 }
5385
5386 @BinderThread
Tarandeep Singh75a92392018-01-12 14:58:59 -08005387 @ShellCommandResult
5388 private int refreshDebugProperties() {
5389 DebugFlags.FLAG_OPTIMIZE_START_INPUT.refresh();
Tarandeep Singheadb1392018-11-09 18:15:57 +01005390 DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.refresh();
Tarandeep Singh75a92392018-01-12 14:58:59 -08005391 return ShellCommandResult.SUCCESS;
5392 }
5393
5394 @BinderThread
Yohei Yukawa926488d2017-12-11 17:24:55 -08005395 @Override
5396 public void onHelp() {
5397 try (PrintWriter pw = getOutPrintWriter()) {
5398 pw.println("InputMethodManagerService commands:");
5399 pw.println(" help");
5400 pw.println(" Prints this help text.");
5401 pw.println(" dump [options]");
5402 pw.println(" Synonym of dumpsys.");
Yohei Yukawacac97722017-12-15 16:52:05 -08005403 pw.println(" ime <command> [options]");
5404 pw.println(" Manipulate IMEs. Run \"ime help\" for details.");
5405 }
5406 }
5407
5408 private void onImeCommandHelp() {
5409 try (IndentingPrintWriter pw =
5410 new IndentingPrintWriter(getOutPrintWriter(), " ", 100)) {
5411 pw.println("ime <command>:");
5412 pw.increaseIndent();
5413
5414 pw.println("list [-a] [-s]");
5415 pw.increaseIndent();
5416 pw.println("prints all enabled input methods.");
5417 pw.increaseIndent();
5418 pw.println("-a: see all input methods");
5419 pw.println("-s: only a single summary line of each");
5420 pw.decreaseIndent();
5421 pw.decreaseIndent();
5422
Yohei Yukawae1771702019-04-10 23:20:51 -07005423 pw.println("enable [--user <USER_ID>] <ID>");
Yohei Yukawacac97722017-12-15 16:52:05 -08005424 pw.increaseIndent();
5425 pw.println("allows the given input method ID to be used.");
Yohei Yukawae1771702019-04-10 23:20:51 -07005426 pw.increaseIndent();
5427 pw.print("--user <USER_ID>: Specify which user to enable.");
5428 pw.println(" Assumes the current user if not specified.");
5429 pw.decreaseIndent();
Yohei Yukawacac97722017-12-15 16:52:05 -08005430 pw.decreaseIndent();
5431
Yohei Yukawae1771702019-04-10 23:20:51 -07005432 pw.println("disable [--user <USER_ID>] <ID>");
Yohei Yukawacac97722017-12-15 16:52:05 -08005433 pw.increaseIndent();
5434 pw.println("disallows the given input method ID to be used.");
Yohei Yukawae1771702019-04-10 23:20:51 -07005435 pw.increaseIndent();
5436 pw.print("--user <USER_ID>: Specify which user to disable.");
5437 pw.println(" Assumes the current user if not specified.");
5438 pw.decreaseIndent();
Yohei Yukawacac97722017-12-15 16:52:05 -08005439 pw.decreaseIndent();
5440
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005441 pw.println("set [--user <USER_ID>] <ID>");
Yohei Yukawacac97722017-12-15 16:52:05 -08005442 pw.increaseIndent();
5443 pw.println("switches to the given input method ID.");
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005444 pw.increaseIndent();
5445 pw.print("--user <USER_ID>: Specify which user to enable.");
5446 pw.println(" Assumes the current user if not specified.");
5447 pw.decreaseIndent();
Yohei Yukawacac97722017-12-15 16:52:05 -08005448 pw.decreaseIndent();
5449
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005450 pw.println("reset [--user <USER_ID>]");
Yohei Yukawacac97722017-12-15 16:52:05 -08005451 pw.increaseIndent();
5452 pw.println("reset currently selected/enabled IMEs to the default ones as if "
5453 + "the device is initially booted with the current locale.");
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005454 pw.increaseIndent();
5455 pw.print("--user <USER_ID>: Specify which user to reset.");
5456 pw.println(" Assumes the current user if not specified.");
5457 pw.decreaseIndent();
5458
Yohei Yukawacac97722017-12-15 16:52:05 -08005459 pw.decreaseIndent();
5460
5461 pw.decreaseIndent();
Yohei Yukawa926488d2017-12-11 17:24:55 -08005462 }
5463 }
5464 }
5465
5466 // ----------------------------------------------------------------------
5467 // Shell command handlers:
5468
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08005469 @BinderThread
5470 @ShellCommandResult
5471 private int getLastSwitchUserId(@NonNull ShellCommand shellCommand) {
5472 synchronized (mMethodMap) {
5473 shellCommand.getOutPrintWriter().println(mLastSwitchUserId);
5474 return ShellCommandResult.SUCCESS;
5475 }
5476 }
5477
Yohei Yukawa926488d2017-12-11 17:24:55 -08005478 /**
5479 * Handles {@code adb shell ime list}.
5480 * @param shellCommand {@link ShellCommand} object that is handling this command.
5481 * @return Exit code of the command.
5482 */
5483 @BinderThread
5484 @ShellCommandResult
5485 private int handleShellCommandListInputMethods(@NonNull ShellCommand shellCommand) {
5486 boolean all = false;
5487 boolean brief = false;
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08005488 int userIdToBeResolved = UserHandle.USER_CURRENT;
Yohei Yukawa926488d2017-12-11 17:24:55 -08005489 while (true) {
5490 final String nextOption = shellCommand.getNextOption();
5491 if (nextOption == null) {
5492 break;
5493 }
5494 switch (nextOption) {
5495 case "-a":
5496 all = true;
5497 break;
5498 case "-s":
5499 brief = true;
5500 break;
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08005501 case "-u":
5502 case "--user":
5503 userIdToBeResolved = UserHandle.parseUserArg(shellCommand.getNextArgRequired());
5504 break;
Yohei Yukawa926488d2017-12-11 17:24:55 -08005505 }
5506 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08005507 synchronized (mMethodMap) {
5508 final PrintWriter pr = shellCommand.getOutPrintWriter();
5509 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
5510 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
5511 for (int userId : userIds) {
5512 final List<InputMethodInfo> methods = all
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08005513 ? getInputMethodListLocked(userId)
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08005514 : getEnabledInputMethodListLocked(userId);
5515 if (userIds.length > 1) {
5516 pr.print("User #");
5517 pr.print(userId);
5518 pr.println(":");
5519 }
5520 for (InputMethodInfo info : methods) {
5521 if (brief) {
5522 pr.println(info.getId());
5523 } else {
5524 pr.print(info.getId());
5525 pr.println(":");
5526 info.dump(pr::println, " ");
5527 }
5528 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005529 }
5530 }
5531 return ShellCommandResult.SUCCESS;
5532 }
5533
5534 /**
5535 * Handles {@code adb shell ime enable} and {@code adb shell ime disable}.
5536 * @param shellCommand {@link ShellCommand} object that is handling this command.
5537 * @param enabled {@code true} if the command was {@code adb shell ime enable}.
5538 * @return Exit code of the command.
5539 */
5540 @BinderThread
5541 @ShellCommandResult
Yohei Yukawa926488d2017-12-11 17:24:55 -08005542 private int handleShellCommandEnableDisableInputMethod(
5543 @NonNull ShellCommand shellCommand, boolean enabled) {
Yohei Yukawa3403f2d2019-04-15 08:16:58 -07005544 final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
Yohei Yukawae1771702019-04-10 23:20:51 -07005545 final String imeId = shellCommand.getNextArgRequired();
5546 final PrintWriter out = shellCommand.getOutPrintWriter();
5547 final PrintWriter error = shellCommand.getErrPrintWriter();
Yohei Yukawa926488d2017-12-11 17:24:55 -08005548 synchronized (mMethodMap) {
Yohei Yukawae1771702019-04-10 23:20:51 -07005549 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
5550 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
5551 for (int userId : userIds) {
5552 if (!userHasDebugPriv(userId, shellCommand)) {
5553 continue;
5554 }
5555 handleShellCommandEnableDisableInputMethodInternalLocked(userId, imeId, enabled,
5556 out, error);
Tarandeep Singh87e2e512019-03-06 14:28:52 -08005557 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005558 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005559 return ShellCommandResult.SUCCESS;
5560 }
5561
5562 /**
Yohei Yukawae1771702019-04-10 23:20:51 -07005563 * A special helper method for commands that only have {@code -u} and {@code --user} options.
5564 *
5565 * <p>You cannot use this helper method if the command has other options.</p>
5566 *
Yohei Yukawa3403f2d2019-04-15 08:16:58 -07005567 * <p>CAVEAT: This method must be called only once before any other
5568 * {@link ShellCommand#getNextArg()} and {@link ShellCommand#getNextArgRequired()} for the
5569 * main arguments.</p>
5570 *
Yohei Yukawae1771702019-04-10 23:20:51 -07005571 * @param shellCommand {@link ShellCommand} from which options should be obtained.
5572 * @return User ID to be resolved. {@link UserHandle#CURRENT} if not specified.
5573 */
5574 @BinderThread
5575 @UserIdInt
5576 private static int handleOptionsForCommandsThatOnlyHaveUserOption(ShellCommand shellCommand) {
5577 while (true) {
5578 final String nextOption = shellCommand.getNextOption();
5579 if (nextOption == null) {
5580 break;
5581 }
5582 switch (nextOption) {
5583 case "-u":
5584 case "--user":
5585 return UserHandle.parseUserArg(shellCommand.getNextArgRequired());
5586 }
5587 }
5588 return UserHandle.USER_CURRENT;
5589 }
5590
5591 @BinderThread
5592 private void handleShellCommandEnableDisableInputMethodInternalLocked(
5593 @UserIdInt int userId, String imeId, boolean enabled, PrintWriter out,
5594 PrintWriter error) {
5595 boolean failedToEnableUnknownIme = false;
5596 boolean previouslyEnabled = false;
5597 if (userId == mSettings.getCurrentUserId()) {
5598 if (enabled && !mMethodMap.containsKey(imeId)) {
5599 failedToEnableUnknownIme = true;
5600 } else {
5601 previouslyEnabled = setInputMethodEnabledLocked(imeId, enabled);
5602 }
5603 } else {
5604 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
5605 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
5606 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
5607 new ArrayMap<>();
5608 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
5609 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
5610 methodMap, methodList);
5611 final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
5612 mContext.getContentResolver(), methodMap, userId, false);
5613 if (enabled) {
5614 if (!methodMap.containsKey(imeId)) {
5615 failedToEnableUnknownIme = true;
5616 } else {
5617 for (InputMethodInfo imi : settings.getEnabledInputMethodListLocked()) {
5618 if (TextUtils.equals(imi.getId(), imeId)) {
5619 previouslyEnabled = true;
5620 break;
5621 }
5622 }
5623 if (!previouslyEnabled) {
5624 settings.appendAndPutEnabledInputMethodLocked(imeId, false);
5625 }
5626 }
5627 } else {
5628 previouslyEnabled =
5629 settings.buildAndPutEnabledInputMethodsStrRemovingIdLocked(
5630 new StringBuilder(),
5631 settings.getEnabledInputMethodsAndSubtypeListLocked(), imeId);
5632 }
5633 }
5634 if (failedToEnableUnknownIme) {
5635 error.print("Unknown input method ");
5636 error.print(imeId);
5637 error.println(" cannot be enabled for user #" + userId);
5638 } else {
5639 out.print("Input method ");
5640 out.print(imeId);
5641 out.print(": ");
5642 out.print((enabled == previouslyEnabled) ? "already " : "now ");
5643 out.print(enabled ? "enabled" : "disabled");
5644 out.print(" for user #");
5645 out.println(userId);
5646 }
5647 }
5648
5649 /**
Yohei Yukawa926488d2017-12-11 17:24:55 -08005650 * Handles {@code adb shell ime set}.
5651 * @param shellCommand {@link ShellCommand} object that is handling this command.
5652 * @return Exit code of the command.
5653 */
5654 @BinderThread
5655 @ShellCommandResult
5656 private int handleShellCommandSetInputMethod(@NonNull ShellCommand shellCommand) {
Yohei Yukawa3403f2d2019-04-15 08:16:58 -07005657 final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005658 final String imeId = shellCommand.getNextArgRequired();
5659 final PrintWriter out = shellCommand.getOutPrintWriter();
5660 final PrintWriter error = shellCommand.getErrPrintWriter();
Yohei Yukawadb25df72018-12-27 08:40:41 -08005661 synchronized (mMethodMap) {
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005662 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
5663 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
5664 for (int userId : userIds) {
5665 if (!userHasDebugPriv(userId, shellCommand)) {
5666 continue;
5667 }
mincheli850892b2019-12-05 19:47:59 +08005668 boolean failedToSelectUnknownIme = !switchToInputMethod(imeId, userId);
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005669 if (failedToSelectUnknownIme) {
5670 error.print("Unknown input method ");
5671 error.print(imeId);
5672 error.print(" cannot be selected for user #");
5673 error.println(userId);
5674 } else {
5675 out.print("Input method ");
5676 out.print(imeId);
5677 out.print(" selected for user #");
Yohei Yukawa3403f2d2019-04-15 08:16:58 -07005678 out.println(userId);
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005679 }
Tarandeep Singh87e2e512019-03-06 14:28:52 -08005680 }
Yohei Yukawadb25df72018-12-27 08:40:41 -08005681 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005682 return ShellCommandResult.SUCCESS;
5683 }
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005684
5685 /**
5686 * Handles {@code adb shell ime reset-ime}.
5687 * @param shellCommand {@link ShellCommand} object that is handling this command.
5688 * @return Exit code of the command.
5689 */
5690 @BinderThread
5691 @ShellCommandResult
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005692 private int handleShellCommandResetInputMethod(@NonNull ShellCommand shellCommand) {
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005693 final PrintWriter out = shellCommand.getOutPrintWriter();
5694 final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005695 synchronized (mMethodMap) {
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005696 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
5697 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
5698 for (int userId : userIds) {
5699 if (!userHasDebugPriv(userId, shellCommand)) {
5700 continue;
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005701 }
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005702 final String nextIme;
5703 final List<InputMethodInfo> nextEnabledImes;
5704 if (userId == mSettings.getCurrentUserId()) {
Tarandeep Singh4fe5b652020-02-20 17:20:19 -08005705 hideCurrentInputLocked(mCurFocusedWindow, 0, null,
lumarkd85e1582019-12-29 20:20:41 +08005706 SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND);
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005707 unbindCurrentMethodLocked();
5708 // Reset the current IME
5709 resetSelectedInputMethodAndSubtypeLocked(null);
5710 // Also reset the settings of the current IME
5711 mSettings.putSelectedInputMethod(null);
5712 // Disable all enabled IMEs.
5713 mSettings.getEnabledInputMethodListLocked().forEach(
5714 imi -> setInputMethodEnabledLocked(imi.getId(), false));
5715 // Re-enable with default enabled IMEs.
5716 InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList).forEach(
5717 imi -> setInputMethodEnabledLocked(imi.getId(), true));
5718 updateInputMethodsFromSettingsLocked(true /* enabledMayChange */);
5719 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
5720 mSettings.getEnabledInputMethodListLocked(),
5721 mSettings.getCurrentUserId(),
5722 mContext.getBasePackageName());
5723 nextIme = mSettings.getSelectedInputMethod();
5724 nextEnabledImes = mSettings.getEnabledInputMethodListLocked();
5725 } else {
5726 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
5727 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
5728 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
5729 new ArrayMap<>();
5730 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
5731 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
5732 methodMap, methodList);
5733 final InputMethodSettings settings = new InputMethodSettings(
5734 mContext.getResources(), mContext.getContentResolver(), methodMap,
5735 userId, false);
5736
5737 nextEnabledImes = InputMethodUtils.getDefaultEnabledImes(mContext, methodList);
5738 nextIme = InputMethodUtils.getMostApplicableDefaultIME(nextEnabledImes).getId();
5739
5740 // Reset enabled IMEs.
5741 settings.putEnabledInputMethodsStr("");
5742 nextEnabledImes.forEach(imi -> settings.appendAndPutEnabledInputMethodLocked(
5743 imi.getId(), false));
5744
5745 // Reset selected IME.
5746 settings.putSelectedInputMethod(nextIme);
5747 settings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
5748 }
5749 out.println("Reset current and enabled IMEs for user #" + userId);
5750 out.println(" Selected: " + nextIme);
5751 nextEnabledImes.forEach(ime -> out.println(" Enabled: " + ime.getId()));
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005752 }
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005753 }
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005754 return ShellCommandResult.SUCCESS;
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005755 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07005756
Tarandeep Singh87e2e512019-03-06 14:28:52 -08005757 /**
5758 * @param userId the actual user handle obtained by {@link UserHandle#getIdentifier()}
5759 * and *not* pseudo ids like {@link UserHandle#USER_ALL etc}.
5760 * @return {@code true} if userId has debugging privileges.
5761 * i.e. {@link UserManager#DISALLOW_DEBUGGING_FEATURES} is {@code false}.
5762 */
5763 private boolean userHasDebugPriv(int userId, final ShellCommand shellCommand) {
5764 if (mUserManager.hasUserRestriction(
5765 UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.of(userId))) {
5766 shellCommand.getErrPrintWriter().println("User #" + userId
5767 + " is restricted with DISALLOW_DEBUGGING_FEATURES.");
5768 return false;
5769 }
5770 return true;
5771 }
5772
Yohei Yukawac54c1172018-09-06 11:39:50 -07005773 private static final class InputMethodPrivilegedOperationsImpl
5774 extends IInputMethodPrivilegedOperations.Stub {
5775 private final InputMethodManagerService mImms;
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08005776 @NonNull
Yohei Yukawac54c1172018-09-06 11:39:50 -07005777 private final IBinder mToken;
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08005778 InputMethodPrivilegedOperationsImpl(InputMethodManagerService imms,
5779 @NonNull IBinder token) {
Yohei Yukawac54c1172018-09-06 11:39:50 -07005780 mImms = imms;
5781 mToken = token;
5782 }
5783
5784 @BinderThread
5785 @Override
5786 public void setImeWindowStatus(int vis, int backDisposition) {
5787 mImms.setImeWindowStatus(mToken, vis, backDisposition);
5788 }
5789
5790 @BinderThread
5791 @Override
5792 public void reportStartInput(IBinder startInputToken) {
5793 mImms.reportStartInput(mToken, startInputToken);
5794 }
5795
5796 @BinderThread
5797 @Override
Yohei Yukawac54c1172018-09-06 11:39:50 -07005798 public IInputContentUriToken createInputContentUriToken(Uri contentUri,
5799 String packageName) {
5800 return mImms.createInputContentUriToken(mToken, contentUri, packageName);
5801 }
5802
5803 @BinderThread
5804 @Override
5805 public void reportFullscreenMode(boolean fullscreen) {
5806 mImms.reportFullscreenMode(mToken, fullscreen);
5807 }
Yohei Yukawac7ca3682018-09-09 20:48:38 -07005808
5809 @BinderThread
5810 @Override
5811 public void setInputMethod(String id) {
5812 mImms.setInputMethod(mToken, id);
5813 }
5814
5815 @BinderThread
5816 @Override
5817 public void setInputMethodAndSubtype(String id, InputMethodSubtype subtype) {
5818 mImms.setInputMethodAndSubtype(mToken, id, subtype);
5819 }
5820
5821 @BinderThread
5822 @Override
5823 public void hideMySoftInput(int flags) {
5824 mImms.hideMySoftInput(mToken, flags);
5825 }
5826
5827 @BinderThread
5828 @Override
5829 public void showMySoftInput(int flags) {
5830 mImms.showMySoftInput(mToken, flags);
5831 }
5832
5833 @BinderThread
5834 @Override
Yohei Yukawa41b094f2018-09-09 23:58:45 -07005835 public void updateStatusIcon(String packageName, @DrawableRes int iconId) {
Yohei Yukawac7ca3682018-09-09 20:48:38 -07005836 mImms.updateStatusIcon(mToken, packageName, iconId);
5837 }
5838
5839 @BinderThread
5840 @Override
5841 public boolean switchToPreviousInputMethod() {
5842 return mImms.switchToPreviousInputMethod(mToken);
5843 }
5844
5845 @BinderThread
5846 @Override
5847 public boolean switchToNextInputMethod(boolean onlyCurrentIme) {
5848 return mImms.switchToNextInputMethod(mToken, onlyCurrentIme);
5849 }
5850
5851 @BinderThread
5852 @Override
5853 public boolean shouldOfferSwitchingToNextInputMethod() {
5854 return mImms.shouldOfferSwitchingToNextInputMethod(mToken);
5855 }
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07005856
5857 @BinderThread
5858 @Override
Yohei Yukawa9b60ba02019-01-21 00:06:27 -08005859 public void notifyUserAction() {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07005860 mImms.notifyUserAction(mToken);
5861 }
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08005862
5863 @BinderThread
5864 @Override
5865 public void reportPreRendered(EditorInfo info) {
5866 mImms.reportPreRendered(mToken, info);
5867 }
5868
5869 @BinderThread
5870 @Override
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08005871 public void applyImeVisibility(IBinder windowToken, boolean setVisible) {
5872 mImms.applyImeVisibility(mToken, windowToken, setVisible);
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08005873 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07005874 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005875}