CursorAnchorInfoCompatWrapper.java revision deff9495f771a54b8ea55e07e0d44a0302ea9e10
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.inputmethod.compat;
18
19import android.graphics.Matrix;
20import android.graphics.RectF;
21
22import com.android.inputmethod.annotations.UsedForTesting;
23
24import java.lang.reflect.Method;
25
26@UsedForTesting
27public final class CursorAnchorInfoCompatWrapper {
28    // Note that CursorAnchorInfo has been introduced in API level XX (Build.VERSION_CODE.LXX).
29    private static Class<?> getCursorAnchorInfoClass() {
30        try {
31            return Class.forName("android.view.inputmethod.CursorAnchorInfo");
32        } catch (ClassNotFoundException e) {
33            return null;
34        }
35    }
36    private static final Class<?> CLASS;
37    private static final Method METHOD_GET_CHARACTER_RECT;
38    private static final Method METHOD_GET_CHARACTER_RECT_FLAGS;
39    private static final Method METHOD_GET_COMPOSING_TEXT;
40    private static final Method METHOD_GET_COMPOSING_TEXT_START;
41    private static final Method METHOD_GET_MATRIX;
42    static {
43        CLASS = getCursorAnchorInfoClass();
44        METHOD_GET_CHARACTER_RECT = CompatUtils.getMethod(CLASS, "getCharacterRect", int.class);
45        METHOD_GET_CHARACTER_RECT_FLAGS = CompatUtils.getMethod(CLASS, "getCharacterRectFlags",
46                int.class);
47        METHOD_GET_COMPOSING_TEXT = CompatUtils.getMethod(CLASS, "getComposingText");
48        METHOD_GET_COMPOSING_TEXT_START = CompatUtils.getMethod(CLASS, "getComposingTextStart");
49        METHOD_GET_MATRIX = CompatUtils.getMethod(CLASS, "getMatrix");
50    }
51
52    @UsedForTesting
53    public static boolean isAvailable() {
54        return CLASS != null;
55    }
56
57    public static final int CHARACTER_RECT_TYPE_MASK = 0x0f;
58
59    /**
60     * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the editor did not specify any type of this
61     * character. Editor authors should not use this flag.
62     */
63    public static final int CHARACTER_RECT_TYPE_UNSPECIFIED = 0;
64
65    /**
66     * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the character is entirely visible.
67     */
68    public static final int CHARACTER_RECT_TYPE_FULLY_VISIBLE = 1;
69
70    /**
71     * Type for {@link #CHARACTER_RECT_TYPE_MASK}: some area of the character is invisible.
72     */
73    public static final int CHARACTER_RECT_TYPE_PARTIALLY_VISIBLE = 2;
74
75    /**
76     * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the character is entirely invisible.
77     */
78    public static final int CHARACTER_RECT_TYPE_INVISIBLE = 3;
79
80    /**
81     * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the editor gave up to calculate the rectangle
82     * for this character. Input method authors should ignore the returned rectangle.
83     */
84    public static final int CHARACTER_RECT_TYPE_NOT_FEASIBLE = 4;
85
86    private Object mInstance;
87
88    private CursorAnchorInfoCompatWrapper(final Object instance) {
89        mInstance = instance;
90    }
91
92    @UsedForTesting
93    public static CursorAnchorInfoCompatWrapper fromObject(final Object instance) {
94        if (!isAvailable()) {
95            return new CursorAnchorInfoCompatWrapper(null);
96        }
97        return new CursorAnchorInfoCompatWrapper(instance);
98    }
99
100    private static final class FakeHolder {
101        static CursorAnchorInfoCompatWrapper sInstance = new CursorAnchorInfoCompatWrapper(null);
102    }
103
104    @UsedForTesting
105    public static CursorAnchorInfoCompatWrapper getFake() {
106        return FakeHolder.sInstance;
107    }
108
109    public CharSequence getComposingText() {
110        return (CharSequence) CompatUtils.invoke(mInstance, null, METHOD_GET_COMPOSING_TEXT);
111    }
112
113    private static int COMPOSING_TEXT_START_DEFAULT = -1;
114    public int getComposingTextStart() {
115        if (mInstance == null || METHOD_GET_COMPOSING_TEXT_START == null) {
116            return COMPOSING_TEXT_START_DEFAULT;
117        }
118        return (int) CompatUtils.invoke(mInstance, null, METHOD_GET_COMPOSING_TEXT_START);
119    }
120
121    public Matrix getMatrix() {
122        return (Matrix) CompatUtils.invoke(mInstance, null, METHOD_GET_MATRIX);
123    }
124
125    public RectF getCharacterRect(final int index) {
126        return (RectF) CompatUtils.invoke(mInstance, null, METHOD_GET_CHARACTER_RECT, index);
127    }
128
129    public int getCharacterRectFlags(final int index) {
130        if (mInstance == null || METHOD_GET_CHARACTER_RECT_FLAGS == null) {
131            return CHARACTER_RECT_TYPE_UNSPECIFIED;
132        }
133        return (int) CompatUtils.invoke(mInstance, null, METHOD_GET_CHARACTER_RECT_FLAGS, index);
134    }
135}
136