Support more methods in the wrapper of CursorAnchorInfo
This CL add more compatibility wrapper methods for CursorAnchorInfo. This CL also adds more utility functions and types into CompatUtils to reduce explict cast operations. Change-Id: Id50165b552bbf28b832a6da13bf06eedcd2a190emain
parent
23f41049d6
commit
fa39ffcf84
|
@ -127,4 +127,92 @@ public final class CompatUtils {
|
||||||
Log.e(TAG, "Exception in setFieldValue", e);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,39 +21,8 @@ import android.graphics.RectF;
|
||||||
|
|
||||||
import com.android.inputmethod.annotations.UsedForTesting;
|
import com.android.inputmethod.annotations.UsedForTesting;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
@UsedForTesting
|
@UsedForTesting
|
||||||
public final class CursorAnchorInfoCompatWrapper {
|
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;
|
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;
|
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 Object mInstance;
|
||||||
|
|
||||||
private CursorAnchorInfoCompatWrapper(final Object instance) {
|
private CursorAnchorInfoCompatWrapper(final Object instance) {
|
||||||
|
@ -107,29 +119,42 @@ public final class CursorAnchorInfoCompatWrapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public CharSequence getComposingText() {
|
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() {
|
public int getComposingTextStart() {
|
||||||
if (mInstance == null || METHOD_GET_COMPOSING_TEXT_START == null) {
|
return sGetComposingTextStartMethod.invoke(mInstance);
|
||||||
return COMPOSING_TEXT_START_DEFAULT;
|
|
||||||
}
|
|
||||||
return (int) CompatUtils.invoke(mInstance, null, METHOD_GET_COMPOSING_TEXT_START);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Matrix getMatrix() {
|
public Matrix getMatrix() {
|
||||||
return (Matrix) CompatUtils.invoke(mInstance, null, METHOD_GET_MATRIX);
|
return sGetMatrixMethod.invoke(mInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RectF getCharacterRect(final int index) {
|
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) {
|
public int getCharacterRectFlags(final int index) {
|
||||||
if (mInstance == null || METHOD_GET_CHARACTER_RECT_FLAGS == null) {
|
return sGetCharacterRectFlagsMethod.invoke(mInstance, index);
|
||||||
return CHARACTER_RECT_TYPE_UNSPECIFIED;
|
}
|
||||||
}
|
|
||||||
return (int) CompatUtils.invoke(mInstance, null, METHOD_GET_CHARACTER_RECT_FLAGS, index);
|
public float getInsertionMarkerBaseline() {
|
||||||
|
return sGetInsertionMarkerBaselineMethod.invoke(mInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue