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

Commit 8b483861 authored by Charles Chen's avatar Charles Chen Committed by Android (Google) Code Review
Browse files

Merge "Introduce InputMethodMenuController"

parents c0b7d9b2 c88452c3
Loading
Loading
Loading
Loading
+29 −280
Original line number Original line Diff line number Diff line
@@ -37,8 +37,6 @@ import android.annotation.RequiresPermission;
import android.annotation.UserIdInt;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal;
import android.app.ActivityThread;
import android.app.AlertDialog;
import android.app.AppGlobals;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.AppOpsManager;
import android.app.KeyguardManager;
import android.app.KeyguardManager;
@@ -50,9 +48,6 @@ import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.ServiceConnection;
@@ -64,10 +59,8 @@ import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.database.ContentObserver;
import android.graphics.Matrix;
import android.graphics.Matrix;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.input.InputManagerInternal;
import android.hardware.input.InputManagerInternal;
import android.inputmethodservice.InputMethodService;
import android.inputmethodservice.InputMethodService;
@@ -108,14 +101,10 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseArray;
import android.util.imetracing.ImeTracing;
import android.util.imetracing.ImeTracing;
import android.util.proto.ProtoOutputStream;
import android.util.proto.ProtoOutputStream;
import android.view.ContextThemeWrapper;
import android.view.DisplayInfo;
import android.view.DisplayInfo;
import android.view.IWindowManager;
import android.view.IWindowManager;
import android.view.InputChannel;
import android.view.InputChannel;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillId;
@@ -129,12 +118,6 @@ import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import android.view.inputmethod.InputMethodSubtype;
import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.RadioButton;
import android.widget.Switch;
import android.widget.TextView;


import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
import com.android.internal.content.PackageMonitor;
@@ -165,7 +148,6 @@ import com.android.internal.view.InputBindResult;
import com.android.server.EventLogTags;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemService;
import com.android.server.SystemService.TargetUser;
import com.android.server.inputmethod.InputMethodManagerInternal.InputMethodListListener;
import com.android.server.inputmethod.InputMethodManagerInternal.InputMethodListListener;
import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
import com.android.server.inputmethod.InputMethodUtils.InputMethodSettings;
import com.android.server.inputmethod.InputMethodUtils.InputMethodSettings;
@@ -330,10 +312,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
    private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypeMap =
    private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypeMap =
            new ArrayMap<>();
            new ArrayMap<>();
    private final boolean mIsLowRam;
    private final boolean mIsLowRam;
    private final HardKeyboardListener mHardKeyboardListener;
    private final AppOpsManager mAppOpsManager;
    private final AppOpsManager mAppOpsManager;
    private final UserManager mUserManager;
    private final UserManager mUserManager;
    private final UserManagerInternal mUserManagerInternal;
    private final UserManagerInternal mUserManagerInternal;
    private final InputMethodMenuController mMenuController;


    /**
    /**
     * Cache the result of {@code LocalServices.getService(AudioManagerInternal.class)}.
     * Cache the result of {@code LocalServices.getService(AudioManagerInternal.class)}.
@@ -351,7 +333,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
    final ArrayMap<String, InputMethodInfo> mMethodMap = new ArrayMap<>();
    final ArrayMap<String, InputMethodInfo> mMethodMap = new ArrayMap<>();
    private final LruCache<SuggestionSpan, InputMethodInfo> mSecureSuggestionSpans =
    private final LruCache<SuggestionSpan, InputMethodInfo> mSecureSuggestionSpans =
            new LruCache<>(SECURE_SUGGESTION_SPANS_MAX_SIZE);
            new LruCache<>(SECURE_SUGGESTION_SPANS_MAX_SIZE);
    private final InputMethodSubtypeSwitchingController mSwitchingController;
    final InputMethodSubtypeSwitchingController mSwitchingController;


    /**
    /**
     * Tracks how many times {@link #mMethodMap} was updated.
     * Tracks how many times {@link #mMethodMap} was updated.
@@ -380,7 +362,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub


    // Ongoing notification
    // Ongoing notification
    private NotificationManager mNotificationManager;
    private NotificationManager mNotificationManager;
    private KeyguardManager mKeyguardManager;
    KeyguardManager mKeyguardManager;
    private @Nullable StatusBarManagerService mStatusBar;
    private @Nullable StatusBarManagerService mStatusBar;
    private Notification.Builder mImeSwitcherNotification;
    private Notification.Builder mImeSwitcherNotification;
    private PendingIntent mImeSwitchPendingIntent;
    private PendingIntent mImeSwitchPendingIntent;
@@ -724,21 +706,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
     */
     */
    int mImeWindowVis;
    int mImeWindowVis;


    private AlertDialog.Builder mDialogBuilder;
    private AlertDialog mSwitchingDialog;
    private IBinder mSwitchingDialogToken = new Binder();
    private View mSwitchingDialogTitleView;
    private InputMethodInfo[] mIms;
    private int[] mSubtypeIds;
    private LocaleList mLastSystemLocales;
    private LocaleList mLastSystemLocales;
    private boolean mShowImeWithHardKeyboard;
    private boolean mAccessibilityRequestingNoSoftKeyboard;
    private boolean mAccessibilityRequestingNoSoftKeyboard;
    private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
    private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
    private final IPackageManager mIPackageManager;
    private final IPackageManager mIPackageManager;
    private final String mSlotIme;
    private final String mSlotIme;


    /**
    /**
     * Registered {@link InputMethodListListeners}.
     * Registered {@link InputMethodListListener}.
     * This variable can be accessed from both of MainThread and BinderThread.
     * This variable can be accessed from both of MainThread and BinderThread.
     */
     */
    private final CopyOnWriteArrayList<InputMethodListListener> mInputMethodListListeners =
    private final CopyOnWriteArrayList<InputMethodListListener> mInputMethodListListeners =
@@ -1138,7 +1113,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                    Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
                    Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
            synchronized (mMethodMap) {
            synchronized (mMethodMap) {
                if (showImeUri.equals(uri)) {
                if (showImeUri.equals(uri)) {
                    updateKeyboardFromSettingsLocked();
                    mMenuController.updateKeyboardFromSettingsLocked();
                } else if (accessibilityRequestingNoImeUri.equals(uri)) {
                } else if (accessibilityRequestingNoImeUri.equals(uri)) {
                    final int accessibilitySoftKeyboardSetting = Settings.Secure.getIntForUser(
                    final int accessibilitySoftKeyboardSetting = Settings.Secure.getIntForUser(
                            mContext.getContentResolver(),
                            mContext.getContentResolver(),
@@ -1226,7 +1201,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                        return;
                        return;
                    }
                    }
                }
                }
                hideInputMethodMenu();
                mMenuController.hideInputMethodMenu();
            } else {
            } else {
                Slog.w(TAG, "Unexpected intent " + intent);
                Slog.w(TAG, "Unexpected intent " + intent);
            }
            }
@@ -1526,29 +1501,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        }
        }
    }
    }


    private class HardKeyboardListener
            implements WindowManagerInternal.OnHardKeyboardStatusChangeListener {
        @Override
        public void onHardKeyboardStatusChange(boolean available) {
            mHandler.sendMessage(mHandler.obtainMessage(MSG_HARD_KEYBOARD_SWITCH_CHANGED,
                        available ? 1 : 0));
        }

        public void handleHardKeyboardStatusChange(boolean available) {
            if (DEBUG) {
                Slog.w(TAG, "HardKeyboardStatusChanged: available=" + available);
            }
            synchronized(mMethodMap) {
                if (mSwitchingDialog != null && mSwitchingDialogTitleView != null
                        && mSwitchingDialog.isShowing()) {
                    mSwitchingDialogTitleView.findViewById(
                            com.android.internal.R.id.hard_keyboard_section).setVisibility(
                                    available ? View.VISIBLE : View.GONE);
                }
            }
        }
    }

    private static final class UserSwitchHandlerTask implements Runnable {
    private static final class UserSwitchHandlerTask implements Runnable {
        final InputMethodManagerService mService;
        final InputMethodManagerService mService;


@@ -1687,7 +1639,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
        mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
        mUserManager = mContext.getSystemService(UserManager.class);
        mUserManager = mContext.getSystemService(UserManager.class);
        mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
        mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
        mHardKeyboardListener = new HardKeyboardListener();
        mHasFeature = context.getPackageManager().hasSystemFeature(
        mHasFeature = context.getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_INPUT_METHODS);
                PackageManager.FEATURE_INPUT_METHODS);
        mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
        mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
@@ -1731,6 +1682,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, userId);
        AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, userId);
        mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
        mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
                mSettings, context);
                mSettings, context);
        mMenuController = new InputMethodMenuController(this);
    }
    }


    private void resetDefaultImeLocked(Context context) {
    private void resetDefaultImeLocked(Context context) {
@@ -1861,8 +1813,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
                mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
                        com.android.internal.R.bool.show_ongoing_ime_switcher);
                        com.android.internal.R.bool.show_ongoing_ime_switcher);
                if (mShowOngoingImeSwitcherForPhones) {
                if (mShowOngoingImeSwitcherForPhones) {
                    final InputMethodMenuController.HardKeyboardListener hardKeyboardListener =
                            mMenuController.getHardKeyboardListener();
                    mWindowManagerInternal.setOnHardKeyboardStatusChangeListener(
                    mWindowManagerInternal.setOnHardKeyboardStatusChangeListener(
                            mHardKeyboardListener);
                            hardKeyboardListener);
                }
                }


                mMyPackageMonitor.register(mContext, null, UserHandle.ALL, true);
                mMyPackageMonitor.register(mContext, null, UserHandle.ALL, true);
@@ -2331,7 +2285,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
            mCurClient = null;
            mCurClient = null;
            mCurActivityViewToScreenMatrix = null;
            mCurActivityViewToScreenMatrix = null;


            hideInputMethodMenuLocked();
            mMenuController.hideInputMethodMenuLocked();
        }
        }
    }
    }


@@ -2813,7 +2767,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub


    private boolean shouldShowImeSwitcherLocked(int visibility) {
    private boolean shouldShowImeSwitcherLocked(int visibility) {
        if (!mShowOngoingImeSwitcherForPhones) return false;
        if (!mShowOngoingImeSwitcherForPhones) return false;
        if (mSwitchingDialog != null) return false;
        if (mMenuController.getSwitchingDialogLocked() != null) return false;
        if (mWindowManagerInternal.isKeyguardShowingAndNotOccluded()
        if (mWindowManagerInternal.isKeyguardShowingAndNotOccluded()
                && mKeyguardManager != null && mKeyguardManager.isKeyguardSecure()) return false;
                && mKeyguardManager != null && mKeyguardManager.isKeyguardSecure()) return false;
        if ((visibility & InputMethodService.IME_ACTIVE) == 0
        if ((visibility & InputMethodService.IME_ACTIVE) == 0
@@ -2930,6 +2884,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        }
        }
    }
    }


    void updateSystemUiLocked() {
        updateSystemUiLocked(mImeWindowVis, mBackDisposition);
    }

    // Caution! This method is called in this class. Handle multi-user carefully
    // Caution! This method is called in this class. Handle multi-user carefully
    private void updateSystemUiLocked(int vis, int backDisposition) {
    private void updateSystemUiLocked(int vis, int backDisposition) {
        if (mCurToken == null) {
        if (mCurToken == null) {
@@ -3000,7 +2958,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub


    void updateFromSettingsLocked(boolean enabledMayChange) {
    void updateFromSettingsLocked(boolean enabledMayChange) {
        updateInputMethodsFromSettingsLocked(enabledMayChange);
        updateInputMethodsFromSettingsLocked(enabledMayChange);
        updateKeyboardFromSettingsLocked();
        mMenuController.updateKeyboardFromSettingsLocked();
    }
    }


    void updateInputMethodsFromSettingsLocked(boolean enabledMayChange) {
    void updateInputMethodsFromSettingsLocked(boolean enabledMayChange) {
@@ -3057,17 +3015,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub


    }
    }


    public void updateKeyboardFromSettingsLocked() {
        mShowImeWithHardKeyboard = mSettings.isShowImeWithHardKeyboardEnabled();
        if (mSwitchingDialog != null
                && mSwitchingDialogTitleView != null
                && mSwitchingDialog.isShowing()) {
            final Switch hardKeySwitch = (Switch)mSwitchingDialogTitleView.findViewById(
                    com.android.internal.R.id.hard_keyboard_switch);
            hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
        }
    }

    /* package */ void setInputMethodLocked(String id, int subtypeId) {
    /* package */ void setInputMethodLocked(String id, int subtypeId) {
        InputMethodInfo info = mMethodMap.get(id);
        InputMethodInfo info = mMethodMap.get(id);
        if (info == null) {
        if (info == null) {
@@ -3697,10 +3644,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub


    public boolean isInputMethodPickerShownForTest() {
    public boolean isInputMethodPickerShownForTest() {
        synchronized(mMethodMap) {
        synchronized(mMethodMap) {
            if (mSwitchingDialog == null) {
            return mMenuController.isisInputMethodPickerShownForTestLocked();
                return false;
            }
            return mSwitchingDialog.isShowing();
        }
        }
    }
    }


@@ -3935,7 +3879,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
     * {@link InputMethodService#onCreate()}.
     * {@link InputMethodService#onCreate()}.
     *
     *
     * <p>TODO(Bug 113914148): Check if we can remove this.</p>
     * <p>TODO(Bug 113914148): Check if we can remove this.</p>
     * @return {@link WindowManagerInternal#getInputMethodWindowVisibleHeight()}
     * @return {@link WindowManagerInternal#getInputMethodWindowVisibleHeight(int)}
     */
     */
    @Override
    @Override
    public int getInputMethodWindowVisibleHeight() {
    public int getInputMethodWindowVisibleHeight() {
@@ -4247,7 +4191,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                        Slog.e(TAG, "Unknown subtype picker mode = " + msg.arg1);
                        Slog.e(TAG, "Unknown subtype picker mode = " + msg.arg1);
                        return false;
                        return false;
                }
                }
                showInputMethodMenu(showAuxSubtypes, displayId);
                mMenuController.showInputMethodMenu(showAuxSubtypes, displayId);
                return true;
                return true;


            case MSG_SHOW_IM_SUBTYPE_ENABLER:
            case MSG_SHOW_IM_SUBTYPE_ENABLER:
@@ -4484,7 +4428,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub


            // --------------------------------------------------------------
            // --------------------------------------------------------------
            case MSG_HARD_KEYBOARD_SWITCH_CHANGED:
            case MSG_HARD_KEYBOARD_SWITCH_CHANGED:
                mHardKeyboardListener.handleHardKeyboardStatusChange(msg.arg1 == 1);
                final InputMethodMenuController.HardKeyboardListener hardKeyboardListener =
                        mMenuController.getHardKeyboardListener();
                hardKeyboardListener.handleHardKeyboardStatusChange(msg.arg1 == 1);
                return true;
                return true;
            case MSG_SYSTEM_UNLOCK_USER: {
            case MSG_SYSTEM_UNLOCK_USER: {
                final int userId = msg.arg1;
                final int userId = msg.arg1;
@@ -4735,208 +4681,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
        mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
    }
    }


    private boolean isScreenLocked() {
        return mKeyguardManager != null
                && mKeyguardManager.isKeyguardLocked() && mKeyguardManager.isKeyguardSecure();
    }

    private void showInputMethodMenu(boolean showAuxSubtypes, int displayId) {
        if (DEBUG) Slog.v(TAG, "Show switching menu. showAuxSubtypes=" + showAuxSubtypes);

        final boolean isScreenLocked = isScreenLocked();

        final String lastInputMethodId = mSettings.getSelectedInputMethod();
        int lastInputMethodSubtypeId = mSettings.getSelectedInputMethodSubtypeId(lastInputMethodId);
        if (DEBUG) Slog.v(TAG, "Current IME: " + lastInputMethodId);

        synchronized (mMethodMap) {
            final List<ImeSubtypeListItem> imList =
                    mSwitchingController.getSortedInputMethodAndSubtypeListLocked(
                            showAuxSubtypes, isScreenLocked);
            if (imList.isEmpty()) {
                return;
            }

            hideInputMethodMenuLocked();

            if (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID) {
                final InputMethodSubtype currentSubtype = getCurrentInputMethodSubtypeLocked();
                if (currentSubtype != null) {
                    final InputMethodInfo currentImi = mMethodMap.get(mCurMethodId);
                    lastInputMethodSubtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
                            currentImi, currentSubtype.hashCode());
                }
            }

            final int N = imList.size();
            mIms = new InputMethodInfo[N];
            mSubtypeIds = new int[N];
            int checkedItem = 0;
            for (int i = 0; i < N; ++i) {
                final ImeSubtypeListItem item = imList.get(i);
                mIms[i] = item.mImi;
                mSubtypeIds[i] = item.mSubtypeId;
                if (mIms[i].getId().equals(lastInputMethodId)) {
                    int subtypeId = mSubtypeIds[i];
                    if ((subtypeId == NOT_A_SUBTYPE_ID)
                            || (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID && subtypeId == 0)
                            || (subtypeId == lastInputMethodSubtypeId)) {
                        checkedItem = i;
                    }
                }
            }

            final ActivityThread currentThread = ActivityThread.currentActivityThread();
            final Context settingsContext = new ContextThemeWrapper(
                    displayId == DEFAULT_DISPLAY ? currentThread.getSystemUiContext()
                            : currentThread.createSystemUiContext(displayId),
                    com.android.internal.R.style.Theme_DeviceDefault_Settings);

            mDialogBuilder = new AlertDialog.Builder(settingsContext);
            mDialogBuilder.setOnCancelListener(new OnCancelListener() {
                @Override
                public void onCancel(DialogInterface dialog) {
                    hideInputMethodMenu();
                }
            });

            final Context dialogContext = mDialogBuilder.getContext();
            final TypedArray a = dialogContext.obtainStyledAttributes(null,
                    com.android.internal.R.styleable.DialogPreference,
                    com.android.internal.R.attr.alertDialogStyle, 0);
            final Drawable dialogIcon = a.getDrawable(
                    com.android.internal.R.styleable.DialogPreference_dialogIcon);
            a.recycle();

            mDialogBuilder.setIcon(dialogIcon);

            final LayoutInflater inflater = dialogContext.getSystemService(LayoutInflater.class);
            final View tv = inflater.inflate(
                    com.android.internal.R.layout.input_method_switch_dialog_title, null);
            mDialogBuilder.setCustomTitle(tv);

            // Setup layout for a toggle switch of the hardware keyboard
            mSwitchingDialogTitleView = tv;
            mSwitchingDialogTitleView
                    .findViewById(com.android.internal.R.id.hard_keyboard_section)
                    .setVisibility(mWindowManagerInternal.isHardKeyboardAvailable()
                            ? View.VISIBLE : View.GONE);
            final Switch hardKeySwitch = (Switch) mSwitchingDialogTitleView.findViewById(
                    com.android.internal.R.id.hard_keyboard_switch);
            hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
            hardKeySwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    mSettings.setShowImeWithHardKeyboard(isChecked);
                    // Ensure that the input method dialog is dismissed when changing
                    // the hardware keyboard state.
                    hideInputMethodMenu();
                }
            });

            final ImeSubtypeListAdapter adapter = new ImeSubtypeListAdapter(dialogContext,
                    com.android.internal.R.layout.input_method_switch_item, imList, checkedItem);
            final OnClickListener choiceListener = new OnClickListener() {
                @Override
                public void onClick(final DialogInterface dialog, final int which) {
                    synchronized (mMethodMap) {
                        if (mIms == null || mIms.length <= which || mSubtypeIds == null
                                || mSubtypeIds.length <= which) {
                            return;
                        }
                        final InputMethodInfo im = mIms[which];
                        int subtypeId = mSubtypeIds[which];
                        adapter.mCheckedItem = which;
                        adapter.notifyDataSetChanged();
                        hideInputMethodMenu();
                        if (im != null) {
                            if (subtypeId < 0 || subtypeId >= im.getSubtypeCount()) {
                                subtypeId = NOT_A_SUBTYPE_ID;
                            }
                            setInputMethodLocked(im.getId(), subtypeId);
                        }
                    }
                }
            };
            mDialogBuilder.setSingleChoiceItems(adapter, checkedItem, choiceListener);

            mSwitchingDialog = mDialogBuilder.create();
            mSwitchingDialog.setCanceledOnTouchOutside(true);
            final Window w = mSwitchingDialog.getWindow();
            final LayoutParams attrs = w.getAttributes();
            w.setType(LayoutParams.TYPE_INPUT_METHOD_DIALOG);
            // Use an alternate token for the dialog for that window manager can group the token
            // with other IME windows based on type vs. grouping based on whichever token happens
            // to get selected by the system later on.
            attrs.token = mSwitchingDialogToken;
            attrs.privateFlags |= LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
            attrs.setTitle("Select input method");
            w.setAttributes(attrs);
            updateSystemUiLocked(mImeWindowVis, mBackDisposition);
            mSwitchingDialog.show();
        }
    }

    private static class ImeSubtypeListAdapter extends ArrayAdapter<ImeSubtypeListItem> {
        private final LayoutInflater mInflater;
        private final int mTextViewResourceId;
        private final List<ImeSubtypeListItem> mItemsList;
        public int mCheckedItem;
        public ImeSubtypeListAdapter(Context context, int textViewResourceId,
                List<ImeSubtypeListItem> itemsList, int checkedItem) {
            super(context, textViewResourceId, itemsList);

            mTextViewResourceId = textViewResourceId;
            mItemsList = itemsList;
            mCheckedItem = checkedItem;
            mInflater = context.getSystemService(LayoutInflater.class);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            final View view = convertView != null ? convertView
                    : mInflater.inflate(mTextViewResourceId, null);
            if (position < 0 || position >= mItemsList.size()) return view;
            final ImeSubtypeListItem item = mItemsList.get(position);
            final CharSequence imeName = item.mImeName;
            final CharSequence subtypeName = item.mSubtypeName;
            final TextView firstTextView = (TextView)view.findViewById(android.R.id.text1);
            final TextView secondTextView = (TextView)view.findViewById(android.R.id.text2);
            if (TextUtils.isEmpty(subtypeName)) {
                firstTextView.setText(imeName);
                secondTextView.setVisibility(View.GONE);
            } else {
                firstTextView.setText(subtypeName);
                secondTextView.setText(imeName);
                secondTextView.setVisibility(View.VISIBLE);
            }
            final RadioButton radioButton =
                    (RadioButton)view.findViewById(com.android.internal.R.id.radio);
            radioButton.setChecked(position == mCheckedItem);
            return view;
        }
    }

    void hideInputMethodMenu() {
        synchronized (mMethodMap) {
            hideInputMethodMenuLocked();
        }
    }

    void hideInputMethodMenuLocked() {
        if (DEBUG) Slog.v(TAG, "Hide switching menu");

        if (mSwitchingDialog != null) {
            mSwitchingDialog.dismiss();
            mSwitchingDialog = null;
            mSwitchingDialogTitleView = null;
        }

        updateSystemUiLocked(mImeWindowVis, mBackDisposition);
        mDialogBuilder = null;
        mIms = null;
    }

    // ----------------------------------------------------------------------
    // ----------------------------------------------------------------------


    /**
    /**
@@ -5040,7 +4784,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        }
        }
    }
    }


    private InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
    InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
        if (mCurMethodId == null) {
        if (mCurMethodId == null) {
            return null;
            return null;
        }
        }
@@ -5079,6 +4823,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        return mCurrentSubtype;
        return mCurrentSubtype;
    }
    }


    @Nullable
    String getCurrentMethodId() {
        return mCurMethodId;
    }

    private List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
    private List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
        synchronized (mMethodMap) {
        synchronized (mMethodMap) {
            return getInputMethodListLocked(userId);
            return getInputMethodListLocked(userId);
+327 −0

File added.

Preview size limit exceeded, changes collapsed.