119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa/*
219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa * Copyright (C) 2016 The Android Open Source Project
319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa *
419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa * Licensed under the Apache License, Version 2.0 (the "License");
519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa * you may not use this file except in compliance with the License.
619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa * You may obtain a copy of the License at
719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa *
819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa *      http://www.apache.org/licenses/LICENSE-2.0
919a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa *
1019a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa * Unless required by applicable law or agreed to in writing, software
1119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa * distributed under the License is distributed on an "AS IS" BASIS,
1219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa * See the License for the specific language governing permissions and
1419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa * limitations under the License.
1519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa */
1619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa
1719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawapackage android.view.inputmethod;
1819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa
1919a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawaimport android.annotation.IntDef;
2019a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawaimport android.annotation.NonNull;
2119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawaimport android.annotation.Nullable;
2219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa
2319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawaimport java.lang.annotation.Retention;
2419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawaimport java.lang.reflect.Method;
2519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawaimport java.lang.reflect.Modifier;
2619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawaimport java.util.Collections;
2719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawaimport java.util.Map;
2819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawaimport java.util.WeakHashMap;
2919a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa
3019a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawaimport static java.lang.annotation.RetentionPolicy.SOURCE;
3119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa
3219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa/**
3319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa * @hide
3419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa */
3519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawapublic final class InputConnectionInspector {
3619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa
3719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    @Retention(SOURCE)
3819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    @IntDef({MissingMethodFlags.GET_SELECTED_TEXT,
3919a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            MissingMethodFlags.SET_COMPOSING_REGION,
4019a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            MissingMethodFlags.COMMIT_CORRECTION,
4119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            MissingMethodFlags.REQUEST_CURSOR_UPDATES,
4219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            MissingMethodFlags.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS,
4319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            MissingMethodFlags.GET_HANDLER,
4419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    })
4519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    public @interface MissingMethodFlags {
4619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        /**
4719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa         * {@link InputConnection#getSelectedText(int)} is available in
4819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa         * {@link android.os.Build.VERSION_CODES#GINGERBREAD} and later.
4919a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa         */
5019a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        int GET_SELECTED_TEXT = 1 << 0;
5119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        /**
5219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa         * {@link InputConnection#setComposingRegion(int, int)} is available in
5319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa         * {@link android.os.Build.VERSION_CODES#GINGERBREAD} and later.
5419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa         */
5519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        int SET_COMPOSING_REGION = 1 << 1;
5619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        /**
5719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa         * {@link InputConnection#commitCorrection(CorrectionInfo)} is available in
5819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa         * {@link android.os.Build.VERSION_CODES#HONEYCOMB} and later.
5919a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa         */
6019a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        int COMMIT_CORRECTION = 1 << 2;
6119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        /**
6219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa         * {@link InputConnection#requestCursorUpdates(int)} is available in
6319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa         * {@link android.os.Build.VERSION_CODES#LOLLIPOP} and later.
6419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa         */
6519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        int REQUEST_CURSOR_UPDATES = 1 << 3;
6619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        /**
6719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa         * {@link InputConnection#deleteSurroundingTextInCodePoints(int, int)}} is available in
6819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa         * {@link android.os.Build.VERSION_CODES#N} and later.
6919a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa         */
7019a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        int DELETE_SURROUNDING_TEXT_IN_CODE_POINTS = 1 << 4;
7119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        /**
7219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa         * {@link InputConnection#deleteSurroundingTextInCodePoints(int, int)}} is available in
7319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa         * {@link android.os.Build.VERSION_CODES#N} and later.
7419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa         */
7519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        int GET_HANDLER = 1 << 5;
769f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa        /**
779f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa         * {@link InputConnection#closeConnection()}} is available in
789f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa         * {@link android.os.Build.VERSION_CODES#N} and later.
799f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa         */
809f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa        int CLOSE_CONNECTION = 1 << 6;
8119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    }
8219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa
8319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    private static final Map<Class, Integer> sMissingMethodsMap = Collections.synchronizedMap(
8419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            new WeakHashMap<>());
8519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa
8619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    @MissingMethodFlags
8719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    public static int getMissingMethodFlags(@Nullable final InputConnection ic) {
8819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        if (ic == null) {
8919a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            return 0;
9019a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
9119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        // Optimization for a known class.
9219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        if (ic instanceof BaseInputConnection) {
9319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            return 0;
9419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
9519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        // Optimization for a known class.
9619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        if (ic instanceof InputConnectionWrapper) {
9719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            return ((InputConnectionWrapper) ic).getMissingMethodFlags();
9819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
9919a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        return getMissingMethodFlagsInternal(ic.getClass());
10019a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    }
10119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa
10219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    @MissingMethodFlags
10319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    public static int getMissingMethodFlagsInternal(@NonNull final Class clazz) {
10419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        final Integer cachedFlags = sMissingMethodsMap.get(clazz);
10519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        if (cachedFlags != null) {
10619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            return cachedFlags;
10719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
10819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        int flags = 0;
10919a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        if (!hasGetSelectedText(clazz)) {
11019a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            flags |= MissingMethodFlags.GET_SELECTED_TEXT;
11119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
11219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        if (!hasSetComposingRegion(clazz)) {
11319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            flags |= MissingMethodFlags.SET_COMPOSING_REGION;
11419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
11519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        if (!hasCommitCorrection(clazz)) {
11619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            flags |= MissingMethodFlags.COMMIT_CORRECTION;
11719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
11819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        if (!hasRequestCursorUpdate(clazz)) {
11919a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            flags |= MissingMethodFlags.REQUEST_CURSOR_UPDATES;
12019a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
12119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        if (!hasDeleteSurroundingTextInCodePoints(clazz)) {
12219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            flags |= MissingMethodFlags.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS;
12319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
12419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        if (!hasGetHandler(clazz)) {
12519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            flags |= MissingMethodFlags.GET_HANDLER;
12619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
1279f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa        if (!hasCloseConnection(clazz)) {
1289f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa            flags |= MissingMethodFlags.CLOSE_CONNECTION;
1299f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa        }
13019a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        sMissingMethodsMap.put(clazz, flags);
13119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        return flags;
13219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    }
13319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa
13419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    private static boolean hasGetSelectedText(@NonNull final Class clazz) {
13519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        try {
13619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            final Method method = clazz.getMethod("getSelectedText", int.class);
13719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            return !Modifier.isAbstract(method.getModifiers());
13819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        } catch (NoSuchMethodException e) {
13919a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            return false;
14019a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
14119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    }
14219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa
14319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    private static boolean hasSetComposingRegion(@NonNull final Class clazz) {
14419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        try {
14519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            final Method method = clazz.getMethod("setComposingRegion", int.class, int.class);
14619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            return !Modifier.isAbstract(method.getModifiers());
14719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        } catch (NoSuchMethodException e) {
14819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            return false;
14919a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
15019a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    }
15119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa
15219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    private static boolean hasCommitCorrection(@NonNull final Class clazz) {
15319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        try {
15419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            final Method method = clazz.getMethod("commitCorrection", CorrectionInfo.class);
15519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            return !Modifier.isAbstract(method.getModifiers());
15619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        } catch (NoSuchMethodException e) {
15719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            return false;
15819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
15919a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    }
16019a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa
16119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    private static boolean hasRequestCursorUpdate(@NonNull final Class clazz) {
16219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        try {
16319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            final Method method = clazz.getMethod("requestCursorUpdates", int.class);
16419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            return !Modifier.isAbstract(method.getModifiers());
16519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        } catch (NoSuchMethodException e) {
16619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            return false;
16719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
16819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    }
16919a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa
17019a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    private static boolean hasDeleteSurroundingTextInCodePoints(@NonNull final Class clazz) {
17119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        try {
17219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            final Method method = clazz.getMethod("deleteSurroundingTextInCodePoints", int.class,
17319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa                    int.class);
17419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            return !Modifier.isAbstract(method.getModifiers());
17519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        } catch (NoSuchMethodException e) {
17619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            return false;
17719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
17819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    }
17919a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa
18019a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    private static boolean hasGetHandler(@NonNull final Class clazz) {
18119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        try {
18219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            final Method method = clazz.getMethod("getHandler");
18319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            return !Modifier.isAbstract(method.getModifiers());
18419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        } catch (NoSuchMethodException e) {
18519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            return false;
18619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
18719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    }
18819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa
1899f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa    private static boolean hasCloseConnection(@NonNull final Class clazz) {
1909f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa        try {
1919f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa            final Method method = clazz.getMethod("closeConnection");
1929f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa            return !Modifier.isAbstract(method.getModifiers());
1939f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa        } catch (NoSuchMethodException e) {
1949f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa            return false;
1959f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa        }
1969f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa    }
1979f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa
19819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    public static String getMissingMethodFlagsAsString(@MissingMethodFlags final int flags) {
19919a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        final StringBuilder sb = new StringBuilder();
20019a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        boolean isEmpty = true;
20119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        if ((flags & MissingMethodFlags.GET_SELECTED_TEXT) != 0) {
20219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            sb.append("getSelectedText(int)");
20319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            isEmpty = false;
20419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
20519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        if ((flags & MissingMethodFlags.SET_COMPOSING_REGION) != 0) {
20619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            if (!isEmpty) {
20719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa                sb.append(",");
20819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            }
20919a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            sb.append("setComposingRegion(int, int)");
21019a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            isEmpty = false;
21119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
21219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        if ((flags & MissingMethodFlags.COMMIT_CORRECTION) != 0) {
21319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            if (!isEmpty) {
21419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa                sb.append(",");
21519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            }
21619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            sb.append("commitCorrection(CorrectionInfo)");
21719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            isEmpty = false;
21819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
21919a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        if ((flags & MissingMethodFlags.REQUEST_CURSOR_UPDATES) != 0) {
22019a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            if (!isEmpty) {
22119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa                sb.append(",");
22219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            }
22319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            sb.append("requestCursorUpdate(int)");
22419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            isEmpty = false;
22519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
22619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        if ((flags & MissingMethodFlags.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS) != 0) {
22719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            if (!isEmpty) {
22819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa                sb.append(",");
22919a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            }
23019a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            sb.append("deleteSurroundingTextInCodePoints(int, int)");
23119a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            isEmpty = false;
23219a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
23319a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        if ((flags & MissingMethodFlags.GET_HANDLER) != 0) {
23419a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            if (!isEmpty) {
23519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa                sb.append(",");
23619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            }
23719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa            sb.append("getHandler()");
23819a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        }
2399f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa        if ((flags & MissingMethodFlags.CLOSE_CONNECTION) != 0) {
2409f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa            if (!isEmpty) {
2419f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa                sb.append(",");
2429f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa            }
2439f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa            sb.append("closeConnection()");
2449f9afe526d1f8ad17c628fc9e1e839725ffe913eYohei Yukawa        }
24519a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa        return sb.toString();
24619a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa    }
24719a80a1e807acd00bec999eaac7812da6ffce954Yohei Yukawa}
248