blob: 47622f38f3f225d005754cc9d51268874ce493f2 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 * use this file except in compliance with the License. You may obtain a copy of
5 * the License at
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007 * http://www.apache.org/licenses/LICENSE-2.0
Doug Zongkerab5c49c2009-12-04 10:31:43 -08008 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 * License for the specific language governing permissions and limitations under
13 * the License.
14 */
15
Yohei Yukawa603f4d02018-09-11 15:04:58 -070016package com.android.server.inputmethod;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080017
lumarkef1965b2018-09-12 17:42:53 +080018import static android.view.Display.DEFAULT_DISPLAY;
lumark90120a82018-08-15 00:33:03 +080019import static android.view.Display.INVALID_DISPLAY;
Yohei Yukawa0569a182018-08-28 16:09:28 -070020
Yohei Yukawafa0e47e2016-04-05 09:55:56 -070021import static java.lang.annotation.RetentionPolicy.SOURCE;
22
Yohei Yukawa926488d2017-12-11 17:24:55 -080023import android.Manifest;
Phil Weaver03a65b02018-07-19 16:07:57 -070024import android.accessibilityservice.AccessibilityService;
Tarandeep Singh75a92392018-01-12 14:58:59 -080025import android.annotation.AnyThread;
Yohei Yukawad6475a62017-04-17 10:35:27 -070026import android.annotation.BinderThread;
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +090027import android.annotation.ColorInt;
Yohei Yukawa41b094f2018-09-09 23:58:45 -070028import android.annotation.DrawableRes;
Yohei Yukawafa0e47e2016-04-05 09:55:56 -070029import android.annotation.IntDef;
Yohei Yukawa930328c2017-10-18 20:19:53 -070030import android.annotation.MainThread;
Yohei Yukawa6ab1a822015-08-25 14:01:28 -070031import android.annotation.NonNull;
Yohei Yukawae13a20fa2015-09-30 19:11:32 -070032import android.annotation.Nullable;
Yohei Yukawa926488d2017-12-11 17:24:55 -080033import android.annotation.RequiresPermission;
Yohei Yukawa7b18aec2016-03-07 13:04:32 -080034import android.annotation.UserIdInt;
Sudheer Shankadc589ac2016-11-10 15:30:17 -080035import android.app.ActivityManager;
Sudheer Shankafc46e9b2016-10-21 17:55:27 -070036import android.app.ActivityManagerInternal;
Andrew Sapperstein8a3b4cb2017-04-28 14:35:31 -070037import android.app.ActivityThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.app.AlertDialog;
Yohei Yukawa6ab1a822015-08-25 14:01:28 -070039import android.app.AppGlobals;
Yohei Yukawae63b5fa2014-09-19 13:14:55 +090040import android.app.AppOpsManager;
satokf90a33e2011-07-19 11:55:52 +090041import android.app.KeyguardManager;
satok7cfc0ed2011-06-20 21:29:36 +090042import android.app.Notification;
43import android.app.NotificationManager;
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070044import android.app.PendingIntent;
satok5b927c432012-05-01 20:09:34 +090045import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.content.ComponentName;
Yohei Yukawa3933a6e2016-11-10 00:47:48 -080047import android.content.ContentProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.content.ContentResolver;
49import android.content.Context;
50import android.content.DialogInterface;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.content.DialogInterface.OnCancelListener;
Tadashi G. Takaokad130b802014-08-01 14:05:47 +090052import android.content.DialogInterface.OnClickListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.content.Intent;
satoke7c6998e2011-06-03 17:57:59 +090054import android.content.IntentFilter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.content.ServiceConnection;
Brandon Ballinger6da35a02009-10-21 00:38:13 -070056import android.content.pm.ApplicationInfo;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +090057import android.content.pm.IPackageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.content.pm.PackageManager;
59import android.content.pm.ResolveInfo;
60import android.content.pm.ServiceInfo;
Amith Yamasanie861ec12010-03-24 21:39:27 -070061import android.content.res.Configuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.content.res.Resources;
63import android.content.res.TypedArray;
64import android.database.ContentObserver;
Yohei Yukawab4f328a2019-05-02 08:41:27 -070065import android.graphics.Matrix;
Alan Viverette505e3ab2014-11-24 15:22:11 -080066import android.graphics.drawable.Drawable;
Yohei Yukawab4f328a2019-05-02 08:41:27 -070067import android.hardware.display.DisplayManagerInternal;
Joe Onorato857fd9b2011-01-27 15:08:35 -080068import android.inputmethodservice.InputMethodService;
Michael Wright7b5a96b2014-08-09 19:28:42 -070069import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070import android.os.Binder;
Chris Wren1ce4b6d2015-06-11 10:19:43 -040071import android.os.Bundle;
Seigo Nonakae27dc2b2015-08-14 18:21:27 -070072import android.os.Debug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.os.Handler;
74import android.os.IBinder;
75import android.os.IInterface;
Yohei Yukawa23cbe852016-05-17 16:42:58 -070076import android.os.LocaleList;
Yohei Yukawa0569a182018-08-28 16:09:28 -070077import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078import android.os.Parcel;
Yohei Yukawa6ab1a822015-08-25 14:01:28 -070079import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080import android.os.RemoteException;
The Android Open Source Project4df24232009-03-05 14:34:35 -080081import android.os.ResultReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082import android.os.ServiceManager;
Yohei Yukawa926488d2017-12-11 17:24:55 -080083import android.os.ShellCallback;
84import android.os.ShellCommand;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.os.SystemClock;
Tarandeep Singh75a92392018-01-12 14:58:59 -080086import android.os.SystemProperties;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +090087import android.os.UserHandle;
Amith Yamasani734983f2014-03-04 16:48:05 -080088import android.os.UserManager;
Yohei Yukawa42081402019-01-15 09:57:50 -080089import android.os.UserManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090import android.provider.Settings;
91import android.text.TextUtils;
satokf9f01002011-05-19 21:31:50 +090092import android.text.style.SuggestionSpan;
Yohei Yukawaac9311e2018-11-20 19:25:23 -080093import android.util.ArrayMap;
Christopher Tate7b9a28c2015-03-18 13:06:16 -070094import android.util.ArraySet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095import android.util.EventLog;
satokf9f01002011-05-19 21:31:50 +090096import android.util.LruCache;
satokab751aa2010-09-14 19:17:36 +090097import android.util.Pair;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098import android.util.PrintWriterPrinter;
99import android.util.Printer;
satoke7c6998e2011-06-03 17:57:59 +0900100import android.util.Slog;
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700101import android.util.SparseArray;
Tadashi G. Takaokad130b802014-08-01 14:05:47 +0900102import android.view.ContextThemeWrapper;
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700103import android.view.DisplayInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104import android.view.IWindowManager;
Jeff Brownc28867a2013-03-26 15:42:39 -0700105import android.view.InputChannel;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900106import android.view.LayoutInflater;
107import android.view.View;
108import android.view.ViewGroup;
Wale Ogunwale3a931692016-11-02 16:49:48 -0700109import android.view.Window;
Yohei Yukawa6e875592019-01-28 00:49:30 -0800110import android.view.WindowManager.LayoutParams;
Yohei Yukawab0c26452018-10-21 10:42:52 -0700111import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
Adam Hebc67f2e2019-11-13 14:34:56 -0800112import android.view.autofill.AutofillId;
satokab751aa2010-09-14 19:17:36 +0900113import android.view.inputmethod.EditorInfo;
Feng Cao16b2de52020-01-09 17:27:27 -0800114import android.view.inputmethod.InlineSuggestionsRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115import android.view.inputmethod.InputBinding;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800116import android.view.inputmethod.InputConnection;
Yohei Yukawa19a80a12016-03-14 22:57:37 -0700117import android.view.inputmethod.InputConnectionInspector;
Yohei Yukawa432cf602018-10-21 10:41:37 -0700118import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119import android.view.inputmethod.InputMethod;
120import android.view.inputmethod.InputMethodInfo;
121import android.view.inputmethod.InputMethodManager;
satokab751aa2010-09-14 19:17:36 +0900122import android.view.inputmethod.InputMethodSubtype;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900123import android.widget.ArrayAdapter;
satok01038492012-04-09 21:08:27 +0900124import android.widget.CompoundButton;
125import android.widget.CompoundButton.OnCheckedChangeListener;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900126import android.widget.RadioButton;
satok01038492012-04-09 21:08:27 +0900127import android.widget.Switch;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900128import android.widget.TextView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129
Yohei Yukawa0569a182018-08-28 16:09:28 -0700130import com.android.internal.annotations.GuardedBy;
131import com.android.internal.content.PackageMonitor;
132import com.android.internal.inputmethod.IInputContentUriToken;
Yohei Yukawac54c1172018-09-06 11:39:50 -0700133import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
Yohei Yukawaa468d702018-10-21 11:42:34 -0700134import com.android.internal.inputmethod.InputMethodDebug;
Yohei Yukawa35fa6d52018-10-31 11:33:32 -0700135import com.android.internal.inputmethod.StartInputFlags;
Yohei Yukawac6632df2018-10-21 11:47:16 -0700136import com.android.internal.inputmethod.StartInputReason;
Yohei Yukawa499e3f72018-10-21 20:15:11 -0700137import com.android.internal.inputmethod.UnbindReason;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700138import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
139import com.android.internal.notification.SystemNotificationChannels;
140import com.android.internal.os.HandlerCaller;
141import com.android.internal.os.SomeArgs;
142import com.android.internal.os.TransferPipe;
143import com.android.internal.util.DumpUtils;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700144import com.android.internal.util.IndentingPrintWriter;
Adam Hebc67f2e2019-11-13 14:34:56 -0800145import com.android.internal.view.IInlineSuggestionsRequestCallback;
Feng Cao16b2de52020-01-09 17:27:27 -0800146import com.android.internal.view.IInlineSuggestionsResponseCallback;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700147import com.android.internal.view.IInputContext;
148import com.android.internal.view.IInputMethod;
149import com.android.internal.view.IInputMethodClient;
150import com.android.internal.view.IInputMethodManager;
151import com.android.internal.view.IInputMethodSession;
152import com.android.internal.view.IInputSessionCallback;
153import com.android.internal.view.InputBindResult;
Yohei Yukawa603f4d02018-09-11 15:04:58 -0700154import com.android.server.EventLogTags;
155import com.android.server.LocalServices;
156import com.android.server.SystemService;
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +0900157import com.android.server.inputmethod.InputMethodManagerInternal.InputMethodListListener;
Yohei Yukawae6b6e0e2018-09-12 16:42:48 -0700158import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
159import com.android.server.inputmethod.InputMethodUtils.InputMethodSettings;
Yohei Yukawa0569a182018-08-28 16:09:28 -0700160import com.android.server.statusbar.StatusBarManagerService;
Adrian Roose99bc052017-11-20 17:55:31 +0100161import com.android.server.wm.WindowManagerInternal;
162
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163import java.io.FileDescriptor;
164import java.io.IOException;
165import java.io.PrintWriter;
Yohei Yukawafa0e47e2016-04-05 09:55:56 -0700166import java.lang.annotation.Retention;
Yohei Yukawa25e08132016-06-22 16:31:41 -0700167import java.security.InvalidParameterException;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800168import java.text.SimpleDateFormat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169import java.util.ArrayList;
Yohei Yukawab8d240f2018-12-26 10:03:11 -0800170import java.util.Arrays;
satok688bd472012-02-09 20:09:17 +0900171import java.util.Collections;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800172import java.util.Date;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173import java.util.List;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800174import java.util.Locale;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800175import java.util.WeakHashMap;
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +0900176import java.util.concurrent.CopyOnWriteArrayList;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800177import java.util.concurrent.atomic.AtomicInteger;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178
179/**
180 * This class provides a system service that manages input methods.
181 */
182public class InputMethodManagerService extends IInputMethodManager.Stub
183 implements ServiceConnection, Handler.Callback {
184 static final boolean DEBUG = false;
Jeff Brown6ec6f792012-04-17 16:52:41 -0700185 static final String TAG = "InputMethodManagerService";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186
Yohei Yukawa926488d2017-12-11 17:24:55 -0800187 @Retention(SOURCE)
188 @IntDef({ShellCommandResult.SUCCESS, ShellCommandResult.FAILURE})
189 private @interface ShellCommandResult {
190 int SUCCESS = 0;
191 int FAILURE = -1;
192 }
193
Seigo Nonakad4474cb2015-05-04 16:53:24 -0700194 static final int MSG_SHOW_IM_SUBTYPE_PICKER = 1;
195 static final int MSG_SHOW_IM_SUBTYPE_ENABLER = 2;
196 static final int MSG_SHOW_IM_CONFIG = 3;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800197
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 static final int MSG_UNBIND_INPUT = 1000;
199 static final int MSG_BIND_INPUT = 1010;
200 static final int MSG_SHOW_SOFT_INPUT = 1020;
201 static final int MSG_HIDE_SOFT_INPUT = 1030;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -0700202 static final int MSG_HIDE_CURRENT_INPUT_METHOD = 1035;
Yohei Yukawac54c1172018-09-06 11:39:50 -0700203 static final int MSG_INITIALIZE_IME = 1040;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 static final int MSG_CREATE_SESSION = 1050;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800205
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 static final int MSG_START_INPUT = 2000;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800207
Yohei Yukawa33e81792015-11-17 21:14:42 -0800208 static final int MSG_UNBIND_CLIENT = 3000;
209 static final int MSG_BIND_CLIENT = 3010;
Dianne Hackborna6e41342012-05-22 16:30:34 -0700210 static final int MSG_SET_ACTIVE = 3020;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700211 static final int MSG_SET_INTERACTIVE = 3030;
Yohei Yukawa2bc66172017-02-08 11:13:25 -0800212 static final int MSG_REPORT_FULLSCREEN_MODE = 3045;
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -0800213 static final int MSG_REPORT_PRE_RENDERED = 3060;
214 static final int MSG_APPLY_IME_VISIBILITY = 3070;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800215
satok01038492012-04-09 21:08:27 +0900216 static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000;
217
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -0700218 static final int MSG_SYSTEM_UNLOCK_USER = 5000;
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +0900219 static final int MSG_DISPATCH_ON_INPUT_METHOD_LIST_UPDATED = 5010;
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -0700220
Adam Hebc67f2e2019-11-13 14:34:56 -0800221 static final int MSG_INLINE_SUGGESTIONS_REQUEST = 6000;
222
Satoshi Kataokabcacc322013-10-21 17:57:27 -0700223 static final long TIME_TO_RECONNECT = 3 * 1000;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800224
satokf9f01002011-05-19 21:31:50 +0900225 static final int SECURE_SUGGESTION_SPANS_MAX_SIZE = 20;
226
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +0900227 private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID;
satokb6359412011-06-28 17:47:41 +0900228 private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +0900229
Yohei Yukawaa67a4592017-03-30 15:57:02 -0700230 /**
231 * Binding flags for establishing connection to the {@link InputMethodService}.
232 */
233 private static final int IME_CONNECTION_BIND_FLAGS =
234 Context.BIND_AUTO_CREATE
235 | Context.BIND_NOT_VISIBLE
236 | Context.BIND_NOT_FOREGROUND
Yohei Yukawaad78a612017-08-04 01:57:27 -0700237 | Context.BIND_IMPORTANT_BACKGROUND;
Yohei Yukawaa67a4592017-03-30 15:57:02 -0700238
239 /**
240 * Binding flags used only while the {@link InputMethodService} is showing window.
241 */
242 private static final int IME_VISIBLE_BIND_FLAGS =
243 Context.BIND_AUTO_CREATE
244 | Context.BIND_TREAT_LIKE_ACTIVITY
Yohei Yukawaad78a612017-08-04 01:57:27 -0700245 | Context.BIND_FOREGROUND_SERVICE
Amith Yamasanic45a9902019-04-05 16:29:30 -0700246 | Context.BIND_INCLUDE_CAPABILITIES
Yohei Yukawa59730962019-03-18 10:47:22 -0700247 | Context.BIND_SHOWING_UI
248 | Context.BIND_SCHEDULE_LIKE_TOP_APP;
Yohei Yukawaa67a4592017-03-30 15:57:02 -0700249
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +0900250 /**
251 * A protected broadcast intent action for internal use for {@link PendingIntent} in
252 * the notification.
253 */
254 private static final String ACTION_SHOW_INPUT_METHOD_PICKER =
Yohei Yukawa603f4d02018-09-11 15:04:58 -0700255 "com.android.server.inputmethod.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER";
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +0900256
Tarandeep Singh75a92392018-01-12 14:58:59 -0800257 /**
258 * Debug flag for overriding runtime {@link SystemProperties}.
259 */
260 @AnyThread
261 private static final class DebugFlag {
262 private static final Object LOCK = new Object();
263 private final String mKey;
Tarandeep Singh9df4ad12018-04-03 13:35:50 -0700264 private final boolean mDefaultValue;
Tarandeep Singh75a92392018-01-12 14:58:59 -0800265 @GuardedBy("LOCK")
266 private boolean mValue;
267
Tarandeep Singh1c042c52018-03-29 17:04:44 -0700268 public DebugFlag(String key, boolean defaultValue) {
Tarandeep Singh75a92392018-01-12 14:58:59 -0800269 mKey = key;
Tarandeep Singh9df4ad12018-04-03 13:35:50 -0700270 mDefaultValue = defaultValue;
Tarandeep Singh1c042c52018-03-29 17:04:44 -0700271 mValue = SystemProperties.getBoolean(key, defaultValue);
Tarandeep Singh75a92392018-01-12 14:58:59 -0800272 }
273
274 void refresh() {
275 synchronized (LOCK) {
Tarandeep Singh9df4ad12018-04-03 13:35:50 -0700276 mValue = SystemProperties.getBoolean(mKey, mDefaultValue);
Tarandeep Singh75a92392018-01-12 14:58:59 -0800277 }
278 }
279
280 boolean value() {
281 synchronized (LOCK) {
282 return mValue;
283 }
284 }
285 }
286
287 /**
288 * Debug flags that can be overridden using "adb shell setprop <key>"
289 * Note: These flags are cached. To refresh, run "adb shell ime refresh_debug_properties".
290 */
291 private static final class DebugFlags {
292 static final DebugFlag FLAG_OPTIMIZE_START_INPUT =
Tarandeep Singh1c042c52018-03-29 17:04:44 -0700293 new DebugFlag("debug.optimize_startinput", false);
Tarandeep Singheadb1392018-11-09 18:15:57 +0100294 static final DebugFlag FLAG_PRE_RENDER_IME_VIEWS =
295 new DebugFlag("persist.pre_render_ime_views", false);
Tarandeep Singh75a92392018-01-12 14:58:59 -0800296 }
297
Yohei Yukawaa7babbb2019-01-08 16:45:34 -0800298 @UserIdInt
299 private int mLastSwitchUserId;
Tarandeep Singh75a92392018-01-12 14:58:59 -0800300
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 final Context mContext;
Dianne Hackborn7d3a5bc2010-11-29 22:52:12 -0800302 final Resources mRes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303 final Handler mHandler;
satokd87c2592010-09-29 11:52:06 +0900304 final InputMethodSettings mSettings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305 final SettingsObserver mSettingsObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 final IWindowManager mIWindowManager;
Seigo Nonaka7309b122015-08-17 18:34:13 -0700307 final WindowManagerInternal mWindowManagerInternal;
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700308 private final DisplayManagerInternal mDisplayManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309 final HandlerCaller mCaller;
Dianne Hackborn119bbc32013-03-22 17:27:25 -0700310 final boolean mHasFeature;
Yohei Yukawab557d572018-12-29 21:26:26 -0800311 private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypeMap =
312 new ArrayMap<>();
Tarandeep Singheadb1392018-11-09 18:15:57 +0100313 private final boolean mIsLowRam;
satok01038492012-04-09 21:08:27 +0900314 private final HardKeyboardListener mHardKeyboardListener;
Yohei Yukawae63b5fa2014-09-19 13:14:55 +0900315 private final AppOpsManager mAppOpsManager;
Yohei Yukawaed4952a2016-02-17 07:57:25 -0800316 private final UserManager mUserManager;
Yohei Yukawa42081402019-01-15 09:57:50 -0800317 private final UserManagerInternal mUserManagerInternal;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800318
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 // All known input methods. mMethodMap also serves as the global
320 // lock for this class.
Yohei Yukawab0377bb2015-08-10 21:06:30 -0700321 final ArrayList<InputMethodInfo> mMethodList = new ArrayList<>();
Yohei Yukawa1dd7de62018-11-20 19:25:29 -0800322 final ArrayMap<String, InputMethodInfo> mMethodMap = new ArrayMap<>();
satokf9f01002011-05-19 21:31:50 +0900323 private final LruCache<SuggestionSpan, InputMethodInfo> mSecureSuggestionSpans =
Yohei Yukawab0377bb2015-08-10 21:06:30 -0700324 new LruCache<>(SECURE_SUGGESTION_SPANS_MAX_SIZE);
Satoshi Kataokad787f692013-10-26 04:44:21 +0900325 private final InputMethodSubtypeSwitchingController mSwitchingController;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800326
Yohei Yukawae0733062017-02-09 22:49:35 -0800327 /**
328 * Tracks how many times {@link #mMethodMap} was updated.
329 */
330 @GuardedBy("mMethodMap")
331 private int mMethodMapUpdateCount = 0;
332
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -0700333 // Used to bring IME service up to visible adjustment while it is being shown.
334 final ServiceConnection mVisibleConnection = new ServiceConnection() {
Yohei Yukawad3ef8422018-06-07 16:28:07 -0700335 @Override public void onBindingDied(ComponentName name) {
336 synchronized (mMethodMap) {
337 if (mVisibleBound) {
338 mContext.unbindService(mVisibleConnection);
339 mVisibleBound = false;
340 }
341 }
342 }
343
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -0700344 @Override public void onServiceConnected(ComponentName name, IBinder service) {
345 }
346
347 @Override public void onServiceDisconnected(ComponentName name) {
348 }
349 };
350 boolean mVisibleBound = false;
351
satok7cfc0ed2011-06-20 21:29:36 +0900352 // Ongoing notification
Dianne Hackborn661cd522011-08-22 00:26:20 -0700353 private NotificationManager mNotificationManager;
354 private KeyguardManager mKeyguardManager;
Griff Hazen6090c262016-03-25 08:11:24 -0700355 private @Nullable StatusBarManagerService mStatusBar;
Chris Wren1ce4b6d2015-06-11 10:19:43 -0400356 private Notification.Builder mImeSwitcherNotification;
Dianne Hackborn661cd522011-08-22 00:26:20 -0700357 private PendingIntent mImeSwitchPendingIntent;
satokb858c732011-07-22 19:54:34 +0900358 private boolean mShowOngoingImeSwitcherForPhones;
satok7cfc0ed2011-06-20 21:29:36 +0900359 private boolean mNotificationShown;
360
Tadashi G. Takaoka8c6d4772014-08-05 15:29:17 +0900361 static class SessionState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 final ClientState client;
363 final IInputMethod method;
Jeff Brownc28867a2013-03-26 15:42:39 -0700364
365 IInputMethodSession session;
366 InputChannel channel;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800367
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 @Override
369 public String toString() {
370 return "SessionState{uid " + client.uid + " pid " + client.pid
371 + " method " + Integer.toHexString(
372 System.identityHashCode(method))
373 + " session " + Integer.toHexString(
374 System.identityHashCode(session))
Jeff Brownc28867a2013-03-26 15:42:39 -0700375 + " channel " + channel
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 + "}";
377 }
378
379 SessionState(ClientState _client, IInputMethod _method,
Jeff Brownc28867a2013-03-26 15:42:39 -0700380 IInputMethodSession _session, InputChannel _channel) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 client = _client;
382 method = _method;
383 session = _session;
Jeff Brownc28867a2013-03-26 15:42:39 -0700384 channel = _channel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 }
386 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800387
Yohei Yukawaa71bb252018-09-19 19:21:24 -0700388 private static final class ClientDeathRecipient implements IBinder.DeathRecipient {
389 private final InputMethodManagerService mImms;
390 private final IInputMethodClient mClient;
391
392 ClientDeathRecipient(InputMethodManagerService imms, IInputMethodClient client) {
393 mImms = imms;
394 mClient = client;
395 }
396
397 @Override
398 public void binderDied() {
399 mImms.removeClient(mClient);
400 }
401 }
402
Jeff Brownc28867a2013-03-26 15:42:39 -0700403 static final class ClientState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 final IInputMethodClient client;
405 final IInputContext inputContext;
406 final int uid;
407 final int pid;
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800408 final int selfReportedDisplayId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 final InputBinding binding;
Yohei Yukawaa71bb252018-09-19 19:21:24 -0700410 final ClientDeathRecipient clientDeathRecipient;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800411
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 boolean sessionRequested;
Tarandeep Singheadb1392018-11-09 18:15:57 +0100413 // Determines if IMEs should be pre-rendered.
414 // DebugFlag can be flipped anytime. This flag is kept per-client to maintain behavior
415 // through the life of the current client.
416 boolean shouldPreRenderIme;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 SessionState curSession;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800418
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 @Override
420 public String toString() {
421 return "ClientState{" + Integer.toHexString(
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800422 System.identityHashCode(this)) + " uid=" + uid
423 + " pid=" + pid + " displayId=" + selfReportedDisplayId + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 }
425
426 ClientState(IInputMethodClient _client, IInputContext _inputContext,
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800427 int _uid, int _pid, int _selfReportedDisplayId,
428 ClientDeathRecipient _clientDeathRecipient) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 client = _client;
430 inputContext = _inputContext;
431 uid = _uid;
432 pid = _pid;
Yohei Yukawa4052a10f2018-10-15 15:35:55 +0800433 selfReportedDisplayId = _selfReportedDisplayId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434 binding = new InputBinding(null, inputContext.asBinder(), uid, pid);
Yohei Yukawaa71bb252018-09-19 19:21:24 -0700435 clientDeathRecipient = _clientDeathRecipient;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 }
437 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800438
Yohei Yukawaac9311e2018-11-20 19:25:23 -0800439 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800440
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700441 private static final class ActivityViewInfo {
442 /**
443 * {@link ClientState} where {@link android.app.ActivityView} is running.
444 */
445 private final ClientState mParentClient;
446 /**
447 * {@link Matrix} to convert screen coordinates in the embedded virtual display to
448 * screen coordinates where {@link #mParentClient} exists.
449 */
450 private final Matrix mMatrix;
451
452 ActivityViewInfo(ClientState parentClient, Matrix matrix) {
453 mParentClient = parentClient;
454 mMatrix = matrix;
455 }
456 }
457
458 /**
459 * A mapping table from virtual display IDs created for {@link android.app.ActivityView}
460 * to its parent IME client where {@link android.app.ActivityView} is running.
461 *
462 * <p>Note: this can be used only for virtual display IDs created by
463 * {@link android.app.ActivityView}.</p>
464 */
465 private SparseArray<ActivityViewInfo> mActivityViewDisplayIdToParentMap = new SparseArray<>();
466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 /**
Dianne Hackborna34f1ad2009-09-02 13:26:28 -0700468 * Set once the system is ready to run third party code.
469 */
470 boolean mSystemReady;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800471
Dianne Hackborna34f1ad2009-09-02 13:26:28 -0700472 /**
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700473 * Id obtained with {@link InputMethodInfo#getId()} for the currently selected input method.
474 * method. This is to be synchronized with the secure settings keyed with
475 * {@link Settings.Secure#DEFAULT_INPUT_METHOD}.
476 *
477 * <p>This can be transiently {@code null} when the system is re-initializing input method
478 * settings, e.g., the system locale is just changed.</p>
479 *
480 * <p>Note that {@link #mCurId} is used to track which IME is being connected to
481 * {@link InputMethodManagerService}.</p>
482 *
483 * @see #mCurId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800484 */
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700485 @Nullable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 String mCurMethodId;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800487
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488 /**
489 * The current binding sequence number, incremented every time there is
490 * a new bind performed.
491 */
492 int mCurSeq;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800493
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 /**
495 * The client that is currently bound to an input method.
496 */
497 ClientState mCurClient;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800498
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499 /**
Yohei Yukawae39d4ed2015-11-19 03:38:49 -0800500 * The last window token that we confirmed to be focused. This is always updated upon reports
501 * from the input method client. If the window state is already changed before the report is
502 * handled, this field just keeps the last value.
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700503 */
504 IBinder mCurFocusedWindow;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800505
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700506 /**
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -0700507 * The last window token that we confirmed that IME started talking to. This is always updated
508 * upon reports from the input method. If the window state is already changed before the report
509 * is handled, this field just keeps the last value.
510 */
511 IBinder mLastImeTargetWindow;
512
513 /**
Yohei Yukawa6e875592019-01-28 00:49:30 -0800514 * {@link LayoutParams#softInputMode} of {@link #mCurFocusedWindow}.
Yohei Yukawa22a89232017-02-12 16:38:59 -0800515 *
516 * @see #mCurFocusedWindow
517 */
Yohei Yukawab0c26452018-10-21 10:42:52 -0700518 @SoftInputModeFlags
Yohei Yukawa22a89232017-02-12 16:38:59 -0800519 int mCurFocusedWindowSoftInputMode;
520
521 /**
Tarandeep Singheb570612018-01-29 16:20:32 -0800522 * The client by which {@link #mCurFocusedWindow} was reported.
Yohei Yukawae39d4ed2015-11-19 03:38:49 -0800523 */
524 ClientState mCurFocusedWindowClient;
525
526 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800527 * The input context last provided by the current client.
528 */
529 IInputContext mCurInputContext;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800530
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 /**
Yohei Yukawa19a80a12016-03-14 22:57:37 -0700532 * The missing method flags for the input context last provided by the current client.
533 *
534 * @see android.view.inputmethod.InputConnectionInspector.MissingMethodFlags
535 */
Yohei Yukawa432cf602018-10-21 10:41:37 -0700536 @MissingMethodFlags
Yohei Yukawa19a80a12016-03-14 22:57:37 -0700537 int mCurInputContextMissingMethods;
538
539 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800540 * The attributes last provided by the current client.
541 */
542 EditorInfo mCurAttribute;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 /**
Yohei Yukawab4f328a2019-05-02 08:41:27 -0700545 * A special {@link Matrix} to convert virtual screen coordinates to the IME target display
546 * coordinates.
547 *
548 * <p>Used only while the IME client is running in a virtual display inside
549 * {@link android.app.ActivityView}. {@code null} otherwise.</p>
550 */
551 @Nullable
552 private Matrix mCurActivityViewToScreenMatrix = null;
553
554 /**
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700555 * Id obtained with {@link InputMethodInfo#getId()} for the input method that we are currently
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800556 * connected to or in the process of connecting to.
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700557 *
558 * <p>This can be {@code null} when no input method is connected.</p>
559 *
560 * @see #mCurMethodId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 */
Yohei Yukawae13a20fa2015-09-30 19:11:32 -0700562 @Nullable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 String mCurId;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800564
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565 /**
satokab751aa2010-09-14 19:17:36 +0900566 * The current subtype of the current input method.
567 */
568 private InputMethodSubtype mCurrentSubtype;
569
John Spurlocke0980502013-10-25 11:59:29 -0400570 // Was the keyguard locked when this client became current?
571 private boolean mCurClientInKeyguard;
572
satokab751aa2010-09-14 19:17:36 +0900573 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574 * Set to true if our ServiceConnection is currently actively bound to
575 * a service (whether or not we have gotten its IBinder back yet).
576 */
577 boolean mHaveConnection;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800578
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 /**
580 * Set if the client has asked for the input method to be shown.
581 */
582 boolean mShowRequested;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800583
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 /**
585 * Set if we were explicitly told to show the input method.
586 */
587 boolean mShowExplicitlyRequested;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800588
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589 /**
590 * Set if we were forced to be shown.
591 */
592 boolean mShowForced;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800593
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 /**
595 * Set if we last told the input method to show itself.
596 */
597 boolean mInputShown;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800598
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 /**
Yohei Yukawa2bc66172017-02-08 11:13:25 -0800600 * {@code true} if the current input method is in fullscreen mode.
601 */
602 boolean mInFullscreenMode;
603
604 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605 * The Intent used to connect to the current input method.
606 */
607 Intent mCurIntent;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800608
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 /**
610 * The token we have made for the currently active input method, to
611 * identify it in the future.
612 */
613 IBinder mCurToken;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800614
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 /**
lumark90120a82018-08-15 00:33:03 +0800616 * The displayId of current active input method.
617 */
618 int mCurTokenDisplayId = INVALID_DISPLAY;
619
lumark7570cac2019-03-07 22:14:38 +0800620 /**
621 * The display ID of the input method indicates the fallback display which returned by
622 * {@link #computeImeDisplayIdForTarget}.
623 */
624 private static final int FALLBACK_DISPLAY_ID = DEFAULT_DISPLAY;
625
lumarkef1965b2018-09-12 17:42:53 +0800626 final ImeDisplayValidator mImeDisplayValidator;
627
lumark90120a82018-08-15 00:33:03 +0800628 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629 * If non-null, this is the input method service we are currently connected
630 * to.
631 */
632 IInputMethod mCurMethod;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800633
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800634 /**
635 * Time that we last initiated a bind to the input method, to determine
636 * if we should try to disconnect and reconnect to it.
637 */
638 long mLastBindTime;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800639
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800640 /**
641 * Have we called mCurMethod.bindInput()?
642 */
643 boolean mBoundToMethod;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800644
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800645 /**
646 * Currently enabled session. Only touched by service thread, not
647 * protected by a lock.
648 */
649 SessionState mEnabledSession;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800650
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651 /**
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700652 * True if the device is currently interactive with user. The value is true initially.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 */
Yohei Yukawafa6e0a82015-07-23 15:08:59 -0700654 boolean mIsInteractive = true;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800655
Joe Onorato857fd9b2011-01-27 15:08:35 -0800656 int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
Seigo Nonakad9eb9112015-05-26 20:54:43 +0900657
658 /**
659 * A set of status bits regarding the active IME.
660 *
661 * <p>This value is a combination of following two bits:</p>
662 * <dl>
663 * <dt>{@link InputMethodService#IME_ACTIVE}</dt>
664 * <dd>
665 * If this bit is ON, connected IME is ready to accept touch/key events.
666 * </dd>
667 * <dt>{@link InputMethodService#IME_VISIBLE}</dt>
668 * <dd>
669 * If this bit is ON, some of IME view, e.g. software input, candidate view, is visible.
670 * </dd>
Tarandeep Singheadb1392018-11-09 18:15:57 +0100671 * dt>{@link InputMethodService#IME_INVISIBLE}</dt>
672 * <dd> If this bit is ON, IME is ready with views from last EditorInfo but is
673 * currently invisible.
674 * </dd>
Seigo Nonakad9eb9112015-05-26 20:54:43 +0900675 * </dl>
lumark7570cac2019-03-07 22:14:38 +0800676 * <em>Do not update this value outside of {@link #setImeWindowStatus(IBinder, int, int)} and
677 * {@link #unbindCurrentMethodLocked()}.</em>
Seigo Nonakad9eb9112015-05-26 20:54:43 +0900678 */
Joe Onorato857fd9b2011-01-27 15:08:35 -0800679 int mImeWindowVis;
680
Ken Wakasa05dbb652011-08-22 15:22:43 +0900681 private AlertDialog.Builder mDialogBuilder;
682 private AlertDialog mSwitchingDialog;
Wale Ogunwale3a931692016-11-02 16:49:48 -0700683 private IBinder mSwitchingDialogToken = new Binder();
satok01038492012-04-09 21:08:27 +0900684 private View mSwitchingDialogTitleView;
Ken Wakasa05dbb652011-08-22 15:22:43 +0900685 private InputMethodInfo[] mIms;
686 private int[] mSubtypeIds;
Yohei Yukawae985c242016-02-24 18:27:04 -0800687 private LocaleList mLastSystemLocales;
Michael Wright7b5a96b2014-08-09 19:28:42 -0700688 private boolean mShowImeWithHardKeyboard;
Anna Galusza9b278112016-01-04 11:37:37 -0800689 private boolean mAccessibilityRequestingNoSoftKeyboard;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +0900690 private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
691 private final IPackageManager mIPackageManager;
Jason Monk3e189872016-01-12 09:10:34 -0500692 private final String mSlotIme;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800693
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800694 /**
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +0900695 * Registered {@link InputMethodListListeners}.
696 * This variable can be accessed from both of MainThread and BinderThread.
697 */
698 private final CopyOnWriteArrayList<InputMethodListListener> mInputMethodListListeners =
699 new CopyOnWriteArrayList<>();
700
701 /**
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800702 * Internal state snapshot when {@link #MSG_START_INPUT} message is about to be posted to the
703 * internal message queue. Any subsequent state change inside {@link InputMethodManagerService}
704 * will not affect those tasks that are already posted.
705 *
706 * <p>Posting {@link #MSG_START_INPUT} message basically means that
707 * {@link InputMethodService#doStartInput(InputConnection, EditorInfo, boolean)} will be called
708 * back in the current IME process shortly, which will also affect what the current IME starts
709 * receiving from {@link InputMethodService#getCurrentInputConnection()}. In other words, this
710 * snapshot will be taken every time when {@link InputMethodManagerService} is initiating a new
711 * logical input session between the client application and the current IME.</p>
712 *
713 * <p>Be careful to not keep strong references to this object forever, which can prevent
714 * {@link StartInputInfo#mImeToken} and {@link StartInputInfo#mTargetWindow} from being GC-ed.
715 * </p>
716 */
717 private static class StartInputInfo {
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800718 private static final AtomicInteger sSequenceNumber = new AtomicInteger(0);
719
720 final int mSequenceNumber;
721 final long mTimestamp;
722 final long mWallTime;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800723 @UserIdInt
724 final int mImeUserId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800725 @NonNull
726 final IBinder mImeToken;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800727 final int mImeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800728 @NonNull
729 final String mImeId;
Yohei Yukawadc66e522018-10-21 10:43:14 -0700730 @StartInputReason
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800731 final int mStartInputReason;
732 final boolean mRestarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800733 @UserIdInt
734 final int mTargetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800735 final int mTargetDisplayId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800736 @Nullable
737 final IBinder mTargetWindow;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800738 @NonNull
739 final EditorInfo mEditorInfo;
Yohei Yukawab0c26452018-10-21 10:42:52 -0700740 @SoftInputModeFlags
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800741 final int mTargetWindowSoftInputMode;
742 final int mClientBindSequenceNumber;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800743
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800744 StartInputInfo(@UserIdInt int imeUserId, @NonNull IBinder imeToken, int imeDisplayId,
745 @NonNull String imeId, @StartInputReason int startInputReason, boolean restarting,
746 @UserIdInt int targetUserId, int targetDisplayId, @Nullable IBinder targetWindow,
747 @NonNull EditorInfo editorInfo, @SoftInputModeFlags int targetWindowSoftInputMode,
748 int clientBindSequenceNumber) {
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800749 mSequenceNumber = sSequenceNumber.getAndIncrement();
750 mTimestamp = SystemClock.uptimeMillis();
751 mWallTime = System.currentTimeMillis();
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800752 mImeUserId = imeUserId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800753 mImeToken = imeToken;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800754 mImeDisplayId = imeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800755 mImeId = imeId;
756 mStartInputReason = startInputReason;
757 mRestarting = restarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800758 mTargetUserId = targetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800759 mTargetDisplayId = targetDisplayId;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800760 mTargetWindow = targetWindow;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800761 mEditorInfo = editorInfo;
762 mTargetWindowSoftInputMode = targetWindowSoftInputMode;
763 mClientBindSequenceNumber = clientBindSequenceNumber;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800764 }
765 }
766
Yohei Yukawab37d8bd2017-02-13 18:29:05 -0800767 @GuardedBy("mMethodMap")
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -0700768 private final WeakHashMap<IBinder, IBinder> mImeTargetWindowMap = new WeakHashMap<>();
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800769
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800770 /**
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -0800771 * Map of generated token to windowToken that is requesting
772 * {@link InputMethodManager#showSoftInput(View, int)}.
773 * This map tracks origin of showSoftInput requests.
774 */
775 @GuardedBy("mMethodMap")
776 private final WeakHashMap<IBinder, IBinder> mShowRequestWindowMap = new WeakHashMap<>();
777
778 /**
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800779 * A ring buffer to store the history of {@link StartInputInfo}.
780 */
781 private static final class StartInputHistory {
782 /**
783 * Entry size for non low-RAM devices.
784 *
785 * <p>TODO: Consider to follow what other system services have been doing to manage
786 * constants (e.g. {@link android.provider.Settings.Global#ACTIVITY_MANAGER_CONSTANTS}).</p>
787 */
788 private final static int ENTRY_SIZE_FOR_HIGH_RAM_DEVICE = 16;
789
790 /**
791 * Entry size for non low-RAM devices.
792 *
793 * <p>TODO: Consider to follow what other system services have been doing to manage
794 * constants (e.g. {@link android.provider.Settings.Global#ACTIVITY_MANAGER_CONSTANTS}).</p>
795 */
796 private final static int ENTRY_SIZE_FOR_LOW_RAM_DEVICE = 5;
797
798 private static int getEntrySize() {
799 if (ActivityManager.isLowRamDeviceStatic()) {
800 return ENTRY_SIZE_FOR_LOW_RAM_DEVICE;
801 } else {
802 return ENTRY_SIZE_FOR_HIGH_RAM_DEVICE;
803 }
804 }
805
806 /**
807 * Backing store for the ring bugger.
808 */
809 private final Entry[] mEntries = new Entry[getEntrySize()];
810
811 /**
812 * An index of {@link #mEntries}, to which next {@link #addEntry(StartInputInfo)} should
813 * write.
814 */
815 private int mNextIndex = 0;
816
817 /**
818 * Recyclable entry to store the information in {@link StartInputInfo}.
819 */
820 private static final class Entry {
821 int mSequenceNumber;
822 long mTimestamp;
823 long mWallTime;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800824 @UserIdInt
825 int mImeUserId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800826 @NonNull
827 String mImeTokenString;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800828 int mImeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800829 @NonNull
830 String mImeId;
Yohei Yukawadc66e522018-10-21 10:43:14 -0700831 @StartInputReason
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800832 int mStartInputReason;
833 boolean mRestarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800834 @UserIdInt
835 int mTargetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800836 int mTargetDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800837 @NonNull
838 String mTargetWindowString;
839 @NonNull
840 EditorInfo mEditorInfo;
Yohei Yukawab0c26452018-10-21 10:42:52 -0700841 @SoftInputModeFlags
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800842 int mTargetWindowSoftInputMode;
843 int mClientBindSequenceNumber;
844
845 Entry(@NonNull StartInputInfo original) {
846 set(original);
847 }
848
849 void set(@NonNull StartInputInfo original) {
850 mSequenceNumber = original.mSequenceNumber;
851 mTimestamp = original.mTimestamp;
852 mWallTime = original.mWallTime;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800853 mImeUserId = original.mImeUserId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800854 // Intentionally convert to String so as not to keep a strong reference to a Binder
855 // object.
856 mImeTokenString = String.valueOf(original.mImeToken);
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800857 mImeDisplayId = original.mImeDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800858 mImeId = original.mImeId;
859 mStartInputReason = original.mStartInputReason;
860 mRestarting = original.mRestarting;
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800861 mTargetUserId = original.mTargetUserId;
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800862 mTargetDisplayId = original.mTargetDisplayId;
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800863 // Intentionally convert to String so as not to keep a strong reference to a Binder
864 // object.
865 mTargetWindowString = String.valueOf(original.mTargetWindow);
866 mEditorInfo = original.mEditorInfo;
867 mTargetWindowSoftInputMode = original.mTargetWindowSoftInputMode;
868 mClientBindSequenceNumber = original.mClientBindSequenceNumber;
869 }
870 }
871
872 /**
873 * Add a new entry and discard the oldest entry as needed.
874 * @param info {@lin StartInputInfo} to be added.
875 */
876 void addEntry(@NonNull StartInputInfo info) {
877 final int index = mNextIndex;
878 if (mEntries[index] == null) {
879 mEntries[index] = new Entry(info);
880 } else {
881 mEntries[index].set(info);
882 }
883 mNextIndex = (mNextIndex + 1) % mEntries.length;
884 }
885
886 void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
887 final SimpleDateFormat dataFormat =
888 new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
889
890 for (int i = 0; i < mEntries.length; ++i) {
891 final Entry entry = mEntries[(i + mNextIndex) % mEntries.length];
892 if (entry == null) {
893 continue;
894 }
895 pw.print(prefix);
896 pw.println("StartInput #" + entry.mSequenceNumber + ":");
897
898 pw.print(prefix);
899 pw.println(" time=" + dataFormat.format(new Date(entry.mWallTime))
900 + " (timestamp=" + entry.mTimestamp + ")"
901 + " reason="
Yohei Yukawaa468d702018-10-21 11:42:34 -0700902 + InputMethodDebug.startInputReasonToString(entry.mStartInputReason)
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800903 + " restarting=" + entry.mRestarting);
904
905 pw.print(prefix);
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800906 pw.print(" imeToken=" + entry.mImeTokenString + " [" + entry.mImeId + "]");
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800907 pw.print(" imeUserId=" + entry.mImeUserId);
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800908 pw.println(" imeDisplayId=" + entry.mImeDisplayId);
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800909
910 pw.print(prefix);
911 pw.println(" targetWin=" + entry.mTargetWindowString
912 + " [" + entry.mEditorInfo.packageName + "]"
Yohei Yukawa7979e1a2019-02-12 02:01:10 -0800913 + " targetUserId=" + entry.mTargetUserId
Yohei Yukawa557afbb2019-02-12 02:01:00 -0800914 + " targetDisplayId=" + entry.mTargetDisplayId
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800915 + " clientBindSeq=" + entry.mClientBindSequenceNumber);
916
917 pw.print(prefix);
Yohei Yukawaa468d702018-10-21 11:42:34 -0700918 pw.println(" softInputMode=" + InputMethodDebug.softInputModeToString(
Yohei Yukawa357b2f62017-02-14 09:40:03 -0800919 entry.mTargetWindowSoftInputMode));
920
921 pw.print(prefix);
922 pw.println(" inputType=0x" + Integer.toHexString(entry.mEditorInfo.inputType)
923 + " imeOptions=0x" + Integer.toHexString(entry.mEditorInfo.imeOptions)
924 + " fieldId=0x" + Integer.toHexString(entry.mEditorInfo.fieldId)
925 + " fieldName=" + entry.mEditorInfo.fieldName
926 + " actionId=" + entry.mEditorInfo.actionId
927 + " actionLabel=" + entry.mEditorInfo.actionLabel);
928 }
929 }
930 }
931
932 @GuardedBy("mMethodMap")
933 @NonNull
934 private final StartInputHistory mStartInputHistory = new StartInputHistory();
935
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936 class SettingsObserver extends ContentObserver {
Yohei Yukawa81482972015-06-04 00:58:59 -0700937 int mUserId;
938 boolean mRegistered = false;
Yohei Yukawa7b574cb2016-03-16 17:22:22 -0700939 @NonNull
Dianne Hackbornfd7aded2013-01-22 17:10:23 -0800940 String mLastEnabled = "";
941
Yohei Yukawa81482972015-06-04 00:58:59 -0700942 /**
943 * <em>This constructor must be called within the lock.</em>
944 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 SettingsObserver(Handler handler) {
946 super(handler);
Yohei Yukawa81482972015-06-04 00:58:59 -0700947 }
948
Yohei Yukawa7b18aec2016-03-07 13:04:32 -0800949 public void registerContentObserverLocked(@UserIdInt int userId) {
Yohei Yukawa81482972015-06-04 00:58:59 -0700950 if (mRegistered && mUserId == userId) {
951 return;
952 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 ContentResolver resolver = mContext.getContentResolver();
Yohei Yukawa81482972015-06-04 00:58:59 -0700954 if (mRegistered) {
955 mContext.getContentResolver().unregisterContentObserver(this);
956 mRegistered = false;
957 }
958 if (mUserId != userId) {
959 mLastEnabled = "";
960 mUserId = userId;
961 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -0700963 Settings.Secure.DEFAULT_INPUT_METHOD), false, this, userId);
satokab751aa2010-09-14 19:17:36 +0900964 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -0700965 Settings.Secure.ENABLED_INPUT_METHODS), false, this, userId);
satokb6109bb2011-02-03 22:24:54 +0900966 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -0700967 Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this, userId);
Michael Wright7b5a96b2014-08-09 19:28:42 -0700968 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa81482972015-06-04 00:58:59 -0700969 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, this, userId);
Anna Galusza9b278112016-01-04 11:37:37 -0800970 resolver.registerContentObserver(Settings.Secure.getUriFor(
971 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE), false, this, userId);
Yohei Yukawa81482972015-06-04 00:58:59 -0700972 mRegistered = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800974
Michael Wright7b5a96b2014-08-09 19:28:42 -0700975 @Override public void onChange(boolean selfChange, Uri uri) {
Anna Galusza9b278112016-01-04 11:37:37 -0800976 final Uri showImeUri = Settings.Secure.getUriFor(
977 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
978 final Uri accessibilityRequestingNoImeUri = Settings.Secure.getUriFor(
979 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 synchronized (mMethodMap) {
Michael Wright7b5a96b2014-08-09 19:28:42 -0700981 if (showImeUri.equals(uri)) {
982 updateKeyboardFromSettingsLocked();
Anna Galusza9b278112016-01-04 11:37:37 -0800983 } else if (accessibilityRequestingNoImeUri.equals(uri)) {
Phil Weaver03a65b02018-07-19 16:07:57 -0700984 final int accessibilitySoftKeyboardSetting = Settings.Secure.getIntForUser(
Anna Galusza9b278112016-01-04 11:37:37 -0800985 mContext.getContentResolver(),
Phil Weaver03a65b02018-07-19 16:07:57 -0700986 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0, mUserId);
987 mAccessibilityRequestingNoSoftKeyboard =
988 (accessibilitySoftKeyboardSetting & AccessibilityService.SHOW_MODE_MASK)
989 == AccessibilityService.SHOW_MODE_HIDDEN;
Anna Galusza9b278112016-01-04 11:37:37 -0800990 if (mAccessibilityRequestingNoSoftKeyboard) {
991 final boolean showRequested = mShowRequested;
992 hideCurrentInputLocked(0, null);
993 mShowRequested = showRequested;
994 } else if (mShowRequested) {
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -0800995 showCurrentInputLocked(
996 mCurFocusedWindow, InputMethodManager.SHOW_IMPLICIT, null);
Anna Galusza9b278112016-01-04 11:37:37 -0800997 }
Michael Wright7b5a96b2014-08-09 19:28:42 -0700998 } else {
999 boolean enabledChanged = false;
1000 String newEnabled = mSettings.getEnabledInputMethodsStr();
1001 if (!mLastEnabled.equals(newEnabled)) {
1002 mLastEnabled = newEnabled;
1003 enabledChanged = true;
1004 }
1005 updateInputMethodsFromSettingsLocked(enabledChanged);
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08001006 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 }
1008 }
Yohei Yukawa81482972015-06-04 00:58:59 -07001009
1010 @Override
1011 public String toString() {
1012 return "SettingsObserver{mUserId=" + mUserId + " mRegistered=" + mRegistered
1013 + " mLastEnabled=" + mLastEnabled + "}";
1014 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001016
Yohei Yukawa0ec08002019-03-08 10:48:26 -08001017 /**
1018 * {@link BroadcastReceiver} that is intended to listen to broadcasts sent to the system user
1019 * only.
1020 */
1021 private final class ImmsBroadcastReceiverForSystemUser extends BroadcastReceiver {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001022 @Override
1023 public void onReceive(Context context, Intent intent) {
1024 final String action = intent.getAction();
Yohei Yukawa4225c7d2019-03-08 00:06:11 -08001025 if (Intent.ACTION_USER_ADDED.equals(action)
Amith Yamasani734983f2014-03-04 16:48:05 -08001026 || Intent.ACTION_USER_REMOVED.equals(action)) {
Kenny Guy2a764942014-04-02 13:29:20 +01001027 updateCurrentProfileIds();
Amith Yamasani734983f2014-03-04 16:48:05 -08001028 return;
Yohei Yukawa79247822017-01-23 15:26:15 -08001029 } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001030 onActionLocaleChanged();
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001031 } else if (ACTION_SHOW_INPUT_METHOD_PICKER.equals(action)) {
1032 // ACTION_SHOW_INPUT_METHOD_PICKER action is a protected-broadcast and it is
1033 // guaranteed to be send only from the system, so that there is no need for extra
1034 // security check such as
1035 // {@link #canShowInputMethodPickerLocked(IInputMethodClient)}.
1036 mHandler.obtainMessage(
1037 MSG_SHOW_IM_SUBTYPE_PICKER,
lumark0b05f9e2018-11-26 15:09:06 +08001038 // TODO(b/120076400): Design and implement IME switcher for heterogeneous
1039 // navbar configuration.
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001040 InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES,
lumark0b05f9e2018-11-26 15:09:06 +08001041 DEFAULT_DISPLAY).sendToTarget();
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001042 } else {
1043 Slog.w(TAG, "Unexpected intent " + intent);
1044 }
1045 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001047
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001048 /**
Yohei Yukawa0ec08002019-03-08 10:48:26 -08001049 * {@link BroadcastReceiver} that is intended to listen to broadcasts sent to all the users.
1050 */
1051 private final class ImmsBroadcastReceiverForAllUsers extends BroadcastReceiver {
1052 @Override
1053 public void onReceive(Context context, Intent intent) {
1054 final String action = intent.getAction();
1055 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
1056 final PendingResult pendingResult = getPendingResult();
1057 if (pendingResult == null) {
1058 return;
1059 }
1060 // sender userId can be a real user ID or USER_ALL.
1061 final int senderUserId = pendingResult.getSendingUserId();
1062 if (senderUserId != UserHandle.USER_ALL) {
Tarandeep Singhcf5ff822019-07-08 14:06:27 -07001063 if (senderUserId != mSettings.getCurrentUserId()) {
Yohei Yukawa0ec08002019-03-08 10:48:26 -08001064 // A background user is trying to hide the dialog. Ignore.
1065 return;
1066 }
1067 }
1068 hideInputMethodMenu();
1069 } else {
1070 Slog.w(TAG, "Unexpected intent " + intent);
1071 }
1072 }
1073 }
1074
1075 /**
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001076 * Handles {@link Intent#ACTION_LOCALE_CHANGED}.
1077 *
1078 * <p>Note: For historical reasons, {@link Intent#ACTION_LOCALE_CHANGED} has been sent to all
1079 * the users. We should ignore this event if this is about any background user's locale.</p>
1080 *
1081 * <p>Caution: This method must not be called when system is not ready.</p>
1082 */
1083 void onActionLocaleChanged() {
1084 synchronized (mMethodMap) {
1085 final LocaleList possibleNewLocale = mRes.getConfiguration().getLocales();
1086 if (possibleNewLocale != null && possibleNewLocale.equals(mLastSystemLocales)) {
1087 return;
1088 }
1089 buildInputMethodListLocked(true);
1090 // If the locale is changed, needs to reset the default ime
1091 resetDefaultImeLocked(mContext);
1092 updateFromSettingsLocked(true);
1093 mLastSystemLocales = possibleNewLocale;
1094 }
1095 }
1096
Yohei Yukawac4e44912017-02-09 19:30:22 -08001097 final class MyPackageMonitor extends PackageMonitor {
1098 /**
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001099 * Package names that are known to contain {@link InputMethodService}.
Yohei Yukawac4e44912017-02-09 19:30:22 -08001100 *
1101 * <p>No need to include packages because of direct-boot unaware IMEs since we always rescan
1102 * all the packages when the user is unlocked, and direct-boot awareness will not be changed
1103 * dynamically unless the entire package is updated, which also always triggers package
1104 * rescanning.</p>
1105 */
1106 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001107 final private ArraySet<String> mKnownImePackageNames = new ArraySet<>();
1108
1109 /**
1110 * Packages that are appeared, disappeared, or modified for whatever reason.
1111 *
1112 * <p>Note: For now we intentionally use {@link ArrayList} instead of {@link ArraySet}
1113 * because 1) the number of elements is almost always 1 or so, and 2) we do not care
1114 * duplicate elements for our use case.</p>
1115 *
1116 * <p>This object must be accessed only from callback methods in {@link PackageMonitor},
1117 * which should be bound to {@link #getRegisteredHandler()}.</p>
1118 */
1119 private final ArrayList<String> mChangedPackages = new ArrayList<>();
1120
1121 /**
1122 * {@code true} if one or more packages that contain {@link InputMethodService} appeared.
1123 *
1124 * <p>This field must be accessed only from callback methods in {@link PackageMonitor},
1125 * which should be bound to {@link #getRegisteredHandler()}.</p>
1126 */
1127 private boolean mImePackageAppeared = false;
Yohei Yukawac4e44912017-02-09 19:30:22 -08001128
1129 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001130 void clearKnownImePackageNamesLocked() {
1131 mKnownImePackageNames.clear();
Yohei Yukawac4e44912017-02-09 19:30:22 -08001132 }
1133
1134 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001135 final void addKnownImePackageNameLocked(@NonNull String packageName) {
1136 mKnownImePackageNames.add(packageName);
Yohei Yukawac4e44912017-02-09 19:30:22 -08001137 }
1138
Yohei Yukawa278f2ab2017-02-14 19:51:33 -08001139 @GuardedBy("mMethodMap")
1140 private boolean isChangingPackagesOfCurrentUserLocked() {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001141 final int userId = getChangingUserId();
1142 final boolean retval = userId == mSettings.getCurrentUserId();
1143 if (DEBUG) {
satok81f8b7c2012-12-04 20:42:56 +09001144 if (!retval) {
1145 Slog.d(TAG, "--- ignore this call back from a background user: " + userId);
1146 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001147 }
1148 return retval;
1149 }
1150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001152 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001153 synchronized (mMethodMap) {
Yohei Yukawa278f2ab2017-02-14 19:51:33 -08001154 if (!isChangingPackagesOfCurrentUserLocked()) {
1155 return false;
1156 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001157 String curInputMethodId = mSettings.getSelectedInputMethod();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001158 final int N = mMethodList.size();
1159 if (curInputMethodId != null) {
1160 for (int i=0; i<N; i++) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001161 InputMethodInfo imi = mMethodList.get(i);
1162 if (imi.getId().equals(curInputMethodId)) {
1163 for (String pkg : packages) {
1164 if (imi.getPackageName().equals(pkg)) {
1165 if (!doit) {
1166 return true;
1167 }
satok723a27e2010-11-11 14:58:11 +09001168 resetSelectedInputMethodAndSubtypeLocked("");
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001169 chooseNewDefaultIMELocked();
1170 return true;
1171 }
1172 }
1173 }
1174 }
1175 }
1176 }
1177 return false;
1178 }
1179
1180 @Override
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001181 public void onBeginPackageChanges() {
1182 clearPackageChangeState();
1183 }
1184
1185 @Override
1186 public void onPackageAppeared(String packageName, int reason) {
1187 if (!mImePackageAppeared) {
1188 final PackageManager pm = mContext.getPackageManager();
1189 final List<ResolveInfo> services = pm.queryIntentServicesAsUser(
1190 new Intent(InputMethod.SERVICE_INTERFACE).setPackage(packageName),
Yohei Yukawa5ec1fce2018-12-17 07:56:14 -08001191 PackageManager.MATCH_DISABLED_COMPONENTS, getChangingUserId());
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001192 // No need to lock this because we access it only on getRegisteredHandler().
1193 if (!services.isEmpty()) {
1194 mImePackageAppeared = true;
1195 }
1196 }
1197 // No need to lock this because we access it only on getRegisteredHandler().
1198 mChangedPackages.add(packageName);
1199 }
1200
1201 @Override
1202 public void onPackageDisappeared(String packageName, int reason) {
1203 // No need to lock this because we access it only on getRegisteredHandler().
1204 mChangedPackages.add(packageName);
1205 }
1206
1207 @Override
1208 public void onPackageModified(String packageName) {
1209 // No need to lock this because we access it only on getRegisteredHandler().
1210 mChangedPackages.add(packageName);
1211 }
1212
1213 @Override
1214 public void onPackagesSuspended(String[] packages) {
1215 // No need to lock this because we access it only on getRegisteredHandler().
1216 for (String packageName : packages) {
1217 mChangedPackages.add(packageName);
Yohei Yukawac4e44912017-02-09 19:30:22 -08001218 }
1219 }
1220
1221 @Override
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001222 public void onPackagesUnsuspended(String[] packages) {
1223 // No need to lock this because we access it only on getRegisteredHandler().
1224 for (String packageName : packages) {
1225 mChangedPackages.add(packageName);
1226 }
1227 }
1228
1229 @Override
1230 public void onFinishPackageChanges() {
1231 onFinishPackageChangesInternal();
1232 clearPackageChangeState();
1233 }
1234
1235 private void clearPackageChangeState() {
1236 // No need to lock them because we access these fields only on getRegisteredHandler().
1237 mChangedPackages.clear();
1238 mImePackageAppeared = false;
1239 }
1240
Andreas Gampea36dc622018-02-05 17:19:22 -08001241 @GuardedBy("mMethodMap")
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001242 private boolean shouldRebuildInputMethodListLocked() {
1243 // This method is guaranteed to be called only by getRegisteredHandler().
1244
1245 // If there is any new package that contains at least one IME, then rebuilt the list
1246 // of IMEs.
1247 if (mImePackageAppeared) {
1248 return true;
1249 }
1250
1251 // Otherwise, check if mKnownImePackageNames and mChangedPackages have any intersection.
1252 // TODO: Consider to create a utility method to do the following test. List.retainAll()
1253 // is an option, but it may still do some extra operations that we do not need here.
1254 final int N = mChangedPackages.size();
1255 for (int i = 0; i < N; ++i) {
1256 final String packageName = mChangedPackages.get(i);
1257 if (mKnownImePackageNames.contains(packageName)) {
1258 return true;
1259 }
1260 }
1261 return false;
1262 }
1263
1264 private void onFinishPackageChangesInternal() {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001265 synchronized (mMethodMap) {
Yohei Yukawa278f2ab2017-02-14 19:51:33 -08001266 if (!isChangingPackagesOfCurrentUserLocked()) {
1267 return;
1268 }
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08001269 if (!shouldRebuildInputMethodListLocked()) {
1270 return;
1271 }
1272
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001273 InputMethodInfo curIm = null;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001274 String curInputMethodId = mSettings.getSelectedInputMethod();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001275 final int N = mMethodList.size();
1276 if (curInputMethodId != null) {
1277 for (int i=0; i<N; i++) {
1278 InputMethodInfo imi = mMethodList.get(i);
satoke7c6998e2011-06-03 17:57:59 +09001279 final String imiId = imi.getId();
1280 if (imiId.equals(curInputMethodId)) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001281 curIm = imi;
1282 }
satoke7c6998e2011-06-03 17:57:59 +09001283
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001284 int change = isPackageDisappearing(imi.getPackageName());
satoke7c6998e2011-06-03 17:57:59 +09001285 if (isPackageModified(imi.getPackageName())) {
Yohei Yukawab557d572018-12-29 21:26:26 -08001286 mAdditionalSubtypeMap.remove(imi.getId());
1287 AdditionalSubtypeUtils.save(mAdditionalSubtypeMap, mMethodMap,
1288 mSettings.getCurrentUserId());
satoke7c6998e2011-06-03 17:57:59 +09001289 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001290 if (change == PACKAGE_TEMPORARY_CHANGE
1291 || change == PACKAGE_PERMANENT_CHANGE) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001292 Slog.i(TAG, "Input method uninstalled, disabling: "
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001293 + imi.getComponent());
1294 setInputMethodEnabledLocked(imi.getId(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001295 }
1296 }
1297 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001298
Yohei Yukawa94e33302016-02-12 19:37:03 -08001299 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001300
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001301 boolean changed = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001302
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001303 if (curIm != null) {
Anna Galusza9b278112016-01-04 11:37:37 -08001304 int change = isPackageDisappearing(curIm.getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001305 if (change == PACKAGE_TEMPORARY_CHANGE
1306 || change == PACKAGE_PERMANENT_CHANGE) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001307 ServiceInfo si = null;
1308 try {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001309 si = mIPackageManager.getServiceInfo(
1310 curIm.getComponent(), 0, mSettings.getCurrentUserId());
1311 } catch (RemoteException ex) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001312 }
1313 if (si == null) {
1314 // Uh oh, current input method is no longer around!
1315 // Pick another one...
Joe Onorato8a9b2202010-02-26 18:56:32 -08001316 Slog.i(TAG, "Current input method removed: " + curInputMethodId);
Yohei Yukawa849443c2019-01-21 09:02:25 -08001317 updateSystemUiLocked(0 /* vis */, mBackDisposition);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001318 if (!chooseNewDefaultIMELocked()) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001319 changed = true;
1320 curIm = null;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001321 Slog.i(TAG, "Unsetting current input method");
satok723a27e2010-11-11 14:58:11 +09001322 resetSelectedInputMethodAndSubtypeLocked("");
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001323 }
1324 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001325 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001326 }
satokab751aa2010-09-14 19:17:36 +09001327
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001328 if (curIm == null) {
1329 // We currently don't have a default input method... is
1330 // one now available?
1331 changed = chooseNewDefaultIMELocked();
Yohei Yukawa54d512c2015-05-19 22:15:02 -07001332 } else if (!changed && isPackageModified(curIm.getPackageName())) {
1333 // Even if the current input method is still available, mCurrentSubtype could
1334 // be obsolete when the package is modified in practice.
1335 changed = true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001336 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001337
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001338 if (changed) {
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08001339 updateFromSettingsLocked(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001340 }
1341 }
1342 }
1343 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001344
Jeff Brownc28867a2013-03-26 15:42:39 -07001345 private static final class MethodCallback extends IInputSessionCallback.Stub {
Jean Chalarde0d32a62011-10-20 20:36:07 +09001346 private final InputMethodManagerService mParentIMMS;
Jeff Brownc28867a2013-03-26 15:42:39 -07001347 private final IInputMethod mMethod;
1348 private final InputChannel mChannel;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001349
Jeff Brownc28867a2013-03-26 15:42:39 -07001350 MethodCallback(InputMethodManagerService imms, IInputMethod method,
1351 InputChannel channel) {
Jean Chalarde0d32a62011-10-20 20:36:07 +09001352 mParentIMMS = imms;
Jeff Brownc28867a2013-03-26 15:42:39 -07001353 mMethod = method;
1354 mChannel = channel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001355 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001356
satoke7c6998e2011-06-03 17:57:59 +09001357 @Override
Jeff Brownc28867a2013-03-26 15:42:39 -07001358 public void sessionCreated(IInputMethodSession session) {
Dianne Hackborn6b6b3fd2014-03-24 11:27:18 -07001359 long ident = Binder.clearCallingIdentity();
1360 try {
1361 mParentIMMS.onSessionCreated(mMethod, session, mChannel);
1362 } finally {
1363 Binder.restoreCallingIdentity(ident);
1364 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001365 }
1366 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001367
satok01038492012-04-09 21:08:27 +09001368 private class HardKeyboardListener
Seigo Nonaka7309b122015-08-17 18:34:13 -07001369 implements WindowManagerInternal.OnHardKeyboardStatusChangeListener {
satok01038492012-04-09 21:08:27 +09001370 @Override
Michael Wright7b5a96b2014-08-09 19:28:42 -07001371 public void onHardKeyboardStatusChange(boolean available) {
1372 mHandler.sendMessage(mHandler.obtainMessage(MSG_HARD_KEYBOARD_SWITCH_CHANGED,
1373 available ? 1 : 0));
satok01038492012-04-09 21:08:27 +09001374 }
1375
Michael Wright7b5a96b2014-08-09 19:28:42 -07001376 public void handleHardKeyboardStatusChange(boolean available) {
satok01038492012-04-09 21:08:27 +09001377 if (DEBUG) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07001378 Slog.w(TAG, "HardKeyboardStatusChanged: available=" + available);
satok01038492012-04-09 21:08:27 +09001379 }
1380 synchronized(mMethodMap) {
1381 if (mSwitchingDialog != null && mSwitchingDialogTitleView != null
1382 && mSwitchingDialog.isShowing()) {
1383 mSwitchingDialogTitleView.findViewById(
1384 com.android.internal.R.id.hard_keyboard_section).setVisibility(
1385 available ? View.VISIBLE : View.GONE);
1386 }
1387 }
1388 }
1389 }
1390
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001391 public static final class Lifecycle extends SystemService {
1392 private InputMethodManagerService mService;
1393
1394 public Lifecycle(Context context) {
1395 super(context);
1396 mService = new InputMethodManagerService(context);
1397 }
1398
1399 @Override
1400 public void onStart() {
1401 LocalServices.addService(InputMethodManagerInternal.class,
Yohei Yukawafffc0e52018-09-04 13:24:00 -07001402 new LocalServiceImpl(mService));
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001403 publishBinderService(Context.INPUT_METHOD_SERVICE, mService);
1404 }
1405
1406 @Override
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001407 public void onSwitchUser(@UserIdInt int userHandle) {
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07001408 // Called on ActivityManager thread.
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001409 // TODO: Dispatch this to a worker thread as needed.
1410 mService.onSwitchUser(userHandle);
1411 }
1412
1413 @Override
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001414 public void onBootPhase(int phase) {
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07001415 // Called on ActivityManager thread.
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001416 // TODO: Dispatch this to a worker thread as needed.
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001417 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
1418 StatusBarManagerService statusBarService = (StatusBarManagerService) ServiceManager
1419 .getService(Context.STATUS_BAR_SERVICE);
1420 mService.systemRunning(statusBarService);
1421 }
1422 }
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001423
1424 @Override
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07001425 public void onUnlockUser(final @UserIdInt int userHandle) {
1426 // Called on ActivityManager thread.
1427 mService.mHandler.sendMessage(mService.mHandler.obtainMessage(MSG_SYSTEM_UNLOCK_USER,
Fyodor Kupolov0f57cce2016-09-09 10:36:30 -07001428 userHandle /* arg1 */, 0 /* arg2 */));
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001429 }
1430 }
1431
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001432 void onUnlockUser(@UserIdInt int userId) {
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001433 synchronized(mMethodMap) {
1434 final int currentUserId = mSettings.getCurrentUserId();
1435 if (DEBUG) {
1436 Slog.d(TAG, "onUnlockUser: userId=" + userId + " curUserId=" + currentUserId);
1437 }
1438 if (userId != currentUserId) {
1439 return;
1440 }
1441 mSettings.switchCurrentUser(currentUserId, !mSystemReady);
Yohei Yukawa79247822017-01-23 15:26:15 -08001442 if (mSystemReady) {
1443 // We need to rebuild IMEs.
1444 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
1445 updateInputMethodsFromSettingsLocked(true /* enabledChanged */);
1446 }
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001447 }
Fyodor Kupolov1e33dc82016-01-21 12:02:58 -08001448 }
1449
Yohei Yukawa7b18aec2016-03-07 13:04:32 -08001450 void onSwitchUser(@UserIdInt int userId) {
1451 synchronized (mMethodMap) {
1452 switchUserLocked(userId);
1453 }
1454 }
1455
Seigo Nonaka7309b122015-08-17 18:34:13 -07001456 public InputMethodManagerService(Context context) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001457 mIPackageManager = AppGlobals.getPackageManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001458 mContext = context;
Dianne Hackborn7d3a5bc2010-11-29 22:52:12 -08001459 mRes = context.getResources();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 mHandler = new Handler(this);
Yohei Yukawa81482972015-06-04 00:58:59 -07001461 // Note: SettingsObserver doesn't register observers in its constructor.
1462 mSettingsObserver = new SettingsObserver(mHandler);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001463 mIWindowManager = IWindowManager.Stub.asInterface(
1464 ServiceManager.getService(Context.WINDOW_SERVICE));
Seigo Nonaka7309b122015-08-17 18:34:13 -07001465 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
Yohei Yukawab4f328a2019-05-02 08:41:27 -07001466 mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
lumark9a72d222019-03-30 18:31:45 +08001467 mImeDisplayValidator = displayId -> mWindowManagerInternal.shouldShowIme(displayId);
Mita Yuned218c72012-12-06 17:18:25 -08001468 mCaller = new HandlerCaller(context, null, new HandlerCaller.Callback() {
satoke7c6998e2011-06-03 17:57:59 +09001469 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001470 public void executeMessage(Message msg) {
1471 handleMessage(msg);
1472 }
Mita Yuned218c72012-12-06 17:18:25 -08001473 }, true /*asyncHandler*/);
Yohei Yukawad34e1482016-02-11 08:03:52 -08001474 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001475 mUserManager = mContext.getSystemService(UserManager.class);
Yohei Yukawa42081402019-01-15 09:57:50 -08001476 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
satok01038492012-04-09 21:08:27 +09001477 mHardKeyboardListener = new HardKeyboardListener();
Dianne Hackborn119bbc32013-03-22 17:27:25 -07001478 mHasFeature = context.getPackageManager().hasSystemFeature(
1479 PackageManager.FEATURE_INPUT_METHODS);
Jason Monk3e189872016-01-12 09:10:34 -05001480 mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
Tarandeep Singheadb1392018-11-09 18:15:57 +01001481 mIsLowRam = ActivityManager.isLowRamDeviceStatic();
satok7cfc0ed2011-06-20 21:29:36 +09001482
Chris Wren1ce4b6d2015-06-11 10:19:43 -04001483 Bundle extras = new Bundle();
1484 extras.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, true);
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001485 @ColorInt final int accentColor = mContext.getColor(
1486 com.android.internal.R.color.system_notification_accent_color);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05001487 mImeSwitcherNotification =
1488 new Notification.Builder(mContext, SystemNotificationChannels.VIRTUAL_KEYBOARD)
1489 .setSmallIcon(com.android.internal.R.drawable.ic_notification_ime_default)
1490 .setWhen(0)
1491 .setOngoing(true)
1492 .addExtras(extras)
1493 .setCategory(Notification.CATEGORY_SYSTEM)
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001494 .setColor(accentColor);
Daniel Sandler590d5152012-06-14 16:10:13 -04001495
Tadashi G. Takaoka01065a52017-07-19 14:10:24 +09001496 Intent intent = new Intent(ACTION_SHOW_INPUT_METHOD_PICKER)
1497 .setPackage(mContext.getPackageName());
satok683e2382011-07-12 08:28:52 +09001498 mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
satokb858c732011-07-22 19:54:34 +09001499
1500 mShowOngoingImeSwitcherForPhones = false;
satok7cfc0ed2011-06-20 21:29:36 +09001501
satok7cfc0ed2011-06-20 21:29:36 +09001502 mNotificationShown = false;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001503 int userId = 0;
1504 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001505 userId = ActivityManager.getService().getCurrentUser().id;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001506 } catch (RemoteException e) {
1507 Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
1508 }
satok913a8922010-08-26 21:53:41 +09001509
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08001510 mLastSwitchUserId = userId;
1511
satokd87c2592010-09-29 11:52:06 +09001512 // mSettings should be created before buildInputMethodListLocked
satokdf31ae62011-01-15 06:19:44 +09001513 mSettings = new InputMethodSettings(
Yohei Yukawaf9277532019-01-25 02:47:32 -08001514 mRes, context.getContentResolver(), mMethodMap, userId, !mSystemReady);
Svet Ganovadc1cf42015-06-15 16:36:24 -07001515
Kenny Guy2a764942014-04-02 13:29:20 +01001516 updateCurrentProfileIds();
Yohei Yukawab557d572018-12-29 21:26:26 -08001517 AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, userId);
Yohei Yukawa79247822017-01-23 15:26:15 -08001518 mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
1519 mSettings, context);
satok5b927c432012-05-01 20:09:34 +09001520 }
1521
satok5b927c432012-05-01 20:09:34 +09001522 private void resetDefaultImeLocked(Context context) {
1523 // Do not reset the default (current) IME when it is a 3rd-party IME
Yohei Yukawafd70fe82018-04-08 12:19:56 -07001524 if (mCurMethodId != null && !mMethodMap.get(mCurMethodId).isSystem()) {
satok5b927c432012-05-01 20:09:34 +09001525 return;
1526 }
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001527 final List<InputMethodInfo> suitableImes = InputMethodUtils.getDefaultEnabledImes(
Yohei Yukawaaf5cee82017-01-23 16:17:11 -08001528 context, mSettings.getEnabledInputMethodListLocked());
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001529 if (suitableImes.isEmpty()) {
1530 Slog.i(TAG, "No default found");
1531 return;
satok5b927c432012-05-01 20:09:34 +09001532 }
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001533 final InputMethodInfo defIm = suitableImes.get(0);
Yohei Yukawad0332832017-02-01 13:59:43 -08001534 if (DEBUG) {
1535 Slog.i(TAG, "Default found, using " + defIm.getId());
1536 }
Yohei Yukawac2393ac2016-02-18 00:30:45 -08001537 setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
satok5b927c432012-05-01 20:09:34 +09001538 }
1539
Andreas Gampea36dc622018-02-05 17:19:22 -08001540 @GuardedBy("mMethodMap")
Satoshi Kataoka5ade83b2012-09-26 22:59:41 +09001541 private void switchUserLocked(int newUserId) {
Yohei Yukawa90bf7082015-06-03 23:50:27 -07001542 if (DEBUG) Slog.d(TAG, "Switching user stage 1/3. newUserId=" + newUserId
1543 + " currentUserId=" + mSettings.getCurrentUserId());
1544
Yohei Yukawa81482972015-06-04 00:58:59 -07001545 // ContentObserver should be registered again when the user is changed
1546 mSettingsObserver.registerContentObserverLocked(newUserId);
Yohei Yukawa68645a62016-02-17 07:54:20 -08001547
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001548 // If the system is not ready or the device is not yed unlocked by the user, then we use
1549 // copy-on-write settings.
1550 final boolean useCopyOnWriteSettings =
Yohei Yukawa42081402019-01-15 09:57:50 -08001551 !mSystemReady || !mUserManagerInternal.isUserUnlockingOrUnlocked(newUserId);
Yohei Yukawa68645a62016-02-17 07:54:20 -08001552 mSettings.switchCurrentUser(newUserId, useCopyOnWriteSettings);
Kenny Guy2a764942014-04-02 13:29:20 +01001553 updateCurrentProfileIds();
Yohei Yukawab557d572018-12-29 21:26:26 -08001554 // Additional subtypes should be reset when the user is changed
1555 AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, newUserId);
Satoshi Kataoka7f7535f2013-02-18 12:54:16 +09001556 final String defaultImiId = mSettings.getSelectedInputMethod();
Yohei Yukawa90bf7082015-06-03 23:50:27 -07001557
1558 if (DEBUG) Slog.d(TAG, "Switching user stage 2/3. newUserId=" + newUserId
1559 + " defaultImiId=" + defaultImiId);
1560
Satoshi Kataoka7c4a2a12013-02-25 15:25:43 +09001561 // For secondary users, the list of enabled IMEs may not have been updated since the
1562 // callbacks to PackageMonitor are ignored for the secondary user. Here, defaultImiId may
1563 // not be empty even if the IME has been uninstalled by the primary user.
1564 // Even in such cases, IMMS works fine because it will find the most applicable
1565 // IME for that user.
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09001566 final boolean initialUserSwitch = TextUtils.isEmpty(defaultImiId);
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001567 mLastSystemLocales = mRes.getConfiguration().getLocales();
1568
1569 // TODO: Is it really possible that switchUserLocked() happens before system ready?
1570 if (mSystemReady) {
1571 hideCurrentInputLocked(0, null);
Yohei Yukawab7526452018-10-21 20:15:17 -07001572 resetCurrentMethodAndClient(UnbindReason.SWITCH_USER);
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001573 buildInputMethodListLocked(initialUserSwitch);
1574 if (TextUtils.isEmpty(mSettings.getSelectedInputMethod())) {
1575 // This is the first time of the user switch and
1576 // set the current ime to the proper one.
1577 resetDefaultImeLocked(mContext);
1578 }
1579 updateFromSettingsLocked(true);
Yohei Yukawa0d7aff82017-02-10 00:40:51 -08001580 }
1581
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09001582 if (initialUserSwitch) {
Yohei Yukawa094c71f2015-06-20 00:41:31 -07001583 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
1584 mSettings.getEnabledInputMethodListLocked(), newUserId,
1585 mContext.getBasePackageName());
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09001586 }
Yohei Yukawa90bf7082015-06-03 23:50:27 -07001587
1588 if (DEBUG) Slog.d(TAG, "Switching user stage 3/3. newUserId=" + newUserId
1589 + " selectedIme=" + mSettings.getSelectedInputMethod());
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08001590
1591 mLastSwitchUserId = newUserId;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001592 }
1593
Kenny Guy2a764942014-04-02 13:29:20 +01001594 void updateCurrentProfileIds() {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -07001595 mSettings.setCurrentProfileIds(
1596 mUserManager.getProfileIdsWithDisabled(mSettings.getCurrentUserId()));
Amith Yamasani734983f2014-03-04 16:48:05 -08001597 }
1598
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001599 @Override
1600 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1601 throws RemoteException {
1602 try {
1603 return super.onTransact(code, data, reply, flags);
1604 } catch (RuntimeException e) {
1605 // The input method manager only throws security exceptions, so let's
1606 // log all others.
1607 if (!(e instanceof SecurityException)) {
Dianne Hackborn164371f2013-10-01 19:10:13 -07001608 Slog.wtf(TAG, "Input Method Manager Crash", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001609 }
1610 throw e;
1611 }
1612 }
1613
Svetoslav Ganova0027152013-06-25 14:59:53 -07001614 public void systemRunning(StatusBarManagerService statusBar) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07001615 synchronized (mMethodMap) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001616 if (DEBUG) {
1617 Slog.d(TAG, "--- systemReady");
1618 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07001619 if (!mSystemReady) {
1620 mSystemReady = true;
Yohei Yukawa79247822017-01-23 15:26:15 -08001621 mLastSystemLocales = mRes.getConfiguration().getLocales();
Yohei Yukawa68645a62016-02-17 07:54:20 -08001622 final int currentUserId = mSettings.getCurrentUserId();
Yohei Yukawaed4952a2016-02-17 07:57:25 -08001623 mSettings.switchCurrentUser(currentUserId,
Yohei Yukawa42081402019-01-15 09:57:50 -08001624 !mUserManagerInternal.isUserUnlockingOrUnlocked(currentUserId));
Yohei Yukawad34e1482016-02-11 08:03:52 -08001625 mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
1626 mNotificationManager = mContext.getSystemService(NotificationManager.class);
Dianne Hackborn661cd522011-08-22 00:26:20 -07001627 mStatusBar = statusBar;
Griff Hazen6090c262016-03-25 08:11:24 -07001628 if (mStatusBar != null) {
1629 mStatusBar.setIconVisibility(mSlotIme, false);
1630 }
Yohei Yukawa849443c2019-01-21 09:02:25 -08001631 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
satokb858c732011-07-22 19:54:34 +09001632 mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
1633 com.android.internal.R.bool.show_ongoing_ime_switcher);
satok01038492012-04-09 21:08:27 +09001634 if (mShowOngoingImeSwitcherForPhones) {
Seigo Nonaka7309b122015-08-17 18:34:13 -07001635 mWindowManagerInternal.setOnHardKeyboardStatusChangeListener(
satok01038492012-04-09 21:08:27 +09001636 mHardKeyboardListener);
1637 }
Yohei Yukawa79247822017-01-23 15:26:15 -08001638
1639 mMyPackageMonitor.register(mContext, null, UserHandle.ALL, true);
1640 mSettingsObserver.registerContentObserverLocked(currentUserId);
1641
Yohei Yukawa0ec08002019-03-08 10:48:26 -08001642 final IntentFilter broadcastFilterForSystemUser = new IntentFilter();
1643 broadcastFilterForSystemUser.addAction(Intent.ACTION_USER_ADDED);
1644 broadcastFilterForSystemUser.addAction(Intent.ACTION_USER_REMOVED);
1645 broadcastFilterForSystemUser.addAction(Intent.ACTION_LOCALE_CHANGED);
1646 broadcastFilterForSystemUser.addAction(ACTION_SHOW_INPUT_METHOD_PICKER);
1647 mContext.registerReceiver(new ImmsBroadcastReceiverForSystemUser(),
1648 broadcastFilterForSystemUser);
1649
1650 final IntentFilter broadcastFilterForAllUsers = new IntentFilter();
1651 broadcastFilterForAllUsers.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
1652 mContext.registerReceiverAsUser(new ImmsBroadcastReceiverForAllUsers(),
1653 UserHandle.ALL, broadcastFilterForAllUsers, null, null);
Yohei Yukawa79247822017-01-23 15:26:15 -08001654
Yohei Yukawa1f9a3cb2017-10-26 15:00:59 -07001655 final String defaultImiId = mSettings.getSelectedInputMethod();
1656 final boolean imeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId);
1657 buildInputMethodListLocked(!imeSelectedOnBoot /* resetDefaultEnabledIme */);
Yohei Yukawa79247822017-01-23 15:26:15 -08001658 updateFromSettingsLocked(true);
1659 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
1660 mSettings.getEnabledInputMethodListLocked(), currentUserId,
1661 mContext.getBasePackageName());
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07001662 }
1663 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001664 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001665
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001666 // ---------------------------------------------------------------------------------------
1667 // Check whether or not this is a valid IPC. Assumes an IPC is valid when either
1668 // 1) it comes from the system process
1669 // 2) the calling process' user id is identical to the current user id IMMS thinks.
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08001670 @GuardedBy("mMethodMap")
Yohei Yukawa46d74762019-01-22 10:17:22 -08001671 private boolean calledFromValidUserLocked() {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001672 final int uid = Binder.getCallingUid();
1673 final int userId = UserHandle.getUserId(uid);
1674 if (DEBUG) {
1675 Slog.d(TAG, "--- calledFromForegroundUserOrSystemProcess ? "
1676 + "calling uid = " + uid + " system uid = " + Process.SYSTEM_UID
1677 + " calling userId = " + userId + ", foreground user id = "
Satoshi Kataoka87c29142013-07-31 23:11:54 +09001678 + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid()
1679 + InputMethodUtils.getApiCallStack());
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001680 }
Yohei Yukawaa878b952019-01-10 19:36:24 -08001681 if (uid == Process.SYSTEM_UID) {
1682 return true;
1683 }
1684 if (userId == mSettings.getCurrentUserId()) {
1685 return true;
1686 }
Satoshi Kataoka135e5fb2012-09-28 18:25:06 +09001687
1688 // Caveat: A process which has INTERACT_ACROSS_USERS_FULL gets results for the
1689 // foreground user, not for the user of that process. Accordingly InputMethodManagerService
1690 // must not manage background users' states in any functions.
1691 // Note that privacy-sensitive IPCs, such as setInputMethod, are still securely guarded
1692 // by a token.
1693 if (mContext.checkCallingOrSelfPermission(
1694 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1695 == PackageManager.PERMISSION_GRANTED) {
1696 if (DEBUG) {
1697 Slog.d(TAG, "--- Access granted because the calling process has "
1698 + "the INTERACT_ACROSS_USERS_FULL permission");
1699 }
1700 return true;
1701 }
Yohei Yukawad0332832017-02-01 13:59:43 -08001702 // TODO(b/34886274): The semantics of this verification is actually not well-defined.
Seigo Nonakae27dc2b2015-08-14 18:21:27 -07001703 Slog.w(TAG, "--- IPC called from background users. Ignore. callers="
1704 + Debug.getCallers(10));
Satoshi Kataoka135e5fb2012-09-28 18:25:06 +09001705 return false;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001706 }
1707
Yohei Yukawa22c97be2014-06-04 19:43:36 +09001708
1709 /**
1710 * Returns true iff the caller is identified to be the current input method with the token.
1711 * @param token The window token given to the input method when it was started.
1712 * @return true if and only if non-null valid token is specified.
1713 */
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08001714 @GuardedBy("mMethodMap")
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08001715 private boolean calledWithValidTokenLocked(@NonNull IBinder token) {
1716 if (token == null) {
1717 throw new InvalidParameterException("token must not be null.");
Yohei Yukawad0332832017-02-01 13:59:43 -08001718 }
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08001719 if (token != mCurToken) {
Yohei Yukawad0332832017-02-01 13:59:43 -08001720 Slog.e(TAG, "Ignoring " + Debug.getCaller() + " due to an invalid token."
1721 + " uid:" + Binder.getCallingUid() + " token:" + token);
Yohei Yukawa22c97be2014-06-04 19:43:36 +09001722 return false;
1723 }
1724 return true;
1725 }
1726
Yohei Yukawaf80087c2018-05-21 09:47:53 -07001727 @GuardedBy("mMethodMap")
1728 private boolean bindCurrentInputMethodServiceLocked(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001729 Intent service, ServiceConnection conn, int flags) {
1730 if (service == null || conn == null) {
1731 Slog.e(TAG, "--- bind failed: service = " + service + ", conn = " + conn);
1732 return false;
1733 }
Amith Yamasani27b89e62013-01-16 12:30:11 -08001734 return mContext.bindServiceAsUser(service, conn, flags,
1735 new UserHandle(mSettings.getCurrentUserId()));
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09001736 }
1737
satoke7c6998e2011-06-03 17:57:59 +09001738 @Override
Yohei Yukawad20eef82019-02-05 10:45:32 -08001739 public List<InputMethodInfo> getInputMethodList(@UserIdInt int userId) {
1740 if (UserHandle.getCallingUserId() != userId) {
1741 mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
1742 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001743 synchronized (mMethodMap) {
Yohei Yukawad20eef82019-02-05 10:45:32 -08001744 final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001745 mSettings.getCurrentUserId(), null);
1746 if (resolvedUserIds.length != 1) {
1747 return Collections.emptyList();
1748 }
1749 final long ident = Binder.clearCallingIdentity();
1750 try {
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08001751 return getInputMethodListLocked(resolvedUserIds[0]);
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001752 } finally {
1753 Binder.restoreCallingIdentity(ident);
Tarandeep Singh89a6c482017-11-21 14:26:11 -08001754 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 }
1756 }
1757
satoke7c6998e2011-06-03 17:57:59 +09001758 @Override
Yohei Yukawa1fb13c52019-02-05 07:55:28 -08001759 public List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) {
1760 if (UserHandle.getCallingUserId() != userId) {
1761 mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
1762 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001763 synchronized (mMethodMap) {
Yohei Yukawa1fb13c52019-02-05 07:55:28 -08001764 final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001765 mSettings.getCurrentUserId(), null);
1766 if (resolvedUserIds.length != 1) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08001767 return Collections.emptyList();
1768 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001769 final long ident = Binder.clearCallingIdentity();
1770 try {
1771 return getEnabledInputMethodListLocked(resolvedUserIds[0]);
1772 } finally {
1773 Binder.restoreCallingIdentity(ident);
1774 }
1775 }
1776 }
1777
1778 @GuardedBy("mMethodMap")
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08001779 private List<InputMethodInfo> getInputMethodListLocked(@UserIdInt int userId) {
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001780 final ArrayList<InputMethodInfo> methodList;
1781 if (userId == mSettings.getCurrentUserId()) {
1782 // Create a copy.
1783 methodList = new ArrayList<>(mMethodList);
1784 } else {
1785 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
1786 methodList = new ArrayList<>();
1787 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
1788 new ArrayMap<>();
1789 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
1790 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
1791 methodList);
1792 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001793 return methodList;
1794 }
1795
1796 @GuardedBy("mMethodMap")
1797 private List<InputMethodInfo> getEnabledInputMethodListLocked(@UserIdInt int userId) {
1798 if (userId == mSettings.getCurrentUserId()) {
satokd87c2592010-09-29 11:52:06 +09001799 return mSettings.getEnabledInputMethodListLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001800 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001801 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
1802 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
1803 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
1804 new ArrayMap<>();
1805 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
1806 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
1807 methodList);
1808 final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
Yohei Yukawaf9277532019-01-25 02:47:32 -08001809 mContext.getContentResolver(), methodMap, userId, true);
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001810 return settings.getEnabledInputMethodListLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001811 }
1812
Adam Hebc67f2e2019-11-13 14:34:56 -08001813 @GuardedBy("mMethodMap")
Feng Cao16b2de52020-01-09 17:27:27 -08001814 private void onCreateInlineSuggestionsRequestLocked(@UserIdInt int userId,
1815 ComponentName componentName, AutofillId autofillId,
1816 IInlineSuggestionsRequestCallback callback) {
Adam He7bc8f602019-12-12 17:00:34 -08001817 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
1818 try {
Feng Cao16b2de52020-01-09 17:27:27 -08001819 if (userId == mSettings.getCurrentUserId() && imi != null
1820 && imi.isInlineSuggestionsEnabled() && mCurMethod != null) {
Adam He7bc8f602019-12-12 17:00:34 -08001821 executeOrSendMessage(mCurMethod,
1822 mCaller.obtainMessageOOOO(MSG_INLINE_SUGGESTIONS_REQUEST, mCurMethod,
Feng Cao16b2de52020-01-09 17:27:27 -08001823 componentName, autofillId,
1824 new InlineSuggestionsRequestCallbackDecorator(callback,
1825 imi.getPackageName())));
Adam He7bc8f602019-12-12 17:00:34 -08001826 } else {
1827 callback.onInlineSuggestionsUnsupported();
1828 }
1829 } catch (RemoteException e) {
1830 Slog.w(TAG, "RemoteException calling onCreateInlineSuggestionsRequest(): " + e);
Adam Hebc67f2e2019-11-13 14:34:56 -08001831 }
1832 }
1833
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09001834 /**
Feng Cao16b2de52020-01-09 17:27:27 -08001835 * The decorator which validates the host package name in the
1836 * {@link InlineSuggestionsRequest} argument to make sure it matches the IME package name.
1837 */
1838 private static final class InlineSuggestionsRequestCallbackDecorator
1839 extends IInlineSuggestionsRequestCallback.Stub {
1840 @NonNull
1841 private final IInlineSuggestionsRequestCallback mCallback;
1842 @NonNull
1843 private final String mImePackageName;
1844
1845 InlineSuggestionsRequestCallbackDecorator(
1846 @NonNull IInlineSuggestionsRequestCallback callback,
1847 @NonNull String imePackageName) {
1848 mCallback = callback;
1849 mImePackageName = imePackageName;
1850 }
1851
1852 @Override
1853 public void onInlineSuggestionsUnsupported() throws RemoteException {
1854 mCallback.onInlineSuggestionsUnsupported();
1855 }
1856
1857 @Override
1858 public void onInlineSuggestionsRequest(InlineSuggestionsRequest request,
1859 IInlineSuggestionsResponseCallback callback) throws RemoteException {
1860 if (!mImePackageName.equals(request.getHostPackageName())) {
1861 throw new SecurityException(
1862 "Host package name in the provide request=[" + request.getHostPackageName()
1863 + "] doesn't match the IME package name=[" + mImePackageName
1864 + "].");
1865 }
1866 mCallback.onInlineSuggestionsRequest(request, callback);
1867 }
1868 }
1869
1870 /**
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09001871 * @param imiId if null, returns enabled subtypes for the current imi
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09001872 * @return enabled subtypes of the specified imi
1873 */
satoke7c6998e2011-06-03 17:57:59 +09001874 @Override
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09001875 public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
satok16331c82010-12-20 23:48:46 +09001876 boolean allowsImplicitlySelectedSubtypes) {
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001877 final int callingUserId = UserHandle.getCallingUserId();
satok67ddf9c2010-11-17 09:45:54 +09001878 synchronized (mMethodMap) {
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001879 final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
1880 mSettings.getCurrentUserId(), null);
1881 if (resolvedUserIds.length != 1) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08001882 return Collections.emptyList();
1883 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001884 final long ident = Binder.clearCallingIdentity();
1885 try {
1886 return getEnabledInputMethodSubtypeListLocked(imiId,
1887 allowsImplicitlySelectedSubtypes, resolvedUserIds[0]);
1888 } finally {
1889 Binder.restoreCallingIdentity(ident);
1890 }
1891 }
1892 }
1893
1894 @GuardedBy("mMethodMap")
1895 private List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(String imiId,
1896 boolean allowsImplicitlySelectedSubtypes, @UserIdInt int userId) {
1897 if (userId == mSettings.getCurrentUserId()) {
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09001898 final InputMethodInfo imi;
1899 if (imiId == null && mCurMethodId != null) {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09001900 imi = mMethodMap.get(mCurMethodId);
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +09001901 } else {
1902 imi = mMethodMap.get(imiId);
1903 }
1904 if (imi == null) {
Yohei Yukawab0377bb2015-08-10 21:06:30 -07001905 return Collections.emptyList();
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09001906 }
1907 return mSettings.getEnabledInputMethodSubtypeListLocked(
1908 mContext, imi, allowsImplicitlySelectedSubtypes);
satok67ddf9c2010-11-17 09:45:54 +09001909 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001910 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
1911 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
1912 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
1913 new ArrayMap<>();
1914 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
1915 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
1916 methodList);
1917 final InputMethodInfo imi = methodMap.get(imiId);
1918 if (imi == null) {
1919 return Collections.emptyList();
1920 }
1921 final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
Yohei Yukawaf9277532019-01-25 02:47:32 -08001922 mContext.getContentResolver(), methodMap, userId, true);
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08001923 return settings.getEnabledInputMethodSubtypeListLocked(
1924 mContext, imi, allowsImplicitlySelectedSubtypes);
satok67ddf9c2010-11-17 09:45:54 +09001925 }
1926
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001927 /**
1928 * Called by each application process as a preparation to start interacting with
1929 * {@link InputMethodManagerService}.
1930 *
1931 * <p>As a general principle, IPCs from the application process that take
Yohei Yukawa499e3f72018-10-21 20:15:11 -07001932 * {@link IInputMethodClient} will be rejected without this step.</p>
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001933 *
1934 * @param client {@link android.os.Binder} proxy that is associated with the singleton instance
1935 * of {@link android.view.inputmethod.InputMethodManager} that runs on the client
1936 * process
1937 * @param inputContext communication channel for the dummy
1938 * {@link android.view.inputmethod.InputConnection}
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08001939 * @param selfReportedDisplayId self-reported display ID to which the client is associated.
1940 * Whether the client is still allowed to access to this display
1941 * or not needs to be evaluated every time the client interacts
1942 * with the display
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001943 */
1944 @Override
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08001945 public void addClient(IInputMethodClient client, IInputContext inputContext,
1946 int selfReportedDisplayId) {
Yohei Yukawacb768bc2018-10-24 16:05:09 -07001947 // Here there are two scenarios where this method is called:
1948 // A. IMM is being instantiated in a different process and this is an IPC from that process
1949 // B. IMM is being instantiated in the same process but Binder.clearCallingIdentity() is
1950 // called in the caller side if necessary.
1951 // In either case the following UID/PID should be the ones where InputMethodManager is
1952 // actually running.
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001953 final int callerUid = Binder.getCallingUid();
1954 final int callerPid = Binder.getCallingPid();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001955 synchronized (mMethodMap) {
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001956 // TODO: Optimize this linear search.
Yohei Yukawaac9311e2018-11-20 19:25:23 -08001957 final int numClients = mClients.size();
1958 for (int i = 0; i < numClients; ++i) {
1959 final ClientState state = mClients.valueAt(i);
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08001960 if (state.uid == callerUid && state.pid == callerPid
1961 && state.selfReportedDisplayId == selfReportedDisplayId) {
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001962 throw new SecurityException("uid=" + callerUid + "/pid=" + callerPid
Yohei Yukawacb768bc2018-10-24 16:05:09 -07001963 + "/displayId=" + selfReportedDisplayId + " is already registered.");
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001964 }
1965 }
1966 final ClientDeathRecipient deathRecipient = new ClientDeathRecipient(this, client);
1967 try {
1968 client.asBinder().linkToDeath(deathRecipient, 0);
1969 } catch (RemoteException e) {
1970 throw new IllegalStateException(e);
1971 }
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08001972 // We cannot fully avoid race conditions where the client UID already lost the access to
1973 // the given self-reported display ID, even if the client is not maliciously reporting
1974 // a fake display ID. Unconditionally returning SecurityException just because the
1975 // client doesn't pass display ID verification can cause many test failures hence not an
1976 // option right now. At the same time
1977 // context.getSystemService(InputMethodManager.class)
1978 // is expected to return a valid non-null instance at any time if we do not choose to
1979 // have the client crash. Thus we do not verify the display ID at all here. Instead we
1980 // later check the display ID every time the client needs to interact with the specified
1981 // display.
1982 mClients.put(client.asBinder(), new ClientState(client, inputContext, callerUid,
1983 callerPid, selfReportedDisplayId, deathRecipient));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001984 }
1985 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001986
Yohei Yukawae24ed792018-08-28 19:10:32 -07001987 void removeClient(IInputMethodClient client) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001988 synchronized (mMethodMap) {
Jeff Brownc28867a2013-03-26 15:42:39 -07001989 ClientState cs = mClients.remove(client.asBinder());
1990 if (cs != null) {
Yohei Yukawaa71bb252018-09-19 19:21:24 -07001991 client.asBinder().unlinkToDeath(cs.clientDeathRecipient, 0);
Jeff Brownc28867a2013-03-26 15:42:39 -07001992 clearClientSessionLocked(cs);
Yohei Yukawab4f328a2019-05-02 08:41:27 -07001993
1994 final int numItems = mActivityViewDisplayIdToParentMap.size();
1995 for (int i = numItems - 1; i >= 0; --i) {
1996 final ActivityViewInfo info = mActivityViewDisplayIdToParentMap.valueAt(i);
1997 if (info.mParentClient == cs) {
1998 mActivityViewDisplayIdToParentMap.removeAt(i);
1999 }
2000 }
2001
Yohei Yukawa072b1b52015-11-18 15:54:34 -08002002 if (mCurClient == cs) {
Tarandeep Singh93c00cea2018-02-16 14:31:17 -08002003 if (mBoundToMethod) {
2004 mBoundToMethod = false;
2005 if (mCurMethod != null) {
2006 executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
2007 MSG_UNBIND_INPUT, mCurMethod));
2008 }
2009 }
Yohei Yukawa072b1b52015-11-18 15:54:34 -08002010 mCurClient = null;
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002011 mCurActivityViewToScreenMatrix = null;
Yohei Yukawa072b1b52015-11-18 15:54:34 -08002012 }
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08002013 if (mCurFocusedWindowClient == cs) {
2014 mCurFocusedWindowClient = null;
2015 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002016 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002017 }
2018 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002019
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002020 void executeOrSendMessage(IInterface target, Message msg) {
2021 if (target.asBinder() instanceof Binder) {
2022 mCaller.sendMessage(msg);
2023 } else {
2024 handleMessage(msg);
2025 msg.recycle();
2026 }
2027 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002028
Yohei Yukawa4afd9332018-10-21 10:43:53 -07002029 void unbindCurrentClientLocked(@UnbindReason int unbindClientReason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002030 if (mCurClient != null) {
Yohei Yukawa35d3f372015-11-25 11:07:19 -08002031 if (DEBUG) Slog.v(TAG, "unbindCurrentInputLocked: client="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002032 + mCurClient.client.asBinder());
2033 if (mBoundToMethod) {
2034 mBoundToMethod = false;
2035 if (mCurMethod != null) {
2036 executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
2037 MSG_UNBIND_INPUT, mCurMethod));
2038 }
2039 }
Dianne Hackborna6e41342012-05-22 16:30:34 -07002040
Yohei Yukawa2bc66172017-02-08 11:13:25 -08002041 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
2042 MSG_SET_ACTIVE, 0, 0, mCurClient));
Yohei Yukawa33e81792015-11-17 21:14:42 -08002043 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
2044 MSG_UNBIND_CLIENT, mCurSeq, unbindClientReason, mCurClient.client));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002045 mCurClient.sessionRequested = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002046 mCurClient = null;
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002047 mCurActivityViewToScreenMatrix = null;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002048
The Android Open Source Project10592532009-03-18 17:39:46 -07002049 hideInputMethodMenuLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002050 }
2051 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002052
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002053 private int getImeShowFlags() {
2054 int flags = 0;
2055 if (mShowForced) {
2056 flags |= InputMethod.SHOW_FORCED
2057 | InputMethod.SHOW_EXPLICIT;
2058 } else if (mShowExplicitlyRequested) {
2059 flags |= InputMethod.SHOW_EXPLICIT;
2060 }
2061 return flags;
2062 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002063
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002064 private int getAppShowFlags() {
2065 int flags = 0;
2066 if (mShowForced) {
2067 flags |= InputMethodManager.SHOW_FORCED;
2068 } else if (!mShowExplicitlyRequested) {
2069 flags |= InputMethodManager.SHOW_IMPLICIT;
2070 }
2071 return flags;
2072 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002073
Andreas Gampea36dc622018-02-05 17:19:22 -08002074 @GuardedBy("mMethodMap")
Yohei Yukawa2553e482017-12-15 15:47:33 -08002075 @NonNull
Yohei Yukawadc66e522018-10-21 10:43:14 -07002076 InputBindResult attachNewInputLocked(@StartInputReason int startInputReason, boolean initial) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002077 if (!mBoundToMethod) {
2078 executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
2079 MSG_BIND_INPUT, mCurMethod, mCurClient.binding));
2080 mBoundToMethod = true;
2081 }
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08002082
2083 final Binder startInputToken = new Binder();
Yohei Yukawa7979e1a2019-02-12 02:01:10 -08002084 final StartInputInfo info = new StartInputInfo(mSettings.getCurrentUserId(), mCurToken,
2085 mCurTokenDisplayId, mCurId, startInputReason, !initial,
2086 UserHandle.getUserId(mCurClient.uid), mCurClient.selfReportedDisplayId,
2087 mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode, mCurSeq);
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002088 mImeTargetWindowMap.put(startInputToken, mCurFocusedWindow);
Yohei Yukawa357b2f62017-02-14 09:40:03 -08002089 mStartInputHistory.addEntry(info);
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08002090
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002091 final SessionState session = mCurClient.curSession;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08002092 executeOrSendMessage(session.method, mCaller.obtainMessageIIOOOO(
Yohei Yukawaf7526b52017-02-11 20:57:10 -08002093 MSG_START_INPUT, mCurInputContextMissingMethods, initial ? 0 : 1 /* restarting */,
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08002094 startInputToken, session, mCurInputContext, mCurAttribute));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002095 if (mShowRequested) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002096 if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08002097 showCurrentInputLocked(mCurFocusedWindow, getAppShowFlags(), null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002098 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002099 return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
2100 session.session, (session.channel != null ? session.channel.dup() : null),
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002101 mCurId, mCurSeq, mCurActivityViewToScreenMatrix);
2102 }
2103
2104 @Nullable
2105 private Matrix getActivityViewToScreenMatrixLocked(int clientDisplayId, int imeDisplayId) {
2106 if (clientDisplayId == imeDisplayId) {
2107 return null;
2108 }
2109 int displayId = clientDisplayId;
2110 Matrix matrix = null;
2111 while (true) {
2112 final ActivityViewInfo info = mActivityViewDisplayIdToParentMap.get(displayId);
2113 if (info == null) {
2114 return null;
2115 }
2116 if (matrix == null) {
2117 matrix = new Matrix(info.mMatrix);
2118 } else {
2119 matrix.postConcat(info.mMatrix);
2120 }
2121 if (info.mParentClient.selfReportedDisplayId == imeDisplayId) {
2122 return matrix;
2123 }
2124 displayId = info.mParentClient.selfReportedDisplayId;
2125 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002126 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002127
Andreas Gampea36dc622018-02-05 17:19:22 -08002128 @GuardedBy("mMethodMap")
Yohei Yukawa2553e482017-12-15 15:47:33 -08002129 @NonNull
Yohei Yukawa35d3f372015-11-25 11:07:19 -08002130 InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07002131 @MissingMethodFlags int missingMethods, @NonNull EditorInfo attribute,
2132 @StartInputFlags int startInputFlags, @StartInputReason int startInputReason) {
Dianne Hackborn7663d802012-02-24 13:08:49 -08002133 // If no method is currently selected, do nothing.
2134 if (mCurMethodId == null) {
Yohei Yukawa2553e482017-12-15 15:47:33 -08002135 return InputBindResult.NO_IME;
Dianne Hackborn7663d802012-02-24 13:08:49 -08002136 }
2137
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002138 if (!mSystemReady) {
2139 // If the system is not yet ready, we shouldn't be running third
2140 // party code.
2141 return new InputBindResult(
2142 InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002143 null, null, mCurMethodId, mCurSeq, null);
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002144 }
2145
Yohei Yukawad57ba672015-06-08 16:39:46 -07002146 if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid,
2147 attribute.packageName)) {
2148 Slog.e(TAG, "Rejecting this client as it reported an invalid package name."
2149 + " uid=" + cs.uid + " package=" + attribute.packageName);
Yohei Yukawa2553e482017-12-15 15:47:33 -08002150 return InputBindResult.INVALID_PACKAGE_NAME;
Yohei Yukawa0f3ad12015-04-06 16:48:24 -07002151 }
2152
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002153 if (!mWindowManagerInternal.isUidAllowedOnDisplay(cs.selfReportedDisplayId, cs.uid)) {
2154 // Wait, the client no longer has access to the display.
2155 return InputBindResult.INVALID_DISPLAY_ID;
2156 }
lumarkef1965b2018-09-12 17:42:53 +08002157 // Compute the final shown display ID with validated cs.selfReportedDisplayId for this
2158 // session & other conditions.
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08002159 final int displayIdToShowIme = computeImeDisplayIdForTarget(cs.selfReportedDisplayId,
2160 mImeDisplayValidator);
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002161
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002162 if (mCurClient != cs) {
John Spurlocke0980502013-10-25 11:59:29 -04002163 // Was the keyguard locked when switching over to the new client?
2164 mCurClientInKeyguard = isKeyguardLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002165 // If the client is changing, we need to switch over to the new
2166 // one.
Yohei Yukawab7526452018-10-21 20:15:17 -07002167 unbindCurrentClientLocked(UnbindReason.SWITCH_CLIENT);
Yohei Yukawa35d3f372015-11-25 11:07:19 -08002168 if (DEBUG) Slog.v(TAG, "switching to client: client="
John Spurlocke0980502013-10-25 11:59:29 -04002169 + cs.client.asBinder() + " keyguard=" + mCurClientInKeyguard);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002170
2171 // If the screen is on, inform the new client it is active
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07002172 if (mIsInteractive) {
tiansiming [田思明]e102c972018-04-17 18:15:33 +08002173 executeOrSendMessage(cs.client, mCaller.obtainMessageIO(MSG_SET_ACTIVE, 1, cs));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002174 }
2175 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002177 // Bump up the sequence for this client and attach it.
2178 mCurSeq++;
2179 if (mCurSeq <= 0) mCurSeq = 1;
2180 mCurClient = cs;
2181 mCurInputContext = inputContext;
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002182 mCurActivityViewToScreenMatrix =
2183 getActivityViewToScreenMatrixLocked(cs.selfReportedDisplayId, displayIdToShowIme);
2184 if (cs.selfReportedDisplayId != displayIdToShowIme
2185 && mCurActivityViewToScreenMatrix == null) {
Yohei Yukawa3d2cc0f2019-04-25 18:32:15 -07002186 // CursorAnchorInfo API does not work as-is for cross-display scenario. Pretend that
2187 // InputConnection#requestCursorUpdates() is not implemented in the application so that
2188 // IMEs will always receive false from this API.
2189 missingMethods |= MissingMethodFlags.REQUEST_CURSOR_UPDATES;
2190 }
Yohei Yukawa19a80a12016-03-14 22:57:37 -07002191 mCurInputContextMissingMethods = missingMethods;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002192 mCurAttribute = attribute;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002193
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002194 // Check if the input method is changing.
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002195 // We expect the caller has already verified that the client is allowed to access this
2196 // display ID.
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002197 if (mCurId != null && mCurId.equals(mCurMethodId)
2198 && displayIdToShowIme == mCurTokenDisplayId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002199 if (cs.curSession != null) {
2200 // Fast case: if we are already connected to the input method,
2201 // then just return it.
Yohei Yukawa87ca8402017-02-07 00:13:14 -08002202 return attachNewInputLocked(startInputReason,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07002203 (startInputFlags & StartInputFlags.INITIAL_CONNECTION) != 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002204 }
2205 if (mHaveConnection) {
2206 if (mCurMethod != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002207 // Return to client, and we will get back with it when
2208 // we have had a session made for it.
Jeff Brownc28867a2013-03-26 15:42:39 -07002209 requestClientSessionLocked(cs);
Yohei Yukawa2553e482017-12-15 15:47:33 -08002210 return new InputBindResult(
2211 InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002212 null, null, mCurId, mCurSeq, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002213 } else if (SystemClock.uptimeMillis()
2214 < (mLastBindTime+TIME_TO_RECONNECT)) {
2215 // In this case we have connected to the service, but
2216 // don't yet have its interface. If it hasn't been too
2217 // long since we did the connection, we'll return to
2218 // the client and wait to get the service interface so
2219 // we can report back. If it has been too long, we want
2220 // to fall through so we can try a disconnect/reconnect
2221 // to see if we can get back in touch with the service.
Yohei Yukawa2553e482017-12-15 15:47:33 -08002222 return new InputBindResult(
2223 InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002224 null, null, mCurId, mCurSeq, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002225 } else {
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002226 EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
2227 mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002228 }
2229 }
2230 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002231
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002232 InputMethodInfo info = mMethodMap.get(mCurMethodId);
2233 if (info == null) {
2234 throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
2235 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002236
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002237 unbindCurrentMethodLocked();
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002238
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002239 mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE);
2240 mCurIntent.setComponent(info.getComponent());
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07002241 mCurIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
2242 com.android.internal.R.string.input_method_binding_label);
2243 mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
2244 mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002245
Yohei Yukawaf80087c2018-05-21 09:47:53 -07002246 if (bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002247 mLastBindTime = SystemClock.uptimeMillis();
2248 mHaveConnection = true;
2249 mCurId = info.getId();
2250 mCurToken = new Binder();
Yohei Yukawa0deaef02018-10-17 10:33:48 +08002251 mCurTokenDisplayId = displayIdToShowIme;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002252 try {
lumark90120a82018-08-15 00:33:03 +08002253 if (DEBUG) {
2254 Slog.v(TAG, "Adding window token: " + mCurToken + " for display: "
2255 + mCurTokenDisplayId);
2256 }
Yohei Yukawa6e875592019-01-28 00:49:30 -08002257 mIWindowManager.addWindowToken(mCurToken, LayoutParams.TYPE_INPUT_METHOD,
2258 mCurTokenDisplayId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002259 } catch (RemoteException e) {
2260 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002261 return new InputBindResult(
2262 InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07002263 null, null, mCurId, mCurSeq, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002264 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08002265 mCurIntent = null;
2266 Slog.w(TAG, "Failure connecting to input method service: " + mCurIntent);
2267 return InputBindResult.IME_NOT_CONNECTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002268 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002269
lumarkef1965b2018-09-12 17:42:53 +08002270 @FunctionalInterface
2271 interface ImeDisplayValidator {
2272 boolean displayCanShowIme(int displayId);
2273 }
2274
2275 /**
2276 * Find the display where the IME should be shown.
2277 *
2278 * @param displayId the ID of the display where the IME client target is.
lumarkef1965b2018-09-12 17:42:53 +08002279 * @param checker instance of {@link ImeDisplayValidator} which is used for
2280 * checking display config to adjust the final target display.
2281 * @return The ID of the display where the IME should be shown.
2282 */
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08002283 static int computeImeDisplayIdForTarget(int displayId, @NonNull ImeDisplayValidator checker) {
lumarkef1965b2018-09-12 17:42:53 +08002284 if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) {
lumark7570cac2019-03-07 22:14:38 +08002285 return FALLBACK_DISPLAY_ID;
lumarkef1965b2018-09-12 17:42:53 +08002286 }
lumark9a72d222019-03-30 18:31:45 +08002287
2288 // Show IME window on fallback display when the display doesn't support system decorations
2289 // or the display is virtual and isn't owned by system for security concern.
lumark7570cac2019-03-07 22:14:38 +08002290 return checker.displayCanShowIme(displayId) ? displayId : FALLBACK_DISPLAY_ID;
lumarkef1965b2018-09-12 17:42:53 +08002291 }
2292
satoke7c6998e2011-06-03 17:57:59 +09002293 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002294 public void onServiceConnected(ComponentName name, IBinder service) {
2295 synchronized (mMethodMap) {
2296 if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
2297 mCurMethod = IInputMethod.Stub.asInterface(service);
Dianne Hackborncc278702009-09-02 23:07:23 -07002298 if (mCurToken == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002299 Slog.w(TAG, "Service connected without a token!");
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002300 unbindCurrentMethodLocked();
Dianne Hackborncc278702009-09-02 23:07:23 -07002301 return;
2302 }
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002303 if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
lumark90120a82018-08-15 00:33:03 +08002304 // Dispatch display id for InputMethodService to update context display.
2305 executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
2306 MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002307 if (mCurClient != null) {
Jeff Brownc28867a2013-03-26 15:42:39 -07002308 clearClientSessionLocked(mCurClient);
2309 requestClientSessionLocked(mCurClient);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002310 }
2311 }
2312 }
2313 }
2314
Jeff Brownc28867a2013-03-26 15:42:39 -07002315 void onSessionCreated(IInputMethod method, IInputMethodSession session,
2316 InputChannel channel) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002317 synchronized (mMethodMap) {
2318 if (mCurMethod != null && method != null
2319 && mCurMethod.asBinder() == method.asBinder()) {
2320 if (mCurClient != null) {
Jeff Brownc28867a2013-03-26 15:42:39 -07002321 clearClientSessionLocked(mCurClient);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002322 mCurClient.curSession = new SessionState(mCurClient,
Jeff Brownc28867a2013-03-26 15:42:39 -07002323 method, session, channel);
Yohei Yukawa87ca8402017-02-07 00:13:14 -08002324 InputBindResult res = attachNewInputLocked(
Yohei Yukawa42194222018-10-21 20:14:40 -07002325 StartInputReason.SESSION_CREATED_BY_IME, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002326 if (res.method != null) {
2327 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
Yohei Yukawa33e81792015-11-17 21:14:42 -08002328 MSG_BIND_CLIENT, mCurClient.client, res));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002329 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002330 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002331 }
2332 }
2333 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002334
2335 // Session abandoned. Close its associated input channel.
2336 channel.dispose();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002337 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002338
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002339 void unbindCurrentMethodLocked() {
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002340 if (mVisibleBound) {
2341 mContext.unbindService(mVisibleConnection);
2342 mVisibleBound = false;
2343 }
2344
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002345 if (mHaveConnection) {
2346 mContext.unbindService(this);
2347 mHaveConnection = false;
2348 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002349
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002350 if (mCurToken != null) {
2351 try {
lumark90120a82018-08-15 00:33:03 +08002352 if (DEBUG) {
2353 Slog.v(TAG, "Removing window token: " + mCurToken + " for display: "
2354 + mCurTokenDisplayId);
2355 }
lumark90120a82018-08-15 00:33:03 +08002356 mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId);
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002357 } catch (RemoteException e) {
2358 }
lumark7570cac2019-03-07 22:14:38 +08002359 // Set IME window status as invisible when unbind current method.
2360 mImeWindowVis = 0;
2361 mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
2362 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002363 mCurToken = null;
lumark90120a82018-08-15 00:33:03 +08002364 mCurTokenDisplayId = INVALID_DISPLAY;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002365 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002366
The Android Open Source Project10592532009-03-18 17:39:46 -07002367 mCurId = null;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002368 clearCurMethodLocked();
Yohei Yukawabc7b5262015-11-17 17:38:41 -08002369 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002370
Yohei Yukawa4afd9332018-10-21 10:43:53 -07002371 void resetCurrentMethodAndClient(@UnbindReason int unbindClientReason) {
Yohei Yukawabc7b5262015-11-17 17:38:41 -08002372 mCurMethodId = null;
Yohei Yukawad4d895e2018-09-24 16:01:20 -07002373 unbindCurrentMethodLocked();
Yohei Yukawa33e81792015-11-17 21:14:42 -08002374 unbindCurrentClientLocked(unbindClientReason);
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002375 }
Jeff Brownc28867a2013-03-26 15:42:39 -07002376
2377 void requestClientSessionLocked(ClientState cs) {
2378 if (!cs.sessionRequested) {
2379 if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs);
2380 InputChannel[] channels = InputChannel.openInputChannelPair(cs.toString());
2381 cs.sessionRequested = true;
2382 executeOrSendMessage(mCurMethod, mCaller.obtainMessageOOO(
2383 MSG_CREATE_SESSION, mCurMethod, channels[1],
2384 new MethodCallback(this, mCurMethod, channels[0])));
2385 }
2386 }
2387
2388 void clearClientSessionLocked(ClientState cs) {
2389 finishSessionLocked(cs.curSession);
2390 cs.curSession = null;
2391 cs.sessionRequested = false;
2392 }
2393
2394 private void finishSessionLocked(SessionState sessionState) {
2395 if (sessionState != null) {
2396 if (sessionState.session != null) {
2397 try {
2398 sessionState.session.finishSession();
2399 } catch (RemoteException e) {
2400 Slog.w(TAG, "Session failed to close due to remote exception", e);
Yohei Yukawa849443c2019-01-21 09:02:25 -08002401 updateSystemUiLocked(0 /* vis */, mBackDisposition);
Jeff Brownc28867a2013-03-26 15:42:39 -07002402 }
2403 sessionState.session = null;
2404 }
2405 if (sessionState.channel != null) {
2406 sessionState.channel.dispose();
2407 sessionState.channel = null;
Devin Taylor0c33ed22010-02-23 13:26:46 -06002408 }
2409 }
2410 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002411
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002412 void clearCurMethodLocked() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002413 if (mCurMethod != null) {
Yohei Yukawaac9311e2018-11-20 19:25:23 -08002414 final int numClients = mClients.size();
2415 for (int i = 0; i < numClients; ++i) {
2416 clearClientSessionLocked(mClients.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002417 }
Devin Taylor0c33ed22010-02-23 13:26:46 -06002418
Jeff Brownc28867a2013-03-26 15:42:39 -07002419 finishSessionLocked(mEnabledSession);
Devin Taylor0c33ed22010-02-23 13:26:46 -06002420 mEnabledSession = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002421 mCurMethod = null;
2422 }
Dianne Hackborn661cd522011-08-22 00:26:20 -07002423 if (mStatusBar != null) {
Jason Monk3e189872016-01-12 09:10:34 -05002424 mStatusBar.setIconVisibility(mSlotIme, false);
Dianne Hackborn661cd522011-08-22 00:26:20 -07002425 }
Yohei Yukawa2bc66172017-02-08 11:13:25 -08002426 mInFullscreenMode = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002427 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002428
satoke7c6998e2011-06-03 17:57:59 +09002429 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002430 public void onServiceDisconnected(ComponentName name) {
Yohei Yukawa817d5f72017-01-04 20:15:02 -08002431 // Note that mContext.unbindService(this) does not trigger this. Hence if we are here the
2432 // disconnection is not intended by IMMS (e.g. triggered because the current IMS crashed),
2433 // which is irregular but can eventually happen for everyone just by continuing using the
2434 // device. Thus it is important to make sure that all the internal states are properly
2435 // refreshed when this method is called back. Running
2436 // adb install -r <APK that implements the current IME>
2437 // would be a good way to trigger such a situation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002438 synchronized (mMethodMap) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002439 if (DEBUG) Slog.v(TAG, "Service disconnected: " + name
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002440 + " mCurIntent=" + mCurIntent);
2441 if (mCurMethod != null && mCurIntent != null
2442 && name.equals(mCurIntent.getComponent())) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002443 clearCurMethodLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002444 // We consider this to be a new bind attempt, since the system
2445 // should now try to restart the service for us.
2446 mLastBindTime = SystemClock.uptimeMillis();
2447 mShowRequested = mInputShown;
2448 mInputShown = false;
Yohei Yukawab7526452018-10-21 20:15:17 -07002449 unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002450 }
2451 }
2452 }
2453
Yohei Yukawaeec552e2018-09-09 20:48:41 -07002454 @BinderThread
Yohei Yukawa41b094f2018-09-09 23:58:45 -07002455 private void updateStatusIcon(@NonNull IBinder token, String packageName,
2456 @DrawableRes int iconId) {
Yohei Yukawa59377ca2017-01-31 21:32:26 -08002457 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08002458 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa59377ca2017-01-31 21:32:26 -08002459 return;
2460 }
2461 final long ident = Binder.clearCallingIdentity();
2462 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002463 if (iconId == 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002464 if (DEBUG) Slog.d(TAG, "hide the small icon for the input method");
Dianne Hackborn661cd522011-08-22 00:26:20 -07002465 if (mStatusBar != null) {
Jason Monk3e189872016-01-12 09:10:34 -05002466 mStatusBar.setIconVisibility(mSlotIme, false);
Dianne Hackborn661cd522011-08-22 00:26:20 -07002467 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002468 } else if (packageName != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002469 if (DEBUG) Slog.d(TAG, "show a small icon for the input method");
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002470 CharSequence contentDescription = null;
2471 try {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002472 // Use PackageManager to load label
2473 final PackageManager packageManager = mContext.getPackageManager();
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002474 contentDescription = packageManager.getApplicationLabel(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002475 mIPackageManager.getApplicationInfo(packageName, 0,
2476 mSettings.getCurrentUserId()));
2477 } catch (RemoteException e) {
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002478 /* ignore */
2479 }
Dianne Hackborn661cd522011-08-22 00:26:20 -07002480 if (mStatusBar != null) {
Jason Monk3e189872016-01-12 09:10:34 -05002481 mStatusBar.setIcon(mSlotIme, packageName, iconId, 0,
Dianne Hackborn661cd522011-08-22 00:26:20 -07002482 contentDescription != null
2483 ? contentDescription.toString() : null);
Jason Monk3e189872016-01-12 09:10:34 -05002484 mStatusBar.setIconVisibility(mSlotIme, true);
Dianne Hackborn661cd522011-08-22 00:26:20 -07002485 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002486 }
Yohei Yukawa59377ca2017-01-31 21:32:26 -08002487 } finally {
2488 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002489 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002490 }
2491 }
2492
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002493 private boolean shouldShowImeSwitcherLocked(int visibility) {
satok7cfc0ed2011-06-20 21:29:36 +09002494 if (!mShowOngoingImeSwitcherForPhones) return false;
Jason Monk807ef762014-05-08 15:47:46 -04002495 if (mSwitchingDialog != null) return false;
Yohei Yukawad2bc3092017-07-31 15:37:14 -07002496 if (mWindowManagerInternal.isKeyguardShowingAndNotOccluded()
2497 && mKeyguardManager != null && mKeyguardManager.isKeyguardSecure()) return false;
Tarandeep Singheadb1392018-11-09 18:15:57 +01002498 if ((visibility & InputMethodService.IME_ACTIVE) == 0
2499 || (visibility & InputMethodService.IME_INVISIBLE) != 0) {
2500 return false;
2501 }
Seigo Nonaka7309b122015-08-17 18:34:13 -07002502 if (mWindowManagerInternal.isHardKeyboardAvailable()) {
Yohei Yukawaaf023f22019-06-21 16:38:22 -07002503 // When physical keyboard is attached, we show the ime switcher (or notification if
2504 // NavBar is not available) because SHOW_IME_WITH_HARD_KEYBOARD settings currently
2505 // exists in the IME switcher dialog. Might be OK to remove this condition once
2506 // SHOW_IME_WITH_HARD_KEYBOARD settings finds a good place to live.
2507 return true;
Yohei Yukawa89398382016-03-29 11:37:04 -07002508 } else if ((visibility & InputMethodService.IME_VISIBLE) == 0) {
2509 return false;
Yohei Yukawac6c7cd22015-05-12 15:00:33 -07002510 }
Yohei Yukawac6c7cd22015-05-12 15:00:33 -07002511
2512 List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked();
2513 final int N = imis.size();
2514 if (N > 2) return true;
2515 if (N < 1) return false;
2516 int nonAuxCount = 0;
2517 int auxCount = 0;
2518 InputMethodSubtype nonAuxSubtype = null;
2519 InputMethodSubtype auxSubtype = null;
2520 for(int i = 0; i < N; ++i) {
2521 final InputMethodInfo imi = imis.get(i);
2522 final List<InputMethodSubtype> subtypes =
2523 mSettings.getEnabledInputMethodSubtypeListLocked(mContext, imi, true);
2524 final int subtypeCount = subtypes.size();
2525 if (subtypeCount == 0) {
2526 ++nonAuxCount;
2527 } else {
2528 for (int j = 0; j < subtypeCount; ++j) {
2529 final InputMethodSubtype subtype = subtypes.get(j);
2530 if (!subtype.isAuxiliary()) {
2531 ++nonAuxCount;
2532 nonAuxSubtype = subtype;
2533 } else {
2534 ++auxCount;
2535 auxSubtype = subtype;
satok7cfc0ed2011-06-20 21:29:36 +09002536 }
2537 }
satok7cfc0ed2011-06-20 21:29:36 +09002538 }
2539 }
Yohei Yukawac6c7cd22015-05-12 15:00:33 -07002540 if (nonAuxCount > 1 || auxCount > 1) {
2541 return true;
2542 } else if (nonAuxCount == 1 && auxCount == 1) {
2543 if (nonAuxSubtype != null && auxSubtype != null
2544 && (nonAuxSubtype.getLocale().equals(auxSubtype.getLocale())
2545 || auxSubtype.overridesImplicitlyEnabledSubtype()
2546 || nonAuxSubtype.overridesImplicitlyEnabledSubtype())
2547 && nonAuxSubtype.containsExtraValueKey(TAG_TRY_SUPPRESSING_IME_SWITCHER)) {
2548 return false;
2549 }
2550 return true;
2551 }
2552 return false;
satok7cfc0ed2011-06-20 21:29:36 +09002553 }
2554
John Spurlocke0980502013-10-25 11:59:29 -04002555 private boolean isKeyguardLocked() {
2556 return mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
2557 }
2558
Yohei Yukawad6475a62017-04-17 10:35:27 -07002559 @BinderThread
satokdbf29502011-08-25 15:28:23 +09002560 @SuppressWarnings("deprecation")
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08002561 private void setImeWindowStatus(@NonNull IBinder token, int vis, int backDisposition) {
lumark7570cac2019-03-07 22:14:38 +08002562 final int topFocusedDisplayId = mWindowManagerInternal.getTopFocusedDisplayId();
2563
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002564 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08002565 if (!calledWithValidTokenLocked(token)) {
2566 return;
2567 }
lumark7570cac2019-03-07 22:14:38 +08002568 // Skip update IME status when current token display is not same as focused display.
2569 // Note that we still need to update IME status when focusing external display
2570 // that does not support system decoration and fallback to show IME on default
2571 // display since it is intentional behavior.
2572 if (mCurTokenDisplayId != topFocusedDisplayId
2573 && mCurTokenDisplayId != FALLBACK_DISPLAY_ID) {
2574 return;
2575 }
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002576 mImeWindowVis = vis;
2577 mBackDisposition = backDisposition;
Yohei Yukawa849443c2019-01-21 09:02:25 -08002578 updateSystemUiLocked(vis, backDisposition);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002579 }
Yohei Yukawad6475a62017-04-17 10:35:27 -07002580
2581 final boolean dismissImeOnBackKeyPressed;
2582 switch (backDisposition) {
2583 case InputMethodService.BACK_DISPOSITION_WILL_DISMISS:
2584 dismissImeOnBackKeyPressed = true;
2585 break;
2586 case InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS:
2587 dismissImeOnBackKeyPressed = false;
2588 break;
2589 default:
2590 case InputMethodService.BACK_DISPOSITION_DEFAULT:
2591 dismissImeOnBackKeyPressed = ((vis & InputMethodService.IME_VISIBLE) != 0);
2592 break;
2593 }
Yohei Yukawaee2a7ed2017-02-15 21:38:57 -08002594 mWindowManagerInternal.updateInputMethodWindowStatus(token,
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002595 (vis & InputMethodService.IME_VISIBLE) != 0, dismissImeOnBackKeyPressed);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002596 }
2597
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002598 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08002599 private void reportStartInput(@NonNull IBinder token, IBinder startInputToken) {
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002600 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08002601 if (!calledWithValidTokenLocked(token)) {
2602 return;
2603 }
Yohei Yukawa99e1f6e2018-06-22 17:33:19 -07002604 final IBinder targetWindow = mImeTargetWindowMap.get(startInputToken);
2605 if (targetWindow != null && mLastImeTargetWindow != targetWindow) {
2606 mWindowManagerInternal.updateInputMethodTargetWindow(token, targetWindow);
2607 }
2608 mLastImeTargetWindow = targetWindow;
2609 }
2610 }
2611
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002612 // Caution! This method is called in this class. Handle multi-user carefully
Yohei Yukawa849443c2019-01-21 09:02:25 -08002613 private void updateSystemUiLocked(int vis, int backDisposition) {
2614 if (mCurToken == null) {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002615 return;
2616 }
Tarandeep Singheadb1392018-11-09 18:15:57 +01002617 if (DEBUG) {
2618 Slog.d(TAG, "IME window vis: " + vis
2619 + " active: " + (vis & InputMethodService.IME_ACTIVE)
lumark7570cac2019-03-07 22:14:38 +08002620 + " inv: " + (vis & InputMethodService.IME_INVISIBLE)
2621 + " displayId: " + mCurTokenDisplayId);
Tarandeep Singheadb1392018-11-09 18:15:57 +01002622 }
2623
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002624 // TODO: Move this clearing calling identity block to setImeWindowStatus after making sure
2625 // all updateSystemUi happens on system previlege.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002626 final long ident = Binder.clearCallingIdentity();
satok06487a52010-10-29 11:37:18 +09002627 try {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002628 // apply policy for binder calls
2629 if (vis != 0 && isKeyguardLocked() && !mCurClientInKeyguard) {
2630 vis = 0;
satok06487a52010-10-29 11:37:18 +09002631 }
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002632 // mImeWindowVis should be updated before calling shouldShowImeSwitcherLocked().
2633 final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis);
2634 if (mStatusBar != null) {
lumark7570cac2019-03-07 22:14:38 +08002635 mStatusBar.setImeWindowStatus(mCurTokenDisplayId, mCurToken, vis, backDisposition,
Tarandeep Singh07b318b2019-07-17 11:12:04 -07002636 needsToShowImeSwitcher, false /*isMultiClientImeEnabled*/);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002637 }
2638 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
2639 if (imi != null && needsToShowImeSwitcher) {
2640 // Used to load label
2641 final CharSequence title = mRes.getText(
2642 com.android.internal.R.string.select_input_method);
2643 final CharSequence summary = InputMethodUtils.getImeAndSubtypeDisplayName(
2644 mContext, imi, mCurrentSubtype);
Chris Wren1ce4b6d2015-06-11 10:19:43 -04002645 mImeSwitcherNotification.setContentTitle(title)
2646 .setContentText(summary)
2647 .setContentIntent(mImeSwitchPendingIntent);
Seigo Nonaka7309b122015-08-17 18:34:13 -07002648 try {
Charles Chenea6e7f02018-11-19 21:37:45 +08002649 // TODO(b/120076400): Figure out what is the best behavior
Seigo Nonaka7309b122015-08-17 18:34:13 -07002650 if ((mNotificationManager != null)
Charles Chenea6e7f02018-11-19 21:37:45 +08002651 && !mIWindowManager.hasNavigationBar(DEFAULT_DISPLAY)) {
Seigo Nonaka7309b122015-08-17 18:34:13 -07002652 if (DEBUG) {
2653 Slog.d(TAG, "--- show notification: label = " + summary);
2654 }
2655 mNotificationManager.notifyAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04002656 SystemMessage.NOTE_SELECT_INPUT_METHOD,
Seigo Nonaka7309b122015-08-17 18:34:13 -07002657 mImeSwitcherNotification.build(), UserHandle.ALL);
2658 mNotificationShown = true;
Dianne Hackborn661cd522011-08-22 00:26:20 -07002659 }
Seigo Nonaka7309b122015-08-17 18:34:13 -07002660 } catch (RemoteException e) {
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002661 }
2662 } else {
2663 if (mNotificationShown && mNotificationManager != null) {
2664 if (DEBUG) {
2665 Slog.d(TAG, "--- hide notification");
satok7cfc0ed2011-06-20 21:29:36 +09002666 }
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002667 mNotificationManager.cancelAsUser(null,
Chris Wren282cfef2017-03-27 15:01:44 -04002668 SystemMessage.NOTE_SELECT_INPUT_METHOD, UserHandle.ALL);
Seigo Nonakad9eb9112015-05-26 20:54:43 +09002669 mNotificationShown = false;
satok7cfc0ed2011-06-20 21:29:36 +09002670 }
satok06487a52010-10-29 11:37:18 +09002671 }
2672 } finally {
2673 Binder.restoreCallingIdentity(ident);
2674 }
2675 }
2676
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002677 void updateFromSettingsLocked(boolean enabledMayChange) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07002678 updateInputMethodsFromSettingsLocked(enabledMayChange);
2679 updateKeyboardFromSettingsLocked();
2680 }
2681
2682 void updateInputMethodsFromSettingsLocked(boolean enabledMayChange) {
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002683 if (enabledMayChange) {
2684 List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
2685 for (int i=0; i<enabled.size(); i++) {
2686 // We allow the user to select "disabled until used" apps, so if they
2687 // are enabling one of those here we now need to make it enabled.
2688 InputMethodInfo imm = enabled.get(i);
2689 try {
2690 ApplicationInfo ai = mIPackageManager.getApplicationInfo(imm.getPackageName(),
2691 PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
2692 mSettings.getCurrentUserId());
Satoshi Kataoka7987a312013-04-17 18:59:33 +09002693 if (ai != null && ai.enabledSetting
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002694 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
Satoshi Kataokaed1cdb22013-04-17 16:41:58 +09002695 if (DEBUG) {
2696 Slog.d(TAG, "Update state(" + imm.getId()
2697 + "): DISABLED_UNTIL_USED -> DEFAULT");
2698 }
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002699 mIPackageManager.setApplicationEnabledSetting(imm.getPackageName(),
2700 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
Dianne Hackborn3fa3c28a2013-03-26 16:15:41 -07002701 PackageManager.DONT_KILL_APP, mSettings.getCurrentUserId(),
2702 mContext.getBasePackageName());
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08002703 }
2704 } catch (RemoteException e) {
2705 }
2706 }
2707 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002708 // We are assuming that whoever is changing DEFAULT_INPUT_METHOD and
2709 // ENABLED_INPUT_METHODS is taking care of keeping them correctly in
2710 // sync, so we will never have a DEFAULT_INPUT_METHOD that is not
2711 // enabled.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002712 String id = mSettings.getSelectedInputMethod();
satok03eb319a2010-11-11 18:17:42 +09002713 // There is no input method selected, try to choose new applicable input method.
2714 if (TextUtils.isEmpty(id) && chooseNewDefaultIMELocked()) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002715 id = mSettings.getSelectedInputMethod();
satok03eb319a2010-11-11 18:17:42 +09002716 }
2717 if (!TextUtils.isEmpty(id)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002718 try {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09002719 setInputMethodLocked(id, mSettings.getSelectedInputMethodSubtypeId(id));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002720 } catch (IllegalArgumentException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002721 Slog.w(TAG, "Unknown input method from prefs: " + id, e);
Yohei Yukawab7526452018-10-21 20:15:17 -07002722 resetCurrentMethodAndClient(UnbindReason.SWITCH_IME_FAILED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002723 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002724 } else {
2725 // There is no longer an input method set, so stop any current one.
Yohei Yukawab7526452018-10-21 20:15:17 -07002726 resetCurrentMethodAndClient(UnbindReason.NO_IME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002727 }
Yohei Yukawa3d46bab2014-05-30 18:10:18 +09002728 // Here is not the perfect place to reset the switching controller. Ideally
2729 // mSwitchingController and mSettings should be able to share the same state.
2730 // TODO: Make sure that mSwitchingController and mSettings are sharing the
2731 // the same enabled IMEs list.
2732 mSwitchingController.resetCircularListLocked(mContext);
Michael Wright7b5a96b2014-08-09 19:28:42 -07002733
2734 }
2735
2736 public void updateKeyboardFromSettingsLocked() {
2737 mShowImeWithHardKeyboard = mSettings.isShowImeWithHardKeyboardEnabled();
2738 if (mSwitchingDialog != null
2739 && mSwitchingDialogTitleView != null
2740 && mSwitchingDialog.isShowing()) {
2741 final Switch hardKeySwitch = (Switch)mSwitchingDialogTitleView.findViewById(
2742 com.android.internal.R.id.hard_keyboard_switch);
2743 hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
2744 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002745 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002746
satokab751aa2010-09-14 19:17:36 +09002747 /* package */ void setInputMethodLocked(String id, int subtypeId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002748 InputMethodInfo info = mMethodMap.get(id);
2749 if (info == null) {
satok913a8922010-08-26 21:53:41 +09002750 throw new IllegalArgumentException("Unknown id: " + id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002751 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002752
satokd81e9502012-05-21 12:58:45 +09002753 // See if we need to notify a subtype change within the same IME.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002754 if (id.equals(mCurMethodId)) {
satokd81e9502012-05-21 12:58:45 +09002755 final int subtypeCount = info.getSubtypeCount();
2756 if (subtypeCount <= 0) {
2757 return;
satokcd7cd292010-11-20 15:46:23 +09002758 }
satokd81e9502012-05-21 12:58:45 +09002759 final InputMethodSubtype oldSubtype = mCurrentSubtype;
2760 final InputMethodSubtype newSubtype;
2761 if (subtypeId >= 0 && subtypeId < subtypeCount) {
2762 newSubtype = info.getSubtypeAt(subtypeId);
2763 } else {
2764 // If subtype is null, try to find the most applicable one from
2765 // getCurrentInputMethodSubtype.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002766 newSubtype = getCurrentInputMethodSubtypeLocked();
satokd81e9502012-05-21 12:58:45 +09002767 }
2768 if (newSubtype == null || oldSubtype == null) {
2769 Slog.w(TAG, "Illegal subtype state: old subtype = " + oldSubtype
2770 + ", new subtype = " + newSubtype);
2771 return;
2772 }
2773 if (newSubtype != oldSubtype) {
2774 setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true);
2775 if (mCurMethod != null) {
2776 try {
Yohei Yukawa849443c2019-01-21 09:02:25 -08002777 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
satokd81e9502012-05-21 12:58:45 +09002778 mCurMethod.changeInputMethodSubtype(newSubtype);
2779 } catch (RemoteException e) {
2780 Slog.w(TAG, "Failed to call changeInputMethodSubtype");
satokab751aa2010-09-14 19:17:36 +09002781 }
2782 }
2783 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002784 return;
2785 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002786
satokd81e9502012-05-21 12:58:45 +09002787 // Changing to a different IME.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002788 final long ident = Binder.clearCallingIdentity();
2789 try {
satokab751aa2010-09-14 19:17:36 +09002790 // Set a subtype to this input method.
2791 // subtypeId the name of a subtype which will be set.
satok723a27e2010-11-11 14:58:11 +09002792 setSelectedInputMethodAndSubtypeLocked(info, subtypeId, false);
2793 // mCurMethodId should be updated after setSelectedInputMethodAndSubtypeLocked()
2794 // because mCurMethodId is stored as a history in
2795 // setSelectedInputMethodAndSubtypeLocked().
2796 mCurMethodId = id;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002797
Sudheer Shankafc46e9b2016-10-21 17:55:27 -07002798 if (LocalServices.getService(ActivityManagerInternal.class).isSystemReady()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002799 Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08002800 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002801 intent.putExtra("input_method_id", id);
Amith Yamasanicd757062012-10-19 18:23:52 -07002802 mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002803 }
Yohei Yukawab7526452018-10-21 20:15:17 -07002804 unbindCurrentClientLocked(UnbindReason.SWITCH_IME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002805 } finally {
2806 Binder.restoreCallingIdentity(ident);
2807 }
2808 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002809
satok42c5a162011-05-26 16:46:14 +09002810 @Override
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08002811 public boolean showSoftInput(IInputMethodClient client, IBinder windowToken, int flags,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002812 ResultReceiver resultReceiver) {
Dianne Hackborncef65ee2010-09-30 18:27:22 -07002813 int uid = Binder.getCallingUid();
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002814 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08002815 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002816 return false;
2817 }
2818 final long ident = Binder.clearCallingIdentity();
2819 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002820 if (mCurClient == null || client == null
2821 || mCurClient.client.asBinder() != client.asBinder()) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07002822 // We need to check if this is the current client with
2823 // focus in the window manager, to allow this call to
2824 // be made before input is started in it.
Yohei Yukawa41f89c32018-09-19 14:30:04 -07002825 final ClientState cs = mClients.get(client.asBinder());
2826 if (cs == null) {
2827 throw new IllegalArgumentException("unknown client " + client.asBinder());
2828 }
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002829 if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
2830 cs.selfReportedDisplayId)) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07002831 Slog.w(TAG, "Ignoring showSoftInput of uid " + uid + ": " + client);
The Android Open Source Project4df24232009-03-05 14:34:35 -08002832 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002833 }
2834 }
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002835 if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08002836 return showCurrentInputLocked(windowToken, flags, resultReceiver);
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002837 } finally {
2838 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002839 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002840 }
2841 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002842
Andreas Gamped6d42062018-07-20 13:08:21 -07002843 @GuardedBy("mMethodMap")
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08002844 boolean showCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002845 mShowRequested = true;
Anna Galusza9b278112016-01-04 11:37:37 -08002846 if (mAccessibilityRequestingNoSoftKeyboard) {
2847 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002848 }
Anna Galusza9b278112016-01-04 11:37:37 -08002849
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002850 if ((flags&InputMethodManager.SHOW_FORCED) != 0) {
2851 mShowExplicitlyRequested = true;
2852 mShowForced = true;
Anna Galusza9b278112016-01-04 11:37:37 -08002853 } else if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
2854 mShowExplicitlyRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002855 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002856
Dianne Hackborncc278702009-09-02 23:07:23 -07002857 if (!mSystemReady) {
2858 return false;
2859 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002860
The Android Open Source Project4df24232009-03-05 14:34:35 -08002861 boolean res = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002862 if (mCurMethod != null) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002863 if (DEBUG) Slog.d(TAG, "showCurrentInputLocked: mCurToken=" + mCurToken);
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08002864 // create a dummy token for IMS so that IMS cannot inject windows into client app.
2865 Binder showInputToken = new Binder();
2866 mShowRequestWindowMap.put(showInputToken, windowToken);
2867 executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOOO(
The Android Open Source Project4df24232009-03-05 14:34:35 -08002868 MSG_SHOW_SOFT_INPUT, getImeShowFlags(), mCurMethod,
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08002869 resultReceiver, showInputToken));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002870 mInputShown = true;
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002871 if (mHaveConnection && !mVisibleBound) {
Yohei Yukawaf80087c2018-05-21 09:47:53 -07002872 bindCurrentInputMethodServiceLocked(
Yohei Yukawaa67a4592017-03-30 15:57:02 -07002873 mCurIntent, mVisibleConnection, IME_VISIBLE_BIND_FLAGS);
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002874 mVisibleBound = true;
2875 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08002876 res = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002877 } else if (mHaveConnection && SystemClock.uptimeMillis()
satok59b424c2011-09-30 17:21:46 +09002878 >= (mLastBindTime+TIME_TO_RECONNECT)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002879 // The client has asked to have the input method shown, but
2880 // we have been sitting here too long with a connection to the
2881 // service and no interface received, so let's disconnect/connect
2882 // to try to prod things along.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002883 EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, mCurMethodId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002884 SystemClock.uptimeMillis()-mLastBindTime,1);
satok59b424c2011-09-30 17:21:46 +09002885 Slog.w(TAG, "Force disconnect/connect to the IME in showCurrentInputLocked()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002886 mContext.unbindService(this);
Yohei Yukawaf80087c2018-05-21 09:47:53 -07002887 bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09002888 } else {
2889 if (DEBUG) {
2890 Slog.d(TAG, "Can't show input: connection = " + mHaveConnection + ", time = "
2891 + ((mLastBindTime+TIME_TO_RECONNECT) - SystemClock.uptimeMillis()));
2892 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002893 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002894
The Android Open Source Project4df24232009-03-05 14:34:35 -08002895 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002896 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002897
satok42c5a162011-05-26 16:46:14 +09002898 @Override
The Android Open Source Project4df24232009-03-05 14:34:35 -08002899 public boolean hideSoftInput(IInputMethodClient client, int flags,
2900 ResultReceiver resultReceiver) {
Dianne Hackborncef65ee2010-09-30 18:27:22 -07002901 int uid = Binder.getCallingUid();
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002902 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08002903 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002904 return false;
2905 }
2906 final long ident = Binder.clearCallingIdentity();
2907 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002908 if (mCurClient == null || client == null
2909 || mCurClient.client.asBinder() != client.asBinder()) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07002910 // We need to check if this is the current client with
2911 // focus in the window manager, to allow this call to
2912 // be made before input is started in it.
Yohei Yukawa41f89c32018-09-19 14:30:04 -07002913 final ClientState cs = mClients.get(client.asBinder());
2914 if (cs == null) {
2915 throw new IllegalArgumentException("unknown client " + client.asBinder());
2916 }
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08002917 if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
2918 cs.selfReportedDisplayId)) {
Yohei Yukawacf93f9a2018-08-30 15:58:47 -07002919 if (DEBUG) {
2920 Slog.w(TAG, "Ignoring hideSoftInput of uid " + uid + ": " + client);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002921 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08002922 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002923 }
2924 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002925
Joe Onorato8a9b2202010-02-26 18:56:32 -08002926 if (DEBUG) Slog.v(TAG, "Client requesting input be hidden");
The Android Open Source Project4df24232009-03-05 14:34:35 -08002927 return hideCurrentInputLocked(flags, resultReceiver);
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08002928 } finally {
2929 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002930 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002931 }
2932 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002933
The Android Open Source Project4df24232009-03-05 14:34:35 -08002934 boolean hideCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002935 if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
2936 && (mShowExplicitlyRequested || mShowForced)) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002937 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 -08002938 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002939 }
2940 if (mShowForced && (flags&InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07002941 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 -08002942 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002943 }
Seigo Nonakaec928652015-06-10 15:31:20 +09002944
2945 // There is a chance that IMM#hideSoftInput() is called in a transient state where
2946 // IMMS#InputShown is already updated to be true whereas IMMS#mImeWindowVis is still waiting
2947 // to be updated with the new value sent from IME process. Even in such a transient state
2948 // historically we have accepted an incoming call of IMM#hideSoftInput() from the
2949 // application process as a valid request, and have even promised such a behavior with CTS
2950 // since Android Eclair. That's why we need to accept IMM#hideSoftInput() even when only
2951 // IMMS#InputShown indicates that the software keyboard is shown.
2952 // TODO: Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested.
2953 final boolean shouldHideSoftInput = (mCurMethod != null) && (mInputShown ||
2954 (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0);
The Android Open Source Project4df24232009-03-05 14:34:35 -08002955 boolean res;
Seigo Nonakaec928652015-06-10 15:31:20 +09002956 if (shouldHideSoftInput) {
2957 // The IME will report its visible state again after the following message finally
2958 // delivered to the IME process as an IPC. Hence the inconsistency between
2959 // IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in
2960 // the final state.
The Android Open Source Project4df24232009-03-05 14:34:35 -08002961 executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
2962 MSG_HIDE_SOFT_INPUT, mCurMethod, resultReceiver));
2963 res = true;
2964 } else {
2965 res = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002966 }
Dianne Hackborn2c84cfc2011-10-31 15:39:59 -07002967 if (mHaveConnection && mVisibleBound) {
2968 mContext.unbindService(mVisibleConnection);
2969 mVisibleBound = false;
2970 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002971 mInputShown = false;
2972 mShowRequested = false;
2973 mShowExplicitlyRequested = false;
2974 mShowForced = false;
The Android Open Source Project4df24232009-03-05 14:34:35 -08002975 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002976 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002977
Yohei Yukawa2553e482017-12-15 15:47:33 -08002978 @NonNull
satok42c5a162011-05-26 16:46:14 +09002979 @Override
Yohei Yukawa05c25f82016-02-22 12:41:17 -08002980 public InputBindResult startInputOrWindowGainedFocus(
Yohei Yukawadc66e522018-10-21 10:43:14 -07002981 @StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07002982 @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
2983 int windowFlags, @Nullable EditorInfo attribute, IInputContext inputContext,
Yohei Yukawadc66e522018-10-21 10:43:14 -07002984 @MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion) {
Yohei Yukawa80498d52018-06-21 16:24:36 -07002985 if (windowToken == null) {
2986 Slog.e(TAG, "windowToken cannot be null.");
2987 return InputBindResult.NULL;
Yohei Yukawa05c25f82016-02-22 12:41:17 -08002988 }
Yohei Yukawa0f5eade2019-01-18 08:48:07 -08002989 final int callingUserId = UserHandle.getCallingUserId();
2990 final int userId;
Yohei Yukawa716897c2019-01-22 00:00:53 -08002991 if (attribute != null && attribute.targetInputMethodUser != null
Yohei Yukawa0f5eade2019-01-18 08:48:07 -08002992 && attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
2993 mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
Yohei Yukawa670abea2019-01-28 00:00:50 -08002994 "Using EditorInfo.targetInputMethodUser requires INTERACT_ACROSS_USERS_FULL.");
Yohei Yukawa0f5eade2019-01-18 08:48:07 -08002995 userId = attribute.targetInputMethodUser.getIdentifier();
2996 if (!mUserManagerInternal.isUserRunning(userId)) {
2997 // There is a chance that we hit here because of race condition. Let's just return
2998 // an error code instead of crashing the caller process, which at least has
2999 // INTERACT_ACROSS_USERS_FULL permission thus is likely to be an important process.
3000 Slog.e(TAG, "User #" + userId + " is not running.");
3001 return InputBindResult.INVALID_USER;
3002 }
3003 } else {
3004 userId = callingUserId;
3005 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003006 final InputBindResult result;
3007 synchronized (mMethodMap) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003008 final long ident = Binder.clearCallingIdentity();
3009 try {
3010 result = startInputOrWindowGainedFocusInternalLocked(startInputReason, client,
3011 windowToken, startInputFlags, softInputMode, windowFlags, attribute,
3012 inputContext, missingMethods, unverifiedTargetSdkVersion, userId);
3013 } finally {
3014 Binder.restoreCallingIdentity(ident);
3015 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003016 }
Yohei Yukawa2553e482017-12-15 15:47:33 -08003017 if (result == null) {
3018 // This must never happen, but just in case.
3019 Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
Yohei Yukawaa468d702018-10-21 11:42:34 -07003020 + InputMethodDebug.startInputReasonToString(startInputReason)
Yohei Yukawa2553e482017-12-15 15:47:33 -08003021 + " windowFlags=#" + Integer.toHexString(windowFlags)
3022 + " editorInfo=" + attribute);
3023 return InputBindResult.NULL;
3024 }
3025 return result;
Yohei Yukawa05c25f82016-02-22 12:41:17 -08003026 }
3027
Yohei Yukawa2553e482017-12-15 15:47:33 -08003028 @NonNull
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003029 private InputBindResult startInputOrWindowGainedFocusInternalLocked(
Yohei Yukawadc66e522018-10-21 10:43:14 -07003030 @StartInputReason int startInputReason, IInputMethodClient client,
Yohei Yukawa35fa6d52018-10-31 11:33:32 -07003031 @NonNull IBinder windowToken, @StartInputFlags int startInputFlags,
3032 @SoftInputModeFlags int softInputMode, int windowFlags, EditorInfo attribute,
3033 IInputContext inputContext, @MissingMethodFlags int missingMethods,
Yohei Yukawa4391c202019-01-28 00:49:10 -08003034 int unverifiedTargetSdkVersion, @UserIdInt int userId) {
Yohei Yukawa67464522019-01-28 00:50:09 -08003035 if (DEBUG) {
3036 Slog.v(TAG, "startInputOrWindowGainedFocusInternalLocked: reason="
3037 + InputMethodDebug.startInputReasonToString(startInputReason)
3038 + " client=" + client.asBinder()
3039 + " inputContext=" + inputContext
3040 + " missingMethods="
3041 + InputConnectionInspector.getMissingMethodFlagsAsString(missingMethods)
3042 + " attribute=" + attribute
3043 + " startInputFlags="
3044 + InputMethodDebug.startInputFlagsToString(startInputFlags)
3045 + " softInputMode=" + InputMethodDebug.softInputModeToString(softInputMode)
3046 + " windowFlags=#" + Integer.toHexString(windowFlags)
3047 + " unverifiedTargetSdkVersion=" + unverifiedTargetSdkVersion);
3048 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003049
Yohei Yukawa67464522019-01-28 00:50:09 -08003050 final int windowDisplayId = mWindowManagerInternal.getDisplayIdForWindow(windowToken);
3051
3052 final ClientState cs = mClients.get(client.asBinder());
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003053 if (cs == null) {
Yohei Yukawa67464522019-01-28 00:50:09 -08003054 throw new IllegalArgumentException("unknown client " + client.asBinder());
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003055 }
3056 if (cs.selfReportedDisplayId != windowDisplayId) {
3057 Slog.e(TAG, "startInputOrWindowGainedFocusInternal: display ID mismatch."
3058 + " from client:" + cs.selfReportedDisplayId
3059 + " from window:" + windowDisplayId);
3060 return InputBindResult.DISPLAY_ID_MISMATCH;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003061 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08003062
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003063 if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
3064 cs.selfReportedDisplayId)) {
3065 // Check with the window manager to make sure this client actually
3066 // has a window with focus. If not, reject. This is thread safe
3067 // because if the focus changes some time before or after, the
3068 // next client receiving focus that has any interest in input will
3069 // be calling through here after that change happens.
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003070 if (DEBUG) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003071 Slog.w(TAG, "Focus gain on non-focused client " + cs.client
3072 + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003073 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003074 return InputBindResult.NOT_IME_TARGET_WINDOW;
3075 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003076
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003077 // cross-profile access is always allowed here to allow profile-switching.
3078 if (!mSettings.isCurrentProfile(userId)) {
3079 Slog.w(TAG, "A background user is requesting window. Hiding IME.");
3080 Slog.w(TAG, "If you need to impersonate a foreground user/profile from"
3081 + " a background user, use EditorInfo.targetInputMethodUser with"
3082 + " INTERACT_ACROSS_USERS_FULL permission.");
3083 hideCurrentInputLocked(0, null);
3084 return InputBindResult.INVALID_USER;
3085 }
3086
Tarandeep Singhcf5ff822019-07-08 14:06:27 -07003087 if (userId != mSettings.getCurrentUserId()) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003088 switchUserLocked(userId);
3089 }
3090 // Master feature flag that overrides other conditions and forces IME preRendering.
3091 if (DEBUG) {
3092 Slog.v(TAG, "IME PreRendering MASTER flag: "
Yohei Yukawa67464522019-01-28 00:50:09 -08003093 + DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() + ", LowRam: " + mIsLowRam);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003094 }
3095 // pre-rendering not supported on low-ram devices.
3096 cs.shouldPreRenderIme = DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() && !mIsLowRam;
3097
3098 if (mCurFocusedWindow == windowToken) {
3099 if (DEBUG) {
3100 Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
3101 + " attribute=" + attribute + ", token = " + windowToken);
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003102 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003103 if (attribute != null) {
3104 return startInputUncheckedLocked(cs, inputContext, missingMethods,
3105 attribute, startInputFlags, startInputReason);
3106 }
3107 return new InputBindResult(
3108 InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
Yohei Yukawab4f328a2019-05-02 08:41:27 -07003109 null, null, null, -1, null);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003110 }
3111 mCurFocusedWindow = windowToken;
3112 mCurFocusedWindowSoftInputMode = softInputMode;
3113 mCurFocusedWindowClient = cs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003114
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003115 // Should we auto-show the IME even if the caller has not
3116 // specified what should be done with it?
3117 // We only do this automatically if the window can resize
3118 // to accommodate the IME (so what the user sees will give
3119 // them good context without input information being obscured
3120 // by the IME) or if running on a large screen where there
3121 // is more room for the target window + IME.
3122 final boolean doAutoShow =
Yohei Yukawa6e875592019-01-28 00:49:30 -08003123 (softInputMode & LayoutParams.SOFT_INPUT_MASK_ADJUST)
3124 == LayoutParams.SOFT_INPUT_ADJUST_RESIZE
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003125 || mRes.getConfiguration().isLayoutSizeAtLeast(
3126 Configuration.SCREENLAYOUT_SIZE_LARGE);
Yohei Yukawa67464522019-01-28 00:50:09 -08003127 final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003128
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003129 // We want to start input before showing the IME, but after closing
3130 // it. We want to do this after closing it to help the IME disappear
3131 // more quickly (not get stuck behind it initializing itself for the
3132 // new focused input, even if its window wants to hide the IME).
3133 boolean didStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003134
Yohei Yukawa67464522019-01-28 00:50:09 -08003135 InputBindResult res = null;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003136 switch (softInputMode & LayoutParams.SOFT_INPUT_MASK_STATE) {
3137 case LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003138 if (!isTextEditor || !doAutoShow) {
Yohei Yukawa6e875592019-01-28 00:49:30 -08003139 if (LayoutParams.mayUseInputMethod(windowFlags)) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003140 // There is no focus view, and this window will
3141 // be behind any soft input window, so hide the
3142 // soft input window if it is shown.
3143 if (DEBUG) Slog.v(TAG, "Unspecified window will hide input");
3144 hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003145
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003146 // If focused display changed, we should unbind current method
3147 // to make app window in previous display relayout after Ime
3148 // window token removed.
3149 // Note that we can trust client's display ID as long as it matches
3150 // to the display ID obtained from the window.
3151 if (cs.selfReportedDisplayId != mCurTokenDisplayId) {
3152 unbindCurrentMethodLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003153 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003154 }
Yohei Yukawa6e875592019-01-28 00:49:30 -08003155 } else if (isTextEditor && doAutoShow
3156 && (softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003157 // There is a focus view, and we are navigating forward
3158 // into the window, so show the input window for the user.
3159 // We only do this automatically if the window can resize
3160 // to accommodate the IME (so what the user sees will give
3161 // them good context without input information being obscured
3162 // by the IME) or if running on a large screen where there
3163 // is more room for the target window + IME.
3164 if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
3165 if (attribute != null) {
3166 res = startInputUncheckedLocked(cs, inputContext, missingMethods,
3167 attribute, startInputFlags, startInputReason);
3168 didStart = true;
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003169 }
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08003170 showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003171 }
3172 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003173 case LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003174 // Do nothing.
3175 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003176 case LayoutParams.SOFT_INPUT_STATE_HIDDEN:
3177 if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003178 if (DEBUG) Slog.v(TAG, "Window asks to hide input going forward");
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003179 hideCurrentInputLocked(0, null);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003180 }
3181 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003182 case LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003183 if (DEBUG) Slog.v(TAG, "Window asks to hide input");
3184 hideCurrentInputLocked(0, null);
3185 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003186 case LayoutParams.SOFT_INPUT_STATE_VISIBLE:
3187 if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003188 if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003189 if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
3190 unverifiedTargetSdkVersion, startInputFlags)) {
3191 if (attribute != null) {
Yohei Yukawa67464522019-01-28 00:50:09 -08003192 res = startInputUncheckedLocked(cs, inputContext, missingMethods,
3193 attribute, startInputFlags, startInputReason);
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003194 didStart = true;
3195 }
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08003196 showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null);
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003197 } else {
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003198 Slog.e(TAG, "SOFT_INPUT_STATE_VISIBLE is ignored because"
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003199 + " there is no focused view that also returns true from"
3200 + " View#onCheckIsTextEditor()");
3201 }
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003202 }
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003203 break;
Yohei Yukawa6e875592019-01-28 00:49:30 -08003204 case LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003205 if (DEBUG) Slog.v(TAG, "Window asks to always show input");
3206 if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
3207 unverifiedTargetSdkVersion, startInputFlags)) {
3208 if (attribute != null) {
3209 res = startInputUncheckedLocked(cs, inputContext, missingMethods,
3210 attribute, startInputFlags, startInputReason);
3211 didStart = true;
3212 }
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08003213 showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null);
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003214 } else {
3215 Slog.e(TAG, "SOFT_INPUT_STATE_ALWAYS_VISIBLE is ignored because"
3216 + " there is no focused view that also returns true from"
3217 + " View#onCheckIsTextEditor()");
3218 }
3219 break;
3220 }
3221
3222 if (!didStart) {
3223 if (attribute != null) {
3224 if (!DebugFlags.FLAG_OPTIMIZE_START_INPUT.value()
3225 || (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0) {
Yohei Yukawa67464522019-01-28 00:50:09 -08003226 res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
Yohei Yukawa13dc12f2019-01-28 00:49:24 -08003227 startInputFlags, startInputReason);
3228 } else {
3229 res = InputBindResult.NO_EDITOR;
3230 }
3231 } else {
3232 res = InputBindResult.NULL_EDITOR_INFO;
Yohei Yukawa7cc33562019-01-28 00:49:18 -08003233 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003234 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08003235 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003236 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003237
Guliz Tuncay6908c152017-06-02 16:06:10 -07003238 private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08003239 // TODO(yukawa): multi-display support.
Guliz Tuncay6908c152017-06-02 16:06:10 -07003240 final int uid = Binder.getCallingUid();
lumark0b05f9e2018-11-26 15:09:06 +08003241 if (mCurFocusedWindowClient != null && client != null
Tarandeep Singheb570612018-01-29 16:20:32 -08003242 && mCurFocusedWindowClient.client.asBinder() == client.asBinder()) {
Guliz Tuncay6908c152017-06-02 16:06:10 -07003243 return true;
3244 } else if (mCurIntent != null && InputMethodUtils.checkIfPackageBelongsToUid(
3245 mAppOpsManager,
3246 uid,
3247 mCurIntent.getComponent().getPackageName())) {
3248 return true;
Guliz Tuncay6908c152017-06-02 16:06:10 -07003249 }
Guliz Tuncay6908c152017-06-02 16:06:10 -07003250 return false;
3251 }
3252
satok42c5a162011-05-26 16:46:14 +09003253 @Override
Seigo Nonaka14e13912015-05-06 21:04:13 -07003254 public void showInputMethodPickerFromClient(
3255 IInputMethodClient client, int auxiliarySubtypeMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003256 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003257 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003258 return;
3259 }
Guliz Tuncay6908c152017-06-02 16:06:10 -07003260 if(!canShowInputMethodPickerLocked(client)) {
satok47a44912010-10-06 16:03:58 +09003261 Slog.w(TAG, "Ignoring showInputMethodPickerFromClient of uid "
Dianne Hackborncef65ee2010-09-30 18:27:22 -07003262 + Binder.getCallingUid() + ": " + client);
Guliz Tuncay6908c152017-06-02 16:06:10 -07003263 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003264 }
3265
satok440aab52010-11-25 09:43:11 +09003266 // Always call subtype picker, because subtype picker is a superset of input method
3267 // picker.
lumark0b05f9e2018-11-26 15:09:06 +08003268 mHandler.sendMessage(mCaller.obtainMessageII(
3269 MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode,
3270 (mCurClient != null) ? mCurClient.selfReportedDisplayId : DEFAULT_DISPLAY));
satokab751aa2010-09-14 19:17:36 +09003271 }
3272 }
3273
lumark0b05f9e2018-11-26 15:09:06 +08003274 @Override
3275 public void showInputMethodPickerFromSystem(IInputMethodClient client, int auxiliarySubtypeMode,
3276 int displayId) {
3277 if (mContext.checkCallingPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
3278 != PackageManager.PERMISSION_GRANTED) {
3279 throw new SecurityException(
3280 "showInputMethodPickerFromSystem requires WRITE_SECURE_SETTINGS permission");
3281 }
3282 // Always call subtype picker, because subtype picker is a superset of input method
3283 // picker.
3284 mHandler.sendMessage(mCaller.obtainMessageII(
3285 MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode, displayId));
3286 }
3287
Tarandeep Singheb570612018-01-29 16:20:32 -08003288 public boolean isInputMethodPickerShownForTest() {
3289 synchronized(mMethodMap) {
3290 if (mSwitchingDialog == null) {
3291 return false;
3292 }
3293 return mSwitchingDialog.isShowing();
3294 }
3295 }
3296
Yohei Yukawa0c1ebff2018-12-27 14:06:28 -08003297 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003298 private void setInputMethod(@NonNull IBinder token, String id) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003299 synchronized (mMethodMap) {
Yohei Yukawa0c1ebff2018-12-27 14:06:28 -08003300 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003301 return;
3302 }
3303 setInputMethodWithSubtypeIdLocked(token, id, NOT_A_SUBTYPE_ID);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003304 }
satok28203512010-11-24 11:06:49 +09003305 }
3306
Yohei Yukawa4773ee12018-12-24 21:13:53 -08003307 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003308 private void setInputMethodAndSubtype(@NonNull IBinder token, String id,
3309 InputMethodSubtype subtype) {
satok28203512010-11-24 11:06:49 +09003310 synchronized (mMethodMap) {
Yohei Yukawa4773ee12018-12-24 21:13:53 -08003311 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003312 return;
3313 }
satok28203512010-11-24 11:06:49 +09003314 if (subtype != null) {
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003315 setInputMethodWithSubtypeIdLocked(token, id,
3316 InputMethodUtils.getSubtypeIdFromHashCode(mMethodMap.get(id),
3317 subtype.hashCode()));
satok28203512010-11-24 11:06:49 +09003318 } else {
3319 setInputMethod(token, id);
3320 }
3321 }
satokab751aa2010-09-14 19:17:36 +09003322 }
3323
satok42c5a162011-05-26 16:46:14 +09003324 @Override
satokb416a712010-11-25 20:42:14 +09003325 public void showInputMethodAndSubtypeEnablerFromClient(
satok217f5482010-12-15 05:19:19 +09003326 IInputMethodClient client, String inputMethodId) {
satokb416a712010-11-25 20:42:14 +09003327 synchronized (mMethodMap) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003328 // TODO(yukawa): Should we verify the display ID?
Yohei Yukawa46d74762019-01-22 10:17:22 -08003329 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003330 return;
3331 }
satok7fee71f2010-12-17 18:54:26 +09003332 executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
3333 MSG_SHOW_IM_SUBTYPE_ENABLER, inputMethodId));
satokb416a712010-11-25 20:42:14 +09003334 }
3335 }
3336
Yohei Yukawa0c499082018-12-09 18:52:02 -08003337 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003338 private boolean switchToPreviousInputMethod(@NonNull IBinder token) {
satok735cf382010-11-11 20:40:09 +09003339 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003340 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa0c499082018-12-09 18:52:02 -08003341 return false;
3342 }
satokc445bcd2011-01-25 18:57:24 +09003343 final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
satok4fc87d62011-05-20 16:13:43 +09003344 final InputMethodInfo lastImi;
satok208d5632011-05-20 22:13:38 +09003345 if (lastIme != null) {
satok4fc87d62011-05-20 16:13:43 +09003346 lastImi = mMethodMap.get(lastIme.first);
3347 } else {
3348 lastImi = null;
satok735cf382010-11-11 20:40:09 +09003349 }
satok4fc87d62011-05-20 16:13:43 +09003350 String targetLastImiId = null;
3351 int subtypeId = NOT_A_SUBTYPE_ID;
3352 if (lastIme != null && lastImi != null) {
3353 final boolean imiIdIsSame = lastImi.getId().equals(mCurMethodId);
Narayan Kamatha09b4d22016-04-15 18:32:45 +01003354 final int lastSubtypeHash = Integer.parseInt(lastIme.second);
satok4fc87d62011-05-20 16:13:43 +09003355 final int currentSubtypeHash = mCurrentSubtype == null ? NOT_A_SUBTYPE_ID
3356 : mCurrentSubtype.hashCode();
3357 // If the last IME is the same as the current IME and the last subtype is not
3358 // defined, there is no need to switch to the last IME.
3359 if (!imiIdIsSame || lastSubtypeHash != currentSubtypeHash) {
3360 targetLastImiId = lastIme.first;
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003361 subtypeId = InputMethodUtils.getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
satok4fc87d62011-05-20 16:13:43 +09003362 }
3363 }
3364
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003365 if (TextUtils.isEmpty(targetLastImiId)
3366 && !InputMethodUtils.canAddToLastInputMethod(mCurrentSubtype)) {
satok4fc87d62011-05-20 16:13:43 +09003367 // This is a safety net. If the currentSubtype can't be added to the history
3368 // and the framework couldn't find the last ime, we will make the last ime be
3369 // the most applicable enabled keyboard subtype of the system imes.
3370 final List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
3371 if (enabled != null) {
3372 final int N = enabled.size();
3373 final String locale = mCurrentSubtype == null
3374 ? mRes.getConfiguration().locale.toString()
3375 : mCurrentSubtype.getLocale();
3376 for (int i = 0; i < N; ++i) {
3377 final InputMethodInfo imi = enabled.get(i);
Yohei Yukawafd70fe82018-04-08 12:19:56 -07003378 if (imi.getSubtypeCount() > 0 && imi.isSystem()) {
satok4fc87d62011-05-20 16:13:43 +09003379 InputMethodSubtype keyboardSubtype =
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003380 InputMethodUtils.findLastResortApplicableSubtypeLocked(mRes,
3381 InputMethodUtils.getSubtypes(imi),
3382 InputMethodUtils.SUBTYPE_MODE_KEYBOARD, locale, true);
satok4fc87d62011-05-20 16:13:43 +09003383 if (keyboardSubtype != null) {
3384 targetLastImiId = imi.getId();
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003385 subtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
satok4fc87d62011-05-20 16:13:43 +09003386 imi, keyboardSubtype.hashCode());
3387 if(keyboardSubtype.getLocale().equals(locale)) {
3388 break;
3389 }
3390 }
3391 }
3392 }
3393 }
3394 }
3395
3396 if (!TextUtils.isEmpty(targetLastImiId)) {
3397 if (DEBUG) {
3398 Slog.d(TAG, "Switch to: " + lastImi.getId() + ", " + lastIme.second
3399 + ", from: " + mCurMethodId + ", " + subtypeId);
3400 }
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003401 setInputMethodWithSubtypeIdLocked(token, targetLastImiId, subtypeId);
satok4fc87d62011-05-20 16:13:43 +09003402 return true;
3403 } else {
3404 return false;
3405 }
satok735cf382010-11-11 20:40:09 +09003406 }
3407 }
3408
Yohei Yukawa70f17e72018-12-09 18:51:38 -08003409 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08003410 private boolean switchToNextInputMethod(@NonNull IBinder token, boolean onlyCurrentIme) {
satok688bd472012-02-09 20:09:17 +09003411 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003412 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawaa0755742014-06-04 20:28:18 +09003413 return false;
3414 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003415 final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
Yohei Yukawa136b6ce2018-05-02 10:55:35 -07003416 onlyCurrentIme, mMethodMap.get(mCurMethodId), mCurrentSubtype);
satok688bd472012-02-09 20:09:17 +09003417 if (nextSubtype == null) {
3418 return false;
3419 }
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003420 setInputMethodWithSubtypeIdLocked(token, nextSubtype.mImi.getId(),
3421 nextSubtype.mSubtypeId);
satok688bd472012-02-09 20:09:17 +09003422 return true;
3423 }
3424 }
3425
Yohei Yukawaeec552e2018-09-09 20:48:41 -07003426 @BinderThread
3427 private boolean shouldOfferSwitchingToNextInputMethod(@NonNull IBinder token) {
Satoshi Kataoka2b10b522013-08-21 20:39:12 +09003428 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003429 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawaa0755742014-06-04 20:28:18 +09003430 return false;
3431 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003432 final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
Yohei Yukawa136b6ce2018-05-02 10:55:35 -07003433 false /* onlyCurrentIme */, mMethodMap.get(mCurMethodId), mCurrentSubtype);
Satoshi Kataoka2b10b522013-08-21 20:39:12 +09003434 if (nextSubtype == null) {
3435 return false;
3436 }
3437 return true;
3438 }
3439 }
3440
3441 @Override
satok68f1b782011-04-11 14:26:04 +09003442 public InputMethodSubtype getLastInputMethodSubtype() {
3443 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003444 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003445 return null;
3446 }
satok68f1b782011-04-11 14:26:04 +09003447 final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
3448 // TODO: Handle the case of the last IME with no subtypes
3449 if (lastIme == null || TextUtils.isEmpty(lastIme.first)
3450 || TextUtils.isEmpty(lastIme.second)) return null;
3451 final InputMethodInfo lastImi = mMethodMap.get(lastIme.first);
3452 if (lastImi == null) return null;
3453 try {
Narayan Kamatha09b4d22016-04-15 18:32:45 +01003454 final int lastSubtypeHash = Integer.parseInt(lastIme.second);
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09003455 final int lastSubtypeId =
3456 InputMethodUtils.getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
satok0e7d7d62011-07-05 13:28:06 +09003457 if (lastSubtypeId < 0 || lastSubtypeId >= lastImi.getSubtypeCount()) {
3458 return null;
3459 }
3460 return lastImi.getSubtypeAt(lastSubtypeId);
satok68f1b782011-04-11 14:26:04 +09003461 } catch (NumberFormatException e) {
3462 return null;
3463 }
3464 }
3465 }
3466
satoke7c6998e2011-06-03 17:57:59 +09003467 @Override
satokee5e77c2011-09-02 18:50:15 +09003468 public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
satok91e88122011-07-18 11:11:42 +09003469 // By this IPC call, only a process which shares the same uid with the IME can add
3470 // additional input method subtypes to the IME.
Yohei Yukawa70f5c482016-01-04 19:42:36 -08003471 if (TextUtils.isEmpty(imiId) || subtypes == null) return;
Yohei Yukawab557d572018-12-29 21:26:26 -08003472 final ArrayList<InputMethodSubtype> toBeAdded = new ArrayList<>();
3473 for (InputMethodSubtype subtype : subtypes) {
3474 if (!toBeAdded.contains(subtype)) {
3475 toBeAdded.add(subtype);
3476 } else {
3477 Slog.w(TAG, "Duplicated subtype definition found: "
3478 + subtype.getLocale() + ", " + subtype.getMode());
3479 }
3480 }
satoke7c6998e2011-06-03 17:57:59 +09003481 synchronized (mMethodMap) {
Yohei Yukawa46d74762019-01-22 10:17:22 -08003482 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08003483 return;
3484 }
Yohei Yukawa79247822017-01-23 15:26:15 -08003485 if (!mSystemReady) {
3486 return;
3487 }
satok91e88122011-07-18 11:11:42 +09003488 final InputMethodInfo imi = mMethodMap.get(imiId);
satokee5e77c2011-09-02 18:50:15 +09003489 if (imi == null) return;
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09003490 final String[] packageInfos;
3491 try {
3492 packageInfos = mIPackageManager.getPackagesForUid(Binder.getCallingUid());
3493 } catch (RemoteException e) {
3494 Slog.e(TAG, "Failed to get package infos");
3495 return;
3496 }
satok91e88122011-07-18 11:11:42 +09003497 if (packageInfos != null) {
3498 final int packageNum = packageInfos.length;
3499 for (int i = 0; i < packageNum; ++i) {
3500 if (packageInfos[i].equals(imi.getPackageName())) {
Yohei Yukawa7b1c8d72018-12-19 11:21:04 -08003501 if (subtypes.length > 0) {
Yohei Yukawab557d572018-12-29 21:26:26 -08003502 mAdditionalSubtypeMap.put(imi.getId(), toBeAdded);
Yohei Yukawa7b1c8d72018-12-19 11:21:04 -08003503 } else {
Yohei Yukawab557d572018-12-29 21:26:26 -08003504 mAdditionalSubtypeMap.remove(imi.getId());
Yohei Yukawa7b1c8d72018-12-19 11:21:04 -08003505 }
Yohei Yukawab557d572018-12-29 21:26:26 -08003506 AdditionalSubtypeUtils.save(mAdditionalSubtypeMap, mMethodMap,
3507 mSettings.getCurrentUserId());
satokc5933802011-08-31 21:26:04 +09003508 final long ident = Binder.clearCallingIdentity();
3509 try {
Yohei Yukawa94e33302016-02-12 19:37:03 -08003510 buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
satokc5933802011-08-31 21:26:04 +09003511 } finally {
3512 Binder.restoreCallingIdentity(ident);
3513 }
satokee5e77c2011-09-02 18:50:15 +09003514 return;
satok91e88122011-07-18 11:11:42 +09003515 }
3516 }
3517 }
satoke7c6998e2011-06-03 17:57:59 +09003518 }
satokee5e77c2011-09-02 18:50:15 +09003519 return;
satoke7c6998e2011-06-03 17:57:59 +09003520 }
3521
Yohei Yukawab985e6e2018-09-05 17:07:52 -07003522 /**
Artur Satayev192ca302020-01-22 21:38:23 +00003523 * This is kept due to {@code @UnsupportedAppUsage} in
Yohei Yukawab985e6e2018-09-05 17:07:52 -07003524 * {@link InputMethodManager#getInputMethodWindowVisibleHeight()} and a dependency in
3525 * {@link InputMethodService#onCreate()}.
3526 *
3527 * <p>TODO(Bug 113914148): Check if we can remove this.</p>
3528 * @return {@link WindowManagerInternal#getInputMethodWindowVisibleHeight()}
3529 */
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09003530 @Override
3531 public int getInputMethodWindowVisibleHeight() {
Yohei Yukawa4052a10f2018-10-15 15:35:55 +08003532 // TODO(yukawa): Should we verify the display ID?
lumark90120a82018-08-15 00:33:03 +08003533 return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId);
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09003534 }
3535
Yohei Yukawab4f328a2019-05-02 08:41:27 -07003536 @Override
3537 public void reportActivityView(IInputMethodClient parentClient, int childDisplayId,
3538 float[] matrixValues) {
3539 final DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(childDisplayId);
3540 if (displayInfo == null) {
3541 throw new IllegalArgumentException(
3542 "Cannot find display for non-existent displayId: " + childDisplayId);
3543 }
3544 final int callingUid = Binder.getCallingUid();
3545 if (callingUid != displayInfo.ownerUid) {
3546 throw new SecurityException("The caller doesn't own the display.");
3547 }
3548
3549 synchronized (mMethodMap) {
3550 final ClientState cs = mClients.get(parentClient.asBinder());
3551 if (cs == null) {
3552 return;
3553 }
3554
3555 // null matrixValues means that the entry needs to be removed.
3556 if (matrixValues == null) {
3557 final ActivityViewInfo info = mActivityViewDisplayIdToParentMap.get(childDisplayId);
3558 if (info == null) {
3559 return;
3560 }
3561 if (info.mParentClient != cs) {
3562 throw new SecurityException("Only the owner client can clear"
3563 + " ActivityViewGeometry for display #" + childDisplayId);
3564 }
3565 mActivityViewDisplayIdToParentMap.remove(childDisplayId);
3566 return;
3567 }
3568
3569 ActivityViewInfo info = mActivityViewDisplayIdToParentMap.get(childDisplayId);
3570 if (info != null && info.mParentClient != cs) {
3571 throw new InvalidParameterException("Display #" + childDisplayId
3572 + " is already registered by " + info.mParentClient);
3573 }
3574 if (info == null) {
3575 if (!mWindowManagerInternal.isUidAllowedOnDisplay(childDisplayId, cs.uid)) {
3576 throw new SecurityException(cs + " cannot access to display #"
3577 + childDisplayId);
3578 }
3579 info = new ActivityViewInfo(cs, new Matrix());
3580 mActivityViewDisplayIdToParentMap.put(childDisplayId, info);
3581 }
3582 info.mMatrix.setValues(matrixValues);
3583
3584 if (mCurClient == null || mCurClient.curSession == null) {
3585 return;
3586 }
3587
3588 Matrix matrix = null;
3589 int displayId = mCurClient.selfReportedDisplayId;
3590 boolean needToNotify = false;
3591 while (true) {
3592 needToNotify |= (displayId == childDisplayId);
3593 final ActivityViewInfo next = mActivityViewDisplayIdToParentMap.get(displayId);
3594 if (next == null) {
3595 break;
3596 }
3597 if (matrix == null) {
3598 matrix = new Matrix(next.mMatrix);
3599 } else {
3600 matrix.postConcat(next.mMatrix);
3601 }
3602 if (next.mParentClient.selfReportedDisplayId == mCurTokenDisplayId) {
3603 if (needToNotify) {
3604 final float[] values = new float[9];
3605 matrix.getValues(values);
3606 try {
3607 mCurClient.client.updateActivityViewToScreenMatrix(mCurSeq, values);
3608 } catch (RemoteException e) {
3609 }
3610 }
3611 break;
3612 }
3613 displayId = info.mParentClient.selfReportedDisplayId;
3614 }
3615 }
3616 }
3617
Yohei Yukawac54c1172018-09-06 11:39:50 -07003618 @BinderThread
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003619 private void notifyUserAction(@NonNull IBinder token) {
Satoshi Kataokad7443c82013-10-15 17:45:43 +09003620 if (DEBUG) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003621 Slog.d(TAG, "Got the notification of a user action.");
Satoshi Kataokad7443c82013-10-15 17:45:43 +09003622 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003623 synchronized (mMethodMap) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003624 if (mCurToken != token) {
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09003625 if (DEBUG) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07003626 Slog.d(TAG, "Ignoring the user action notification from IMEs that are no longer"
3627 + " active.");
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09003628 }
3629 return;
3630 }
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003631 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
3632 if (imi != null) {
Yohei Yukawa02970512014-06-05 16:16:18 +09003633 mSwitchingController.onUserActionLocked(imi, mCurrentSubtype);
Yohei Yukawa5a647b692014-05-22 12:49:00 +09003634 }
Satoshi Kataokad7443c82013-10-15 17:45:43 +09003635 }
3636 }
3637
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08003638 @BinderThread
3639 private void reportPreRendered(IBinder token, EditorInfo info) {
3640 synchronized (mMethodMap) {
3641 if (!calledWithValidTokenLocked(token)) {
3642 return;
3643 }
3644 if (mCurClient != null && mCurClient.client != null) {
3645 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
3646 MSG_REPORT_PRE_RENDERED, info, mCurClient));
3647 }
3648 }
3649 }
3650
3651 @BinderThread
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08003652 private void applyImeVisibility(IBinder token, IBinder windowToken, boolean setVisible) {
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08003653 synchronized (mMethodMap) {
3654 if (!calledWithValidTokenLocked(token)) {
3655 return;
3656 }
Tarandeep Singh500a38f2019-09-26 13:36:40 -07003657 if (!setVisible) {
Taran Singhd7fc5862019-10-10 14:45:17 +02003658 if (mCurClient != null) {
3659 // IMMS only knows of focused window, not the actual IME target.
3660 // e.g. it isn't aware of any window that has both
3661 // NOT_FOCUSABLE, ALT_FOCUSABLE_IM flags set and can the IME target.
3662 // Send it to window manager to hide IME from IME target window.
3663 // TODO(b/139861270): send to mCurClient.client once IMMS is aware of
3664 // actual IME target.
3665 mWindowManagerInternal.hideIme(mCurClient.selfReportedDisplayId);
Tarandeep Singh500a38f2019-09-26 13:36:40 -07003666 }
3667 } else {
3668 // Send to window manager to show IME after IME layout finishes.
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08003669 mWindowManagerInternal.showImePostLayout(mShowRequestWindowMap.get(windowToken));
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08003670 }
3671 }
3672 }
3673
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003674 private void setInputMethodWithSubtypeIdLocked(IBinder token, String id, int subtypeId) {
3675 if (token == null) {
3676 if (mContext.checkCallingOrSelfPermission(
3677 android.Manifest.permission.WRITE_SECURE_SETTINGS)
3678 != PackageManager.PERMISSION_GRANTED) {
3679 throw new SecurityException(
3680 "Using null token requires permission "
3681 + android.Manifest.permission.WRITE_SECURE_SETTINGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003682 }
Yohei Yukawa4e02bc62014-06-04 18:37:20 +09003683 } else if (mCurToken != token) {
3684 Slog.w(TAG, "Ignoring setInputMethod of uid " + Binder.getCallingUid()
3685 + " token: " + token);
3686 return;
3687 }
3688
3689 final long ident = Binder.clearCallingIdentity();
3690 try {
3691 setInputMethodLocked(id, subtypeId);
3692 } finally {
3693 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003694 }
3695 }
3696
Yohei Yukawaeec552e2018-09-09 20:48:41 -07003697 @BinderThread
3698 private void hideMySoftInput(@NonNull IBinder token, int flags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003699 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003700 if (!calledWithValidTokenLocked(token)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003701 return;
3702 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003703 long ident = Binder.clearCallingIdentity();
3704 try {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003705 hideCurrentInputLocked(flags, null);
3706 } finally {
3707 Binder.restoreCallingIdentity(ident);
3708 }
3709 }
3710 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003711
Yohei Yukawaeec552e2018-09-09 20:48:41 -07003712 @BinderThread
3713 private void showMySoftInput(@NonNull IBinder token, int flags) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003714 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08003715 if (!calledWithValidTokenLocked(token)) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003716 return;
3717 }
3718 long ident = Binder.clearCallingIdentity();
3719 try {
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08003720 showCurrentInputLocked(mLastImeTargetWindow, flags, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003721 } finally {
3722 Binder.restoreCallingIdentity(ident);
3723 }
3724 }
3725 }
3726
3727 void setEnabledSessionInMainThread(SessionState session) {
3728 if (mEnabledSession != session) {
Yohei Yukawa9d91b432014-05-19 16:03:24 +09003729 if (mEnabledSession != null && mEnabledSession.session != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003730 try {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003731 if (DEBUG) Slog.v(TAG, "Disabling: " + mEnabledSession);
Yohei Yukawa9d91b432014-05-19 16:03:24 +09003732 mEnabledSession.method.setSessionEnabled(mEnabledSession.session, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003733 } catch (RemoteException e) {
3734 }
3735 }
3736 mEnabledSession = session;
Yohei Yukawa9d91b432014-05-19 16:03:24 +09003737 if (mEnabledSession != null && mEnabledSession.session != null) {
3738 try {
3739 if (DEBUG) Slog.v(TAG, "Enabling: " + mEnabledSession);
3740 mEnabledSession.method.setSessionEnabled(mEnabledSession.session, true);
3741 } catch (RemoteException e) {
3742 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003743 }
3744 }
3745 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003746
Yohei Yukawa930328c2017-10-18 20:19:53 -07003747 @MainThread
satok42c5a162011-05-26 16:46:14 +09003748 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003749 public boolean handleMessage(Message msg) {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003750 SomeArgs args;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003751 switch (msg.what) {
satokab751aa2010-09-14 19:17:36 +09003752 case MSG_SHOW_IM_SUBTYPE_PICKER:
Seigo Nonaka14e13912015-05-06 21:04:13 -07003753 final boolean showAuxSubtypes;
lumark0b05f9e2018-11-26 15:09:06 +08003754 final int displayId = msg.arg2;
Seigo Nonaka14e13912015-05-06 21:04:13 -07003755 switch (msg.arg1) {
3756 case InputMethodManager.SHOW_IM_PICKER_MODE_AUTO:
3757 // This is undocumented so far, but IMM#showInputMethodPicker() has been
3758 // implemented so that auxiliary subtypes will be excluded when the soft
3759 // keyboard is invisible.
3760 showAuxSubtypes = mInputShown;
3761 break;
3762 case InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES:
3763 showAuxSubtypes = true;
3764 break;
3765 case InputMethodManager.SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES:
3766 showAuxSubtypes = false;
3767 break;
3768 default:
3769 Slog.e(TAG, "Unknown subtype picker mode = " + msg.arg1);
3770 return false;
3771 }
lumark0b05f9e2018-11-26 15:09:06 +08003772 showInputMethodMenu(showAuxSubtypes, displayId);
satokab751aa2010-09-14 19:17:36 +09003773 return true;
3774
satok47a44912010-10-06 16:03:58 +09003775 case MSG_SHOW_IM_SUBTYPE_ENABLER:
Yohei Yukawa41f34272015-12-14 15:41:52 -08003776 showInputMethodAndSubtypeEnabler((String)msg.obj);
satok217f5482010-12-15 05:19:19 +09003777 return true;
3778
3779 case MSG_SHOW_IM_CONFIG:
3780 showConfigureInputMethods();
satok47a44912010-10-06 16:03:58 +09003781 return true;
3782
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003783 // ---------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003784
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003785 case MSG_UNBIND_INPUT:
3786 try {
3787 ((IInputMethod)msg.obj).unbindInput();
3788 } catch (RemoteException e) {
3789 // There is nothing interesting about the method dying.
3790 }
3791 return true;
3792 case MSG_BIND_INPUT:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003793 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003794 try {
3795 ((IInputMethod)args.arg1).bindInput((InputBinding)args.arg2);
3796 } catch (RemoteException e) {
3797 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003798 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003799 return true;
3800 case MSG_SHOW_SOFT_INPUT:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003801 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003802 try {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07003803 if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".showSoftInput("
Craig Mautner6efb4c72013-03-13 10:17:41 -07003804 + msg.arg1 + ", " + args.arg2 + ")");
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08003805 ((IInputMethod) args.arg1).showSoftInput(
3806 (IBinder) args.arg3, msg.arg1, (ResultReceiver) args.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003807 } catch (RemoteException e) {
3808 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003809 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003810 return true;
3811 case MSG_HIDE_SOFT_INPUT:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003812 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003813 try {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07003814 if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".hideSoftInput(0, "
Craig Mautner6efb4c72013-03-13 10:17:41 -07003815 + args.arg2 + ")");
Craig Mautnerca0ac712013-03-14 09:43:02 -07003816 ((IInputMethod)args.arg1).hideSoftInput(0, (ResultReceiver)args.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003817 } catch (RemoteException e) {
3818 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003819 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003820 return true;
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -07003821 case MSG_HIDE_CURRENT_INPUT_METHOD:
3822 synchronized (mMethodMap) {
3823 hideCurrentInputLocked(0, null);
3824 }
3825 return true;
Yohei Yukawac54c1172018-09-06 11:39:50 -07003826 case MSG_INITIALIZE_IME:
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003827 args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003828 try {
lumark90120a82018-08-15 00:33:03 +08003829 if (DEBUG) {
3830 Slog.v(TAG, "Sending attach of token: " + args.arg2 + " for display: "
3831 + msg.arg1);
3832 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07003833 final IBinder token = (IBinder) args.arg2;
lumark90120a82018-08-15 00:33:03 +08003834 ((IInputMethod) args.arg1).initializeInternal(token, msg.arg1,
Yohei Yukawac54c1172018-09-06 11:39:50 -07003835 new InputMethodPrivilegedOperationsImpl(this, token));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003836 } catch (RemoteException e) {
3837 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003838 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003839 return true;
Jeff Brownc28867a2013-03-26 15:42:39 -07003840 case MSG_CREATE_SESSION: {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003841 args = (SomeArgs)msg.obj;
Jeff Brown1951ce82013-04-04 22:45:12 -07003842 IInputMethod method = (IInputMethod)args.arg1;
Jeff Brownc28867a2013-03-26 15:42:39 -07003843 InputChannel channel = (InputChannel)args.arg2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003844 try {
Jeff Brown1951ce82013-04-04 22:45:12 -07003845 method.createSession(channel, (IInputSessionCallback)args.arg3);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003846 } catch (RemoteException e) {
Jeff Brownc28867a2013-03-26 15:42:39 -07003847 } finally {
Jeff Brown1951ce82013-04-04 22:45:12 -07003848 // Dispose the channel if the input method is not local to this process
3849 // because the remote proxy will get its own copy when unparceled.
3850 if (channel != null && Binder.isProxy(method)) {
Jeff Brownc28867a2013-03-26 15:42:39 -07003851 channel.dispose();
3852 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003853 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003854 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003855 return true;
Jeff Brownc28867a2013-03-26 15:42:39 -07003856 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003857 // ---------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003858
Yohei Yukawa19a80a12016-03-14 22:57:37 -07003859 case MSG_START_INPUT: {
Yohei Yukawaf7526b52017-02-11 20:57:10 -08003860 final int missingMethods = msg.arg1;
3861 final boolean restarting = msg.arg2 != 0;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07003862 args = (SomeArgs) msg.obj;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08003863 final IBinder startInputToken = (IBinder) args.arg1;
3864 final SessionState session = (SessionState) args.arg2;
3865 final IInputContext inputContext = (IInputContext) args.arg3;
3866 final EditorInfo editorInfo = (EditorInfo) args.arg4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003867 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003868 setEnabledSessionInMainThread(session);
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08003869 session.method.startInput(startInputToken, inputContext, missingMethods,
Tarandeep Singheadb1392018-11-09 18:15:57 +01003870 editorInfo, restarting, session.client.shouldPreRenderIme);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003871 } catch (RemoteException e) {
3872 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003873 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003874 return true;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07003875 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003876
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003877 // ---------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003878
Yohei Yukawa33e81792015-11-17 21:14:42 -08003879 case MSG_UNBIND_CLIENT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003880 try {
Yohei Yukawa33e81792015-11-17 21:14:42 -08003881 ((IInputMethodClient)msg.obj).onUnbindMethod(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003882 } catch (RemoteException e) {
3883 // There is nothing interesting about the last client dying.
3884 }
3885 return true;
Yohei Yukawa33e81792015-11-17 21:14:42 -08003886 case MSG_BIND_CLIENT: {
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003887 args = (SomeArgs)msg.obj;
Jeff Brown1951ce82013-04-04 22:45:12 -07003888 IInputMethodClient client = (IInputMethodClient)args.arg1;
3889 InputBindResult res = (InputBindResult)args.arg2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003890 try {
Jeff Brown1951ce82013-04-04 22:45:12 -07003891 client.onBindMethod(res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003892 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003893 Slog.w(TAG, "Client died receiving input method " + args.arg2);
Jeff Brown1951ce82013-04-04 22:45:12 -07003894 } finally {
3895 // Dispose the channel if the input method is not local to this process
3896 // because the remote proxy will get its own copy when unparceled.
3897 if (res.channel != null && Binder.isProxy(client)) {
3898 res.channel.dispose();
3899 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003900 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -07003901 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003902 return true;
Jeff Brown1951ce82013-04-04 22:45:12 -07003903 }
Dianne Hackborna6e41342012-05-22 16:30:34 -07003904 case MSG_SET_ACTIVE:
3905 try {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08003906 ((ClientState)msg.obj).client.setActive(msg.arg1 != 0, msg.arg2 != 0);
Dianne Hackborna6e41342012-05-22 16:30:34 -07003907 } catch (RemoteException e) {
3908 Slog.w(TAG, "Got RemoteException sending setActive(false) notification to pid "
3909 + ((ClientState)msg.obj).pid + " uid "
3910 + ((ClientState)msg.obj).uid);
3911 }
3912 return true;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07003913 case MSG_SET_INTERACTIVE:
3914 handleSetInteractive(msg.arg1 != 0);
3915 return true;
Yohei Yukawa2bc66172017-02-08 11:13:25 -08003916 case MSG_REPORT_FULLSCREEN_MODE: {
3917 final boolean fullscreen = msg.arg1 != 0;
3918 final ClientState clientState = (ClientState)msg.obj;
3919 try {
3920 clientState.client.reportFullscreenMode(fullscreen);
3921 } catch (RemoteException e) {
3922 Slog.w(TAG, "Got RemoteException sending "
3923 + "reportFullscreen(" + fullscreen + ") notification to pid="
3924 + clientState.pid + " uid=" + clientState.uid);
3925 }
3926 return true;
3927 }
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08003928 case MSG_REPORT_PRE_RENDERED: {
3929 args = (SomeArgs) msg.obj;
3930 final EditorInfo info = (EditorInfo) args.arg1;
3931 final ClientState clientState = (ClientState) args.arg2;
3932 try {
3933 clientState.client.reportPreRendered(info);
3934 } catch (RemoteException e) {
3935 Slog.w(TAG, "Got RemoteException sending "
3936 + "reportPreRendered(" + info + ") notification to pid="
3937 + clientState.pid + " uid=" + clientState.uid);
3938 }
3939 args.recycle();
3940 return true;
3941 }
3942 case MSG_APPLY_IME_VISIBILITY: {
3943 final boolean setVisible = msg.arg1 != 0;
3944 final ClientState clientState = (ClientState) msg.obj;
3945 try {
3946 clientState.client.applyImeVisibility(setVisible);
3947 } catch (RemoteException e) {
3948 Slog.w(TAG, "Got RemoteException sending "
3949 + "applyImeVisibility(" + setVisible + ") notification to pid="
3950 + clientState.pid + " uid=" + clientState.uid);
3951 }
3952 return true;
3953 }
satok01038492012-04-09 21:08:27 +09003954
3955 // --------------------------------------------------------------
3956 case MSG_HARD_KEYBOARD_SWITCH_CHANGED:
Michael Wright7b5a96b2014-08-09 19:28:42 -07003957 mHardKeyboardListener.handleHardKeyboardStatusChange(msg.arg1 == 1);
satok01038492012-04-09 21:08:27 +09003958 return true;
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +09003959 case MSG_SYSTEM_UNLOCK_USER: {
Fyodor Kupolov7877b8a2016-06-29 14:39:19 -07003960 final int userId = msg.arg1;
3961 onUnlockUser(userId);
3962 return true;
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +09003963 }
3964 case MSG_DISPATCH_ON_INPUT_METHOD_LIST_UPDATED: {
3965 final int userId = msg.arg1;
3966 final List<InputMethodInfo> imes = (List<InputMethodInfo>) msg.obj;
3967 mInputMethodListListeners.forEach(
3968 listener -> listener.onInputMethodListUpdated(imes, userId));
3969 return true;
3970 }
Adam Hebc67f2e2019-11-13 14:34:56 -08003971
3972 // ---------------------------------------------------------------
3973 case MSG_INLINE_SUGGESTIONS_REQUEST:
3974 args = (SomeArgs) msg.obj;
3975 final ComponentName componentName = (ComponentName) args.arg2;
3976 final AutofillId autofillId = (AutofillId) args.arg3;
3977 final IInlineSuggestionsRequestCallback callback =
3978 (IInlineSuggestionsRequestCallback) args.arg4;
3979 try {
3980 ((IInputMethod) args.arg1).onCreateInlineSuggestionsRequest(componentName,
3981 autofillId, callback);
3982 } catch (RemoteException e) {
3983 Slog.w(TAG, "RemoteException calling onCreateInlineSuggestionsRequest(): " + e);
3984 }
3985 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003986 }
3987 return false;
3988 }
3989
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07003990 private void handleSetInteractive(final boolean interactive) {
3991 synchronized (mMethodMap) {
3992 mIsInteractive = interactive;
Yohei Yukawa849443c2019-01-21 09:02:25 -08003993 updateSystemUiLocked(interactive ? mImeWindowVis : 0, mBackDisposition);
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07003994
3995 // Inform the current client of the change in active status
3996 if (mCurClient != null && mCurClient.client != null) {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08003997 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
3998 MSG_SET_ACTIVE, mIsInteractive ? 1 : 0, mInFullscreenMode ? 1 : 0,
3999 mCurClient));
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004000 }
4001 }
4002 }
4003
satokdc9ddae2011-10-06 12:22:36 +09004004 private boolean chooseNewDefaultIMELocked() {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004005 final InputMethodInfo imi = InputMethodUtils.getMostApplicableDefaultIME(
4006 mSettings.getEnabledInputMethodListLocked());
satokdc9ddae2011-10-06 12:22:36 +09004007 if (imi != null) {
satok03eb319a2010-11-11 18:17:42 +09004008 if (DEBUG) {
4009 Slog.d(TAG, "New default IME was selected: " + imi.getId());
4010 }
satok723a27e2010-11-11 14:58:11 +09004011 resetSelectedInputMethodAndSubtypeLocked(imi.getId());
Brandon Ballinger6da35a02009-10-21 00:38:13 -07004012 return true;
4013 }
4014
4015 return false;
4016 }
4017
Yohei Yukawa05139322018-12-25 10:34:14 -08004018 static void queryInputMethodServicesInternal(Context context,
4019 @UserIdInt int userId, ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap,
4020 ArrayMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList) {
4021 methodList.clear();
4022 methodMap.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004023
Yohei Yukawaed4952a2016-02-17 07:57:25 -08004024 // Note: We do not specify PackageManager.MATCH_ENCRYPTION_* flags here because the default
4025 // behavior of PackageManager is exactly what we want. It by default picks up appropriate
4026 // services depending on the unlock state for the specified user.
Yohei Yukawa05139322018-12-25 10:34:14 -08004027 final List<ResolveInfo> services = context.getPackageManager().queryIntentServicesAsUser(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004028 new Intent(InputMethod.SERVICE_INTERFACE),
Yohei Yukawa5ec1fce2018-12-17 07:56:14 -08004029 PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS,
Yohei Yukawa05139322018-12-25 10:34:14 -08004030 userId);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004031
Yohei Yukawa05139322018-12-25 10:34:14 -08004032 methodList.ensureCapacity(services.size());
4033 methodMap.ensureCapacity(services.size());
4034
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004035 for (int i = 0; i < services.size(); ++i) {
4036 ResolveInfo ri = services.get(i);
4037 ServiceInfo si = ri.serviceInfo;
Yohei Yukawaddad4b92017-02-02 01:46:13 -08004038 final String imeId = InputMethodInfo.computeId(ri);
4039 if (!android.Manifest.permission.BIND_INPUT_METHOD.equals(si.permission)) {
4040 Slog.w(TAG, "Skipping input method " + imeId
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004041 + ": it does not require the permission "
4042 + android.Manifest.permission.BIND_INPUT_METHOD);
4043 continue;
4044 }
4045
Yohei Yukawaddad4b92017-02-02 01:46:13 -08004046 if (DEBUG) Slog.d(TAG, "Checking " + imeId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004047
4048 try {
Yohei Yukawa05139322018-12-25 10:34:14 -08004049 final InputMethodInfo imi = new InputMethodInfo(context, ri,
4050 additionalSubtypeMap.get(imeId));
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08004051 if (imi.isVrOnly()) {
4052 continue; // Skip VR-only IME, which isn't supported for now.
4053 }
Yohei Yukawa05139322018-12-25 10:34:14 -08004054 methodList.add(imi);
4055 methodMap.put(imi.getId(), imi);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004056 if (DEBUG) {
Yohei Yukawa05139322018-12-25 10:34:14 -08004057 Slog.d(TAG, "Found an input method " + imi);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004058 }
Tadashi G. Takaoka3c23d5b2016-09-16 11:41:07 +09004059 } catch (Exception e) {
Yohei Yukawaddad4b92017-02-02 01:46:13 -08004060 Slog.wtf(TAG, "Unable to load input method " + imeId, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004061 }
4062 }
Yohei Yukawa05139322018-12-25 10:34:14 -08004063 }
4064
4065 @GuardedBy("mMethodMap")
4066 void buildInputMethodListLocked(boolean resetDefaultEnabledIme) {
4067 if (DEBUG) {
4068 Slog.d(TAG, "--- re-buildInputMethodList reset = " + resetDefaultEnabledIme
4069 + " \n ------ caller=" + Debug.getCallers(10));
4070 }
4071 if (!mSystemReady) {
4072 Slog.e(TAG, "buildInputMethodListLocked is not allowed until system is ready");
4073 return;
4074 }
4075 mMethodMapUpdateCount++;
4076 mMyPackageMonitor.clearKnownImePackageNamesLocked();
4077
4078 queryInputMethodServicesInternal(mContext, mSettings.getCurrentUserId(),
Yohei Yukawab557d572018-12-29 21:26:26 -08004079 mAdditionalSubtypeMap, mMethodMap, mMethodList);
Brandon Ballinger6da35a02009-10-21 00:38:13 -07004080
Yohei Yukawac4e44912017-02-09 19:30:22 -08004081 // Construct the set of possible IME packages for onPackageChanged() to avoid false
4082 // negatives when the package state remains to be the same but only the component state is
4083 // changed.
4084 {
4085 // Here we intentionally use PackageManager.MATCH_DISABLED_COMPONENTS since the purpose
4086 // of this query is to avoid false negatives. PackageManager.MATCH_ALL could be more
4087 // conservative, but it seems we cannot use it for now (Issue 35176630).
Yohei Yukawa05139322018-12-25 10:34:14 -08004088 final List<ResolveInfo> allInputMethodServices =
4089 mContext.getPackageManager().queryIntentServicesAsUser(
4090 new Intent(InputMethod.SERVICE_INTERFACE),
4091 PackageManager.MATCH_DISABLED_COMPONENTS, mSettings.getCurrentUserId());
Yohei Yukawac4e44912017-02-09 19:30:22 -08004092 final int N = allInputMethodServices.size();
4093 for (int i = 0; i < N; ++i) {
4094 final ServiceInfo si = allInputMethodServices.get(i).serviceInfo;
Yohei Yukawa5e3e8a52017-02-14 20:05:17 -08004095 if (android.Manifest.permission.BIND_INPUT_METHOD.equals(si.permission)) {
4096 mMyPackageMonitor.addKnownImePackageNameLocked(si.packageName);
Yohei Yukawac4e44912017-02-09 19:30:22 -08004097 }
Yohei Yukawac4e44912017-02-09 19:30:22 -08004098 }
4099 }
4100
Yohei Yukawa9c372192018-03-20 22:54:56 -07004101 boolean reenableMinimumNonAuxSystemImes = false;
Yohei Yukawa859df052016-02-17 07:56:46 -08004102 // TODO: The following code should find better place to live.
4103 if (!resetDefaultEnabledIme) {
4104 boolean enabledImeFound = false;
Yohei Yukawa9c372192018-03-20 22:54:56 -07004105 boolean enabledNonAuxImeFound = false;
Yohei Yukawa859df052016-02-17 07:56:46 -08004106 final List<InputMethodInfo> enabledImes = mSettings.getEnabledInputMethodListLocked();
4107 final int N = enabledImes.size();
4108 for (int i = 0; i < N; ++i) {
4109 final InputMethodInfo imi = enabledImes.get(i);
4110 if (mMethodList.contains(imi)) {
4111 enabledImeFound = true;
Yohei Yukawa9c372192018-03-20 22:54:56 -07004112 if (!imi.isAuxiliaryIme()) {
4113 enabledNonAuxImeFound = true;
4114 break;
4115 }
Yohei Yukawa859df052016-02-17 07:56:46 -08004116 }
4117 }
4118 if (!enabledImeFound) {
Yohei Yukawad0332832017-02-01 13:59:43 -08004119 if (DEBUG) {
4120 Slog.i(TAG, "All the enabled IMEs are gone. Reset default enabled IMEs.");
4121 }
Yohei Yukawa859df052016-02-17 07:56:46 -08004122 resetDefaultEnabledIme = true;
4123 resetSelectedInputMethodAndSubtypeLocked("");
Yohei Yukawa9c372192018-03-20 22:54:56 -07004124 } else if (!enabledNonAuxImeFound) {
4125 if (DEBUG) {
4126 Slog.i(TAG, "All the enabled non-Aux IMEs are gone. Do partial reset.");
4127 }
4128 reenableMinimumNonAuxSystemImes = true;
Yohei Yukawa859df052016-02-17 07:56:46 -08004129 }
4130 }
4131
Yohei Yukawa9c372192018-03-20 22:54:56 -07004132 if (resetDefaultEnabledIme || reenableMinimumNonAuxSystemImes) {
Satoshi Kataokaf1367b72013-01-25 17:20:12 +09004133 final ArrayList<InputMethodInfo> defaultEnabledIme =
Yohei Yukawa9c372192018-03-20 22:54:56 -07004134 InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList,
4135 reenableMinimumNonAuxSystemImes);
Yohei Yukawa68645a62016-02-17 07:54:20 -08004136 final int N = defaultEnabledIme.size();
4137 for (int i = 0; i < N; ++i) {
Satoshi Kataokaf1367b72013-01-25 17:20:12 +09004138 final InputMethodInfo imi = defaultEnabledIme.get(i);
4139 if (DEBUG) {
4140 Slog.d(TAG, "--- enable ime = " + imi);
4141 }
4142 setInputMethodEnabledLocked(imi.getId(), true);
4143 }
4144 }
4145
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004146 final String defaultImiId = mSettings.getSelectedInputMethod();
satok0a1bcf42012-05-16 19:26:31 +09004147 if (!TextUtils.isEmpty(defaultImiId)) {
Yohei Yukawa94e33302016-02-12 19:37:03 -08004148 if (!mMethodMap.containsKey(defaultImiId)) {
satok0a1bcf42012-05-16 19:26:31 +09004149 Slog.w(TAG, "Default IME is uninstalled. Choose new default IME.");
4150 if (chooseNewDefaultIMELocked()) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07004151 updateInputMethodsFromSettingsLocked(true);
satok0a1bcf42012-05-16 19:26:31 +09004152 }
4153 } else {
4154 // Double check that the default IME is certainly enabled.
4155 setInputMethodEnabledLocked(defaultImiId, true);
Brandon Ballinger6da35a02009-10-21 00:38:13 -07004156 }
4157 }
Yohei Yukawa3d46bab2014-05-30 18:10:18 +09004158 // Here is not the perfect place to reset the switching controller. Ideally
4159 // mSwitchingController and mSettings should be able to share the same state.
4160 // TODO: Make sure that mSwitchingController and mSettings are sharing the
4161 // the same enabled IMEs list.
Yohei Yukawac834a252014-05-21 22:42:32 +09004162 mSwitchingController.resetCircularListLocked(mContext);
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +09004163
4164 // Notify InputMethodListListeners of the new installed InputMethods.
4165 final List<InputMethodInfo> inputMethodList = new ArrayList<>(mMethodList);
4166 mHandler.obtainMessage(MSG_DISPATCH_ON_INPUT_METHOD_LIST_UPDATED,
4167 mSettings.getCurrentUserId(), 0 /* unused */, inputMethodList).sendToTarget();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004168 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004170 // ----------------------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004171
satok217f5482010-12-15 05:19:19 +09004172 private void showInputMethodAndSubtypeEnabler(String inputMethodId) {
Tadashi G. Takaokaf49688f2011-01-20 17:56:13 +09004173 Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS);
satok47a44912010-10-06 16:03:58 +09004174 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
satok86417ea2010-10-27 14:11:03 +09004175 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
4176 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
satok7fee71f2010-12-17 18:54:26 +09004177 if (!TextUtils.isEmpty(inputMethodId)) {
Tadashi G. Takaoka25480202011-01-20 23:13:02 +09004178 intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, inputMethodId);
satok7fee71f2010-12-17 18:54:26 +09004179 }
Yohei Yukawa41f34272015-12-14 15:41:52 -08004180 final int userId;
4181 synchronized (mMethodMap) {
4182 userId = mSettings.getCurrentUserId();
4183 }
4184 mContext.startActivityAsUser(intent, null, UserHandle.of(userId));
satok217f5482010-12-15 05:19:19 +09004185 }
4186
4187 private void showConfigureInputMethods() {
4188 Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS);
4189 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
4190 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
4191 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
Satoshi Kataoka3ba439d2012-10-05 18:30:13 +09004192 mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
satok47a44912010-10-06 16:03:58 +09004193 }
4194
satok2c93efc2012-04-02 19:33:47 +09004195 private boolean isScreenLocked() {
4196 return mKeyguardManager != null
4197 && mKeyguardManager.isKeyguardLocked() && mKeyguardManager.isKeyguardSecure();
4198 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004199
lumark0b05f9e2018-11-26 15:09:06 +08004200 private void showInputMethodMenu(boolean showAuxSubtypes, int displayId) {
Seigo Nonaka14e13912015-05-06 21:04:13 -07004201 if (DEBUG) Slog.v(TAG, "Show switching menu. showAuxSubtypes=" + showAuxSubtypes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004202
satok2c93efc2012-04-02 19:33:47 +09004203 final boolean isScreenLocked = isScreenLocked();
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004204
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004205 final String lastInputMethodId = mSettings.getSelectedInputMethod();
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004206 int lastInputMethodSubtypeId = mSettings.getSelectedInputMethodSubtypeId(lastInputMethodId);
Joe Onorato8a9b2202010-02-26 18:56:32 -08004207 if (DEBUG) Slog.v(TAG, "Current IME: " + lastInputMethodId);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004208
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004209 synchronized (mMethodMap) {
Yohei Yukawacf3bbff2018-11-20 17:24:20 -08004210 final List<ImeSubtypeListItem> imList =
4211 mSwitchingController.getSortedInputMethodAndSubtypeListLocked(
4212 showAuxSubtypes, isScreenLocked);
4213 if (imList.isEmpty()) {
satok7f35c8c2010-10-07 21:13:11 +09004214 return;
4215 }
4216
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004217 hideInputMethodMenuLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004218
satokc3690562012-01-10 20:14:43 +09004219 if (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID) {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004220 final InputMethodSubtype currentSubtype = getCurrentInputMethodSubtypeLocked();
satokc3690562012-01-10 20:14:43 +09004221 if (currentSubtype != null) {
4222 final InputMethodInfo currentImi = mMethodMap.get(mCurMethodId);
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004223 lastInputMethodSubtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
4224 currentImi, currentSubtype.hashCode());
satokc3690562012-01-10 20:14:43 +09004225 }
4226 }
4227
Ken Wakasa761eb372011-03-04 19:06:18 +09004228 final int N = imList.size();
satokab751aa2010-09-14 19:17:36 +09004229 mIms = new InputMethodInfo[N];
4230 mSubtypeIds = new int[N];
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004231 int checkedItem = 0;
4232 for (int i = 0; i < N; ++i) {
Ken Wakasa05dbb652011-08-22 15:22:43 +09004233 final ImeSubtypeListItem item = imList.get(i);
4234 mIms[i] = item.mImi;
4235 mSubtypeIds[i] = item.mSubtypeId;
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004236 if (mIms[i].getId().equals(lastInputMethodId)) {
satokab751aa2010-09-14 19:17:36 +09004237 int subtypeId = mSubtypeIds[i];
4238 if ((subtypeId == NOT_A_SUBTYPE_ID)
4239 || (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID && subtypeId == 0)
4240 || (subtypeId == lastInputMethodSubtypeId)) {
4241 checkedItem = i;
4242 }
Dianne Hackborn8cf1bcd2010-03-16 13:06:10 -07004243 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004244 }
Alan Viverette505e3ab2014-11-24 15:22:11 -08004245
lumark0b05f9e2018-11-26 15:09:06 +08004246 final ActivityThread currentThread = ActivityThread.currentActivityThread();
Andrew Sapperstein8a3b4cb2017-04-28 14:35:31 -07004247 final Context settingsContext = new ContextThemeWrapper(
lumark0b05f9e2018-11-26 15:09:06 +08004248 displayId == DEFAULT_DISPLAY ? currentThread.getSystemUiContext()
4249 : currentThread.createSystemUiContext(displayId),
Alan Viverette505e3ab2014-11-24 15:22:11 -08004250 com.android.internal.R.style.Theme_DeviceDefault_Settings);
4251
4252 mDialogBuilder = new AlertDialog.Builder(settingsContext);
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004253 mDialogBuilder.setOnCancelListener(new OnCancelListener() {
4254 @Override
4255 public void onCancel(DialogInterface dialog) {
4256 hideInputMethodMenu();
4257 }
4258 });
Alan Viverette505e3ab2014-11-24 15:22:11 -08004259
4260 final Context dialogContext = mDialogBuilder.getContext();
4261 final TypedArray a = dialogContext.obtainStyledAttributes(null,
4262 com.android.internal.R.styleable.DialogPreference,
4263 com.android.internal.R.attr.alertDialogStyle, 0);
4264 final Drawable dialogIcon = a.getDrawable(
4265 com.android.internal.R.styleable.DialogPreference_dialogIcon);
4266 a.recycle();
4267
4268 mDialogBuilder.setIcon(dialogIcon);
4269
Yohei Yukawad34e1482016-02-11 08:03:52 -08004270 final LayoutInflater inflater = dialogContext.getSystemService(LayoutInflater.class);
satok01038492012-04-09 21:08:27 +09004271 final View tv = inflater.inflate(
4272 com.android.internal.R.layout.input_method_switch_dialog_title, null);
4273 mDialogBuilder.setCustomTitle(tv);
4274
4275 // Setup layout for a toggle switch of the hardware keyboard
4276 mSwitchingDialogTitleView = tv;
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004277 mSwitchingDialogTitleView
4278 .findViewById(com.android.internal.R.id.hard_keyboard_section)
Seigo Nonaka7309b122015-08-17 18:34:13 -07004279 .setVisibility(mWindowManagerInternal.isHardKeyboardAvailable()
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004280 ? View.VISIBLE : View.GONE);
Alan Viverette505e3ab2014-11-24 15:22:11 -08004281 final Switch hardKeySwitch = (Switch) mSwitchingDialogTitleView.findViewById(
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004282 com.android.internal.R.id.hard_keyboard_switch);
Michael Wright7b5a96b2014-08-09 19:28:42 -07004283 hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004284 hardKeySwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
4285 @Override
4286 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Michael Wright7b5a96b2014-08-09 19:28:42 -07004287 mSettings.setShowImeWithHardKeyboard(isChecked);
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004288 // Ensure that the input method dialog is dismissed when changing
4289 // the hardware keyboard state.
4290 hideInputMethodMenu();
4291 }
4292 });
4293
Alan Viverette505e3ab2014-11-24 15:22:11 -08004294 final ImeSubtypeListAdapter adapter = new ImeSubtypeListAdapter(dialogContext,
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004295 com.android.internal.R.layout.input_method_switch_item, imList, checkedItem);
4296 final OnClickListener choiceListener = new OnClickListener() {
4297 @Override
4298 public void onClick(final DialogInterface dialog, final int which) {
4299 synchronized (mMethodMap) {
4300 if (mIms == null || mIms.length <= which || mSubtypeIds == null
4301 || mSubtypeIds.length <= which) {
4302 return;
satok01038492012-04-09 21:08:27 +09004303 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004304 final InputMethodInfo im = mIms[which];
4305 int subtypeId = mSubtypeIds[which];
4306 adapter.mCheckedItem = which;
4307 adapter.notifyDataSetChanged();
4308 hideInputMethodMenu();
4309 if (im != null) {
4310 if (subtypeId < 0 || subtypeId >= im.getSubtypeCount()) {
4311 subtypeId = NOT_A_SUBTYPE_ID;
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08004312 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004313 setInputMethodLocked(im.getId(), subtypeId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004314 }
Tadashi G. Takaokad130b802014-08-01 14:05:47 +09004315 }
4316 }
4317 };
4318 mDialogBuilder.setSingleChoiceItems(adapter, checkedItem, choiceListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004319
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004320 mSwitchingDialog = mDialogBuilder.create();
Dianne Hackborne3a7f622011-03-03 21:48:24 -08004321 mSwitchingDialog.setCanceledOnTouchOutside(true);
Wale Ogunwale3a931692016-11-02 16:49:48 -07004322 final Window w = mSwitchingDialog.getWindow();
Yohei Yukawa6e875592019-01-28 00:49:30 -08004323 final LayoutParams attrs = w.getAttributes();
4324 w.setType(LayoutParams.TYPE_INPUT_METHOD_DIALOG);
Wale Ogunwale3a931692016-11-02 16:49:48 -07004325 // Use an alternate token for the dialog for that window manager can group the token
4326 // with other IME windows based on type vs. grouping based on whichever token happens
4327 // to get selected by the system later on.
4328 attrs.token = mSwitchingDialogToken;
Roshan Piusa3f89c62019-10-11 08:50:53 -07004329 attrs.privateFlags |= LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
Wale Ogunwale3a931692016-11-02 16:49:48 -07004330 attrs.setTitle("Select input method");
4331 w.setAttributes(attrs);
Yohei Yukawa849443c2019-01-21 09:02:25 -08004332 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004333 mSwitchingDialog.show();
4334 }
4335 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004336
Ken Wakasa05dbb652011-08-22 15:22:43 +09004337 private static class ImeSubtypeListAdapter extends ArrayAdapter<ImeSubtypeListItem> {
4338 private final LayoutInflater mInflater;
4339 private final int mTextViewResourceId;
4340 private final List<ImeSubtypeListItem> mItemsList;
Satoshi Kataokad2142962012-11-12 18:43:06 +09004341 public int mCheckedItem;
Ken Wakasa05dbb652011-08-22 15:22:43 +09004342 public ImeSubtypeListAdapter(Context context, int textViewResourceId,
4343 List<ImeSubtypeListItem> itemsList, int checkedItem) {
4344 super(context, textViewResourceId, itemsList);
Alan Viverette505e3ab2014-11-24 15:22:11 -08004345
Ken Wakasa05dbb652011-08-22 15:22:43 +09004346 mTextViewResourceId = textViewResourceId;
4347 mItemsList = itemsList;
4348 mCheckedItem = checkedItem;
Yohei Yukawad34e1482016-02-11 08:03:52 -08004349 mInflater = context.getSystemService(LayoutInflater.class);
Ken Wakasa05dbb652011-08-22 15:22:43 +09004350 }
4351
4352 @Override
4353 public View getView(int position, View convertView, ViewGroup parent) {
4354 final View view = convertView != null ? convertView
4355 : mInflater.inflate(mTextViewResourceId, null);
4356 if (position < 0 || position >= mItemsList.size()) return view;
4357 final ImeSubtypeListItem item = mItemsList.get(position);
4358 final CharSequence imeName = item.mImeName;
4359 final CharSequence subtypeName = item.mSubtypeName;
4360 final TextView firstTextView = (TextView)view.findViewById(android.R.id.text1);
4361 final TextView secondTextView = (TextView)view.findViewById(android.R.id.text2);
4362 if (TextUtils.isEmpty(subtypeName)) {
4363 firstTextView.setText(imeName);
4364 secondTextView.setVisibility(View.GONE);
4365 } else {
4366 firstTextView.setText(subtypeName);
4367 secondTextView.setText(imeName);
4368 secondTextView.setVisibility(View.VISIBLE);
4369 }
4370 final RadioButton radioButton =
4371 (RadioButton)view.findViewById(com.android.internal.R.id.radio);
4372 radioButton.setChecked(position == mCheckedItem);
4373 return view;
4374 }
4375 }
4376
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004377 void hideInputMethodMenu() {
The Android Open Source Project10592532009-03-18 17:39:46 -07004378 synchronized (mMethodMap) {
4379 hideInputMethodMenuLocked();
4380 }
4381 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004382
The Android Open Source Project10592532009-03-18 17:39:46 -07004383 void hideInputMethodMenuLocked() {
Joe Onorato8a9b2202010-02-26 18:56:32 -08004384 if (DEBUG) Slog.v(TAG, "Hide switching menu");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004385
The Android Open Source Project10592532009-03-18 17:39:46 -07004386 if (mSwitchingDialog != null) {
4387 mSwitchingDialog.dismiss();
4388 mSwitchingDialog = null;
Yohei Yukawa1fc7a1d2018-04-18 17:31:27 -07004389 mSwitchingDialogTitleView = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004390 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004391
Yohei Yukawa849443c2019-01-21 09:02:25 -08004392 updateSystemUiLocked(mImeWindowVis, mBackDisposition);
The Android Open Source Project10592532009-03-18 17:39:46 -07004393 mDialogBuilder = null;
The Android Open Source Project10592532009-03-18 17:39:46 -07004394 mIms = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004395 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004396
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004397 // ----------------------------------------------------------------------
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004398
Yohei Yukawa3d3abd22019-04-09 23:20:12 -07004399 /**
4400 * Enable or disable the given IME by updating {@link Settings.Secure#ENABLED_INPUT_METHODS}.
4401 *
4402 * @param id ID of the IME is to be manipulated. It is OK to pass IME ID that is currently not
4403 * recognized by the system.
4404 * @param enabled {@code true} if {@code id} needs to be enabled.
4405 * @return {@code true} if the IME was previously enabled. {@code false} otherwise.
4406 */
4407 private boolean setInputMethodEnabledLocked(String id, boolean enabled) {
satokd87c2592010-09-29 11:52:06 +09004408 List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings
4409 .getEnabledInputMethodsAndSubtypeListLocked();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004410
satokd87c2592010-09-29 11:52:06 +09004411 if (enabled) {
4412 for (Pair<String, ArrayList<String>> pair: enabledInputMethodsList) {
4413 if (pair.first.equals(id)) {
4414 // We are enabling this input method, but it is already enabled.
4415 // Nothing to do. The previous state was enabled.
4416 return true;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004417 }
4418 }
satokd87c2592010-09-29 11:52:06 +09004419 mSettings.appendAndPutEnabledInputMethodLocked(id, false);
4420 // Previous state was disabled.
4421 return false;
4422 } else {
4423 StringBuilder builder = new StringBuilder();
4424 if (mSettings.buildAndPutEnabledInputMethodsStrRemovingIdLocked(
4425 builder, enabledInputMethodsList, id)) {
4426 // Disabled input method is currently selected, switch to another one.
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004427 final String selId = mSettings.getSelectedInputMethod();
satok03eb319a2010-11-11 18:17:42 +09004428 if (id.equals(selId) && !chooseNewDefaultIMELocked()) {
4429 Slog.i(TAG, "Can't find new IME, unsetting the current input method.");
4430 resetSelectedInputMethodAndSubtypeLocked("");
satokd87c2592010-09-29 11:52:06 +09004431 }
4432 // Previous state was enabled.
4433 return true;
4434 } else {
4435 // We are disabling the input method but it is already disabled.
4436 // Nothing to do. The previous state was disabled.
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004437 return false;
4438 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004439 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004440 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08004441
satok723a27e2010-11-11 14:58:11 +09004442 private void setSelectedInputMethodAndSubtypeLocked(InputMethodInfo imi, int subtypeId,
4443 boolean setSubtypeOnly) {
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08004444 mSettings.saveCurrentInputMethodAndSubtypeToHistory(mCurMethodId, mCurrentSubtype);
Tarandeep Singh89a6c482017-11-21 14:26:11 -08004445
satok723a27e2010-11-11 14:58:11 +09004446 // Set Subtype here
4447 if (imi == null || subtypeId < 0) {
4448 mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
Tadashi G. Takaoka0ba75bb2010-11-09 12:19:32 -08004449 mCurrentSubtype = null;
satok723a27e2010-11-11 14:58:11 +09004450 } else {
Ken Wakasa586f0512011-01-20 22:31:01 +09004451 if (subtypeId < imi.getSubtypeCount()) {
4452 InputMethodSubtype subtype = imi.getSubtypeAt(subtypeId);
4453 mSettings.putSelectedSubtype(subtype.hashCode());
4454 mCurrentSubtype = subtype;
satok723a27e2010-11-11 14:58:11 +09004455 } else {
4456 mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
satokd81e9502012-05-21 12:58:45 +09004457 // If the subtype is not specified, choose the most applicable one
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004458 mCurrentSubtype = getCurrentInputMethodSubtypeLocked();
satok723a27e2010-11-11 14:58:11 +09004459 }
satokab751aa2010-09-14 19:17:36 +09004460 }
satok723a27e2010-11-11 14:58:11 +09004461
Yohei Yukawa68645a62016-02-17 07:54:20 -08004462 if (!setSubtypeOnly) {
satok723a27e2010-11-11 14:58:11 +09004463 // Set InputMethod here
4464 mSettings.putSelectedInputMethod(imi != null ? imi.getId() : "");
4465 }
4466 }
4467
4468 private void resetSelectedInputMethodAndSubtypeLocked(String newDefaultIme) {
4469 InputMethodInfo imi = mMethodMap.get(newDefaultIme);
4470 int lastSubtypeId = NOT_A_SUBTYPE_ID;
4471 // newDefaultIme is empty when there is no candidate for the selected IME.
4472 if (imi != null && !TextUtils.isEmpty(newDefaultIme)) {
4473 String subtypeHashCode = mSettings.getLastSubtypeForInputMethodLocked(newDefaultIme);
4474 if (subtypeHashCode != null) {
4475 try {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004476 lastSubtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
Narayan Kamatha09b4d22016-04-15 18:32:45 +01004477 imi, Integer.parseInt(subtypeHashCode));
satok723a27e2010-11-11 14:58:11 +09004478 } catch (NumberFormatException e) {
4479 Slog.w(TAG, "HashCode for subtype looks broken: " + subtypeHashCode, e);
4480 }
4481 }
4482 }
4483 setSelectedInputMethodAndSubtypeLocked(imi, lastSubtypeId, false);
satokab751aa2010-09-14 19:17:36 +09004484 }
4485
satokab751aa2010-09-14 19:17:36 +09004486 /**
4487 * @return Return the current subtype of this input method.
4488 */
satok42c5a162011-05-26 16:46:14 +09004489 @Override
satokab751aa2010-09-14 19:17:36 +09004490 public InputMethodSubtype getCurrentInputMethodSubtype() {
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004491 synchronized (mMethodMap) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08004492 // TODO: Make this work even for non-current users?
Yohei Yukawa46d74762019-01-22 10:17:22 -08004493 if (!calledFromValidUserLocked()) {
Yohei Yukawa91e6cd02018-12-09 22:58:57 -08004494 return null;
4495 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004496 return getCurrentInputMethodSubtypeLocked();
4497 }
4498 }
4499
4500 private InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
satokfdf419e2012-05-08 16:52:08 +09004501 if (mCurMethodId == null) {
4502 return null;
4503 }
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004504 final boolean subtypeIsSelected = mSettings.isSubtypeSelected();
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004505 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
4506 if (imi == null || imi.getSubtypeCount() == 0) {
4507 return null;
satok4e4569d2010-11-19 18:45:53 +09004508 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004509 if (!subtypeIsSelected || mCurrentSubtype == null
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004510 || !InputMethodUtils.isValidSubtypeId(imi, mCurrentSubtype.hashCode())) {
4511 int subtypeId = mSettings.getSelectedInputMethodSubtypeId(mCurMethodId);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004512 if (subtypeId == NOT_A_SUBTYPE_ID) {
4513 // If there are no selected subtypes, the framework will try to find
4514 // the most applicable subtype from explicitly or implicitly enabled
4515 // subtypes.
4516 List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypes =
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004517 mSettings.getEnabledInputMethodSubtypeListLocked(mContext, imi, true);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004518 // If there is only one explicitly or implicitly enabled subtype,
4519 // just returns it.
4520 if (explicitlyOrImplicitlyEnabledSubtypes.size() == 1) {
4521 mCurrentSubtype = explicitlyOrImplicitlyEnabledSubtypes.get(0);
4522 } else if (explicitlyOrImplicitlyEnabledSubtypes.size() > 1) {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004523 mCurrentSubtype = InputMethodUtils.findLastResortApplicableSubtypeLocked(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004524 mRes, explicitlyOrImplicitlyEnabledSubtypes,
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004525 InputMethodUtils.SUBTYPE_MODE_KEYBOARD, null, true);
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004526 if (mCurrentSubtype == null) {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004527 mCurrentSubtype = InputMethodUtils.findLastResortApplicableSubtypeLocked(
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004528 mRes, explicitlyOrImplicitlyEnabledSubtypes, null, null,
4529 true);
satok4e4569d2010-11-19 18:45:53 +09004530 }
satok3ef8b292010-11-23 06:06:29 +09004531 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004532 } else {
Satoshi Kataoka8e303cc2013-01-11 15:55:28 +09004533 mCurrentSubtype = InputMethodUtils.getSubtypes(imi).get(subtypeId);
satok8fbb1e82010-11-02 23:15:58 +09004534 }
4535 }
Satoshi Kataoka4e1ab152012-09-13 21:34:20 +09004536 return mCurrentSubtype;
satokab751aa2010-09-14 19:17:36 +09004537 }
4538
Yohei Yukawaa878b952019-01-10 19:36:24 -08004539 private List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
4540 synchronized (mMethodMap) {
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08004541 return getInputMethodListLocked(userId);
Yohei Yukawaa878b952019-01-10 19:36:24 -08004542 }
4543 }
4544
4545 private List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
4546 synchronized (mMethodMap) {
4547 return getEnabledInputMethodListLocked(userId);
4548 }
4549 }
4550
Feng Cao16b2de52020-01-09 17:27:27 -08004551 private void onCreateInlineSuggestionsRequest(@UserIdInt int userId,
4552 ComponentName componentName, AutofillId autofillId,
4553 IInlineSuggestionsRequestCallback callback) {
Adam Hebc67f2e2019-11-13 14:34:56 -08004554 synchronized (mMethodMap) {
Feng Cao16b2de52020-01-09 17:27:27 -08004555 onCreateInlineSuggestionsRequestLocked(userId, componentName, autofillId, callback);
Adam Hebc67f2e2019-11-13 14:34:56 -08004556 }
4557 }
4558
mincheli850892b2019-12-05 19:47:59 +08004559 private boolean switchToInputMethod(String imeId, @UserIdInt int userId) {
4560 synchronized (mMethodMap) {
4561 if (userId == mSettings.getCurrentUserId()) {
4562 if (!mMethodMap.containsKey(imeId)
4563 || !mSettings.getEnabledInputMethodListLocked()
4564 .contains(mMethodMap.get(imeId))) {
4565 return false; // IME is not is found or not enabled.
4566 }
4567 setInputMethodLocked(imeId, NOT_A_SUBTYPE_ID);
4568 return true;
4569 }
4570 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
4571 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
4572 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
4573 new ArrayMap<>();
4574 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
4575 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
4576 methodMap, methodList);
4577 final InputMethodSettings settings = new InputMethodSettings(
4578 mContext.getResources(), mContext.getContentResolver(), methodMap,
4579 userId, false);
4580 if (!methodMap.containsKey(imeId)
4581 || !settings.getEnabledInputMethodListLocked()
4582 .contains(methodMap.get(imeId))) {
4583 return false; // IME is not is found or not enabled.
4584 }
4585 settings.putSelectedInputMethod(imeId);
4586 settings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
4587 return true;
4588 }
4589 }
4590
Yohei Yukawae24ed792018-08-28 19:10:32 -07004591 private static final class LocalServiceImpl extends InputMethodManagerInternal {
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004592 @NonNull
Yohei Yukawafffc0e52018-09-04 13:24:00 -07004593 private final InputMethodManagerService mService;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004594
Yohei Yukawafffc0e52018-09-04 13:24:00 -07004595 LocalServiceImpl(@NonNull InputMethodManagerService service) {
4596 mService = service;
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004597 }
4598
4599 @Override
4600 public void setInteractive(boolean interactive) {
4601 // Do everything in handler so as not to block the caller.
Yohei Yukawaf16abb72018-09-05 11:28:42 -07004602 mService.mHandler.obtainMessage(MSG_SET_INTERACTIVE, interactive ? 1 : 0, 0)
4603 .sendToTarget();
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004604 }
Yohei Yukawaae61f712015-12-09 13:00:10 -08004605
4606 @Override
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -07004607 public void hideCurrentInputMethod() {
Yohei Yukawaf16abb72018-09-05 11:28:42 -07004608 mService.mHandler.removeMessages(MSG_HIDE_CURRENT_INPUT_METHOD);
4609 mService.mHandler.sendEmptyMessage(MSG_HIDE_CURRENT_INPUT_METHOD);
Jorim Jaggi3c5d0f12016-05-24 19:04:30 -07004610 }
Tarandeep Singh89a6c482017-11-21 14:26:11 -08004611
4612 @Override
Yohei Yukawaa878b952019-01-10 19:36:24 -08004613 public List<InputMethodInfo> getInputMethodListAsUser(int userId) {
4614 return mService.getInputMethodListAsUser(userId);
4615 }
4616
4617 @Override
4618 public List<InputMethodInfo> getEnabledInputMethodListAsUser(int userId) {
4619 return mService.getEnabledInputMethodListAsUser(userId);
4620 }
Adam Hebc67f2e2019-11-13 14:34:56 -08004621
4622 @Override
Feng Cao16b2de52020-01-09 17:27:27 -08004623 public void onCreateInlineSuggestionsRequest(int userId, ComponentName componentName,
Adam Hebc67f2e2019-11-13 14:34:56 -08004624 AutofillId autofillId, IInlineSuggestionsRequestCallback cb) {
Feng Cao16b2de52020-01-09 17:27:27 -08004625 mService.onCreateInlineSuggestionsRequest(userId, componentName, autofillId, cb);
Adam Hebc67f2e2019-11-13 14:34:56 -08004626 }
mincheli850892b2019-12-05 19:47:59 +08004627
4628 @Override
4629 public boolean switchToInputMethod(String imeId, int userId) {
4630 return mService.switchToInputMethod(imeId, userId);
4631 }
Yuichiro Hanada34c4c0e2020-01-15 16:53:07 +09004632
4633 @Override
4634 public void registerInputMethodListListener(InputMethodListListener listener) {
4635 mService.mInputMethodListListeners.addIfAbsent(listener);
4636 }
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004637 }
4638
Yohei Yukawac54c1172018-09-06 11:39:50 -07004639 @BinderThread
4640 private IInputContentUriToken createInputContentUriToken(@Nullable IBinder token,
Yohei Yukawa25e08132016-06-22 16:31:41 -07004641 @Nullable Uri contentUri, @Nullable String packageName) {
Yohei Yukawa25e08132016-06-22 16:31:41 -07004642 if (token == null) {
4643 throw new NullPointerException("token");
4644 }
4645 if (packageName == null) {
4646 throw new NullPointerException("packageName");
4647 }
4648 if (contentUri == null) {
4649 throw new NullPointerException("contentUri");
4650 }
4651 final String contentUriScheme = contentUri.getScheme();
4652 if (!"content".equals(contentUriScheme)) {
4653 throw new InvalidParameterException("contentUri must have content scheme");
4654 }
4655
4656 synchronized (mMethodMap) {
4657 final int uid = Binder.getCallingUid();
4658 if (mCurMethodId == null) {
4659 return null;
4660 }
4661 if (mCurToken != token) {
4662 Slog.e(TAG, "Ignoring createInputContentUriToken mCurToken=" + mCurToken
4663 + " token=" + token);
4664 return null;
4665 }
4666 // We cannot simply distinguish a bad IME that reports an arbitrary package name from
4667 // an unfortunate IME whose internal state is already obsolete due to the asynchronous
4668 // nature of our system. Let's compare it with our internal record.
4669 if (!TextUtils.equals(mCurAttribute.packageName, packageName)) {
4670 Slog.e(TAG, "Ignoring createInputContentUriToken mCurAttribute.packageName="
4671 + mCurAttribute.packageName + " packageName=" + packageName);
4672 return null;
4673 }
Yohei Yukawa3933a6e2016-11-10 00:47:48 -08004674 // This user ID can never bee spoofed.
Yohei Yukawa25e08132016-06-22 16:31:41 -07004675 final int imeUserId = UserHandle.getUserId(uid);
Yohei Yukawa3933a6e2016-11-10 00:47:48 -08004676 // This user ID can never bee spoofed.
Yohei Yukawa25e08132016-06-22 16:31:41 -07004677 final int appUserId = UserHandle.getUserId(mCurClient.uid);
Yohei Yukawa3933a6e2016-11-10 00:47:48 -08004678 // This user ID may be invalid if "contentUri" embedded an invalid user ID.
4679 final int contentUriOwnerUserId = ContentProvider.getUserIdFromUri(contentUri,
4680 imeUserId);
4681 final Uri contentUriWithoutUserId = ContentProvider.getUriWithoutUserId(contentUri);
4682 // Note: InputContentUriTokenHandler.take() checks whether the IME (specified by "uid")
4683 // actually has the right to grant a read permission for "contentUriWithoutUserId" that
4684 // is claimed to belong to "contentUriOwnerUserId". For example, specifying random
4685 // content URI and/or contentUriOwnerUserId just results in a SecurityException thrown
4686 // from InputContentUriTokenHandler.take() and can never be allowed beyond what is
4687 // actually allowed to "uid", which is guaranteed to be the IME's one.
4688 return new InputContentUriTokenHandler(contentUriWithoutUserId, uid,
4689 packageName, contentUriOwnerUserId, appUserId);
Yohei Yukawa25e08132016-06-22 16:31:41 -07004690 }
4691 }
4692
Yohei Yukawac54c1172018-09-06 11:39:50 -07004693 @BinderThread
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08004694 private void reportFullscreenMode(@NonNull IBinder token, boolean fullscreen) {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08004695 synchronized (mMethodMap) {
Yohei Yukawa79e4c6a2018-12-09 19:07:17 -08004696 if (!calledWithValidTokenLocked(token)) {
Yohei Yukawa2bc66172017-02-08 11:13:25 -08004697 return;
4698 }
4699 if (mCurClient != null && mCurClient.client != null) {
4700 mInFullscreenMode = fullscreen;
4701 executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
4702 MSG_REPORT_FULLSCREEN_MODE, fullscreen ? 1 : 0, mCurClient));
4703 }
4704 }
4705 }
4706
4707 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004708 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06004709 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004710
4711 IInputMethod method;
4712 ClientState client;
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08004713 ClientState focusedWindowClient;
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004714
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004715 final Printer p = new PrintWriterPrinter(pw);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004716
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004717 synchronized (mMethodMap) {
4718 p.println("Current Input Method Manager state:");
4719 int N = mMethodList.size();
Yohei Yukawa5ec1fce2018-12-17 07:56:14 -08004720 p.println(" Input Methods: mMethodMapUpdateCount=" + mMethodMapUpdateCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004721 for (int i=0; i<N; i++) {
4722 InputMethodInfo info = mMethodList.get(i);
4723 p.println(" InputMethod #" + i + ":");
4724 info.dump(p, " ");
4725 }
4726 p.println(" Clients:");
Yohei Yukawaac9311e2018-11-20 19:25:23 -08004727 final int numClients = mClients.size();
4728 for (int i = 0; i < numClients; ++i) {
4729 final ClientState ci = mClients.valueAt(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004730 p.println(" Client " + ci + ":");
4731 p.println(" client=" + ci.client);
4732 p.println(" inputContext=" + ci.inputContext);
4733 p.println(" sessionRequested=" + ci.sessionRequested);
4734 p.println(" curSession=" + ci.curSession);
4735 }
The Android Open Source Project10592532009-03-18 17:39:46 -07004736 p.println(" mCurMethodId=" + mCurMethodId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004737 client = mCurClient;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07004738 p.println(" mCurClient=" + client + " mCurSeq=" + mCurSeq);
Yohei Yukawa22a89232017-02-12 16:38:59 -08004739 p.println(" mCurFocusedWindow=" + mCurFocusedWindow
4740 + " softInputMode=" +
Yohei Yukawaa468d702018-10-21 11:42:34 -07004741 InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode)
Yohei Yukawa22a89232017-02-12 16:38:59 -08004742 + " client=" + mCurFocusedWindowClient);
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08004743 focusedWindowClient = mCurFocusedWindowClient;
Yohei Yukawad3ef8422018-06-07 16:28:07 -07004744 p.println(" mCurId=" + mCurId + " mHaveConnection=" + mHaveConnection
4745 + " mBoundToMethod=" + mBoundToMethod + " mVisibleBound=" + mVisibleBound);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004746 p.println(" mCurToken=" + mCurToken);
lumark90120a82018-08-15 00:33:03 +08004747 p.println(" mCurTokenDisplayId=" + mCurTokenDisplayId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004748 p.println(" mCurIntent=" + mCurIntent);
4749 method = mCurMethod;
4750 p.println(" mCurMethod=" + mCurMethod);
4751 p.println(" mEnabledSession=" + mEnabledSession);
4752 p.println(" mShowRequested=" + mShowRequested
4753 + " mShowExplicitlyRequested=" + mShowExplicitlyRequested
4754 + " mShowForced=" + mShowForced
4755 + " mInputShown=" + mInputShown);
Yohei Yukawa2bc66172017-02-08 11:13:25 -08004756 p.println(" mInFullscreenMode=" + mInFullscreenMode);
Yohei Yukawafa6e0a82015-07-23 15:08:59 -07004757 p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
Yohei Yukawa81482972015-06-04 00:58:59 -07004758 p.println(" mSettingsObserver=" + mSettingsObserver);
Yohei Yukawad7248862015-06-03 23:56:12 -07004759 p.println(" mSwitchingController:");
4760 mSwitchingController.dump(p);
Yohei Yukawa68645a62016-02-17 07:54:20 -08004761 p.println(" mSettings:");
4762 mSettings.dumpLocked(p, " ");
Yohei Yukawa357b2f62017-02-14 09:40:03 -08004763
4764 p.println(" mStartInputHistory:");
4765 mStartInputHistory.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004766 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004767
Jeff Brownb88102f2010-09-08 11:49:43 -07004768 p.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004769 if (client != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004770 pw.flush();
4771 try {
Jeff Sharkey850c83e2016-11-09 12:25:44 -07004772 TransferPipe.dumpAsync(client.client.asBinder(), fd, args);
4773 } catch (IOException | RemoteException e) {
4774 p.println("Failed to dump input method client: " + e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004775 }
Jeff Brownb88102f2010-09-08 11:49:43 -07004776 } else {
4777 p.println("No input method client.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004778 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004779
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08004780 if (focusedWindowClient != null && client != focusedWindowClient) {
4781 p.println(" ");
4782 p.println("Warning: Current input method client doesn't match the last focused. "
4783 + "window.");
4784 p.println("Dumping input method client in the last focused window just in case.");
4785 p.println(" ");
4786 pw.flush();
4787 try {
Jeff Sharkey850c83e2016-11-09 12:25:44 -07004788 TransferPipe.dumpAsync(focusedWindowClient.client.asBinder(), fd, args);
4789 } catch (IOException | RemoteException e) {
4790 p.println("Failed to dump input method client in focused window: " + e);
Yohei Yukawae39d4ed2015-11-19 03:38:49 -08004791 }
4792 }
4793
Jeff Brownb88102f2010-09-08 11:49:43 -07004794 p.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004795 if (method != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004796 pw.flush();
4797 try {
Jeff Sharkey850c83e2016-11-09 12:25:44 -07004798 TransferPipe.dumpAsync(method.asBinder(), fd, args);
4799 } catch (IOException | RemoteException e) {
4800 p.println("Failed to dump input method service: " + e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004801 }
Jeff Brownb88102f2010-09-08 11:49:43 -07004802 } else {
4803 p.println("No input method service.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004804 }
4805 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004806
4807 @BinderThread
4808 @Override
4809 public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
4810 @Nullable FileDescriptor err,
4811 @NonNull String[] args, @Nullable ShellCallback callback,
4812 @NonNull ResultReceiver resultReceiver) throws RemoteException {
Yohei Yukawab8d240f2018-12-26 10:03:11 -08004813 final int callingUid = Binder.getCallingUid();
4814 // Reject any incoming calls from non-shell users, including ones from the system user.
4815 if (callingUid != Process.ROOT_UID && callingUid != Process.SHELL_UID) {
4816 // Note that Binder#onTransact() will automatically close "in", "out", and "err" when
4817 // returned from this method, hence there is no need to close those FDs.
4818 // "resultReceiver" is the only thing that needs to be taken care of here.
4819 if (resultReceiver != null) {
4820 resultReceiver.send(ShellCommandResult.FAILURE, null);
4821 }
4822 final String errorMsg = "InputMethodManagerService does not support shell commands from"
4823 + " non-shell users. callingUid=" + callingUid
4824 + " args=" + Arrays.toString(args);
4825 if (Process.isCoreUid(callingUid)) {
4826 // Let's not crash the calling process if the caller is one of core components.
4827 Slog.e(TAG, errorMsg);
4828 return;
4829 }
4830 throw new SecurityException(errorMsg);
4831 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004832 new ShellCommandImpl(this).exec(
4833 this, in, out, err, args, callback, resultReceiver);
4834 }
4835
4836 private static final class ShellCommandImpl extends ShellCommand {
4837 @NonNull
4838 final InputMethodManagerService mService;
4839
4840 ShellCommandImpl(InputMethodManagerService service) {
4841 mService = service;
4842 }
4843
Yohei Yukawadb25df72018-12-27 08:40:41 -08004844 @RequiresPermission(allOf = {
Yohei Yukawa8a2b96b2018-12-28 17:23:29 -08004845 Manifest.permission.DUMP,
4846 Manifest.permission.INTERACT_ACROSS_USERS_FULL,
Yohei Yukawadb25df72018-12-27 08:40:41 -08004847 Manifest.permission.WRITE_SECURE_SETTINGS,
Yohei Yukawa8a2b96b2018-12-28 17:23:29 -08004848 })
Yohei Yukawa926488d2017-12-11 17:24:55 -08004849 @BinderThread
4850 @ShellCommandResult
4851 @Override
4852 public int onCommand(@Nullable String cmd) {
Yohei Yukawadb25df72018-12-27 08:40:41 -08004853 // For shell command, require all the permissions here in favor of code simplicity.
Yohei Yukawa8a2b96b2018-12-28 17:23:29 -08004854 Arrays.asList(
4855 Manifest.permission.DUMP,
4856 Manifest.permission.INTERACT_ACROSS_USERS_FULL,
4857 Manifest.permission.WRITE_SECURE_SETTINGS
4858 ).forEach(permission -> mService.mContext.enforceCallingPermission(permission, null));
Yohei Yukawadb25df72018-12-27 08:40:41 -08004859
4860 final long identity = Binder.clearCallingIdentity();
4861 try {
4862 return onCommandWithSystemIdentity(cmd);
4863 } finally {
4864 Binder.restoreCallingIdentity(identity);
4865 }
4866 }
4867
4868 @BinderThread
4869 @ShellCommandResult
4870 private int onCommandWithSystemIdentity(@Nullable String cmd) {
Yohei Yukawadfdab732018-02-21 07:16:30 +09004871 if ("refresh_debug_properties".equals(cmd)) {
4872 return refreshDebugProperties();
4873 }
4874
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08004875 if ("get-last-switch-user-id".equals(cmd)) {
4876 return mService.getLastSwitchUserId(this);
4877 }
4878
Yohei Yukawacac97722017-12-15 16:52:05 -08004879 // For existing "adb shell ime <command>".
4880 if ("ime".equals(cmd)) {
4881 final String imeCommand = getNextArg();
4882 if (imeCommand == null || "help".equals(imeCommand) || "-h".equals(imeCommand)) {
4883 onImeCommandHelp();
4884 return ShellCommandResult.SUCCESS;
4885 }
4886 switch (imeCommand) {
4887 case "list":
4888 return mService.handleShellCommandListInputMethods(this);
4889 case "enable":
4890 return mService.handleShellCommandEnableDisableInputMethod(this, true);
4891 case "disable":
4892 return mService.handleShellCommandEnableDisableInputMethod(this, false);
4893 case "set":
4894 return mService.handleShellCommandSetInputMethod(this);
4895 case "reset":
4896 return mService.handleShellCommandResetInputMethod(this);
4897 default:
4898 getOutPrintWriter().println("Unknown command: " + imeCommand);
4899 return ShellCommandResult.FAILURE;
4900 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08004901 }
Yohei Yukawacac97722017-12-15 16:52:05 -08004902
4903 return handleDefaultCommands(cmd);
Yohei Yukawa926488d2017-12-11 17:24:55 -08004904 }
4905
4906 @BinderThread
Tarandeep Singh75a92392018-01-12 14:58:59 -08004907 @ShellCommandResult
4908 private int refreshDebugProperties() {
4909 DebugFlags.FLAG_OPTIMIZE_START_INPUT.refresh();
Tarandeep Singheadb1392018-11-09 18:15:57 +01004910 DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.refresh();
Tarandeep Singh75a92392018-01-12 14:58:59 -08004911 return ShellCommandResult.SUCCESS;
4912 }
4913
4914 @BinderThread
Yohei Yukawa926488d2017-12-11 17:24:55 -08004915 @Override
4916 public void onHelp() {
4917 try (PrintWriter pw = getOutPrintWriter()) {
4918 pw.println("InputMethodManagerService commands:");
4919 pw.println(" help");
4920 pw.println(" Prints this help text.");
4921 pw.println(" dump [options]");
4922 pw.println(" Synonym of dumpsys.");
Yohei Yukawacac97722017-12-15 16:52:05 -08004923 pw.println(" ime <command> [options]");
4924 pw.println(" Manipulate IMEs. Run \"ime help\" for details.");
4925 }
4926 }
4927
4928 private void onImeCommandHelp() {
4929 try (IndentingPrintWriter pw =
4930 new IndentingPrintWriter(getOutPrintWriter(), " ", 100)) {
4931 pw.println("ime <command>:");
4932 pw.increaseIndent();
4933
4934 pw.println("list [-a] [-s]");
4935 pw.increaseIndent();
4936 pw.println("prints all enabled input methods.");
4937 pw.increaseIndent();
4938 pw.println("-a: see all input methods");
4939 pw.println("-s: only a single summary line of each");
4940 pw.decreaseIndent();
4941 pw.decreaseIndent();
4942
Yohei Yukawae1771702019-04-10 23:20:51 -07004943 pw.println("enable [--user <USER_ID>] <ID>");
Yohei Yukawacac97722017-12-15 16:52:05 -08004944 pw.increaseIndent();
4945 pw.println("allows the given input method ID to be used.");
Yohei Yukawae1771702019-04-10 23:20:51 -07004946 pw.increaseIndent();
4947 pw.print("--user <USER_ID>: Specify which user to enable.");
4948 pw.println(" Assumes the current user if not specified.");
4949 pw.decreaseIndent();
Yohei Yukawacac97722017-12-15 16:52:05 -08004950 pw.decreaseIndent();
4951
Yohei Yukawae1771702019-04-10 23:20:51 -07004952 pw.println("disable [--user <USER_ID>] <ID>");
Yohei Yukawacac97722017-12-15 16:52:05 -08004953 pw.increaseIndent();
4954 pw.println("disallows the given input method ID to be used.");
Yohei Yukawae1771702019-04-10 23:20:51 -07004955 pw.increaseIndent();
4956 pw.print("--user <USER_ID>: Specify which user to disable.");
4957 pw.println(" Assumes the current user if not specified.");
4958 pw.decreaseIndent();
Yohei Yukawacac97722017-12-15 16:52:05 -08004959 pw.decreaseIndent();
4960
Yohei Yukawa099f80c2019-04-10 23:23:17 -07004961 pw.println("set [--user <USER_ID>] <ID>");
Yohei Yukawacac97722017-12-15 16:52:05 -08004962 pw.increaseIndent();
4963 pw.println("switches to the given input method ID.");
Yohei Yukawa099f80c2019-04-10 23:23:17 -07004964 pw.increaseIndent();
4965 pw.print("--user <USER_ID>: Specify which user to enable.");
4966 pw.println(" Assumes the current user if not specified.");
4967 pw.decreaseIndent();
Yohei Yukawacac97722017-12-15 16:52:05 -08004968 pw.decreaseIndent();
4969
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07004970 pw.println("reset [--user <USER_ID>]");
Yohei Yukawacac97722017-12-15 16:52:05 -08004971 pw.increaseIndent();
4972 pw.println("reset currently selected/enabled IMEs to the default ones as if "
4973 + "the device is initially booted with the current locale.");
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07004974 pw.increaseIndent();
4975 pw.print("--user <USER_ID>: Specify which user to reset.");
4976 pw.println(" Assumes the current user if not specified.");
4977 pw.decreaseIndent();
4978
Yohei Yukawacac97722017-12-15 16:52:05 -08004979 pw.decreaseIndent();
4980
4981 pw.decreaseIndent();
Yohei Yukawa926488d2017-12-11 17:24:55 -08004982 }
4983 }
4984 }
4985
4986 // ----------------------------------------------------------------------
4987 // Shell command handlers:
4988
Yohei Yukawaa7babbb2019-01-08 16:45:34 -08004989 @BinderThread
4990 @ShellCommandResult
4991 private int getLastSwitchUserId(@NonNull ShellCommand shellCommand) {
4992 synchronized (mMethodMap) {
4993 shellCommand.getOutPrintWriter().println(mLastSwitchUserId);
4994 return ShellCommandResult.SUCCESS;
4995 }
4996 }
4997
Yohei Yukawa926488d2017-12-11 17:24:55 -08004998 /**
4999 * Handles {@code adb shell ime list}.
5000 * @param shellCommand {@link ShellCommand} object that is handling this command.
5001 * @return Exit code of the command.
5002 */
5003 @BinderThread
5004 @ShellCommandResult
5005 private int handleShellCommandListInputMethods(@NonNull ShellCommand shellCommand) {
5006 boolean all = false;
5007 boolean brief = false;
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08005008 int userIdToBeResolved = UserHandle.USER_CURRENT;
Yohei Yukawa926488d2017-12-11 17:24:55 -08005009 while (true) {
5010 final String nextOption = shellCommand.getNextOption();
5011 if (nextOption == null) {
5012 break;
5013 }
5014 switch (nextOption) {
5015 case "-a":
5016 all = true;
5017 break;
5018 case "-s":
5019 brief = true;
5020 break;
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08005021 case "-u":
5022 case "--user":
5023 userIdToBeResolved = UserHandle.parseUserArg(shellCommand.getNextArgRequired());
5024 break;
Yohei Yukawa926488d2017-12-11 17:24:55 -08005025 }
5026 }
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08005027 synchronized (mMethodMap) {
5028 final PrintWriter pr = shellCommand.getOutPrintWriter();
5029 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
5030 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
5031 for (int userId : userIds) {
5032 final List<InputMethodInfo> methods = all
Yohei Yukawa2988d2d2019-01-22 21:29:09 -08005033 ? getInputMethodListLocked(userId)
Yohei Yukawa7f8ee4b2019-01-10 08:44:57 -08005034 : getEnabledInputMethodListLocked(userId);
5035 if (userIds.length > 1) {
5036 pr.print("User #");
5037 pr.print(userId);
5038 pr.println(":");
5039 }
5040 for (InputMethodInfo info : methods) {
5041 if (brief) {
5042 pr.println(info.getId());
5043 } else {
5044 pr.print(info.getId());
5045 pr.println(":");
5046 info.dump(pr::println, " ");
5047 }
5048 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005049 }
5050 }
5051 return ShellCommandResult.SUCCESS;
5052 }
5053
5054 /**
5055 * Handles {@code adb shell ime enable} and {@code adb shell ime disable}.
5056 * @param shellCommand {@link ShellCommand} object that is handling this command.
5057 * @param enabled {@code true} if the command was {@code adb shell ime enable}.
5058 * @return Exit code of the command.
5059 */
5060 @BinderThread
5061 @ShellCommandResult
Yohei Yukawa926488d2017-12-11 17:24:55 -08005062 private int handleShellCommandEnableDisableInputMethod(
5063 @NonNull ShellCommand shellCommand, boolean enabled) {
Yohei Yukawa3403f2d2019-04-15 08:16:58 -07005064 final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
Yohei Yukawae1771702019-04-10 23:20:51 -07005065 final String imeId = shellCommand.getNextArgRequired();
5066 final PrintWriter out = shellCommand.getOutPrintWriter();
5067 final PrintWriter error = shellCommand.getErrPrintWriter();
Yohei Yukawa926488d2017-12-11 17:24:55 -08005068 synchronized (mMethodMap) {
Yohei Yukawae1771702019-04-10 23:20:51 -07005069 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
5070 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
5071 for (int userId : userIds) {
5072 if (!userHasDebugPriv(userId, shellCommand)) {
5073 continue;
5074 }
5075 handleShellCommandEnableDisableInputMethodInternalLocked(userId, imeId, enabled,
5076 out, error);
Tarandeep Singh87e2e512019-03-06 14:28:52 -08005077 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005078 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005079 return ShellCommandResult.SUCCESS;
5080 }
5081
5082 /**
Yohei Yukawae1771702019-04-10 23:20:51 -07005083 * A special helper method for commands that only have {@code -u} and {@code --user} options.
5084 *
5085 * <p>You cannot use this helper method if the command has other options.</p>
5086 *
Yohei Yukawa3403f2d2019-04-15 08:16:58 -07005087 * <p>CAVEAT: This method must be called only once before any other
5088 * {@link ShellCommand#getNextArg()} and {@link ShellCommand#getNextArgRequired()} for the
5089 * main arguments.</p>
5090 *
Yohei Yukawae1771702019-04-10 23:20:51 -07005091 * @param shellCommand {@link ShellCommand} from which options should be obtained.
5092 * @return User ID to be resolved. {@link UserHandle#CURRENT} if not specified.
5093 */
5094 @BinderThread
5095 @UserIdInt
5096 private static int handleOptionsForCommandsThatOnlyHaveUserOption(ShellCommand shellCommand) {
5097 while (true) {
5098 final String nextOption = shellCommand.getNextOption();
5099 if (nextOption == null) {
5100 break;
5101 }
5102 switch (nextOption) {
5103 case "-u":
5104 case "--user":
5105 return UserHandle.parseUserArg(shellCommand.getNextArgRequired());
5106 }
5107 }
5108 return UserHandle.USER_CURRENT;
5109 }
5110
5111 @BinderThread
5112 private void handleShellCommandEnableDisableInputMethodInternalLocked(
5113 @UserIdInt int userId, String imeId, boolean enabled, PrintWriter out,
5114 PrintWriter error) {
5115 boolean failedToEnableUnknownIme = false;
5116 boolean previouslyEnabled = false;
5117 if (userId == mSettings.getCurrentUserId()) {
5118 if (enabled && !mMethodMap.containsKey(imeId)) {
5119 failedToEnableUnknownIme = true;
5120 } else {
5121 previouslyEnabled = setInputMethodEnabledLocked(imeId, enabled);
5122 }
5123 } else {
5124 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
5125 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
5126 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
5127 new ArrayMap<>();
5128 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
5129 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
5130 methodMap, methodList);
5131 final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
5132 mContext.getContentResolver(), methodMap, userId, false);
5133 if (enabled) {
5134 if (!methodMap.containsKey(imeId)) {
5135 failedToEnableUnknownIme = true;
5136 } else {
5137 for (InputMethodInfo imi : settings.getEnabledInputMethodListLocked()) {
5138 if (TextUtils.equals(imi.getId(), imeId)) {
5139 previouslyEnabled = true;
5140 break;
5141 }
5142 }
5143 if (!previouslyEnabled) {
5144 settings.appendAndPutEnabledInputMethodLocked(imeId, false);
5145 }
5146 }
5147 } else {
5148 previouslyEnabled =
5149 settings.buildAndPutEnabledInputMethodsStrRemovingIdLocked(
5150 new StringBuilder(),
5151 settings.getEnabledInputMethodsAndSubtypeListLocked(), imeId);
5152 }
5153 }
5154 if (failedToEnableUnknownIme) {
5155 error.print("Unknown input method ");
5156 error.print(imeId);
5157 error.println(" cannot be enabled for user #" + userId);
5158 } else {
5159 out.print("Input method ");
5160 out.print(imeId);
5161 out.print(": ");
5162 out.print((enabled == previouslyEnabled) ? "already " : "now ");
5163 out.print(enabled ? "enabled" : "disabled");
5164 out.print(" for user #");
5165 out.println(userId);
5166 }
5167 }
5168
5169 /**
Yohei Yukawa926488d2017-12-11 17:24:55 -08005170 * Handles {@code adb shell ime set}.
5171 * @param shellCommand {@link ShellCommand} object that is handling this command.
5172 * @return Exit code of the command.
5173 */
5174 @BinderThread
5175 @ShellCommandResult
5176 private int handleShellCommandSetInputMethod(@NonNull ShellCommand shellCommand) {
Yohei Yukawa3403f2d2019-04-15 08:16:58 -07005177 final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005178 final String imeId = shellCommand.getNextArgRequired();
5179 final PrintWriter out = shellCommand.getOutPrintWriter();
5180 final PrintWriter error = shellCommand.getErrPrintWriter();
Yohei Yukawadb25df72018-12-27 08:40:41 -08005181 synchronized (mMethodMap) {
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005182 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
5183 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
5184 for (int userId : userIds) {
5185 if (!userHasDebugPriv(userId, shellCommand)) {
5186 continue;
5187 }
mincheli850892b2019-12-05 19:47:59 +08005188 boolean failedToSelectUnknownIme = !switchToInputMethod(imeId, userId);
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005189 if (failedToSelectUnknownIme) {
5190 error.print("Unknown input method ");
5191 error.print(imeId);
5192 error.print(" cannot be selected for user #");
5193 error.println(userId);
5194 } else {
5195 out.print("Input method ");
5196 out.print(imeId);
5197 out.print(" selected for user #");
Yohei Yukawa3403f2d2019-04-15 08:16:58 -07005198 out.println(userId);
Yohei Yukawa099f80c2019-04-10 23:23:17 -07005199 }
Tarandeep Singh87e2e512019-03-06 14:28:52 -08005200 }
Yohei Yukawadb25df72018-12-27 08:40:41 -08005201 }
Yohei Yukawa926488d2017-12-11 17:24:55 -08005202 return ShellCommandResult.SUCCESS;
5203 }
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005204
5205 /**
5206 * Handles {@code adb shell ime reset-ime}.
5207 * @param shellCommand {@link ShellCommand} object that is handling this command.
5208 * @return Exit code of the command.
5209 */
5210 @BinderThread
5211 @ShellCommandResult
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005212 private int handleShellCommandResetInputMethod(@NonNull ShellCommand shellCommand) {
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005213 final PrintWriter out = shellCommand.getOutPrintWriter();
5214 final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005215 synchronized (mMethodMap) {
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005216 final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
5217 mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
5218 for (int userId : userIds) {
5219 if (!userHasDebugPriv(userId, shellCommand)) {
5220 continue;
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005221 }
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005222 final String nextIme;
5223 final List<InputMethodInfo> nextEnabledImes;
5224 if (userId == mSettings.getCurrentUserId()) {
5225 hideCurrentInputLocked(0, null);
5226 unbindCurrentMethodLocked();
5227 // Reset the current IME
5228 resetSelectedInputMethodAndSubtypeLocked(null);
5229 // Also reset the settings of the current IME
5230 mSettings.putSelectedInputMethod(null);
5231 // Disable all enabled IMEs.
5232 mSettings.getEnabledInputMethodListLocked().forEach(
5233 imi -> setInputMethodEnabledLocked(imi.getId(), false));
5234 // Re-enable with default enabled IMEs.
5235 InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList).forEach(
5236 imi -> setInputMethodEnabledLocked(imi.getId(), true));
5237 updateInputMethodsFromSettingsLocked(true /* enabledMayChange */);
5238 InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
5239 mSettings.getEnabledInputMethodListLocked(),
5240 mSettings.getCurrentUserId(),
5241 mContext.getBasePackageName());
5242 nextIme = mSettings.getSelectedInputMethod();
5243 nextEnabledImes = mSettings.getEnabledInputMethodListLocked();
5244 } else {
5245 final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
5246 final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
5247 final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
5248 new ArrayMap<>();
5249 AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
5250 queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
5251 methodMap, methodList);
5252 final InputMethodSettings settings = new InputMethodSettings(
5253 mContext.getResources(), mContext.getContentResolver(), methodMap,
5254 userId, false);
5255
5256 nextEnabledImes = InputMethodUtils.getDefaultEnabledImes(mContext, methodList);
5257 nextIme = InputMethodUtils.getMostApplicableDefaultIME(nextEnabledImes).getId();
5258
5259 // Reset enabled IMEs.
5260 settings.putEnabledInputMethodsStr("");
5261 nextEnabledImes.forEach(imi -> settings.appendAndPutEnabledInputMethodLocked(
5262 imi.getId(), false));
5263
5264 // Reset selected IME.
5265 settings.putSelectedInputMethod(nextIme);
5266 settings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
5267 }
5268 out.println("Reset current and enabled IMEs for user #" + userId);
5269 out.println(" Selected: " + nextIme);
5270 nextEnabledImes.forEach(ime -> out.println(" Enabled: " + ime.getId()));
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005271 }
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005272 }
Yohei Yukawa2d4b3432019-04-10 23:23:25 -07005273 return ShellCommandResult.SUCCESS;
Yohei Yukawacc97ebd2017-12-11 17:54:43 -08005274 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07005275
Tarandeep Singh87e2e512019-03-06 14:28:52 -08005276 /**
5277 * @param userId the actual user handle obtained by {@link UserHandle#getIdentifier()}
5278 * and *not* pseudo ids like {@link UserHandle#USER_ALL etc}.
5279 * @return {@code true} if userId has debugging privileges.
5280 * i.e. {@link UserManager#DISALLOW_DEBUGGING_FEATURES} is {@code false}.
5281 */
5282 private boolean userHasDebugPriv(int userId, final ShellCommand shellCommand) {
5283 if (mUserManager.hasUserRestriction(
5284 UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.of(userId))) {
5285 shellCommand.getErrPrintWriter().println("User #" + userId
5286 + " is restricted with DISALLOW_DEBUGGING_FEATURES.");
5287 return false;
5288 }
5289 return true;
5290 }
5291
Yohei Yukawac54c1172018-09-06 11:39:50 -07005292 private static final class InputMethodPrivilegedOperationsImpl
5293 extends IInputMethodPrivilegedOperations.Stub {
5294 private final InputMethodManagerService mImms;
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08005295 @NonNull
Yohei Yukawac54c1172018-09-06 11:39:50 -07005296 private final IBinder mToken;
Yohei Yukawad3e0fd932019-01-21 09:16:48 -08005297 InputMethodPrivilegedOperationsImpl(InputMethodManagerService imms,
5298 @NonNull IBinder token) {
Yohei Yukawac54c1172018-09-06 11:39:50 -07005299 mImms = imms;
5300 mToken = token;
5301 }
5302
5303 @BinderThread
5304 @Override
5305 public void setImeWindowStatus(int vis, int backDisposition) {
5306 mImms.setImeWindowStatus(mToken, vis, backDisposition);
5307 }
5308
5309 @BinderThread
5310 @Override
5311 public void reportStartInput(IBinder startInputToken) {
5312 mImms.reportStartInput(mToken, startInputToken);
5313 }
5314
5315 @BinderThread
5316 @Override
Yohei Yukawac54c1172018-09-06 11:39:50 -07005317 public IInputContentUriToken createInputContentUriToken(Uri contentUri,
5318 String packageName) {
5319 return mImms.createInputContentUriToken(mToken, contentUri, packageName);
5320 }
5321
5322 @BinderThread
5323 @Override
5324 public void reportFullscreenMode(boolean fullscreen) {
5325 mImms.reportFullscreenMode(mToken, fullscreen);
5326 }
Yohei Yukawac7ca3682018-09-09 20:48:38 -07005327
5328 @BinderThread
5329 @Override
5330 public void setInputMethod(String id) {
5331 mImms.setInputMethod(mToken, id);
5332 }
5333
5334 @BinderThread
5335 @Override
5336 public void setInputMethodAndSubtype(String id, InputMethodSubtype subtype) {
5337 mImms.setInputMethodAndSubtype(mToken, id, subtype);
5338 }
5339
5340 @BinderThread
5341 @Override
5342 public void hideMySoftInput(int flags) {
5343 mImms.hideMySoftInput(mToken, flags);
5344 }
5345
5346 @BinderThread
5347 @Override
5348 public void showMySoftInput(int flags) {
5349 mImms.showMySoftInput(mToken, flags);
5350 }
5351
5352 @BinderThread
5353 @Override
Yohei Yukawa41b094f2018-09-09 23:58:45 -07005354 public void updateStatusIcon(String packageName, @DrawableRes int iconId) {
Yohei Yukawac7ca3682018-09-09 20:48:38 -07005355 mImms.updateStatusIcon(mToken, packageName, iconId);
5356 }
5357
5358 @BinderThread
5359 @Override
5360 public boolean switchToPreviousInputMethod() {
5361 return mImms.switchToPreviousInputMethod(mToken);
5362 }
5363
5364 @BinderThread
5365 @Override
5366 public boolean switchToNextInputMethod(boolean onlyCurrentIme) {
5367 return mImms.switchToNextInputMethod(mToken, onlyCurrentIme);
5368 }
5369
5370 @BinderThread
5371 @Override
5372 public boolean shouldOfferSwitchingToNextInputMethod() {
5373 return mImms.shouldOfferSwitchingToNextInputMethod(mToken);
5374 }
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07005375
5376 @BinderThread
5377 @Override
Yohei Yukawa9b60ba02019-01-21 00:06:27 -08005378 public void notifyUserAction() {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07005379 mImms.notifyUserAction(mToken);
5380 }
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08005381
5382 @BinderThread
5383 @Override
5384 public void reportPreRendered(EditorInfo info) {
5385 mImms.reportPreRendered(mToken, info);
5386 }
5387
5388 @BinderThread
5389 @Override
Tarandeep Singhbb0e2f72020-01-15 13:58:29 -08005390 public void applyImeVisibility(IBinder windowToken, boolean setVisible) {
5391 mImms.applyImeVisibility(mToken, windowToken, setVisible);
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08005392 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07005393 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005394}