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 17 package com.android.inputmethod.compat; 18 19 import android.graphics.Matrix; 20 import android.graphics.RectF; 21 22 import com.android.inputmethod.annotations.UsedForTesting; 23 24 @UsedForTesting 25 public final class CursorAnchorInfoCompatWrapper { 26 27 /** 28 * The insertion marker or character bounds have at least one visible region. 29 */ 30 public static final int FLAG_HAS_VISIBLE_REGION = 0x01; 31 32 /** 33 * The insertion marker or character bounds have at least one invisible (clipped) region. 34 */ 35 public static final int FLAG_HAS_INVISIBLE_REGION = 0x02; 36 37 /** 38 * The insertion marker or character bounds is placed at right-to-left (RTL) character. 39 */ 40 public static final int FLAG_IS_RTL = 0x04; 41 42 // Note that CursorAnchorInfo has been introduced in API level XX (Build.VERSION_CODE.LXX). 43 private static final CompatUtils.ClassWrapper sCursorAnchorInfoClass; 44 private static final CompatUtils.ToIntMethodWrapper sGetSelectionStartMethod; 45 private static final CompatUtils.ToIntMethodWrapper sGetSelectionEndMethod; 46 private static final CompatUtils.ToObjectMethodWrapper<RectF> sGetCharacterBoundsMethod; 47 private static final CompatUtils.ToIntMethodWrapper sGetCharacterBoundsFlagsMethod; 48 private static final CompatUtils.ToObjectMethodWrapper<CharSequence> sGetComposingTextMethod; 49 private static final CompatUtils.ToIntMethodWrapper sGetComposingTextStartMethod; 50 private static final CompatUtils.ToFloatMethodWrapper sGetInsertionMarkerBaselineMethod; 51 private static final CompatUtils.ToFloatMethodWrapper sGetInsertionMarkerBottomMethod; 52 private static final CompatUtils.ToFloatMethodWrapper sGetInsertionMarkerHorizontalMethod; 53 private static final CompatUtils.ToFloatMethodWrapper sGetInsertionMarkerTopMethod; 54 private static final CompatUtils.ToObjectMethodWrapper<Matrix> sGetMatrixMethod; 55 private static final CompatUtils.ToIntMethodWrapper sGetInsertionMarkerFlagsMethod; 56 57 private static int INVALID_TEXT_INDEX = -1; 58 static { 59 sCursorAnchorInfoClass = CompatUtils.getClassWrapper( 60 "android.view.inputmethod.CursorAnchorInfo"); 61 sGetSelectionStartMethod = sCursorAnchorInfoClass.getPrimitiveMethod( 62 "getSelectionStart", INVALID_TEXT_INDEX); 63 sGetSelectionEndMethod = sCursorAnchorInfoClass.getPrimitiveMethod( 64 "getSelectionEnd", INVALID_TEXT_INDEX); 65 sGetCharacterBoundsMethod = sCursorAnchorInfoClass.getMethod( 66 "getCharacterBounds", (RectF)null, int.class); 67 sGetCharacterBoundsFlagsMethod = sCursorAnchorInfoClass.getPrimitiveMethod( 68 "getCharacterBoundsFlags", 0, int.class); 69 sGetComposingTextMethod = sCursorAnchorInfoClass.getMethod( 70 "getComposingText", (CharSequence)null); 71 sGetComposingTextStartMethod = sCursorAnchorInfoClass.getPrimitiveMethod( 72 "getComposingTextStart", INVALID_TEXT_INDEX); 73 sGetInsertionMarkerBaselineMethod = sCursorAnchorInfoClass.getPrimitiveMethod( 74 "getInsertionMarkerBaseline", 0.0f); 75 sGetInsertionMarkerBottomMethod = sCursorAnchorInfoClass.getPrimitiveMethod( 76 "getInsertionMarkerBottom", 0.0f); 77 sGetInsertionMarkerHorizontalMethod = sCursorAnchorInfoClass.getPrimitiveMethod( 78 "getInsertionMarkerHorizontal", 0.0f); 79 sGetInsertionMarkerTopMethod = sCursorAnchorInfoClass.getPrimitiveMethod( 80 "getInsertionMarkerTop", 0.0f); 81 sGetMatrixMethod = sCursorAnchorInfoClass.getMethod("getMatrix", (Matrix)null); 82 sGetInsertionMarkerFlagsMethod = sCursorAnchorInfoClass.getPrimitiveMethod( 83 "getInsertionMarkerFlags", 0); 84 } 85 86 @UsedForTesting 87 public boolean isAvailable() { 88 return sCursorAnchorInfoClass.exists() && mInstance != null; 89 } 90 91 private Object mInstance; 92 93 private CursorAnchorInfoCompatWrapper(final Object instance) { 94 mInstance = instance; 95 } 96 97 @UsedForTesting 98 public static CursorAnchorInfoCompatWrapper fromObject(final Object instance) { 99 if (!sCursorAnchorInfoClass.exists()) { 100 return new CursorAnchorInfoCompatWrapper(null); 101 } 102 return new CursorAnchorInfoCompatWrapper(instance); 103 } 104 105 private static final class FakeHolder { 106 static CursorAnchorInfoCompatWrapper sInstance = new CursorAnchorInfoCompatWrapper(null); 107 } 108 109 @UsedForTesting 110 public static CursorAnchorInfoCompatWrapper getFake() { 111 return FakeHolder.sInstance; 112 } 113 114 public int getSelectionStart() { 115 return sGetSelectionStartMethod.invoke(mInstance); 116 } 117 118 public int getSelectionEnd() { 119 return sGetSelectionEndMethod.invoke(mInstance); 120 } 121 122 public CharSequence getComposingText() { 123 return sGetComposingTextMethod.invoke(mInstance); 124 } 125 126 public int getComposingTextStart() { 127 return sGetComposingTextStartMethod.invoke(mInstance); 128 } 129 130 public Matrix getMatrix() { 131 return sGetMatrixMethod.invoke(mInstance); 132 } 133 134 public RectF getCharacterBounds(final int index) { 135 return sGetCharacterBoundsMethod.invoke(mInstance, index); 136 } 137 138 public int getCharacterBoundsFlags(final int index) { 139 return sGetCharacterBoundsFlagsMethod.invoke(mInstance, index); 140 } 141 142 public float getInsertionMarkerBaseline() { 143 return sGetInsertionMarkerBaselineMethod.invoke(mInstance); 144 } 145 146 public float getInsertionMarkerBottom() { 147 return sGetInsertionMarkerBottomMethod.invoke(mInstance); 148 } 149 150 public float getInsertionMarkerHorizontal() { 151 return sGetInsertionMarkerHorizontalMethod.invoke(mInstance); 152 } 153 154 public float getInsertionMarkerTop() { 155 return sGetInsertionMarkerTopMethod.invoke(mInstance); 156 } 157 158 public int getInsertionMarkerFlags() { 159 return sGetInsertionMarkerFlagsMethod.invoke(mInstance); 160 } 161 } 162