1d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka/*
2d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka * Copyright (C) 2013 The Android Open Source Project
3d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka *
4d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka * Licensed under the Apache License, Version 2.0 (the "License");
5d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka * you may not use this file except in compliance with the License.
6d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka * You may obtain a copy of the License at
7d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka *
8d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka *      http://www.apache.org/licenses/LICENSE-2.0
9d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka *
10d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka * Unless required by applicable law or agreed to in writing, software
11d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka * distributed under the License is distributed on an "AS IS" BASIS,
12d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka * See the License for the specific language governing permissions and
14d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka * limitations under the License.
15d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka */
16d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka
17d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataokapackage com.android.internal.inputmethod;
18d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka
19b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawaimport android.annotation.Nullable;
20d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataokaimport android.content.Context;
21d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataokaimport android.content.pm.PackageManager;
22d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataokaimport android.text.TextUtils;
239b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawaimport android.util.Log;
24d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawaimport android.util.Printer;
25d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataokaimport android.util.Slog;
26d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataokaimport android.view.inputmethod.InputMethodInfo;
27d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataokaimport android.view.inputmethod.InputMethodSubtype;
28d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka
294013940b62ae2227c9b30d8761d7533ee6190a9fYohei Yukawaimport com.android.internal.annotations.VisibleForTesting;
304013940b62ae2227c9b30d8761d7533ee6190a9fYohei Yukawaimport com.android.internal.inputmethod.InputMethodUtils.InputMethodSettings;
314013940b62ae2227c9b30d8761d7533ee6190a9fYohei Yukawa
32d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataokaimport java.util.ArrayList;
33d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataokaimport java.util.Collections;
34d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataokaimport java.util.Comparator;
35d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataokaimport java.util.HashMap;
36d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataokaimport java.util.HashSet;
37d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataokaimport java.util.List;
38d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataokaimport java.util.Locale;
3907bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawaimport java.util.Objects;
40d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataokaimport java.util.TreeMap;
41d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka
42d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka/**
43d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka * InputMethodSubtypeSwitchingController controls the switching behavior of the subtypes.
445a647b69be8ac8d40c33ed9abe63e41514699e5bYohei Yukawa * <p>
455a647b69be8ac8d40c33ed9abe63e41514699e5bYohei Yukawa * This class is designed to be used from and only from {@link InputMethodManagerService} by using
465a647b69be8ac8d40c33ed9abe63e41514699e5bYohei Yukawa * {@link InputMethodManagerService#mMethodMap} as a global lock.
475a647b69be8ac8d40c33ed9abe63e41514699e5bYohei Yukawa * </p>
48d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka */
49d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataokapublic class InputMethodSubtypeSwitchingController {
50d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka    private static final String TAG = InputMethodSubtypeSwitchingController.class.getSimpleName();
51d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka    private static final boolean DEBUG = false;
52d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka    private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID;
53d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka
54d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka    public static class ImeSubtypeListItem implements Comparable<ImeSubtypeListItem> {
55d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka        public final CharSequence mImeName;
56d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka        public final CharSequence mSubtypeName;
57d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka        public final InputMethodInfo mImi;
58d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka        public final int mSubtypeId;
5971cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa        public final boolean mIsSystemLocale;
6071cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa        public final boolean mIsSystemLanguage;
61d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka
62d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka        public ImeSubtypeListItem(CharSequence imeName, CharSequence subtypeName,
63d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                InputMethodInfo imi, int subtypeId, String subtypeLocale, String systemLocale) {
64d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            mImeName = imeName;
65d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            mSubtypeName = subtypeName;
66d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            mImi = imi;
67d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            mSubtypeId = subtypeId;
68d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            if (TextUtils.isEmpty(subtypeLocale)) {
69d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                mIsSystemLocale = false;
70d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                mIsSystemLanguage = false;
71d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            } else {
72d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                mIsSystemLocale = subtypeLocale.equals(systemLocale);
7371cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa                if (mIsSystemLocale) {
7471cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa                    mIsSystemLanguage = true;
7571cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa                } else {
7671cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa                    // TODO: Use Locale#getLanguage or Locale#toLanguageTag
7771cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa                    final String systemLanguage = parseLanguageFromLocaleString(systemLocale);
7871cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa                    final String subtypeLanguage = parseLanguageFromLocaleString(subtypeLocale);
7971cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa                    mIsSystemLanguage = systemLanguage.length() >= 2 &&
8071cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa                            systemLanguage.equals(subtypeLanguage);
8171cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa                }
8271cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa            }
8371cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa        }
8471cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa
8571cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa        /**
8671cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa         * Returns the language component of a given locale string.
8771cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa         * TODO: Use {@link Locale#getLanguage()} instead.
8871cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa         */
8971cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa        private static String parseLanguageFromLocaleString(final String locale) {
9071cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa            final int idx = locale.indexOf('_');
9171cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa            if (idx < 0) {
9271cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa                return locale;
9371cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa            } else {
9471cf0a32d0d9a45653704a671154f26a8bc3132bYohei Yukawa                return locale.substring(0, idx);
95d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            }
96d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka        }
97d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka
98d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka        @Override
99d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka        public int compareTo(ImeSubtypeListItem other) {
100d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            if (TextUtils.isEmpty(mImeName)) {
101d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                return 1;
102d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            }
103d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            if (TextUtils.isEmpty(other.mImeName)) {
104d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                return -1;
105d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            }
106d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            if (!TextUtils.equals(mImeName, other.mImeName)) {
107d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                return mImeName.toString().compareTo(other.mImeName.toString());
108d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            }
109d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            if (TextUtils.equals(mSubtypeName, other.mSubtypeName)) {
110d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                return 0;
111d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            }
112d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            if (mIsSystemLocale) {
113d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                return -1;
114d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            }
115d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            if (other.mIsSystemLocale) {
116d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                return 1;
117d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            }
118d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            if (mIsSystemLanguage) {
119d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                return -1;
120d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            }
121d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            if (other.mIsSystemLanguage) {
122d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                return 1;
123d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            }
124d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            if (TextUtils.isEmpty(mSubtypeName)) {
125d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                return 1;
126d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            }
127d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            if (TextUtils.isEmpty(other.mSubtypeName)) {
128d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                return -1;
129d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            }
130d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            return mSubtypeName.toString().compareTo(other.mSubtypeName.toString());
131d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka        }
1321c63079b55cbb161ec6bed731a751943e6ac5736Yohei Yukawa
1331c63079b55cbb161ec6bed731a751943e6ac5736Yohei Yukawa        @Override
1341c63079b55cbb161ec6bed731a751943e6ac5736Yohei Yukawa        public String toString() {
1351c63079b55cbb161ec6bed731a751943e6ac5736Yohei Yukawa            return "ImeSubtypeListItem{"
1361c63079b55cbb161ec6bed731a751943e6ac5736Yohei Yukawa                    + "mImeName=" + mImeName
1371c63079b55cbb161ec6bed731a751943e6ac5736Yohei Yukawa                    + " mSubtypeName=" + mSubtypeName
1381c63079b55cbb161ec6bed731a751943e6ac5736Yohei Yukawa                    + " mSubtypeId=" + mSubtypeId
1391c63079b55cbb161ec6bed731a751943e6ac5736Yohei Yukawa                    + " mIsSystemLocale=" + mIsSystemLocale
1401c63079b55cbb161ec6bed731a751943e6ac5736Yohei Yukawa                    + " mIsSystemLanguage=" + mIsSystemLanguage
1411c63079b55cbb161ec6bed731a751943e6ac5736Yohei Yukawa                    + "}";
1421c63079b55cbb161ec6bed731a751943e6ac5736Yohei Yukawa        }
14307bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa
14407bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa        @Override
14507bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa        public boolean equals(Object o) {
14607bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa            if (o == this) {
14707bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                return true;
14807bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa            }
14907bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa            if (o instanceof ImeSubtypeListItem) {
15007bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                final ImeSubtypeListItem that = (ImeSubtypeListItem)o;
15107bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                if (!Objects.equals(this.mImi, that.mImi)) {
15207bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                    return false;
15307bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                }
15407bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                if (this.mSubtypeId != that.mSubtypeId) {
15507bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                    return false;
15607bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                }
15707bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                return true;
15807bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa            }
15907bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa            return false;
16007bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa        }
161d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka    }
162d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka
163d1da11529813f6d3f51518b5fe028e0b8084f5ccYohei Yukawa    private static class InputMethodAndSubtypeList {
164d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka        private final Context mContext;
165d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka        // Used to load label
166d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka        private final PackageManager mPm;
167d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka        private final String mSystemLocaleStr;
168d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka        private final InputMethodSettings mSettings;
169d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka
170d1da11529813f6d3f51518b5fe028e0b8084f5ccYohei Yukawa        public InputMethodAndSubtypeList(Context context, InputMethodSettings settings) {
171d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            mContext = context;
172d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            mSettings = settings;
173d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            mPm = context.getPackageManager();
174d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            final Locale locale = context.getResources().getConfiguration().locale;
175d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            mSystemLocaleStr = locale != null ? locale.toString() : "";
176d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka        }
177d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka
178d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka        private final TreeMap<InputMethodInfo, List<InputMethodSubtype>> mSortedImmis =
1797025964d1230e4fc064658e1911fea9aab3def68Yohei Yukawa                new TreeMap<>(
180d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                        new Comparator<InputMethodInfo>() {
181d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                            @Override
182d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                            public int compare(InputMethodInfo imi1, InputMethodInfo imi2) {
183d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                                if (imi2 == null)
184d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                                    return 0;
185d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                                if (imi1 == null)
186d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                                    return 1;
187d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                                if (mPm == null) {
188d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                                    return imi1.getId().compareTo(imi2.getId());
189d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                                }
190d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                                CharSequence imiId1 = imi1.loadLabel(mPm) + "/" + imi1.getId();
191d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                                CharSequence imiId2 = imi2.loadLabel(mPm) + "/" + imi2.getId();
192d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                                return imiId1.toString().compareTo(imiId2.toString());
193d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                            }
194d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                        });
195d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka
196d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka        public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList(
1975f8e731f18c5cbfd345236c691db0b09aceb7c5dYohei Yukawa                boolean includeAuxiliarySubtypes, boolean isScreenLocked) {
1987025964d1230e4fc064658e1911fea9aab3def68Yohei Yukawa            final ArrayList<ImeSubtypeListItem> imList = new ArrayList<>();
199d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            final HashMap<InputMethodInfo, List<InputMethodSubtype>> immis =
200d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                    mSettings.getExplicitlyOrImplicitlyEnabledInputMethodsAndSubtypeListLocked(
201d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                            mContext);
202d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            if (immis == null || immis.size() == 0) {
203d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                return Collections.emptyList();
204d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            }
20514e139179be7daab6ed452105387a3922752c219Seigo Nonaka            if (isScreenLocked && includeAuxiliarySubtypes) {
20614e139179be7daab6ed452105387a3922752c219Seigo Nonaka                if (DEBUG) {
20714e139179be7daab6ed452105387a3922752c219Seigo Nonaka                    Slog.w(TAG, "Auxiliary subtypes are not allowed to be shown in lock screen.");
20814e139179be7daab6ed452105387a3922752c219Seigo Nonaka                }
20914e139179be7daab6ed452105387a3922752c219Seigo Nonaka                includeAuxiliarySubtypes = false;
21014e139179be7daab6ed452105387a3922752c219Seigo Nonaka            }
211d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            mSortedImmis.clear();
212d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            mSortedImmis.putAll(immis);
213d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            for (InputMethodInfo imi : mSortedImmis.keySet()) {
214d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                if (imi == null) {
215d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                    continue;
216d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                }
217d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypeList = immis.get(imi);
2187025964d1230e4fc064658e1911fea9aab3def68Yohei Yukawa                HashSet<String> enabledSubtypeSet = new HashSet<>();
219d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                for (InputMethodSubtype subtype : explicitlyOrImplicitlyEnabledSubtypeList) {
220d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                    enabledSubtypeSet.add(String.valueOf(subtype.hashCode()));
221d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                }
222d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                final CharSequence imeLabel = imi.loadLabel(mPm);
2235f8e731f18c5cbfd345236c691db0b09aceb7c5dYohei Yukawa                if (enabledSubtypeSet.size() > 0) {
224d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                    final int subtypeCount = imi.getSubtypeCount();
225d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                    if (DEBUG) {
226d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                        Slog.v(TAG, "Add subtypes: " + subtypeCount + ", " + imi.getId());
227d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                    }
228d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                    for (int j = 0; j < subtypeCount; ++j) {
229d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                        final InputMethodSubtype subtype = imi.getSubtypeAt(j);
230d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                        final String subtypeHashCode = String.valueOf(subtype.hashCode());
231d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                        // We show all enabled IMEs and subtypes when an IME is shown.
232d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                        if (enabledSubtypeSet.contains(subtypeHashCode)
23314e139179be7daab6ed452105387a3922752c219Seigo Nonaka                                && (includeAuxiliarySubtypes || !subtype.isAuxiliary())) {
234d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                            final CharSequence subtypeLabel =
235d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                                    subtype.overridesImplicitlyEnabledSubtype() ? null : subtype
236d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                                            .getDisplayName(mContext, imi.getPackageName(),
237d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                                                    imi.getServiceInfo().applicationInfo);
238d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                            imList.add(new ImeSubtypeListItem(imeLabel,
239d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                                    subtypeLabel, imi, j, subtype.getLocale(), mSystemLocaleStr));
240d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka
241d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                            // Removing this subtype from enabledSubtypeSet because we no
242d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                            // longer need to add an entry of this subtype to imList to avoid
243d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                            // duplicated entries.
244d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                            enabledSubtypeSet.remove(subtypeHashCode);
245d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                        }
246d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                    }
247d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                } else {
248d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                    imList.add(new ImeSubtypeListItem(imeLabel, null, imi, NOT_A_SUBTYPE_ID, null,
249d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                            mSystemLocaleStr));
250d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka                }
251d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            }
252d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            Collections.sort(imList);
253d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka            return imList;
254d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka        }
255d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka    }
256d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka
2579b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa    private static int calculateSubtypeId(InputMethodInfo imi, InputMethodSubtype subtype) {
2589b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa        return subtype != null ? InputMethodUtils.getSubtypeIdFromHashCode(imi,
2599b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa                subtype.hashCode()) : NOT_A_SUBTYPE_ID;
2609b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa    }
261d1da11529813f6d3f51518b5fe028e0b8084f5ccYohei Yukawa
2629b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa    private static class StaticRotationList {
2639b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa        private final List<ImeSubtypeListItem> mImeSubtypeList;
2649b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa        public StaticRotationList(final List<ImeSubtypeListItem> imeSubtypeList) {
2659b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            mImeSubtypeList = imeSubtypeList;
266d1da11529813f6d3f51518b5fe028e0b8084f5ccYohei Yukawa        }
2679b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa
2689b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa        /**
2699b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa         * Returns the index of the specified input method and subtype in the given list.
2709b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa         * @param imi The {@link InputMethodInfo} to be searched.
2719b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa         * @param subtype The {@link InputMethodSubtype} to be searched. null if the input method
2729b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa         * does not have a subtype.
2739b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa         * @return The index in the given list. -1 if not found.
2749b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa         */
2759b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa        private int getIndex(InputMethodInfo imi, InputMethodSubtype subtype) {
2769b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            final int currentSubtypeId = calculateSubtypeId(imi, subtype);
2779b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            final int N = mImeSubtypeList.size();
2789b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            for (int i = 0; i < N; ++i) {
2799b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa                final ImeSubtypeListItem isli = mImeSubtypeList.get(i);
2809b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa                // Skip until the current IME/subtype is found.
2819b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa                if (imi.equals(isli.mImi) && isli.mSubtypeId == currentSubtypeId) {
2829b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa                    return i;
2839b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa                }
2849b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            }
2859b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            return -1;
286d1da11529813f6d3f51518b5fe028e0b8084f5ccYohei Yukawa        }
2879b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa
288b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa        /**
289b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * Provides the basic operation to implement bi-directional IME rotation.
290b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * @param onlyCurrentIme {@code true} to limit the search space to IME subtypes that belong
291b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * to {@code imi}.
292b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * @param imi {@link InputMethodInfo} that will be used in conjunction with {@code subtype}
293b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * from which we find the adjacent IME subtype.
294b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * @param subtype {@link InputMethodSubtype} that will be used in conjunction with
295b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * {@code imi} from which we find the next IME subtype.  {@code null} if the input method
296b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * does not have a subtype.
297b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * @param forward {@code true} to do forward search the next IME subtype. Specify
298b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * {@code false} to do backward search.
299b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * @return The IME subtype found. {@code null} if no IME subtype is found.
300b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         */
301b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa        @Nullable
3029b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa        public ImeSubtypeListItem getNextInputMethodLocked(boolean onlyCurrentIme,
303b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa                InputMethodInfo imi, @Nullable InputMethodSubtype subtype, boolean forward) {
3049b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            if (imi == null) {
3059b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa                return null;
306a1223cfe6f2e04da1ab6e0ad781068687446ee56Yohei Yukawa            }
3079b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            if (mImeSubtypeList.size() <= 1) {
3089b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa                return null;
3099b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            }
3109b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            final int currentIndex = getIndex(imi, subtype);
3119b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            if (currentIndex < 0) {
3129b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa                return null;
3139b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            }
3149b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            final int N = mImeSubtypeList.size();
315d39ae854820edebe3f1cb8580117c451ffa5c4ecYohei Yukawa            for (int i = 1; i < N; ++i) {
316b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa                // Start searching the next IME/subtype from +/- 1 indices.
317d39ae854820edebe3f1cb8580117c451ffa5c4ecYohei Yukawa                final int offset = forward ? i : N - i;
3189b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa                final int candidateIndex = (currentIndex + offset) % N;
3199b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa                final ImeSubtypeListItem candidate = mImeSubtypeList.get(candidateIndex);
320a1223cfe6f2e04da1ab6e0ad781068687446ee56Yohei Yukawa                // Skip if searching inside the current IME only, but the candidate is not
321a1223cfe6f2e04da1ab6e0ad781068687446ee56Yohei Yukawa                // the current IME.
3229b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa                if (onlyCurrentIme && !imi.equals(candidate.mImi)) {
323a1223cfe6f2e04da1ab6e0ad781068687446ee56Yohei Yukawa                    continue;
324d1da11529813f6d3f51518b5fe028e0b8084f5ccYohei Yukawa                }
325a1223cfe6f2e04da1ab6e0ad781068687446ee56Yohei Yukawa                return candidate;
326d1da11529813f6d3f51518b5fe028e0b8084f5ccYohei Yukawa            }
327a1223cfe6f2e04da1ab6e0ad781068687446ee56Yohei Yukawa            return null;
328d1da11529813f6d3f51518b5fe028e0b8084f5ccYohei Yukawa        }
329d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa
330d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa        protected void dump(final Printer pw, final String prefix) {
331d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa            final int N = mImeSubtypeList.size();
332d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa            for (int i = 0; i < N; ++i) {
333d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa                final int rank = i;
334d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa                final ImeSubtypeListItem item = mImeSubtypeList.get(i);
335d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa                pw.println(prefix + "rank=" + rank + " item=" + item);
336d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa            }
337d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa        }
338d1da11529813f6d3f51518b5fe028e0b8084f5ccYohei Yukawa    }
339d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka
340a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa    private static class DynamicRotationList {
341a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa        private static final String TAG = DynamicRotationList.class.getSimpleName();
342a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa        private final List<ImeSubtypeListItem> mImeSubtypeList;
343a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa        private final int[] mUsageHistoryOfSubtypeListItemIndex;
344a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa
34507bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa        private DynamicRotationList(final List<ImeSubtypeListItem> imeSubtypeListItems) {
346a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            mImeSubtypeList = imeSubtypeListItems;
347a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            mUsageHistoryOfSubtypeListItemIndex = new int[mImeSubtypeList.size()];
348a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            final int N = mImeSubtypeList.size();
349a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            for (int i = 0; i < N; i++) {
350a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                mUsageHistoryOfSubtypeListItemIndex[i] = i;
351a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            }
352a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa        }
353a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa
354a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa        /**
355a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa         * Returns the index of the specified object in
356a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa         * {@link #mUsageHistoryOfSubtypeListItemIndex}.
357a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa         * <p>We call the index of {@link #mUsageHistoryOfSubtypeListItemIndex} as "Usage Rank"
358a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa         * so as not to be confused with the index in {@link #mImeSubtypeList}.
359a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa         * @return -1 when the specified item doesn't belong to {@link #mImeSubtypeList} actually.
360a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa         */
361a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa        private int getUsageRank(final InputMethodInfo imi, InputMethodSubtype subtype) {
362a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            final int currentSubtypeId = calculateSubtypeId(imi, subtype);
363a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            final int N = mUsageHistoryOfSubtypeListItemIndex.length;
364a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            for (int usageRank = 0; usageRank < N; usageRank++) {
365a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                final int subtypeListItemIndex = mUsageHistoryOfSubtypeListItemIndex[usageRank];
366a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                final ImeSubtypeListItem subtypeListItem =
367a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                        mImeSubtypeList.get(subtypeListItemIndex);
368a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                if (subtypeListItem.mImi.equals(imi) &&
369a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                        subtypeListItem.mSubtypeId == currentSubtypeId) {
370a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                    return usageRank;
371a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                }
372a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            }
373a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            // Not found in the known IME/Subtype list.
374a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            return -1;
375a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa        }
376a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa
377a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa        public void onUserAction(InputMethodInfo imi, InputMethodSubtype subtype) {
378a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            final int currentUsageRank = getUsageRank(imi, subtype);
379a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            // Do nothing if currentUsageRank == -1 (not found), or currentUsageRank == 0
380a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            if (currentUsageRank <= 0) {
381a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                return;
382a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            }
383a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            final int currentItemIndex = mUsageHistoryOfSubtypeListItemIndex[currentUsageRank];
384a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            System.arraycopy(mUsageHistoryOfSubtypeListItemIndex, 0,
385a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                    mUsageHistoryOfSubtypeListItemIndex, 1, currentUsageRank);
386a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            mUsageHistoryOfSubtypeListItemIndex[0] = currentItemIndex;
387a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa        }
388a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa
389b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa        /**
390b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * Provides the basic operation to implement bi-directional IME rotation.
391b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * @param onlyCurrentIme {@code true} to limit the search space to IME subtypes that belong
392b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * to {@code imi}.
393b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * @param imi {@link InputMethodInfo} that will be used in conjunction with {@code subtype}
394b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * from which we find the adjacent IME subtype.
395b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * @param subtype {@link InputMethodSubtype} that will be used in conjunction with
396b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * {@code imi} from which we find the next IME subtype.  {@code null} if the input method
397b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * does not have a subtype.
398b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * @param forward {@code true} to do forward search the next IME subtype. Specify
399b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * {@code false} to do backward search.
400b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * @return The IME subtype found. {@code null} if no IME subtype is found.
401b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         */
402b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa        @Nullable
403a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa        public ImeSubtypeListItem getNextInputMethodLocked(boolean onlyCurrentIme,
404b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa                InputMethodInfo imi, @Nullable InputMethodSubtype subtype, boolean forward) {
405a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            int currentUsageRank = getUsageRank(imi, subtype);
406a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            if (currentUsageRank < 0) {
407a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                if (DEBUG) {
408a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                    Slog.d(TAG, "IME/subtype is not found: " + imi.getId() + ", " + subtype);
409a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                }
410a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                return null;
411a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            }
412a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            final int N = mUsageHistoryOfSubtypeListItemIndex.length;
413a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            for (int i = 1; i < N; i++) {
414d39ae854820edebe3f1cb8580117c451ffa5c4ecYohei Yukawa                final int offset = forward ? i : N - i;
415d39ae854820edebe3f1cb8580117c451ffa5c4ecYohei Yukawa                final int subtypeListItemRank = (currentUsageRank + offset) % N;
416a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                final int subtypeListItemIndex =
417a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                        mUsageHistoryOfSubtypeListItemIndex[subtypeListItemRank];
418a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                final ImeSubtypeListItem subtypeListItem =
419a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                        mImeSubtypeList.get(subtypeListItemIndex);
420a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                if (onlyCurrentIme && !imi.equals(subtypeListItem.mImi)) {
421a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                    continue;
422a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                }
423a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                return subtypeListItem;
424a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            }
425a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            return null;
426a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa        }
427d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa
428d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa        protected void dump(final Printer pw, final String prefix) {
429d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa            for (int i = 0; i < mUsageHistoryOfSubtypeListItemIndex.length; ++i) {
430d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa                final int rank = mUsageHistoryOfSubtypeListItemIndex[i];
431d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa                final ImeSubtypeListItem item = mImeSubtypeList.get(i);
432d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa                pw.println(prefix + "rank=" + rank + " item=" + item);
433d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa            }
434d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa        }
435a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa    }
436a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa
4379b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa    @VisibleForTesting
4389b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa    public static class ControllerImpl {
43907bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa        private final DynamicRotationList mSwitchingAwareRotationList;
44007bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa        private final StaticRotationList mSwitchingUnawareRotationList;
44107bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa
44207bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa        public static ControllerImpl createFrom(final ControllerImpl currentInstance,
44307bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                final List<ImeSubtypeListItem> sortedEnabledItems) {
44407bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa            DynamicRotationList switchingAwareRotationList = null;
44507bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa            {
44607bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                final List<ImeSubtypeListItem> switchingAwareImeSubtypes =
44707bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                        filterImeSubtypeList(sortedEnabledItems,
44807bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                                true /* supportsSwitchingToNextInputMethod */);
44907bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                if (currentInstance != null &&
45007bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                        currentInstance.mSwitchingAwareRotationList != null &&
45107bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                        Objects.equals(currentInstance.mSwitchingAwareRotationList.mImeSubtypeList,
45207bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                                switchingAwareImeSubtypes)) {
45307bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                    // Can reuse the current instance.
45407bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                    switchingAwareRotationList = currentInstance.mSwitchingAwareRotationList;
45507bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                }
45607bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                if (switchingAwareRotationList == null) {
45707bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                    switchingAwareRotationList = new DynamicRotationList(switchingAwareImeSubtypes);
45807bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                }
45907bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa            }
46007bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa
46107bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa            StaticRotationList switchingUnawareRotationList = null;
46207bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa            {
46307bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                final List<ImeSubtypeListItem> switchingUnawareImeSubtypes = filterImeSubtypeList(
46407bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                        sortedEnabledItems, false /* supportsSwitchingToNextInputMethod */);
46507bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                if (currentInstance != null &&
46607bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                        currentInstance.mSwitchingUnawareRotationList != null &&
46707bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                        Objects.equals(
46807bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                                currentInstance.mSwitchingUnawareRotationList.mImeSubtypeList,
46907bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                                switchingUnawareImeSubtypes)) {
47007bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                    // Can reuse the current instance.
47107bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                    switchingUnawareRotationList = currentInstance.mSwitchingUnawareRotationList;
47207bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                }
47307bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                if (switchingUnawareRotationList == null) {
47407bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                    switchingUnawareRotationList =
47507bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                            new StaticRotationList(switchingUnawareImeSubtypes);
47607bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                }
47707bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa            }
47807bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa
47907bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa            return new ControllerImpl(switchingAwareRotationList, switchingUnawareRotationList);
48007bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa        }
48107bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa
48207bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa        private ControllerImpl(final DynamicRotationList switchingAwareRotationList,
48307bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                final StaticRotationList switchingUnawareRotationList) {
48407bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa            mSwitchingAwareRotationList = switchingAwareRotationList;
48507bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa            mSwitchingUnawareRotationList = switchingUnawareRotationList;
4869b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa        }
4879b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa
488b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa        /**
489b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * Provides the basic operation to implement bi-directional IME rotation.
490b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * @param onlyCurrentIme {@code true} to limit the search space to IME subtypes that belong
491b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * to {@code imi}.
492b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * @param imi {@link InputMethodInfo} that will be used in conjunction with {@code subtype}
493b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * from which we find the adjacent IME subtype.
494b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * @param subtype {@link InputMethodSubtype} that will be used in conjunction with
495b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * {@code imi} from which we find the next IME subtype.  {@code null} if the input method
496b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * does not have a subtype.
497b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * @param forward {@code true} to do forward search the next IME subtype. Specify
498b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * {@code false} to do backward search.
499b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         * @return The IME subtype found. {@code null} if no IME subtype is found.
500b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa         */
501b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa        @Nullable
5029b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa        public ImeSubtypeListItem getNextInputMethod(boolean onlyCurrentIme, InputMethodInfo imi,
503b1e2f4fc3a7b6676aa2c19f470338d6d57ff0ce6Yohei Yukawa                @Nullable InputMethodSubtype subtype, boolean forward) {
5049b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            if (imi == null) {
5059b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa                return null;
5069b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            }
5079b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            if (imi.supportsSwitchingToNextInputMethod()) {
50807bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                return mSwitchingAwareRotationList.getNextInputMethodLocked(onlyCurrentIme, imi,
509d39ae854820edebe3f1cb8580117c451ffa5c4ecYohei Yukawa                        subtype, forward);
5109b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            } else {
51107bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                return mSwitchingUnawareRotationList.getNextInputMethodLocked(onlyCurrentIme, imi,
512d39ae854820edebe3f1cb8580117c451ffa5c4ecYohei Yukawa                        subtype, forward);
5139b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            }
5149b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa        }
5159b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa
516a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa        public void onUserActionLocked(InputMethodInfo imi, InputMethodSubtype subtype) {
517a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            if (imi == null) {
518a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                return;
519a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            }
52007bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa            if (imi.supportsSwitchingToNextInputMethod()) {
52107bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa                mSwitchingAwareRotationList.onUserAction(imi, subtype);
52207bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa            }
523a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa        }
524a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa
5259b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa        private static List<ImeSubtypeListItem> filterImeSubtypeList(
5269b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa                final List<ImeSubtypeListItem> items,
5279b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa                final boolean supportsSwitchingToNextInputMethod) {
5289b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            final ArrayList<ImeSubtypeListItem> result = new ArrayList<>();
5299b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            final int ALL_ITEMS_COUNT = items.size();
5309b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            for (int i = 0; i < ALL_ITEMS_COUNT; i++) {
5319b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa                final ImeSubtypeListItem item = items.get(i);
5329b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa                if (item.mImi.supportsSwitchingToNextInputMethod() ==
5339b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa                        supportsSwitchingToNextInputMethod) {
5349b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa                    result.add(item);
5359b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa                }
5369b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            }
5379b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            return result;
5389b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa        }
539d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa
540d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa        protected void dump(final Printer pw) {
541d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa            pw.println("    mSwitchingAwareRotationList:");
542d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa            mSwitchingAwareRotationList.dump(pw, "      ");
543d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa            pw.println("    mSwitchingUnawareRotationList:");
544d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa            mSwitchingUnawareRotationList.dump(pw, "      ");
545d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa        }
5469b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa    }
5479b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa
5489b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa    private final InputMethodSettings mSettings;
5499b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa    private InputMethodAndSubtypeList mSubtypeList;
5509b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa    private ControllerImpl mController;
5519b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa
5525a647b69be8ac8d40c33ed9abe63e41514699e5bYohei Yukawa    private InputMethodSubtypeSwitchingController(InputMethodSettings settings, Context context) {
553d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka        mSettings = settings;
5545a647b69be8ac8d40c33ed9abe63e41514699e5bYohei Yukawa        resetCircularListLocked(context);
5555a647b69be8ac8d40c33ed9abe63e41514699e5bYohei Yukawa    }
5565a647b69be8ac8d40c33ed9abe63e41514699e5bYohei Yukawa
5575a647b69be8ac8d40c33ed9abe63e41514699e5bYohei Yukawa    public static InputMethodSubtypeSwitchingController createInstanceLocked(
5585a647b69be8ac8d40c33ed9abe63e41514699e5bYohei Yukawa            InputMethodSettings settings, Context context) {
5595a647b69be8ac8d40c33ed9abe63e41514699e5bYohei Yukawa        return new InputMethodSubtypeSwitchingController(settings, context);
560d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka    }
561d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka
5620297051162193ef2b7d906409868e404f77e4c31Yohei Yukawa    public void onUserActionLocked(InputMethodInfo imi, InputMethodSubtype subtype) {
563a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa        if (mController == null) {
564a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            if (DEBUG) {
565a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa                Log.e(TAG, "mController shouldn't be null.");
566a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            }
567a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa            return;
568a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa        }
569a9bda774276f1c5a1fc6fd67a7782a06e696be8fYohei Yukawa        mController.onUserActionLocked(imi, subtype);
570d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka    }
571d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka
572d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka    public void resetCircularListLocked(Context context) {
5735a647b69be8ac8d40c33ed9abe63e41514699e5bYohei Yukawa        mSubtypeList = new InputMethodAndSubtypeList(context, mSettings);
57407bd732034fbf4ce0e51b99c7199edf20dff1565Yohei Yukawa        mController = ControllerImpl.createFrom(mController,
575e512f85002379c5949f65daeffdcae3198964dadYohei Yukawa                mSubtypeList.getSortedInputMethodAndSubtypeList(
576e512f85002379c5949f65daeffdcae3198964dadYohei Yukawa                        false /* includeAuxiliarySubtypes */, false /* isScreenLocked */));
577d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka    }
578d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka
5799b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa    public ImeSubtypeListItem getNextInputMethodLocked(boolean onlyCurrentIme, InputMethodInfo imi,
580d39ae854820edebe3f1cb8580117c451ffa5c4ecYohei Yukawa            InputMethodSubtype subtype, boolean forward) {
5819b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa        if (mController == null) {
5829b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            if (DEBUG) {
5839b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa                Log.e(TAG, "mController shouldn't be null.");
5849b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            }
5859b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa            return null;
5869b29d04565e1faf0a49054f538ed1881cb24fe12Yohei Yukawa        }
587d39ae854820edebe3f1cb8580117c451ffa5c4ecYohei Yukawa        return mController.getNextInputMethod(onlyCurrentIme, imi, subtype, forward);
588d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka    }
589d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka
5905f8e731f18c5cbfd345236c691db0b09aceb7c5dYohei Yukawa    public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeListLocked(
59114e139179be7daab6ed452105387a3922752c219Seigo Nonaka            boolean includingAuxiliarySubtypes, boolean isScreenLocked) {
5925a647b69be8ac8d40c33ed9abe63e41514699e5bYohei Yukawa        return mSubtypeList.getSortedInputMethodAndSubtypeList(
5935f8e731f18c5cbfd345236c691db0b09aceb7c5dYohei Yukawa                includingAuxiliarySubtypes, isScreenLocked);
594d787f6953371c4520bd51d6bf8eccc59f1d0f945Satoshi Kataoka    }
595d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa
596d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa    public void dump(final Printer pw) {
597d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa        if (mController != null) {
598d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa            mController.dump(pw);
599d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa        } else {
600d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa            pw.println("    mController=null");
601d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa        }
602d724886cc13990ebcf55134455ef0fa223054ae8Yohei Yukawa    }
603d7443c83ceae0bdd20d68bf84648cf3b40115d85Satoshi Kataoka}
604