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

Commit 3cf13d12 authored by Yohei Yukawa's avatar Yohei Yukawa Committed by Android Git Automerger
Browse files

am 17aeaa75: am fa39ffcf: Support more methods in the wrapper of CursorAnchorInfo

* commit '17aeaa75':
  Support more methods in the wrapper of CursorAnchorInfo
parents 9be350bc 17aeaa75
Loading
Loading
Loading
Loading
+88 −0
Original line number Diff line number Diff line
@@ -127,4 +127,92 @@ public final class CompatUtils {
            Log.e(TAG, "Exception in setFieldValue", e);
        }
    }

    public static ClassWrapper getClassWrapper(final String className) {
        return new ClassWrapper(getClass(className));
    }

    public static final class ClassWrapper {
        private final Class<?> mClass;
        public ClassWrapper(final Class<?> targetClass) {
            mClass = targetClass;
        }

        public boolean exists() {
            return mClass != null;
        }

        public <T> ToObjectMethodWrapper<T> getMethod(final String name,
                final T defaultValue, final Class<?>... parameterTypes) {
            return new ToObjectMethodWrapper<T>(CompatUtils.getMethod(mClass, name, parameterTypes),
                    defaultValue);
        }

        public ToIntMethodWrapper getPrimitiveMethod(final String name, final int defaultValue,
                final Class<?>... parameterTypes) {
            return new ToIntMethodWrapper(CompatUtils.getMethod(mClass, name, parameterTypes),
                    defaultValue);
        }

        public ToFloatMethodWrapper getPrimitiveMethod(final String name, final float defaultValue,
                final Class<?>... parameterTypes) {
            return new ToFloatMethodWrapper(CompatUtils.getMethod(mClass, name, parameterTypes),
                    defaultValue);
        }

        public ToBooleanMethodWrapper getPrimitiveMethod(final String name,
                final boolean defaultValue, final Class<?>... parameterTypes) {
            return new ToBooleanMethodWrapper(CompatUtils.getMethod(mClass, name, parameterTypes),
                    defaultValue);
        }
    }

    public static final class ToObjectMethodWrapper<T> {
        private final Method mMethod;
        private final T mDefaultValue;
        public ToObjectMethodWrapper(final Method method, final T defaultValue) {
            mMethod = method;
            mDefaultValue = defaultValue;
        }
        @SuppressWarnings("unchecked")
        public T invoke(final Object receiver, final Object... args) {
            return (T) CompatUtils.invoke(receiver, mDefaultValue, mMethod, args);
        }
    }

    public static final class ToIntMethodWrapper {
        private final Method mMethod;
        private final int mDefaultValue;
        public ToIntMethodWrapper(final Method method, final int defaultValue) {
            mMethod = method;
            mDefaultValue = defaultValue;
        }
        public int invoke(final Object receiver, final Object... args) {
            return (int) CompatUtils.invoke(receiver, mDefaultValue, mMethod, args);
        }
    }

    public static final class ToFloatMethodWrapper {
        private final Method mMethod;
        private final float mDefaultValue;
        public ToFloatMethodWrapper(final Method method, final float defaultValue) {
            mMethod = method;
            mDefaultValue = defaultValue;
        }
        public float invoke(final Object receiver, final Object... args) {
            return (float) CompatUtils.invoke(receiver, mDefaultValue, mMethod, args);
        }
    }

    public static final class ToBooleanMethodWrapper {
        private final Method mMethod;
        private final boolean mDefaultValue;
        public ToBooleanMethodWrapper(final Method method, final boolean defaultValue) {
            mMethod = method;
            mDefaultValue = defaultValue;
        }
        public boolean invoke(final Object receiver, final Object... args) {
            return (boolean) CompatUtils.invoke(receiver, mDefaultValue, mMethod, args);
        }
    }
}
+68 −43
Original line number Diff line number Diff line
@@ -21,39 +21,8 @@ import android.graphics.RectF;

import com.android.inputmethod.annotations.UsedForTesting;

import java.lang.reflect.Method;

@UsedForTesting
public final class CursorAnchorInfoCompatWrapper {
    // Note that CursorAnchorInfo has been introduced in API level XX (Build.VERSION_CODE.LXX).
    private static Class<?> getCursorAnchorInfoClass() {
        try {
            return Class.forName("android.view.inputmethod.CursorAnchorInfo");
        } catch (ClassNotFoundException e) {
            return null;
        }
    }
    private static final Class<?> CLASS;
    private static final Method METHOD_GET_CHARACTER_RECT;
    private static final Method METHOD_GET_CHARACTER_RECT_FLAGS;
    private static final Method METHOD_GET_COMPOSING_TEXT;
    private static final Method METHOD_GET_COMPOSING_TEXT_START;
    private static final Method METHOD_GET_MATRIX;
    static {
        CLASS = getCursorAnchorInfoClass();
        METHOD_GET_CHARACTER_RECT = CompatUtils.getMethod(CLASS, "getCharacterRect", int.class);
        METHOD_GET_CHARACTER_RECT_FLAGS = CompatUtils.getMethod(CLASS, "getCharacterRectFlags",
                int.class);
        METHOD_GET_COMPOSING_TEXT = CompatUtils.getMethod(CLASS, "getComposingText");
        METHOD_GET_COMPOSING_TEXT_START = CompatUtils.getMethod(CLASS, "getComposingTextStart");
        METHOD_GET_MATRIX = CompatUtils.getMethod(CLASS, "getMatrix");
    }

    @UsedForTesting
    public static boolean isAvailable() {
        return CLASS != null;
    }

    public static final int CHARACTER_RECT_TYPE_MASK = 0x0f;

    /**
@@ -83,6 +52,49 @@ public final class CursorAnchorInfoCompatWrapper {
     */
    public static final int CHARACTER_RECT_TYPE_NOT_FEASIBLE = 4;

    // Note that CursorAnchorInfo has been introduced in API level XX (Build.VERSION_CODE.LXX).
    private static final CompatUtils.ClassWrapper sCursorAnchorInfoClass;
    private static final CompatUtils.ToObjectMethodWrapper<RectF> sGetCharacterRectMethod;
    private static final CompatUtils.ToIntMethodWrapper sGetCharacterRectFlagsMethod;
    private static final CompatUtils.ToObjectMethodWrapper<CharSequence> sGetComposingTextMethod;
    private static final CompatUtils.ToIntMethodWrapper sGetComposingTextStartMethod;
    private static final CompatUtils.ToFloatMethodWrapper sGetInsertionMarkerBaselineMethod;
    private static final CompatUtils.ToFloatMethodWrapper sGetInsertionMarkerBottomMethod;
    private static final CompatUtils.ToFloatMethodWrapper sGetInsertionMarkerHorizontalMethod;
    private static final CompatUtils.ToFloatMethodWrapper sGetInsertionMarkerTopMethod;
    private static final CompatUtils.ToObjectMethodWrapper<Matrix> sGetMatrixMethod;
    private static final CompatUtils.ToBooleanMethodWrapper sIsInsertionMarkerClippedMethod;

    private static int COMPOSING_TEXT_START_DEFAULT = -1;
    static {
        sCursorAnchorInfoClass = CompatUtils.getClassWrapper(
                "android.view.inputmethod.CursorAnchorInfo");
        sGetCharacterRectMethod = sCursorAnchorInfoClass.getMethod(
                "getCharacterRect", (RectF)null, int.class);
        sGetCharacterRectFlagsMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
                "getCharacterRectFlags", CHARACTER_RECT_TYPE_UNSPECIFIED, int.class);
        sGetComposingTextMethod = sCursorAnchorInfoClass.getMethod(
                "getComposingText", (CharSequence)null);
        sGetComposingTextStartMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
                "getComposingTextStart", COMPOSING_TEXT_START_DEFAULT);
        sGetInsertionMarkerBaselineMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
                "getInsertionMarkerBaseline", 0.0f);
        sGetInsertionMarkerBottomMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
                "getInsertionMarkerBottom", 0.0f);
        sGetInsertionMarkerHorizontalMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
                "getInsertionMarkerHorizontal", 0.0f);
        sGetInsertionMarkerTopMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
                "getInsertionMarkerTop", 0.0f);
        sGetMatrixMethod = sCursorAnchorInfoClass.getMethod("getMatrix", (Matrix)null);
        sIsInsertionMarkerClippedMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
                "isInsertionMarkerClipped", false);
    }

    @UsedForTesting
    public static boolean isAvailable() {
        return sCursorAnchorInfoClass.exists();
    }

    private Object mInstance;

    private CursorAnchorInfoCompatWrapper(final Object instance) {
@@ -107,29 +119,42 @@ public final class CursorAnchorInfoCompatWrapper {
    }

    public CharSequence getComposingText() {
        return (CharSequence) CompatUtils.invoke(mInstance, null, METHOD_GET_COMPOSING_TEXT);
        return sGetComposingTextMethod.invoke(mInstance);
    }

    private static int COMPOSING_TEXT_START_DEFAULT = -1;
    public int getComposingTextStart() {
        if (mInstance == null || METHOD_GET_COMPOSING_TEXT_START == null) {
            return COMPOSING_TEXT_START_DEFAULT;
        }
        return (int) CompatUtils.invoke(mInstance, null, METHOD_GET_COMPOSING_TEXT_START);
        return sGetComposingTextStartMethod.invoke(mInstance);
    }

    public Matrix getMatrix() {
        return (Matrix) CompatUtils.invoke(mInstance, null, METHOD_GET_MATRIX);
        return sGetMatrixMethod.invoke(mInstance);
    }

    public RectF getCharacterRect(final int index) {
        return (RectF) CompatUtils.invoke(mInstance, null, METHOD_GET_CHARACTER_RECT, index);
        return sGetCharacterRectMethod.invoke(mInstance, index);
    }

    public int getCharacterRectFlags(final int index) {
        if (mInstance == null || METHOD_GET_CHARACTER_RECT_FLAGS == null) {
            return CHARACTER_RECT_TYPE_UNSPECIFIED;
        return sGetCharacterRectFlagsMethod.invoke(mInstance, index);
    }

    public float getInsertionMarkerBaseline() {
        return sGetInsertionMarkerBaselineMethod.invoke(mInstance);
    }
        return (int) CompatUtils.invoke(mInstance, null, METHOD_GET_CHARACTER_RECT_FLAGS, index);

    public float getInsertionMarkerBottom() {
        return sGetInsertionMarkerBottomMethod.invoke(mInstance);
    }

    public float getInsertionMarkerHorizontal() {
        return sGetInsertionMarkerHorizontalMethod.invoke(mInstance);
    }

    public float getInsertionMarkerTop() {
        return sGetInsertionMarkerTopMethod.invoke(mInstance);
    }

    public boolean isInsertionMarkerClipped() {
        return sIsInsertionMarkerClippedMethod.invoke(mInstance);
    }
}