aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java
blob: 2cec14240259bbb5f81afe6a3e6b6acebdba111f (about) (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.inputmethod.compat;

import android.graphics.Matrix;
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;

    /**
     * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the editor did not specify any type of this
     * character. Editor authors should not use this flag.
     */
    public static final int CHARACTER_RECT_TYPE_UNSPECIFIED = 0;

    /**
     * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the character is entirely visible.
     */
    public static final int CHARACTER_RECT_TYPE_FULLY_VISIBLE = 1;

    /**
     * Type for {@link #CHARACTER_RECT_TYPE_MASK}: some area of the character is invisible.
     */
    public static final int CHARACTER_RECT_TYPE_PARTIALLY_VISIBLE = 2;

    /**
     * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the character is entirely invisible.
     */
    public static final int CHARACTER_RECT_TYPE_INVISIBLE = 3;

    /**
     * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the editor gave up to calculate the rectangle
     * for this character. Input method authors should ignore the returned rectangle.
     */
    public static final int CHARACTER_RECT_TYPE_NOT_FEASIBLE = 4;

    private Object mInstance;

    private CursorAnchorInfoCompatWrapper(final Object instance) {
        mInstance = instance;
    }

    @UsedForTesting
    public static CursorAnchorInfoCompatWrapper fromObject(final Object instance) {
        if (!isAvailable()) {
            return new CursorAnchorInfoCompatWrapper(null);
        }
        return new CursorAnchorInfoCompatWrapper(instance);
    }

    private static final class FakeHolder {
        static CursorAnchorInfoCompatWrapper sInstance = new CursorAnchorInfoCompatWrapper(null);
    }

    @UsedForTesting
    public static CursorAnchorInfoCompatWrapper getFake() {
        return FakeHolder.sInstance;
    }

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

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

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

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

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