Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 62612562 authored by Yohei Yukawa's avatar Yohei Yukawa Committed by Android (Google) Code Review
Browse files

Merge "Offload user-switching task from startInputOrWindowGainedFocus()"

parents 41764f22 d277d690
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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)
+1 −0
Original line number Diff line number Diff line
@@ -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);
+29 −13
Original line number Diff line number Diff line
@@ -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.
         *
@@ -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
@@ -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:
@@ -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);
}
+87 −7
Original line number Diff line number Diff line
@@ -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;

@@ -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
@@ -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) {
@@ -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());

@@ -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() {
@@ -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.");
@@ -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: "