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

Commit d33433cc authored by Yohei Yukawa's avatar Yohei Yukawa Committed by mse1969
Browse files

[BACKPORT] Introduce IInputMethodManagerInvoker

This helps us consolidate binder-related boilerplate code from

  InputMethodManager.java

to a separate utility class.

This is a mechanical refactoring CL. There should be no observable
behavior change.

Bug: 234882948
Test: presubmit
Change-Id: Ifdb676cf0e37165eb4992f649ac0b694590afc7c
parent 5a7a8d24
Loading
Loading
Loading
Loading
+251 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view.inputmethod;

import android.annotation.AnyThread;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.window.ImeOnBackInvokedDispatcher;

import com.android.internal.inputmethod.DirectBootAwareness;
import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
import com.android.internal.inputmethod.InputBindResult;
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.inputmethod.StartInputFlags;
import com.android.internal.inputmethod.StartInputReason;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
import com.android.internal.view.IInputMethodManager;

import java.util.List;

/**
 * A wrapper class to invoke IPCs defined in {@link IInputMethodManager}.
 */
final class IInputMethodManagerInvoker {
    @NonNull
    private final IInputMethodManager mTarget;

    private IInputMethodManagerInvoker(@NonNull IInputMethodManager target) {
        mTarget = target;
    }

    @AnyThread
    @NonNull
    static IInputMethodManagerInvoker create(@NonNull IInputMethodManager imm) {
        return new IInputMethodManagerInvoker(imm);
    }

    @AnyThread
    void addClient(IInputMethodClient client, IInputContext fallbackInputConnection,
            int untrustedDisplayId) {
        try {
            mTarget.addClient(client, fallbackInputConnection, untrustedDisplayId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @AnyThread
    List<InputMethodInfo> getInputMethodList(@UserIdInt int userId) {
        try {
            return mTarget.getInputMethodList(userId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @AnyThread
    List<InputMethodInfo> getAwareLockedInputMethodList(@UserIdInt int userId,
            @DirectBootAwareness int directBootAwareness) {
        try {
            return mTarget.getAwareLockedInputMethodList(userId, directBootAwareness);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @AnyThread
    List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) {
        try {
            return mTarget.getEnabledInputMethodList(userId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @AnyThread
    List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
            boolean allowsImplicitlySelectedSubtypes) {
        try {
            return mTarget.getEnabledInputMethodSubtypeList(imiId,
                    allowsImplicitlySelectedSubtypes);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @AnyThread
    InputMethodSubtype getLastInputMethodSubtype() {
        try {
            return mTarget.getLastInputMethodSubtype();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @AnyThread
    boolean showSoftInput(IInputMethodClient client, IBinder windowToken,
            int flags, ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
        try {
            return mTarget.showSoftInput(client, windowToken, flags, resultReceiver, reason);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @AnyThread
    boolean hideSoftInput(IInputMethodClient client, IBinder windowToken,
            int flags, ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
        try {
            return mTarget.hideSoftInput(client, windowToken, flags, resultReceiver, reason);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @AnyThread
    InputBindResult startInputOrWindowGainedFocus(@StartInputReason int startInputReason,
            IInputMethodClient client, IBinder windowToken,
            @StartInputFlags int startInputFlags,
            @android.view.WindowManager.LayoutParams.SoftInputModeFlags int softInputMode,
            int windowFlags, EditorInfo editorInfo, IInputContext remoteInputConnection,
            IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
            int unverifiedTargetSdkVersion, ImeOnBackInvokedDispatcher imeDispatcher) {
        try {
            return mTarget.startInputOrWindowGainedFocus(startInputReason, client, windowToken,
                    startInputFlags, softInputMode, windowFlags, editorInfo, remoteInputConnection,
                    remoteAccessibilityInputConnection, unverifiedTargetSdkVersion, imeDispatcher);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @AnyThread
    void showInputMethodPickerFromClient(IInputMethodClient client, int auxiliarySubtypeMode) {
        try {
            mTarget.showInputMethodPickerFromClient(client, auxiliarySubtypeMode);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @AnyThread
    void showInputMethodPickerFromSystem(IInputMethodClient client, int auxiliarySubtypeMode,
            int displayId) {
        try {
            mTarget.showInputMethodPickerFromSystem(client, auxiliarySubtypeMode, displayId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @AnyThread
    void showInputMethodAndSubtypeEnablerFromClient(IInputMethodClient client, String imeId) {
        try {
            mTarget.showInputMethodAndSubtypeEnablerFromClient(client, imeId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @AnyThread
    boolean isInputMethodPickerShownForTest() {
        try {
            return mTarget.isInputMethodPickerShownForTest();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @AnyThread
    InputMethodSubtype getCurrentInputMethodSubtype() {
        try {
            return mTarget.getCurrentInputMethodSubtype();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @AnyThread
    void setAdditionalInputMethodSubtypes(String imeId, InputMethodSubtype[] subtypes) {
        try {
            mTarget.setAdditionalInputMethodSubtypes(imeId, subtypes);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @AnyThread
    int getInputMethodWindowVisibleHeight(IInputMethodClient client) {
        try {
            return mTarget.getInputMethodWindowVisibleHeight(client);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @AnyThread
    void reportVirtualDisplayGeometryAsync(IInputMethodClient client, int childDisplayId,
            float[] matrixValues) {
        try {
            mTarget.reportVirtualDisplayGeometryAsync(client, childDisplayId, matrixValues);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @AnyThread
    void reportPerceptibleAsync(IBinder windowToken, boolean perceptible) {
        try {
            mTarget.reportPerceptibleAsync(windowToken, perceptible);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @AnyThread
    void removeImeSurfaceFromWindowAsync(IBinder windowToken) {
        try {
            mTarget.removeImeSurfaceFromWindowAsync(windowToken);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @AnyThread
    void startStylusHandwriting(IInputMethodClient client) {
        try {
            mTarget.startStylusHandwriting(client);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
}
+107 −205
Original line number Diff line number Diff line
@@ -65,7 +65,6 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
@@ -395,10 +394,17 @@ public final class InputMethodManager {
    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
    public static final long CLEAR_SHOW_FORCED_FLAG_WHEN_LEAVING = 214016041L; // This is a bug id.

    /**
     * @deprecated Use {@link #mServiceInvoker} instead.
     */
    @Deprecated
    @UnsupportedAppUsage
    final IInputMethodManager mService;
    final Looper mMainLooper;

    @NonNull
    private final IInputMethodManagerInvoker mServiceInvoker;

    // For scheduling work on the main thread.  This also serves as our
    // global lock.
    // Remark on @UnsupportedAppUsage: there were context leaks on old versions
@@ -637,11 +643,7 @@ public final class InputMethodManager {
     * @hide
     */
    public void reportPerceptible(IBinder windowToken, boolean perceptible) {
        try {
            mService.reportPerceptibleAsync(windowToken, perceptible);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        mServiceInvoker.reportPerceptibleAsync(windowToken, perceptible);
    }

    private final class DelegateImpl implements
@@ -740,7 +742,6 @@ public final class InputMethodManager {
            synchronized (mH) {
                // For some reason we didn't do a startInput + windowFocusGain, so
                // we'll just do a window focus gain and call it a day.
                try {
                View servedView = controller.getServedView();
                boolean nextFocusHasConnection = servedView != null && servedView == focusedView
                        && hasActiveConnection(focusedView);
@@ -753,7 +754,7 @@ public final class InputMethodManager {
                        ? WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION
                        : WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION;
                // ignore the result
                    mService.startInputOrWindowGainedFocus(
                mServiceInvoker.startInputOrWindowGainedFocus(
                        startInputReason, mClient,
                        focusedView.getWindowToken(), startInputFlags, softInputMode,
                        windowFlags,
@@ -761,9 +762,6 @@ public final class InputMethodManager {
                        null, null,
                        mCurRootView.mContext.getApplicationInfo().targetSdkVersion,
                        mImeDispatcher);
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
        }

@@ -1282,9 +1280,7 @@ public final class InputMethodManager {
        // 1) doing so has no effect for A and 2) doing so is sufficient for B.
        final long identity = Binder.clearCallingIdentity();
        try {
            service.addClient(imm.mClient, imm.mFallbackInputConnection, displayId);
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
            imm.mServiceInvoker.addClient(imm.mClient, imm.mFallbackInputConnection, displayId);
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
@@ -1322,8 +1318,9 @@ public final class InputMethodManager {
        return new InputMethodManager(stubInterface, displayId, looper);
    }

    private InputMethodManager(IInputMethodManager service, int displayId, Looper looper) {
        mService = service;
    private InputMethodManager(@NonNull IInputMethodManager service, int displayId, Looper looper) {
        mService = service;  // For @UnsupportedAppUsage
        mServiceInvoker = IInputMethodManagerInvoker.create(service);
        mMainLooper = looper;
        mH = new H(looper);
        mDisplayId = displayId;
@@ -1413,14 +1410,10 @@ public final class InputMethodManager {
     * @return {@link List} of {@link InputMethodInfo}.
     */
    public List<InputMethodInfo> getInputMethodList() {
        try {
        // We intentionally do not use UserHandle.getCallingUserId() here because for system
        // services InputMethodManagerInternal.getInputMethodListAsUser() should be used
        // instead.
            return mService.getInputMethodList(UserHandle.myUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        return mServiceInvoker.getInputMethodList(UserHandle.myUserId());
    }

    /**
@@ -1434,11 +1427,7 @@ public final class InputMethodManager {
    @RequiresPermission(INTERACT_ACROSS_USERS_FULL)
    @NonNull
    public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
        try {
            return mService.getInputMethodList(userId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        return mServiceInvoker.getInputMethodList(userId);
    }

    /**
@@ -1454,11 +1443,7 @@ public final class InputMethodManager {
    @NonNull
    public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId,
            @DirectBootAwareness int directBootAwareness) {
        try {
            return mService.getAwareLockedInputMethodList(userId, directBootAwareness);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        return mServiceInvoker.getAwareLockedInputMethodList(userId, directBootAwareness);
    }

    /**
@@ -1469,14 +1454,10 @@ public final class InputMethodManager {
     * @return {@link List} of {@link InputMethodInfo}.
     */
    public List<InputMethodInfo> getEnabledInputMethodList() {
        try {
        // We intentionally do not use UserHandle.getCallingUserId() here because for system
        // services InputMethodManagerInternal.getEnabledInputMethodListAsUser() should be used
        // instead.
            return mService.getEnabledInputMethodList(UserHandle.myUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        return mServiceInvoker.getEnabledInputMethodList(UserHandle.myUserId());
    }

    /**
@@ -1488,11 +1469,7 @@ public final class InputMethodManager {
     */
    @RequiresPermission(INTERACT_ACROSS_USERS_FULL)
    public List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
        try {
            return mService.getEnabledInputMethodList(userId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        return mServiceInvoker.getEnabledInputMethodList(userId);
    }

    /**
@@ -1507,13 +1484,9 @@ public final class InputMethodManager {
     */
    public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi,
            boolean allowsImplicitlySelectedSubtypes) {
        try {
            return mService.getEnabledInputMethodSubtypeList(
        return mServiceInvoker.getEnabledInputMethodSubtypeList(
                imi == null ? null : imi.getId(),
                allowsImplicitlySelectedSubtypes);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
@@ -1876,18 +1849,14 @@ public final class InputMethodManager {
            // Makes sure to call ImeInsetsSourceConsumer#onShowRequested on the UI thread.
            // TODO(b/229426865): call WindowInsetsController#show instead.
            mH.executeOrSendMessage(Message.obtain(mH, MSG_ON_SHOW_REQUESTED));
            try {
            Log.d(TAG, "showSoftInput() view=" + view + " flags=" + flags + " reason="
                    + InputMethodDebug.softInputDisplayReasonToString(reason));
                return mService.showSoftInput(
            return mServiceInvoker.showSoftInput(
                    mClient,
                    view.getWindowToken(),
                    flags,
                    resultReceiver,
                    reason);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    }

@@ -1903,7 +1872,6 @@ public final class InputMethodManager {
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768499)
    public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) {
        synchronized (mH) {
            try {
            Log.w(TAG, "showSoftInputUnchecked() is a hidden method, which will be"
                    + " removed soon. If you are using androidx.appcompat.widget.SearchView,"
                    + " please update to version 26.0 or newer version.");
@@ -1914,15 +1882,12 @@ public final class InputMethodManager {
            // Makes sure to call ImeInsetsSourceConsumer#onShowRequested on the UI thread.
            // TODO(b/229426865): call WindowInsetsController#show instead.
            mH.executeOrSendMessage(Message.obtain(mH, MSG_ON_SHOW_REQUESTED));
                mService.showSoftInput(
            mServiceInvoker.showSoftInput(
                    mClient,
                    mCurRootView.getView().getWindowToken(),
                    flags,
                    resultReceiver,
                    SoftInputShowHideReason.SHOW_SOFT_INPUT);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    }

@@ -1997,11 +1962,8 @@ public final class InputMethodManager {
                return false;
            }

            try {
                return mService.hideSoftInput(mClient, windowToken, flags, resultReceiver, reason);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
            return mServiceInvoker.hideSoftInput(mClient, windowToken, flags, resultReceiver,
                    reason);
        }
    }

@@ -2055,13 +2017,9 @@ public final class InputMethodManager {
                        mDisplayId);
            }

            try {
                mService.startStylusHandwriting(mClient);
            mServiceInvoker.startStylusHandwriting(mClient);
            // TODO(b/210039666): do we need any extra work for supporting non-native
            //   UI toolkits?
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    }

@@ -2377,17 +2335,13 @@ public final class InputMethodManager {
                        + ic + " tba=" + tba + " startInputFlags="
                        + InputMethodDebug.startInputFlagsToString(startInputFlags));
            }
            try {
                res = mService.startInputOrWindowGainedFocus(
            res = mServiceInvoker.startInputOrWindowGainedFocus(
                    startInputReason, mClient, windowGainingFocus, startInputFlags,
                    softInputMode, windowFlags, tba, servedInputConnection,
                    servedInputConnection == null ? null
                            : servedInputConnection.asIRemoteAccessibilityInputConnection(),
                    view.getContext().getApplicationInfo().targetSdkVersion,
                    mImeDispatcher);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
            if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
            if (res == null) {
                Log.wtf(TAG, "startInputOrWindowGainedFocus must not return"
@@ -2515,16 +2469,12 @@ public final class InputMethodManager {
                Log.w(TAG, "No current root view, ignoring closeCurrentInput()");
                return;
            }
            try {
                mService.hideSoftInput(
            mServiceInvoker.hideSoftInput(
                    mClient,
                    mCurRootView.getView().getWindowToken(),
                    HIDE_NOT_ALWAYS,
                    null,
                    SoftInputShowHideReason.HIDE_SOFT_INPUT);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    }

@@ -2595,13 +2545,9 @@ public final class InputMethodManager {
        synchronized (mH) {
            if (mCurrentInputMethodSession != null && mCurRootView != null
                    && mCurRootView.getWindowToken() == windowToken) {
                try {
                    mService.hideSoftInput(mClient, windowToken, 0 /* flags */,
                mServiceInvoker.hideSoftInput(mClient, windowToken, 0 /* flags */,
                        null /* resultReceiver */,
                        SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API);
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
        }
    }
@@ -2613,11 +2559,7 @@ public final class InputMethodManager {
     */
    public void removeImeSurface(IBinder windowToken) {
        synchronized (mH) {
            try {
                mService.removeImeSurfaceFromWindowAsync(windowToken);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
            mServiceInvoker.removeImeSurfaceFromWindowAsync(windowToken);
        }
    }

@@ -3231,19 +3173,11 @@ public final class InputMethodManager {
        final int mode = showAuxiliarySubtypes
                ? SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES
                : SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES;
        try {
            mService.showInputMethodPickerFromSystem(mClient, mode, displayId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        mServiceInvoker.showInputMethodPickerFromSystem(mClient, mode, displayId);
    }

    private void showInputMethodPickerLocked() {
        try {
            mService.showInputMethodPickerFromClient(mClient, SHOW_IM_PICKER_MODE_AUTO);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        mServiceInvoker.showInputMethodPickerFromClient(mClient, SHOW_IM_PICKER_MODE_AUTO);
    }

    /**
@@ -3259,11 +3193,7 @@ public final class InputMethodManager {
     */
    @TestApi
    public boolean isInputMethodPickerShown() {
        try {
            return mService.isInputMethodPickerShownForTest();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        return mServiceInvoker.isInputMethodPickerShownForTest();
    }

    /**
@@ -3273,11 +3203,7 @@ public final class InputMethodManager {
     * subtypes of all input methods will be shown.
     */
    public void showInputMethodAndSubtypeEnabler(String imiId) {
        try {
            mService.showInputMethodAndSubtypeEnablerFromClient(mClient, imiId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        mServiceInvoker.showInputMethodAndSubtypeEnablerFromClient(mClient, imiId);
    }

    /**
@@ -3286,11 +3212,7 @@ public final class InputMethodManager {
     * have any input method subtype.
     */
    public InputMethodSubtype getCurrentInputMethodSubtype() {
        try {
            return mService.getCurrentInputMethodSubtype();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        return mServiceInvoker.getCurrentInputMethodSubtype();
    }

    /**
@@ -3334,12 +3256,8 @@ public final class InputMethodManager {
            // Null or invalid IME ID format.
            return false;
        }
        final List<InputMethodSubtype> enabledSubtypes;
        try {
            enabledSubtypes = mService.getEnabledInputMethodSubtypeList(imeId, true);
        } catch (RemoteException e) {
            return false;
        }
        final List<InputMethodSubtype> enabledSubtypes =
                mServiceInvoker.getEnabledInputMethodSubtypeList(imeId, true);
        final int numSubtypes = enabledSubtypes.size();
        for (int i = 0; i < numSubtypes; ++i) {
            final InputMethodSubtype enabledSubtype = enabledSubtypes.get(i);
@@ -3404,11 +3322,7 @@ public final class InputMethodManager {
    @UnsupportedAppUsage(trackingBug = 204906124, maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
            publicAlternatives = "Use {@link android.view.WindowInsets} instead")
    public int getInputMethodWindowVisibleHeight() {
        try {
            return mService.getInputMethodWindowVisibleHeight(mClient);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        return mServiceInvoker.getInputMethodWindowVisibleHeight(mClient);
    }

    /**
@@ -3421,7 +3335,6 @@ public final class InputMethodManager {
     * @hide
     */
    public void reportVirtualDisplayGeometry(int childDisplayId, @Nullable Matrix matrix) {
        try {
        final float[] matrixValues;
        if (matrix == null) {
            matrixValues = null;
@@ -3429,10 +3342,7 @@ public final class InputMethodManager {
            matrixValues = new float[9];
            matrix.getValues(matrixValues);
        }
            mService.reportVirtualDisplayGeometryAsync(mClient, childDisplayId, matrixValues);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        mServiceInvoker.reportVirtualDisplayGeometryAsync(mClient, childDisplayId, matrixValues);
    }

    /**
@@ -3536,19 +3446,11 @@ public final class InputMethodManager {
     */
    @Deprecated
    public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
        try {
            mService.setAdditionalInputMethodSubtypes(imiId, subtypes);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        mServiceInvoker.setAdditionalInputMethodSubtypes(imiId, subtypes);
    }

    public InputMethodSubtype getLastInputMethodSubtype() {
        try {
            return mService.getLastInputMethodSubtype();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        return mServiceInvoker.getLastInputMethodSubtype();
    }

    /**