Loading core/java/android/view/inputmethod/InputMethodManager.java +7 −0 Original line number Diff line number Diff line Loading @@ -1007,6 +1007,13 @@ public final class InputMethodManager { mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, fullscreen ? 1 : 0).sendToTarget(); } @Override public void scheduleStartInputIfNecessary(boolean fullscreen) { // TODO(b/149859205): See if we can optimize this by having a fused dedicated operation. mH.obtainMessage(MSG_SET_ACTIVE, 0 /* active */, fullscreen ? 1 : 0).sendToTarget(); mH.obtainMessage(MSG_SET_ACTIVE, 1 /* active */, fullscreen ? 1 : 0).sendToTarget(); } @Override public void reportFullscreenMode(boolean fullscreen) { mH.obtainMessage(MSG_REPORT_FULLSCREEN_MODE, fullscreen ? 1 : 0, 0) Loading core/java/com/android/internal/view/IInputMethodClient.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ oneway interface IInputMethodClient { void onBindMethod(in InputBindResult res); void onUnbindMethod(int sequence, int unbindReason); void setActive(boolean active, boolean fullscreen); void scheduleStartInputIfNecessary(boolean fullscreen); void reportFullscreenMode(boolean fullscreen); void reportPreRendered(in EditorInfo info); void applyImeVisibility(boolean setVisible); Loading core/java/com/android/internal/view/InputBindResult.java +29 −13 Original line number Diff line number Diff line Loading @@ -88,58 +88,65 @@ public final class InputBindResult implements Parcelable { * @see android.content.ServiceConnection#onServiceConnected(ComponentName, IBinder) */ int SUCCESS_WAITING_IME_BINDING = 2; /** * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} has a * pending operation to switch to a different user. * * <p>Note that in this state even what would be the next current IME is not determined.</p> */ int SUCCESS_WAITING_USER_SWITCHING = 3; /** * Indicates that this is not intended for starting input but just for reporting window * focus change from the application process. * * <p>All other fields do not have meaningful value.</p> */ int SUCCESS_REPORT_WINDOW_FOCUS_ONLY = 3; int SUCCESS_REPORT_WINDOW_FOCUS_ONLY = 4; /** * Indicates somehow * {@link * com.android.server.inputmethod.InputMethodManagerService#startInputOrWindowGainedFocus} * is trying to return null {@link InputBindResult}, which must never happen. */ int ERROR_NULL = 4; int ERROR_NULL = 5; /** * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} * recognizes no IME. */ int ERROR_NO_IME = 5; int ERROR_NO_IME = 6; /** * Indicates that {@link android.view.inputmethod.EditorInfo#packageName} does not match * the caller UID. * * @see android.view.inputmethod.EditorInfo#packageName */ int ERROR_INVALID_PACKAGE_NAME = 6; int ERROR_INVALID_PACKAGE_NAME = 7; /** * Indicates that the system is still in an early stage of the boot process and any 3rd * party application is not allowed to run. * * @see com.android.server.SystemService#PHASE_THIRD_PARTY_APPS_CAN_START */ int ERROR_SYSTEM_NOT_READY = 7; int ERROR_SYSTEM_NOT_READY = 8; /** * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} tried to * connect to an {@link android.inputmethodservice.InputMethodService} but failed. * * @see android.content.Context#bindServiceAsUser(Intent, ServiceConnection, int, UserHandle) */ int ERROR_IME_NOT_CONNECTED = 8; int ERROR_IME_NOT_CONNECTED = 9; /** * Indicates that the caller is not the foreground user, does not have * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission, or the user * specified in {@link android.view.inputmethod.EditorInfo#targetInputMethodUser} is not * running. */ int ERROR_INVALID_USER = 9; int ERROR_INVALID_USER = 10; /** * Indicates that the caller should have specified non-null * {@link android.view.inputmethod.EditorInfo}. */ int ERROR_NULL_EDITOR_INFO = 10; int ERROR_NULL_EDITOR_INFO = 11; /** * Indicates that the target window the client specified cannot be the IME target right now. * Loading @@ -149,24 +156,24 @@ public final class InputBindResult implements Parcelable { * * @see com.android.server.wm.WindowManagerInternal#isInputMethodClientFocus(int, int, int) */ int ERROR_NOT_IME_TARGET_WINDOW = 11; int ERROR_NOT_IME_TARGET_WINDOW = 12; /** * Indicates that focused view in the current window is not an editor. */ int ERROR_NO_EDITOR = 12; int ERROR_NO_EDITOR = 13; /** * Indicates that there is a mismatch in display ID between IME client and focused Window. */ int ERROR_DISPLAY_ID_MISMATCH = 13; int ERROR_DISPLAY_ID_MISMATCH = 14; /** * Indicates that current IME client is no longer allowed to access to the associated * display. */ int ERROR_INVALID_DISPLAY_ID = 14; int ERROR_INVALID_DISPLAY_ID = 15; /** * Indicates that the client is not recognized by the system. */ int ERROR_INVALID_CLIENT = 15; int ERROR_INVALID_CLIENT = 16; } @ResultCode Loading Loading @@ -299,6 +306,8 @@ public final class InputBindResult implements Parcelable { return "SUCCESS_WAITING_IME_SESSION"; case ResultCode.SUCCESS_WAITING_IME_BINDING: return "SUCCESS_WAITING_IME_BINDING"; case ResultCode.SUCCESS_WAITING_USER_SWITCHING: return "SUCCESS_WAITING_USER_SWITCHING"; case ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY: return "SUCCESS_REPORT_WINDOW_FOCUS_ONLY"; case ResultCode.ERROR_NULL: Loading Loading @@ -386,4 +395,11 @@ public final class InputBindResult implements Parcelable { * Predefined error object for {@link ResultCode#ERROR_INVALID_CLIENT}. */ public static final InputBindResult INVALID_CLIENT = error(ResultCode.ERROR_INVALID_CLIENT); /** * Predefined <strong>success</strong> object for * {@link ResultCode#SUCCESS_WAITING_USER_SWITCHING}. */ public static final InputBindResult USER_SWITCHING = error(ResultCode.SUCCESS_WAITING_USER_SWITCHING); } services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +87 −7 Original line number Diff line number Diff line Loading @@ -1388,6 +1388,44 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } private static final class UserSwitchHandlerTask implements Runnable { final InputMethodManagerService mService; @UserIdInt final int mToUserId; @Nullable IInputMethodClient mClientToBeReset; UserSwitchHandlerTask(InputMethodManagerService service, @UserIdInt int toUserId, @Nullable IInputMethodClient clientToBeReset) { mService = service; mToUserId = toUserId; mClientToBeReset = clientToBeReset; } @Override public void run() { synchronized (mService.mMethodMap) { if (mService.mUserSwitchHandlerTask != this) { // This task was already canceled before it is handled here. So do nothing. return; } mService.switchUserOnHandlerLocked(mService.mUserSwitchHandlerTask.mToUserId, mClientToBeReset); mService.mUserSwitchHandlerTask = null; } } } /** * When non-{@code null}, this represents pending user-switch task, which is to be executed as * a handler callback. This needs to be set and unset only within the lock. */ @Nullable @GuardedBy("mMethodMap") private UserSwitchHandlerTask mUserSwitchHandlerTask; public static final class Lifecycle extends SystemService { private InputMethodManagerService mService; Loading @@ -1406,8 +1444,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @Override public void onSwitchUser(@UserIdInt int userHandle) { // Called on ActivityManager thread. // TODO: Dispatch this to a worker thread as needed. mService.onSwitchUser(userHandle); synchronized (mService.mMethodMap) { mService.scheduleSwitchUserTaskLocked(userHandle, null /* clientToBeReset */); } } @Override Loading Loading @@ -1447,10 +1486,20 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } void onSwitchUser(@UserIdInt int userId) { synchronized (mMethodMap) { switchUserLocked(userId); @GuardedBy("mMethodMap") void scheduleSwitchUserTaskLocked(@UserIdInt int userId, @Nullable IInputMethodClient clientToBeReset) { if (mUserSwitchHandlerTask != null) { if (mUserSwitchHandlerTask.mToUserId == userId) { mUserSwitchHandlerTask.mClientToBeReset = clientToBeReset; return; } mHandler.removeCallbacks(mUserSwitchHandlerTask); } final UserSwitchHandlerTask task = new UserSwitchHandlerTask(this, userId, clientToBeReset); mUserSwitchHandlerTask = task; mHandler.post(task); } public InputMethodManagerService(Context context) { Loading Loading @@ -1538,7 +1587,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @GuardedBy("mMethodMap") private void switchUserLocked(int newUserId) { private void switchUserOnHandlerLocked(@UserIdInt int newUserId, IInputMethodClient clientToBeReset) { if (DEBUG) Slog.d(TAG, "Switching user stage 1/3. newUserId=" + newUserId + " currentUserId=" + mSettings.getCurrentUserId()); Loading Loading @@ -1589,6 +1639,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub + " selectedIme=" + mSettings.getSelectedInputMethod()); mLastSwitchUserId = newUserId; if (mIsInteractive && clientToBeReset != null) { final ClientState cs = mClients.get(clientToBeReset.asBinder()); if (cs == null) { // The client is already gone. return; } try { cs.client.scheduleStartInputIfNecessary(mInFullscreenMode); } catch (RemoteException e) { } } } void updateCurrentProfileIds() { Loading Loading @@ -3072,6 +3134,22 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return InputBindResult.NOT_IME_TARGET_WINDOW; } if (mUserSwitchHandlerTask != null) { // There is already an on-going pending user switch task. final int nextUserId = mUserSwitchHandlerTask.mToUserId; if (userId == nextUserId) { scheduleSwitchUserTaskLocked(userId, cs.client); return InputBindResult.USER_SWITCHING; } for (int profileId : mUserManager.getProfileIdsWithDisabled(nextUserId)) { if (profileId == userId) { scheduleSwitchUserTaskLocked(userId, cs.client); return InputBindResult.USER_SWITCHING; } } return InputBindResult.INVALID_USER; } // cross-profile access is always allowed here to allow profile-switching. if (!mSettings.isCurrentProfile(userId)) { Slog.w(TAG, "A background user is requesting window. Hiding IME."); Loading @@ -3083,8 +3161,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } if (userId != mSettings.getCurrentUserId()) { switchUserLocked(userId); scheduleSwitchUserTaskLocked(userId, cs.client); return InputBindResult.USER_SWITCHING; } // Master feature flag that overrides other conditions and forces IME preRendering. if (DEBUG) { Slog.v(TAG, "IME PreRendering MASTER flag: " Loading Loading
core/java/android/view/inputmethod/InputMethodManager.java +7 −0 Original line number Diff line number Diff line Loading @@ -1007,6 +1007,13 @@ public final class InputMethodManager { mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, fullscreen ? 1 : 0).sendToTarget(); } @Override public void scheduleStartInputIfNecessary(boolean fullscreen) { // TODO(b/149859205): See if we can optimize this by having a fused dedicated operation. mH.obtainMessage(MSG_SET_ACTIVE, 0 /* active */, fullscreen ? 1 : 0).sendToTarget(); mH.obtainMessage(MSG_SET_ACTIVE, 1 /* active */, fullscreen ? 1 : 0).sendToTarget(); } @Override public void reportFullscreenMode(boolean fullscreen) { mH.obtainMessage(MSG_REPORT_FULLSCREEN_MODE, fullscreen ? 1 : 0, 0) Loading
core/java/com/android/internal/view/IInputMethodClient.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ oneway interface IInputMethodClient { void onBindMethod(in InputBindResult res); void onUnbindMethod(int sequence, int unbindReason); void setActive(boolean active, boolean fullscreen); void scheduleStartInputIfNecessary(boolean fullscreen); void reportFullscreenMode(boolean fullscreen); void reportPreRendered(in EditorInfo info); void applyImeVisibility(boolean setVisible); Loading
core/java/com/android/internal/view/InputBindResult.java +29 −13 Original line number Diff line number Diff line Loading @@ -88,58 +88,65 @@ public final class InputBindResult implements Parcelable { * @see android.content.ServiceConnection#onServiceConnected(ComponentName, IBinder) */ int SUCCESS_WAITING_IME_BINDING = 2; /** * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} has a * pending operation to switch to a different user. * * <p>Note that in this state even what would be the next current IME is not determined.</p> */ int SUCCESS_WAITING_USER_SWITCHING = 3; /** * Indicates that this is not intended for starting input but just for reporting window * focus change from the application process. * * <p>All other fields do not have meaningful value.</p> */ int SUCCESS_REPORT_WINDOW_FOCUS_ONLY = 3; int SUCCESS_REPORT_WINDOW_FOCUS_ONLY = 4; /** * Indicates somehow * {@link * com.android.server.inputmethod.InputMethodManagerService#startInputOrWindowGainedFocus} * is trying to return null {@link InputBindResult}, which must never happen. */ int ERROR_NULL = 4; int ERROR_NULL = 5; /** * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} * recognizes no IME. */ int ERROR_NO_IME = 5; int ERROR_NO_IME = 6; /** * Indicates that {@link android.view.inputmethod.EditorInfo#packageName} does not match * the caller UID. * * @see android.view.inputmethod.EditorInfo#packageName */ int ERROR_INVALID_PACKAGE_NAME = 6; int ERROR_INVALID_PACKAGE_NAME = 7; /** * Indicates that the system is still in an early stage of the boot process and any 3rd * party application is not allowed to run. * * @see com.android.server.SystemService#PHASE_THIRD_PARTY_APPS_CAN_START */ int ERROR_SYSTEM_NOT_READY = 7; int ERROR_SYSTEM_NOT_READY = 8; /** * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} tried to * connect to an {@link android.inputmethodservice.InputMethodService} but failed. * * @see android.content.Context#bindServiceAsUser(Intent, ServiceConnection, int, UserHandle) */ int ERROR_IME_NOT_CONNECTED = 8; int ERROR_IME_NOT_CONNECTED = 9; /** * Indicates that the caller is not the foreground user, does not have * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission, or the user * specified in {@link android.view.inputmethod.EditorInfo#targetInputMethodUser} is not * running. */ int ERROR_INVALID_USER = 9; int ERROR_INVALID_USER = 10; /** * Indicates that the caller should have specified non-null * {@link android.view.inputmethod.EditorInfo}. */ int ERROR_NULL_EDITOR_INFO = 10; int ERROR_NULL_EDITOR_INFO = 11; /** * Indicates that the target window the client specified cannot be the IME target right now. * Loading @@ -149,24 +156,24 @@ public final class InputBindResult implements Parcelable { * * @see com.android.server.wm.WindowManagerInternal#isInputMethodClientFocus(int, int, int) */ int ERROR_NOT_IME_TARGET_WINDOW = 11; int ERROR_NOT_IME_TARGET_WINDOW = 12; /** * Indicates that focused view in the current window is not an editor. */ int ERROR_NO_EDITOR = 12; int ERROR_NO_EDITOR = 13; /** * Indicates that there is a mismatch in display ID between IME client and focused Window. */ int ERROR_DISPLAY_ID_MISMATCH = 13; int ERROR_DISPLAY_ID_MISMATCH = 14; /** * Indicates that current IME client is no longer allowed to access to the associated * display. */ int ERROR_INVALID_DISPLAY_ID = 14; int ERROR_INVALID_DISPLAY_ID = 15; /** * Indicates that the client is not recognized by the system. */ int ERROR_INVALID_CLIENT = 15; int ERROR_INVALID_CLIENT = 16; } @ResultCode Loading Loading @@ -299,6 +306,8 @@ public final class InputBindResult implements Parcelable { return "SUCCESS_WAITING_IME_SESSION"; case ResultCode.SUCCESS_WAITING_IME_BINDING: return "SUCCESS_WAITING_IME_BINDING"; case ResultCode.SUCCESS_WAITING_USER_SWITCHING: return "SUCCESS_WAITING_USER_SWITCHING"; case ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY: return "SUCCESS_REPORT_WINDOW_FOCUS_ONLY"; case ResultCode.ERROR_NULL: Loading Loading @@ -386,4 +395,11 @@ public final class InputBindResult implements Parcelable { * Predefined error object for {@link ResultCode#ERROR_INVALID_CLIENT}. */ public static final InputBindResult INVALID_CLIENT = error(ResultCode.ERROR_INVALID_CLIENT); /** * Predefined <strong>success</strong> object for * {@link ResultCode#SUCCESS_WAITING_USER_SWITCHING}. */ public static final InputBindResult USER_SWITCHING = error(ResultCode.SUCCESS_WAITING_USER_SWITCHING); }
services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +87 −7 Original line number Diff line number Diff line Loading @@ -1388,6 +1388,44 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } private static final class UserSwitchHandlerTask implements Runnable { final InputMethodManagerService mService; @UserIdInt final int mToUserId; @Nullable IInputMethodClient mClientToBeReset; UserSwitchHandlerTask(InputMethodManagerService service, @UserIdInt int toUserId, @Nullable IInputMethodClient clientToBeReset) { mService = service; mToUserId = toUserId; mClientToBeReset = clientToBeReset; } @Override public void run() { synchronized (mService.mMethodMap) { if (mService.mUserSwitchHandlerTask != this) { // This task was already canceled before it is handled here. So do nothing. return; } mService.switchUserOnHandlerLocked(mService.mUserSwitchHandlerTask.mToUserId, mClientToBeReset); mService.mUserSwitchHandlerTask = null; } } } /** * When non-{@code null}, this represents pending user-switch task, which is to be executed as * a handler callback. This needs to be set and unset only within the lock. */ @Nullable @GuardedBy("mMethodMap") private UserSwitchHandlerTask mUserSwitchHandlerTask; public static final class Lifecycle extends SystemService { private InputMethodManagerService mService; Loading @@ -1406,8 +1444,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @Override public void onSwitchUser(@UserIdInt int userHandle) { // Called on ActivityManager thread. // TODO: Dispatch this to a worker thread as needed. mService.onSwitchUser(userHandle); synchronized (mService.mMethodMap) { mService.scheduleSwitchUserTaskLocked(userHandle, null /* clientToBeReset */); } } @Override Loading Loading @@ -1447,10 +1486,20 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } void onSwitchUser(@UserIdInt int userId) { synchronized (mMethodMap) { switchUserLocked(userId); @GuardedBy("mMethodMap") void scheduleSwitchUserTaskLocked(@UserIdInt int userId, @Nullable IInputMethodClient clientToBeReset) { if (mUserSwitchHandlerTask != null) { if (mUserSwitchHandlerTask.mToUserId == userId) { mUserSwitchHandlerTask.mClientToBeReset = clientToBeReset; return; } mHandler.removeCallbacks(mUserSwitchHandlerTask); } final UserSwitchHandlerTask task = new UserSwitchHandlerTask(this, userId, clientToBeReset); mUserSwitchHandlerTask = task; mHandler.post(task); } public InputMethodManagerService(Context context) { Loading Loading @@ -1538,7 +1587,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @GuardedBy("mMethodMap") private void switchUserLocked(int newUserId) { private void switchUserOnHandlerLocked(@UserIdInt int newUserId, IInputMethodClient clientToBeReset) { if (DEBUG) Slog.d(TAG, "Switching user stage 1/3. newUserId=" + newUserId + " currentUserId=" + mSettings.getCurrentUserId()); Loading Loading @@ -1589,6 +1639,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub + " selectedIme=" + mSettings.getSelectedInputMethod()); mLastSwitchUserId = newUserId; if (mIsInteractive && clientToBeReset != null) { final ClientState cs = mClients.get(clientToBeReset.asBinder()); if (cs == null) { // The client is already gone. return; } try { cs.client.scheduleStartInputIfNecessary(mInFullscreenMode); } catch (RemoteException e) { } } } void updateCurrentProfileIds() { Loading Loading @@ -3072,6 +3134,22 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return InputBindResult.NOT_IME_TARGET_WINDOW; } if (mUserSwitchHandlerTask != null) { // There is already an on-going pending user switch task. final int nextUserId = mUserSwitchHandlerTask.mToUserId; if (userId == nextUserId) { scheduleSwitchUserTaskLocked(userId, cs.client); return InputBindResult.USER_SWITCHING; } for (int profileId : mUserManager.getProfileIdsWithDisabled(nextUserId)) { if (profileId == userId) { scheduleSwitchUserTaskLocked(userId, cs.client); return InputBindResult.USER_SWITCHING; } } return InputBindResult.INVALID_USER; } // cross-profile access is always allowed here to allow profile-switching. if (!mSettings.isCurrentProfile(userId)) { Slog.w(TAG, "A background user is requesting window. Hiding IME."); Loading @@ -3083,8 +3161,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } if (userId != mSettings.getCurrentUserId()) { switchUserLocked(userId); scheduleSwitchUserTaskLocked(userId, cs.client); return InputBindResult.USER_SWITCHING; } // Master feature flag that overrides other conditions and forces IME preRendering. if (DEBUG) { Slog.v(TAG, "IME PreRendering MASTER flag: " Loading