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: Id50165b552bbf28b832a6da13bf06eedcd2a190e
main
Yohei Yukawa 2014-08-20 08:48:42 +09:00
parent 23f41049d6
commit fa39ffcf84
2 changed files with 156 additions and 43 deletions

View File

@ -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);
}
}
}

View File

@ -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);
}
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);
}
}