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

Commit f2087397 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Propogate per-display IME status to SysUI" into qt-dev

parents 151675e3 7570cac6
Loading
Loading
Loading
Loading
+1 −2
Original line number Original line Diff line number Diff line
@@ -48,8 +48,7 @@ interface IStatusBarService
    void setIconVisibility(String slot, boolean visible);
    void setIconVisibility(String slot, boolean visible);
    @UnsupportedAppUsage
    @UnsupportedAppUsage
    void removeIcon(String slot);
    void removeIcon(String slot);
    // TODO(b/117478341): support back button change when IME is showing on a external display.
    void setImeWindowStatus(int displayId, in IBinder token, int vis, int backDisposition,
    void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
            boolean showImeSwitcher);
            boolean showImeSwitcher);
    void expandSettingsPanel(String subPanel);
    void expandSettingsPanel(String subPanel);


+38 −4
Original line number Original line Diff line number Diff line
@@ -18,7 +18,10 @@ package com.android.systemui.statusbar;


import static android.app.StatusBarManager.DISABLE2_NONE;
import static android.app.StatusBarManager.DISABLE2_NONE;
import static android.app.StatusBarManager.DISABLE_NONE;
import static android.app.StatusBarManager.DISABLE_NONE;
import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
import static android.inputmethodservice.InputMethodService.IME_INVISIBLE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;


import static com.android.systemui.statusbar.phone.StatusBar.ONLY_CORE_APPS;
import static com.android.systemui.statusbar.phone.StatusBar.ONLY_CORE_APPS;


@@ -40,6 +43,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.Message;
import android.util.Pair;
import android.util.Pair;
import android.util.SparseArray;
import android.util.SparseArray;
import android.view.inputmethod.InputMethodSystemProperty;


import androidx.annotation.VisibleForTesting;
import androidx.annotation.VisibleForTesting;


@@ -127,6 +131,11 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
    private Handler mHandler = new H(Looper.getMainLooper());
    private Handler mHandler = new H(Looper.getMainLooper());
    /** A map of display id - disable flag pair */
    /** A map of display id - disable flag pair */
    private SparseArray<Pair<Integer, Integer>> mDisplayDisabled = new SparseArray<>();
    private SparseArray<Pair<Integer, Integer>> mDisplayDisabled = new SparseArray<>();
    /**
     * The last ID of the display where IME window for which we received setImeWindowStatus
     * event.
     */
    private int mLastUpdatedImeDisplayId = INVALID_DISPLAY;


    /**
    /**
     * These methods are called back on the main thread.
     * These methods are called back on the main thread.
@@ -785,6 +794,32 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
        }
        }
    }
    }


    private void handleShowImeButton(int displayId, IBinder token, int vis, int backDisposition,
            boolean showImeSwitcher) {
        if (displayId == INVALID_DISPLAY) return;

        if (!InputMethodSystemProperty.MULTI_CLIENT_IME_ENABLED
                && mLastUpdatedImeDisplayId != displayId
                && mLastUpdatedImeDisplayId != INVALID_DISPLAY) {
            // Set previous NavBar's IME window status as invisible when IME
            // window switched to another display for single-session IME case.
            sendImeInvisibleStatusForPrevNavBar();
        }
        for (int i = 0; i < mCallbacks.size(); i++) {
            mCallbacks.get(i).setImeWindowStatus(displayId, token, vis, backDisposition,
                    showImeSwitcher);
        }
        mLastUpdatedImeDisplayId = displayId;
    }

    private void sendImeInvisibleStatusForPrevNavBar() {
        for (int i = 0; i < mCallbacks.size(); i++) {
            mCallbacks.get(i).setImeWindowStatus(mLastUpdatedImeDisplayId,
                    null /* token */, IME_INVISIBLE, BACK_DISPOSITION_DEFAULT,
                    false /* showImeSwitcher */);
        }
    }

    private final class H extends Handler {
    private final class H extends Handler {
        private H(Looper l) {
        private H(Looper l) {
            super(l);
            super(l);
@@ -852,10 +887,9 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
                    break;
                    break;
                case MSG_SHOW_IME_BUTTON:
                case MSG_SHOW_IME_BUTTON:
                    args = (SomeArgs) msg.obj;
                    args = (SomeArgs) msg.obj;
                    for (int i = 0; i < mCallbacks.size(); i++) {
                    handleShowImeButton(args.argi1 /* displayId */, (IBinder) args.arg1 /* token */,
                        mCallbacks.get(i).setImeWindowStatus(args.argi1, (IBinder) args.arg1,
                            args.argi2 /* vis */, args.argi3 /* backDisposition */,
                                args.argi2, args.argi3, args.argi4 != 0 /* showImeSwitcher */);
                            args.argi4 != 0 /* showImeSwitcher */);
                    }
                    break;
                    break;
                case MSG_SHOW_RECENT_APPS:
                case MSG_SHOW_RECENT_APPS:
                    for (int i = 0; i < mCallbacks.size(); i++) {
                    for (int i = 0; i < mCallbacks.size(); i++) {
+5 −0
Original line number Original line Diff line number Diff line
@@ -1063,4 +1063,9 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
        context.getSystemService(WindowManager.class).addView(navigationBarView, lp);
        context.getSystemService(WindowManager.class).addView(navigationBarView, lp);
        return navigationBarView;
        return navigationBarView;
    }
    }

    @VisibleForTesting
    int getNavigationIconHints() {
        return mNavigationIconHints;
    }
}
}
+165 −5
Original line number Original line Diff line number Diff line
@@ -14,18 +14,38 @@


package com.android.systemui.statusbar.phone;
package com.android.systemui.statusbar.phone;


import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
import static android.inputmethodservice.InputMethodService.IME_VISIBLE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.when;


import android.annotation.LayoutRes;
import android.annotation.Nullable;
import android.app.Fragment;
import android.app.Fragment;
import android.app.FragmentController;
import android.app.FragmentHostCallback;
import android.content.Context;
import android.content.Context;
import android.hardware.display.DisplayManagerGlobal;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Looper;
import android.testing.AndroidTestingRunner;
import android.testing.AndroidTestingRunner;
import android.testing.LeakCheck.Tracker;
import android.testing.LeakCheck.Tracker;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.Display;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;


@@ -34,6 +54,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.Dependency;
import com.android.systemui.Dependency;
import com.android.systemui.SysuiBaseFragmentTest;
import com.android.systemui.SysuiBaseFragmentTest;
import com.android.systemui.SysuiTestableContext;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.Recents;
@@ -50,9 +71,16 @@ import org.junit.runner.RunWith;
@RunWithLooper()
@RunWithLooper()
@SmallTest
@SmallTest
public class NavigationBarFragmentTest extends SysuiBaseFragmentTest {
public class NavigationBarFragmentTest extends SysuiBaseFragmentTest {
    private static final int EXTERNAL_DISPLAY_ID = 2;
    private static final int NAV_BAR_VIEW_ID = 43;

    private Fragment mFragmentExternalDisplay;
    private FragmentController mControllerExternalDisplay;


    private SysuiTestableContext mSysuiTestableContextExternal;
    private OverviewProxyService mOverviewProxyService =
    private OverviewProxyService mOverviewProxyService =
            mDependency.injectMockDependency(OverviewProxyService.class);
            mDependency.injectMockDependency(OverviewProxyService.class);
    private CommandQueue mCommandQueue;
    private AccessibilityManagerWrapper mAccessibilityWrapper =
    private AccessibilityManagerWrapper mAccessibilityWrapper =
            new AccessibilityManagerWrapper(mContext) {
            new AccessibilityManagerWrapper(mContext) {
                Tracker mTracker = mLeakCheck.getTracker("accessibility_manager");
                Tracker mTracker = mLeakCheck.getTracker("accessibility_manager");
@@ -73,15 +101,51 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest {
    }
    }


    protected void createRootView() {
    protected void createRootView() {
        mView = new NavigationBarFrame(mContext);
        mView = new NavigationBarFrame(mSysuiContext);
        mView.setId(NAV_BAR_VIEW_ID);
    }
    }


    @Before
    @Before
    public void setup() {
    public void setupFragment() throws Exception {
        mSysuiContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
        setupSysuiDependency();
        createRootView();
        TestableLooper.get(this).runWithLooper(() -> {
            mHandler = new Handler();

            mFragment = instantiate(mSysuiContext, NavigationBarFragment.class.getName(), null);
            mFragments = FragmentController.createController(
                    new HostCallbacksForExternalDisplay(mSysuiContext));
            mFragments.attachHost(null);
            mFragments.getFragmentManager().beginTransaction()
                    .replace(NAV_BAR_VIEW_ID, mFragment)
                    .commit();
            mControllerExternalDisplay = FragmentController.createController(
                    new HostCallbacksForExternalDisplay(mSysuiTestableContextExternal));
            mControllerExternalDisplay.attachHost(null);
            mFragmentExternalDisplay = instantiate(mSysuiTestableContextExternal,
                    NavigationBarFragment.class.getName(), null);
            mControllerExternalDisplay.getFragmentManager().beginTransaction()
                    .replace(NAV_BAR_VIEW_ID, mFragmentExternalDisplay)
                    .commit();
        });
    }

    private void setupSysuiDependency() {
        mCommandQueue = new CommandQueue(mContext);
        mSysuiContext.putComponent(CommandQueue.class, mCommandQueue);
        mSysuiContext.putComponent(StatusBar.class, mock(StatusBar.class));
        mSysuiContext.putComponent(StatusBar.class, mock(StatusBar.class));
        mSysuiContext.putComponent(Recents.class, mock(Recents.class));
        mSysuiContext.putComponent(Recents.class, mock(Recents.class));
        mSysuiContext.putComponent(Divider.class, mock(Divider.class));
        mSysuiContext.putComponent(Divider.class, mock(Divider.class));

        Display display = new Display(DisplayManagerGlobal.getInstance(), EXTERNAL_DISPLAY_ID,
                new DisplayInfo(), DEFAULT_DISPLAY_ADJUSTMENTS);
        mSysuiTestableContextExternal = (SysuiTestableContext) mSysuiContext.createDisplayContext(
                display);
        mSysuiTestableContextExternal.putComponent(CommandQueue.class, mCommandQueue);
        mSysuiTestableContextExternal.putComponent(StatusBar.class, mock(StatusBar.class));
        mSysuiTestableContextExternal.putComponent(Recents.class, mock(Recents.class));
        mSysuiTestableContextExternal.putComponent(Divider.class, mock(Divider.class));

        injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
        injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
        WindowManager windowManager = mock(WindowManager.class);
        WindowManager windowManager = mock(WindowManager.class);
        Display defaultDisplay = mContext.getSystemService(WindowManager.class).getDefaultDisplay();
        Display defaultDisplay = mContext.getSystemService(WindowManager.class).getDefaultDisplay();
@@ -102,15 +166,111 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest {
        navigationBarFragment.onHomeLongClick(navigationBarFragment.getView());
        navigationBarFragment.onHomeLongClick(navigationBarFragment.getView());
    }
    }


    @Test
    public void testSetImeWindowStatusWhenImeSwitchOnDisplay() {
        // Create default & external NavBar fragment.
        NavigationBarFragment defaultNavBar = (NavigationBarFragment) mFragment;
        NavigationBarFragment externalNavBar = (NavigationBarFragment) mFragmentExternalDisplay;
        mFragments.dispatchCreate();
        processAllMessages();
        mFragments.dispatchResume();
        processAllMessages();
        mControllerExternalDisplay.dispatchCreate();
        processAllMessages();
        mControllerExternalDisplay.dispatchResume();
        processAllMessages();

        // Set IME window status for default NavBar.
        mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE,
                BACK_DISPOSITION_DEFAULT, true);
        Handler.getMain().runWithScissors(() -> { }, 500);

        // Verify IME window state will be updated in default NavBar & external NavBar state reset.
        assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN,
                defaultNavBar.getNavigationIconHints());
        assertFalse((externalNavBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0);
        assertFalse((externalNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0);

        // Set IME window status for external NavBar.
        mCommandQueue.setImeWindowStatus(EXTERNAL_DISPLAY_ID, null,
                IME_VISIBLE, BACK_DISPOSITION_DEFAULT, true);
        Handler.getMain().runWithScissors(() -> { }, 500);

        // Verify IME window state will be updated in external NavBar & default NavBar state reset.
        assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN,
                externalNavBar.getNavigationIconHints());
        assertFalse((defaultNavBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0);
        assertFalse((defaultNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0);
    }

    @Override
    @Override
    protected Fragment instantiate(Context context, String className, Bundle arguments) {
    protected Fragment instantiate(Context context, String className, Bundle arguments) {
        DeviceProvisionedController deviceProvisionedController =
        DeviceProvisionedController deviceProvisionedController =
                mock(DeviceProvisionedController.class);
                mock(DeviceProvisionedController.class);
        assertNotNull(mAccessibilityWrapper);
        assertNotNull(mAccessibilityWrapper);
        return new NavigationBarFragment(mAccessibilityWrapper,
        return new NavigationBarFragment(
                context.getDisplayId() == DEFAULT_DISPLAY ? mAccessibilityWrapper
                        : mock(AccessibilityManagerWrapper.class),
                deviceProvisionedController,
                deviceProvisionedController,
                new MetricsLogger(),
                new MetricsLogger(),
                new AssistManager(deviceProvisionedController, mContext),
                mock(AssistManager.class),
                mOverviewProxyService);
                mOverviewProxyService);
    }
    }

    private class HostCallbacksForExternalDisplay extends
            FragmentHostCallback<NavigationBarFragmentTest> {
        private Context mDisplayContext;

        HostCallbacksForExternalDisplay(Context context) {
            super(context, mHandler, 0);
            mDisplayContext = context;
        }

        @Override
        public NavigationBarFragmentTest onGetHost() {
            return NavigationBarFragmentTest.this;
        }

        @Override
        public Fragment instantiate(Context context, String className, Bundle arguments) {
            return NavigationBarFragmentTest.this.instantiate(context, className, arguments);
        }

        @Override
        public View onFindViewById(int id) {
            return mView.findViewById(id);
        }

        @Override
        public LayoutInflater onGetLayoutInflater() {
            return new LayoutInflaterWrapper(mDisplayContext);
        }
    }

    private static class LayoutInflaterWrapper extends LayoutInflater {
        protected LayoutInflaterWrapper(Context context) {
            super(context);
        }

        @Override
        public LayoutInflater cloneInContext(Context newContext) {
            return null;
        }

        @Override
        public View inflate(@LayoutRes int resource, @Nullable ViewGroup root,
                boolean attachToRoot) {
            NavigationBarView view = mock(NavigationBarView.class);
            when(view.getDisplay()).thenReturn(mContext.getDisplay());
            when(view.getBackButton()).thenReturn(mock(ButtonDispatcher.class));
            when(view.getHomeButton()).thenReturn(mock(ButtonDispatcher.class));
            when(view.getRecentsButton()).thenReturn(mock(ButtonDispatcher.class));
            when(view.getAccessibilityButton()).thenReturn(mock(ButtonDispatcher.class));
            when(view.getRotateSuggestionButton()).thenReturn(mock(RotationContextButton.class));
            when(view.getBarTransitions()).thenReturn(mock(BarTransitions.class));
            when(view.getLightTransitionsController()).thenReturn(
                    mock(LightBarTransitionsController.class));
            return view;
        }
    }
}
}
+28 −8
Original line number Original line Diff line number Diff line
@@ -575,6 +575,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
     */
     */
    int mCurTokenDisplayId = INVALID_DISPLAY;
    int mCurTokenDisplayId = INVALID_DISPLAY;


    /**
     * The display ID of the input method indicates the fallback display which returned by
     * {@link #computeImeDisplayIdForTarget}.
     */
    private static final int FALLBACK_DISPLAY_ID = DEFAULT_DISPLAY;

    final ImeDisplayValidator mImeDisplayValidator;
    final ImeDisplayValidator mImeDisplayValidator;


    /**
    /**
@@ -625,7 +631,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
     *    currently invisible.
     *    currently invisible.
     * </dd>
     * </dd>
     * </dl>
     * </dl>
     * <em>Do not update this value outside of setImeWindowStatus.</em>
     * <em>Do not update this value outside of {@link #setImeWindowStatus(IBinder, int, int)} and
     * {@link #unbindCurrentMethodLocked()}.</em>
     */
     */
    int mImeWindowVis;
    int mImeWindowVis;


@@ -2124,12 +2131,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
     */
     */
    static int computeImeDisplayIdForTarget(int displayId, @NonNull ImeDisplayValidator checker) {
    static int computeImeDisplayIdForTarget(int displayId, @NonNull ImeDisplayValidator checker) {
        if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) {
        if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) {
            // We always assume that the default display id suitable to show the IME window.
            return FALLBACK_DISPLAY_ID;
            return DEFAULT_DISPLAY;
        }
        }
        // Show IME in default display when the display with IME target doesn't support system
        // Show IME window on fallback display when the display is not allowed.
        // decorations.
        return checker.displayCanShowIme(displayId) ? displayId : FALLBACK_DISPLAY_ID;
        return checker.displayCanShowIme(displayId) ? displayId : DEFAULT_DISPLAY;
    }
    }


    @Override
    @Override
@@ -2198,6 +2203,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId);
                mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId);
            } catch (RemoteException e) {
            } catch (RemoteException e) {
            }
            }
            // Set IME window status as invisible when unbind current method.
            mImeWindowVis = 0;
            mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
            updateSystemUiLocked(mImeWindowVis, mBackDisposition);
            mCurToken = null;
            mCurToken = null;
            mCurTokenDisplayId = INVALID_DISPLAY;
            mCurTokenDisplayId = INVALID_DISPLAY;
        }
        }
@@ -2399,10 +2408,20 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
    @BinderThread
    @BinderThread
    @SuppressWarnings("deprecation")
    @SuppressWarnings("deprecation")
    private void setImeWindowStatus(@NonNull IBinder token, int vis, int backDisposition) {
    private void setImeWindowStatus(@NonNull IBinder token, int vis, int backDisposition) {
        final int topFocusedDisplayId = mWindowManagerInternal.getTopFocusedDisplayId();

        synchronized (mMethodMap) {
        synchronized (mMethodMap) {
            if (!calledWithValidTokenLocked(token)) {
            if (!calledWithValidTokenLocked(token)) {
                return;
                return;
            }
            }
            // Skip update IME status when current token display is not same as focused display.
            // Note that we still need to update IME status when focusing external display
            // that does not support system decoration and fallback to show IME on default
            // display since it is intentional behavior.
            if (mCurTokenDisplayId != topFocusedDisplayId
                    && mCurTokenDisplayId != FALLBACK_DISPLAY_ID) {
                return;
            }
            mImeWindowVis = vis;
            mImeWindowVis = vis;
            mBackDisposition = backDisposition;
            mBackDisposition = backDisposition;
            updateSystemUiLocked(vis, backDisposition);
            updateSystemUiLocked(vis, backDisposition);
@@ -2447,7 +2466,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        if (DEBUG) {
        if (DEBUG) {
            Slog.d(TAG, "IME window vis: " + vis
            Slog.d(TAG, "IME window vis: " + vis
                    + " active: " + (vis & InputMethodService.IME_ACTIVE)
                    + " active: " + (vis & InputMethodService.IME_ACTIVE)
                    + " inv: " + (vis & InputMethodService.IME_INVISIBLE));
                    + " inv: " + (vis & InputMethodService.IME_INVISIBLE)
                    + " displayId: " + mCurTokenDisplayId);
        }
        }


        // TODO: Move this clearing calling identity block to setImeWindowStatus after making sure
        // TODO: Move this clearing calling identity block to setImeWindowStatus after making sure
@@ -2461,7 +2481,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
            // mImeWindowVis should be updated before calling shouldShowImeSwitcherLocked().
            // mImeWindowVis should be updated before calling shouldShowImeSwitcherLocked().
            final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis);
            final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis);
            if (mStatusBar != null) {
            if (mStatusBar != null) {
                mStatusBar.setImeWindowStatus(mCurToken, vis, backDisposition,
                mStatusBar.setImeWindowStatus(mCurTokenDisplayId, mCurToken, vis, backDisposition,
                        needsToShowImeSwitcher);
                        needsToShowImeSwitcher);
            }
            }
            final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
            final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
Loading