Home | History | Annotate | Download | only in compat
      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