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

Commit 703c5f39 authored by satok's avatar satok Committed by Android (Google) Code Review
Browse files

Merge "Add an API to get shortcut IMEs"

parents 656a23ba 4e4569da
Loading
Loading
Loading
Loading
+16 −5
Original line number Diff line number Diff line
@@ -156003,22 +156003,22 @@
 visibility="public"
>
</field>
<field name="GROUP_VISIBLE"
<field name="GROUP_IS_READ_ONLY"
 type="java.lang.String"
 transient="false"
 volatile="false"
 value="&quot;group_visible&quot;"
 value="&quot;group_is_read_only&quot;"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="GROUP_IS_READ_ONLY"
<field name="GROUP_VISIBLE"
 type="java.lang.String"
 transient="false"
 volatile="false"
 value="&quot;group_is_read_only&quot;"
 value="&quot;group_visible&quot;"
 static="true"
 final="true"
 deprecated="not deprecated"
@@ -220894,6 +220894,17 @@
 visibility="public"
>
</method>
<method name="getShortcutInputMethodsAndSubtypes"
 return="java.util.List&lt;android.util.Pair&lt;android.view.inputmethod.InputMethodInfo, android.view.inputmethod.InputMethodSubtype&gt;&gt;"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="hideSoftInputFromInputMethod"
 return="void"
 abstract="false"
@@ -248473,7 +248484,7 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="t" type="T">
<parameter name="arg0" type="T">
</parameter>
</method>
</interface>
+34 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -47,6 +48,7 @@ import com.android.internal.view.InputBindResult;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -1452,6 +1454,38 @@ public final class InputMethodManager {
        }
    }

    public List<Pair<InputMethodInfo, InputMethodSubtype>> getShortcutInputMethodsAndSubtypes() {
        synchronized (mH) {
            List<Pair<InputMethodInfo, InputMethodSubtype>> ret =
                    new ArrayList<Pair<InputMethodInfo, InputMethodSubtype>>();
            try {
                // TODO: We should change the return type from List<Object> to List<Parcelable>
                List<Object> info = mService.getShortcutInputMethodsAndSubtypes();
                // "info" has imi1, subtype1, imi2, subtype2, imi3, subtype3,..... in the list
                Object imi;
                Object subtype;
                if (info != null && info.size() > 0) {
                    final int N = info.size();
                    if (N % 2 == 0) {
                        for (int i = 0; i < N;) {
                            if ((imi = info.get(i++)) instanceof InputMethodInfo) {
                                subtype = info.get(i++);
                                ret.add(new Pair<InputMethodInfo, InputMethodSubtype> (
                                        (InputMethodInfo)imi,
                                        (subtype instanceof InputMethodSubtype) ?
                                                (InputMethodSubtype)subtype : null));
                            }
                        }
                    } else {
                        Log.w(TAG, "The size of list was illegal.");
                    }
                }
            } catch (RemoteException e) {
                Log.w(TAG, "IME died: " + mCurId, e);
            }
            return ret;
        }
    }
    public boolean switchToLastInputMethod(IBinder imeToken) {
        synchronized (mH) {
            try {
+3 −0
Original line number Diff line number Diff line
@@ -32,6 +32,9 @@ interface IInputMethodManager {
    List<InputMethodInfo> getInputMethodList();
    List<InputMethodInfo> getEnabledInputMethodList();
    List<InputMethodSubtype> getEnabledInputMethodSubtypeList(in InputMethodInfo imi);
    // TODO: We should change the return type from List to List<Parcelable>
    // Currently there is a bug that aidl doesn't accept List<Parcelable>
    List getShortcutInputMethodsAndSubtypes();
    void addClient(in IInputMethodClient client,
            in IInputContext inputContext, int uid, int pid);
    void removeClient(in IInputMethodClient client);
+133 −22
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ import android.os.IBinder;
import android.os.IInterface;
import android.os.Message;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -120,6 +121,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
    // If IME doesn't support the system locale, the default subtype will be the first defined one.
    private static final int DEFAULT_SUBTYPE_ID = 0;

    private static final String SUBTYPE_MODE_KEYBOARD = "keyboard";
    private static final String SUBTYPE_MODE_VOICE = "voice";

    final Context mContext;
    final Handler mHandler;
    final InputMethodSettings mSettings;
@@ -235,6 +239,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
     */
    private InputMethodSubtype mCurrentSubtype;

    // This list contains the pairs of InputMethodInfo and InputMethodSubtype.
    private List<Pair<InputMethodInfo, InputMethodSubtype>> mShortcutInputMethodsAndSubtypes;
    // This list is used for returning the pairs of InputMethodInfo and InputMethodSubtype through
    // aidl. This list has imi1, subtype1 imi2, subtype2...
    private List mShortcutInputMethodsAndSubtypesObjectList;

    /**
     * Set to true if our ServiceConnection is currently actively bound to
@@ -983,6 +992,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                mCurMethodId = null;
                unbindCurrentMethodLocked(true);
            }
            mShortcutInputMethodsAndSubtypes = null;
        } else {
            // There is no longer an input method set, so stop any current one.
            mCurMethodId = null;
@@ -1910,25 +1920,31 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        return NOT_A_SUBTYPE_ID;
    }

    // If there are no selected subtypes, tries finding the most applicable one according to the
    // current system locale
    private int findApplicableSubtypeLocked(String id) {
        InputMethodInfo imi = mMethodMap.get(id);
        if (imi == null) {
            return NOT_A_SUBTYPE_ID;
        }
        ArrayList<InputMethodSubtype> subtypes = imi.getSubtypes();
    /**
     * If there are no selected subtypes, tries finding the most applicable one according to the
     * given locale.
     * @param subtypes this function will search the most applicable subtype in subtypes
     * @param mode subtypes will be filtered by mode
     * @param locale subtypes will be filtered by locale
     * @param defaultSubtypeId if this function can't find the most applicable subtype, it will
     * return defaultSubtypeId
     * @return the most applicable subtypeId
     */
    private int findLastResortApplicableSubtypeLocked(
            List<InputMethodSubtype> subtypes, String mode, String locale, int defaultSubtypeId) {
        if (subtypes == null || subtypes.size() == 0) {
            return NOT_A_SUBTYPE_ID;
        }
        final String locale = mContext.getResources().getConfiguration().locale.toString();
        if (TextUtils.isEmpty(locale)) {
            locale = mContext.getResources().getConfiguration().locale.toString();
        }
        final String language = locale.substring(0, 2);
        boolean partialMatchFound = false;
        int applicableSubtypeId = DEFAULT_SUBTYPE_ID;
        int applicableSubtypeId = defaultSubtypeId;
        for (int i = 0; i < subtypes.size(); ++i) {
            final String subtypeLocale = subtypes.get(i).getLocale();
            // An applicable subtype should be a keyboard subtype
            if (subtypes.get(i).getMode().equalsIgnoreCase("keyboard")) {
            // An applicable subtype should match "mode".
            if (subtypes.get(i).getMode().equalsIgnoreCase(mode)) {
                if (locale.equals(subtypeLocale)) {
                    // Exact match (e.g. system locale is "en_US" and subtype locale is "en_US")
                    applicableSubtypeId = i;
@@ -1950,34 +1966,129 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        return applicableSubtypeId;
    }

    // If there are no selected shortcuts, tries finding the most applicable ones.
    private Pair<InputMethodInfo, InputMethodSubtype>
            findLastResortApplicableShortcutInputMethodAndSubtypeLocked(String mode) {
        List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked();
        InputMethodInfo mostApplicableIMI = null;
        int mostApplicableSubtypeId = NOT_A_SUBTYPE_ID;
        boolean foundInSystemIME = false;

        // Search applicable subtype for each InputMethodInfo
        for (InputMethodInfo imi: imis) {
            int subtypeId = NOT_A_SUBTYPE_ID;
            if (mCurrentSubtype != null) {
                // 1. Search with the current subtype's locale and the enabled subtypes
                subtypeId = findLastResortApplicableSubtypeLocked(
                        mSettings.getEnabledInputMethodSubtypeListLocked(
                        imi), mode, mCurrentSubtype.getLocale(), NOT_A_SUBTYPE_ID);
                if (subtypeId == NOT_A_SUBTYPE_ID) {
                    // 2. Search with the current subtype's locale and all subtypes
                    subtypeId = findLastResortApplicableSubtypeLocked(imi.getSubtypes(),
                            mode, mCurrentSubtype.getLocale(), NOT_A_SUBTYPE_ID);
                }
            }
            // 3. Search with the system locale and the enabled subtypes
            if (subtypeId == NOT_A_SUBTYPE_ID) {
                subtypeId = findLastResortApplicableSubtypeLocked(
                        mSettings.getEnabledInputMethodSubtypeListLocked(
                        imi), mode, null, NOT_A_SUBTYPE_ID);
            }
            if (subtypeId == NOT_A_SUBTYPE_ID) {
                // 4. Search with the system locale and all subtypes
                subtypeId = findLastResortApplicableSubtypeLocked(imi.getSubtypes(),
                        mode, null, NOT_A_SUBTYPE_ID);
            }
            if (subtypeId != NOT_A_SUBTYPE_ID) {
                if (imi.getId().equals(mCurMethodId)) {
                    // The current input method is the most applicable IME.
                    mostApplicableIMI = imi;
                    mostApplicableSubtypeId = subtypeId;
                    break;
                } else if ((imi.getServiceInfo().applicationInfo.flags
                        & ApplicationInfo.FLAG_SYSTEM) != 0) {
                    // The system input method is 2nd applicable IME.
                    mostApplicableIMI = imi;
                    mostApplicableSubtypeId = subtypeId;
                    foundInSystemIME = true;
                } else if (!foundInSystemIME) {
                    mostApplicableIMI = imi;
                    mostApplicableSubtypeId = subtypeId;
                }
            }
        }
        if (DEBUG) {
            Slog.w(TAG, "Most applicable shortcut input method subtype was:"
                    + mostApplicableIMI.getId() + "," + mostApplicableSubtypeId);
        }
        if (mostApplicableIMI != null && mostApplicableSubtypeId != NOT_A_SUBTYPE_ID) {
            ArrayList<Parcelable> ret = new ArrayList<Parcelable>(2);
            return new Pair<InputMethodInfo, InputMethodSubtype> (mostApplicableIMI,
                    mostApplicableIMI.getSubtypes().get(mostApplicableSubtypeId));
        } else {
            return null;
        }
    }

    /**
     * @return Return the current subtype of this input method.
     */
    public InputMethodSubtype getCurrentInputMethodSubtype() {
        synchronized (mMethodMap) {
        boolean subtypeIsSelected = false;
        try {
            subtypeIsSelected = Settings.Secure.getInt(mContext.getContentResolver(),
                    Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE) != NOT_A_SUBTYPE_ID;
        } catch (SettingNotFoundException e) {
        }
        synchronized (mMethodMap) {
            if (!subtypeIsSelected || mCurrentSubtype == null) {
                String lastInputMethodId =
                        Settings.Secure.getString(mContext.getContentResolver(),
                                Settings.Secure.DEFAULT_INPUT_METHOD);
                String lastInputMethodId = Settings.Secure.getString(
                        mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
                int subtypeId = getSelectedInputMethodSubtypeId(lastInputMethodId);
                if (subtypeId == NOT_A_SUBTYPE_ID) {
                    subtypeId = findApplicableSubtypeLocked(lastInputMethodId);
                    InputMethodInfo imi = mMethodMap.get(lastInputMethodId);
                    if (imi != null) {
                        // If there are no selected subtypes, the framework will try to find
                        // the most applicable subtype from all subtypes whose mode is
                        // SUBTYPE_MODE_KEYBOARD. This is an exceptional case, so we will hardcode
                        // the mode.
                        subtypeId = findLastResortApplicableSubtypeLocked(imi.getSubtypes(),
                                SUBTYPE_MODE_KEYBOARD, null, DEFAULT_SUBTYPE_ID);
                    }
                }
                if (subtypeId != NOT_A_SUBTYPE_ID) {
                    mCurrentSubtype =
                            mMethodMap.get(lastInputMethodId).getSubtypes().get(subtypeId);
                } else {
                    mCurrentSubtype = null;
                }
            }
            return mCurrentSubtype;
        }
    }

    // TODO: We should change the return type from List to List<Parcelable>
    public List getShortcutInputMethodsAndSubtypes() {
        synchronized (mMethodMap) {
            if (mShortcutInputMethodsAndSubtypesObjectList != null) {
                // If there are no selected shortcut subtypes, the framework will try to find
                // the most applicable subtype from all subtypes whose mode is
                // SUBTYPE_MODE_VOICE. This is an exceptional case, so we will hardcode the mode.
                mShortcutInputMethodsAndSubtypes =
                        new ArrayList<Pair<InputMethodInfo, InputMethodSubtype>>();
                mShortcutInputMethodsAndSubtypes.add(
                        findLastResortApplicableShortcutInputMethodAndSubtypeLocked(
                                SUBTYPE_MODE_VOICE));
                mShortcutInputMethodsAndSubtypesObjectList = new ArrayList<Parcelable>();
                for (Pair ime: mShortcutInputMethodsAndSubtypes) {
                    mShortcutInputMethodsAndSubtypesObjectList.add(ime.first);
                    mShortcutInputMethodsAndSubtypesObjectList.add(ime.second);
                }
            }
            return mShortcutInputMethodsAndSubtypesObjectList;
        }
    }

    public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) {
        synchronized (mMethodMap) {
            if (subtype != null && mCurMethodId != null) {