Loading java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java +104 −82 Original line number Diff line number Diff line Loading @@ -16,13 +16,20 @@ package com.android.inputmethod.compat; import android.annotation.TargetApi; import android.graphics.Matrix; import android.graphics.RectF; import android.os.Build; import android.view.inputmethod.CursorAnchorInfo; import com.android.inputmethod.annotations.UsedForTesting; import javax.annotation.Nonnull; import javax.annotation.Nullable; @UsedForTesting public final class CursorAnchorInfoCompatWrapper { /** * A wrapper for {@link CursorAnchorInfo}, which has been introduced in API Level 21. You can use * this wrapper to avoid direct dependency on newly introduced types. */ public class CursorAnchorInfoCompatWrapper { /** * The insertion marker or character bounds have at least one visible region. Loading @@ -39,123 +46,138 @@ public final class CursorAnchorInfoCompatWrapper { */ public static final int FLAG_IS_RTL = 0x04; // Note that CursorAnchorInfo has been introduced in API level XX (Build.VERSION_CODE.LXX). private static final CompatUtils.ClassWrapper sCursorAnchorInfoClass; private static final CompatUtils.ToIntMethodWrapper sGetSelectionStartMethod; private static final CompatUtils.ToIntMethodWrapper sGetSelectionEndMethod; private static final CompatUtils.ToObjectMethodWrapper<RectF> sGetCharacterBoundsMethod; private static final CompatUtils.ToIntMethodWrapper sGetCharacterBoundsFlagsMethod; 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.ToIntMethodWrapper sGetInsertionMarkerFlagsMethod; private static int INVALID_TEXT_INDEX = -1; static { sCursorAnchorInfoClass = CompatUtils.getClassWrapper( "android.view.inputmethod.CursorAnchorInfo"); sGetSelectionStartMethod = sCursorAnchorInfoClass.getPrimitiveMethod( "getSelectionStart", INVALID_TEXT_INDEX); sGetSelectionEndMethod = sCursorAnchorInfoClass.getPrimitiveMethod( "getSelectionEnd", INVALID_TEXT_INDEX); sGetCharacterBoundsMethod = sCursorAnchorInfoClass.getMethod( "getCharacterBounds", (RectF)null, int.class); sGetCharacterBoundsFlagsMethod = sCursorAnchorInfoClass.getPrimitiveMethod( "getCharacterBoundsFlags", 0, int.class); sGetComposingTextMethod = sCursorAnchorInfoClass.getMethod( "getComposingText", (CharSequence)null); sGetComposingTextStartMethod = sCursorAnchorInfoClass.getPrimitiveMethod( "getComposingTextStart", INVALID_TEXT_INDEX); 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); sGetInsertionMarkerFlagsMethod = sCursorAnchorInfoClass.getPrimitiveMethod( "getInsertionMarkerFlags", 0); } @UsedForTesting public boolean isAvailable() { return sCursorAnchorInfoClass.exists() && mInstance != null; } private Object mInstance; private CursorAnchorInfoCompatWrapper(final Object instance) { mInstance = instance; } @UsedForTesting public static CursorAnchorInfoCompatWrapper fromObject(final Object instance) { if (!sCursorAnchorInfoClass.exists()) { 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; private CursorAnchorInfoCompatWrapper() { // This class is not publicly instantiable. } @TargetApi(BuildCompatUtils.VERSION_CODES_LXX) @Nullable public static CursorAnchorInfoCompatWrapper wrap(@Nullable final CursorAnchorInfo instance) { if (Build.VERSION.SDK_INT < BuildCompatUtils.VERSION_CODES_LXX) { return null; } if (instance == null) { return null; } return new RealWrapper(instance); } public int getSelectionStart() { return sGetSelectionStartMethod.invoke(mInstance); throw new UnsupportedOperationException("not supported."); } public int getSelectionEnd() { return sGetSelectionEndMethod.invoke(mInstance); throw new UnsupportedOperationException("not supported."); } public CharSequence getComposingText() { return sGetComposingTextMethod.invoke(mInstance); throw new UnsupportedOperationException("not supported."); } public int getComposingTextStart() { return sGetComposingTextStartMethod.invoke(mInstance); throw new UnsupportedOperationException("not supported."); } public Matrix getMatrix() { return sGetMatrixMethod.invoke(mInstance); throw new UnsupportedOperationException("not supported."); } public RectF getCharacterBounds(final int index) { return sGetCharacterBoundsMethod.invoke(mInstance, index); throw new UnsupportedOperationException("not supported."); } public int getCharacterBoundsFlags(final int index) { return sGetCharacterBoundsFlagsMethod.invoke(mInstance, index); throw new UnsupportedOperationException("not supported."); } public float getInsertionMarkerBaseline() { return sGetInsertionMarkerBaselineMethod.invoke(mInstance); throw new UnsupportedOperationException("not supported."); } public float getInsertionMarkerBottom() { return sGetInsertionMarkerBottomMethod.invoke(mInstance); throw new UnsupportedOperationException("not supported."); } public float getInsertionMarkerHorizontal() { return sGetInsertionMarkerHorizontalMethod.invoke(mInstance); throw new UnsupportedOperationException("not supported."); } public float getInsertionMarkerTop() { return sGetInsertionMarkerTopMethod.invoke(mInstance); throw new UnsupportedOperationException("not supported."); } public int getInsertionMarkerFlags() { return sGetInsertionMarkerFlagsMethod.invoke(mInstance); throw new UnsupportedOperationException("not supported."); } @TargetApi(BuildCompatUtils.VERSION_CODES_LXX) private static final class RealWrapper extends CursorAnchorInfoCompatWrapper { @Nonnull private final CursorAnchorInfo mInstance; public RealWrapper(@Nonnull final CursorAnchorInfo info) { mInstance = info; } @Override public int getSelectionStart() { return mInstance.getSelectionStart(); } @Override public int getSelectionEnd() { return mInstance.getSelectionEnd(); } @Override public CharSequence getComposingText() { return mInstance.getComposingText(); } @Override public int getComposingTextStart() { return mInstance.getComposingTextStart(); } @Override public Matrix getMatrix() { return mInstance.getMatrix(); } @Override public RectF getCharacterBounds(final int index) { return mInstance.getCharacterBounds(index); } @Override public int getCharacterBoundsFlags(final int index) { return mInstance.getCharacterBoundsFlags(index); } @Override public float getInsertionMarkerBaseline() { return mInstance.getInsertionMarkerBaseline(); } @Override public float getInsertionMarkerBottom() { return mInstance.getInsertionMarkerBottom(); } @Override public float getInsertionMarkerHorizontal() { return mInstance.getInsertionMarkerHorizontal(); } @Override public float getInsertionMarkerTop() { return mInstance.getInsertionMarkerTop(); } @Override public int getInsertionMarkerFlags() { return mInstance.getInsertionMarkerFlags(); } } } java/src/com/android/inputmethod/keyboard/TextDecorator.java +4 −2 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import com.android.inputmethod.compat.CursorAnchorInfoCompatWrapper; import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper; import javax.annotation.Nonnull; import javax.annotation.Nullable; /** * A controller class of the add-to-dictionary indicator (a.k.a. TextDecorator). This class Loading @@ -56,6 +57,7 @@ public class TextDecorator { private String mWaitingWord = null; private int mWaitingCursorStart = INVALID_CURSOR_INDEX; private int mWaitingCursorEnd = INVALID_CURSOR_INDEX; @Nullable private CursorAnchorInfoCompatWrapper mCursorAnchorInfoWrapper = null; @Nonnull Loading Loading @@ -150,7 +152,7 @@ public class TextDecorator { * mode.</p> * @param info the compatibility wrapper object for the received {@link CursorAnchorInfo}. */ public void onUpdateCursorAnchorInfo(final CursorAnchorInfoCompatWrapper info) { public void onUpdateCursorAnchorInfo(@Nullable final CursorAnchorInfoCompatWrapper info) { mCursorAnchorInfoWrapper = info; // Do not use layoutLater() to minimize the latency. layoutImmediately(); Loading Loading @@ -182,7 +184,7 @@ public class TextDecorator { private void layoutMain() { final CursorAnchorInfoCompatWrapper info = mCursorAnchorInfoWrapper; if (info == null || !info.isAvailable()) { if (info == null) { cancelLayoutInternalExpectedly("CursorAnchorInfo isn't available."); return; } Loading java/src/com/android/inputmethod/latin/LatinIME.java +8 −14 Original line number Diff line number Diff line Loading @@ -795,22 +795,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { onExtractTextViewPreDraw(); return true; } }; private void onExtractTextViewPreDraw() { // CursorAnchorInfo is available on L and later. if (Build.VERSION.SDK_INT < Build.VERSION_CODES.L) { return; // CursorAnchorInfo is used on L and later. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.L) { if (isFullscreenMode() && mExtractEditText != null) { mInputLogic.onUpdateCursorAnchorInfo( CursorAnchorInfoUtils.extractFromTextView(mExtractEditText)); } if (!isFullscreenMode() || mExtractEditText == null) { return; } final CursorAnchorInfo info = CursorAnchorInfoUtils.getCursorAnchorInfo(mExtractEditText); mInputLogic.onUpdateCursorAnchorInfo(CursorAnchorInfoCompatWrapper.fromObject(info)); return true; } }; @Override public void setCandidatesView(final View view) { Loading Loading @@ -1094,7 +1088,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (isFullscreenMode()) { return; } mInputLogic.onUpdateCursorAnchorInfo(CursorAnchorInfoCompatWrapper.fromObject(info)); mInputLogic.onUpdateCursorAnchorInfo(CursorAnchorInfoCompatWrapper.wrap(info)); } /** Loading java/src/com/android/inputmethod/latin/utils/CursorAnchorInfoUtils.java +29 −2 Original line number Diff line number Diff line Loading @@ -16,10 +16,12 @@ package com.android.inputmethod.latin.utils; import android.annotation.TargetApi; import android.graphics.Matrix; import android.graphics.Rect; import android.inputmethodservice.ExtractEditText; import android.inputmethodservice.InputMethodService; import android.os.Build; import android.text.Layout; import android.text.Spannable; import android.view.View; Loading @@ -27,6 +29,12 @@ import android.view.ViewParent; import android.view.inputmethod.CursorAnchorInfo; import android.widget.TextView; import com.android.inputmethod.compat.BuildCompatUtils; import com.android.inputmethod.compat.CursorAnchorInfoCompatWrapper; import javax.annotation.Nonnull; import javax.annotation.Nullable; /** * This class allows input methods to extract {@link CursorAnchorInfo} directly from the given * {@link TextView}. This is useful and even necessary to support full-screen mode where the default Loading Loading @@ -76,14 +84,33 @@ public final class CursorAnchorInfoUtils { return true; } /** * Extracts {@link CursorAnchorInfoCompatWrapper} from the given {@link TextView}. * @param textView the target text view from which {@link CursorAnchorInfoCompatWrapper} is to * be extracted. * @return the {@link CursorAnchorInfoCompatWrapper} object based on the current layout. * {@code null} if {@code Build.VERSION.SDK_INT} is 20 or prior or {@link TextView} is not * ready to provide layout information. */ @Nullable public static CursorAnchorInfoCompatWrapper extractFromTextView( @Nonnull final TextView textView) { if (Build.VERSION.SDK_INT < BuildCompatUtils.VERSION_CODES_LXX) { return null; } return CursorAnchorInfoCompatWrapper.wrap(extractFromTextViewInternal(textView)); } /** * Returns {@link CursorAnchorInfo} from the given {@link TextView}. * @param textView the target text view from which {@link CursorAnchorInfo} is to be extracted. * @return the {@link CursorAnchorInfo} object based on the current layout. {@code null} if it * is not feasible. */ public static CursorAnchorInfo getCursorAnchorInfo(final TextView textView) { Layout layout = textView.getLayout(); @TargetApi(BuildCompatUtils.VERSION_CODES_LXX) @Nullable private static CursorAnchorInfo extractFromTextViewInternal(@Nonnull final TextView textView) { final Layout layout = textView.getLayout(); if (layout == null) { return null; } Loading Loading
java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java +104 −82 Original line number Diff line number Diff line Loading @@ -16,13 +16,20 @@ package com.android.inputmethod.compat; import android.annotation.TargetApi; import android.graphics.Matrix; import android.graphics.RectF; import android.os.Build; import android.view.inputmethod.CursorAnchorInfo; import com.android.inputmethod.annotations.UsedForTesting; import javax.annotation.Nonnull; import javax.annotation.Nullable; @UsedForTesting public final class CursorAnchorInfoCompatWrapper { /** * A wrapper for {@link CursorAnchorInfo}, which has been introduced in API Level 21. You can use * this wrapper to avoid direct dependency on newly introduced types. */ public class CursorAnchorInfoCompatWrapper { /** * The insertion marker or character bounds have at least one visible region. Loading @@ -39,123 +46,138 @@ public final class CursorAnchorInfoCompatWrapper { */ public static final int FLAG_IS_RTL = 0x04; // Note that CursorAnchorInfo has been introduced in API level XX (Build.VERSION_CODE.LXX). private static final CompatUtils.ClassWrapper sCursorAnchorInfoClass; private static final CompatUtils.ToIntMethodWrapper sGetSelectionStartMethod; private static final CompatUtils.ToIntMethodWrapper sGetSelectionEndMethod; private static final CompatUtils.ToObjectMethodWrapper<RectF> sGetCharacterBoundsMethod; private static final CompatUtils.ToIntMethodWrapper sGetCharacterBoundsFlagsMethod; 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.ToIntMethodWrapper sGetInsertionMarkerFlagsMethod; private static int INVALID_TEXT_INDEX = -1; static { sCursorAnchorInfoClass = CompatUtils.getClassWrapper( "android.view.inputmethod.CursorAnchorInfo"); sGetSelectionStartMethod = sCursorAnchorInfoClass.getPrimitiveMethod( "getSelectionStart", INVALID_TEXT_INDEX); sGetSelectionEndMethod = sCursorAnchorInfoClass.getPrimitiveMethod( "getSelectionEnd", INVALID_TEXT_INDEX); sGetCharacterBoundsMethod = sCursorAnchorInfoClass.getMethod( "getCharacterBounds", (RectF)null, int.class); sGetCharacterBoundsFlagsMethod = sCursorAnchorInfoClass.getPrimitiveMethod( "getCharacterBoundsFlags", 0, int.class); sGetComposingTextMethod = sCursorAnchorInfoClass.getMethod( "getComposingText", (CharSequence)null); sGetComposingTextStartMethod = sCursorAnchorInfoClass.getPrimitiveMethod( "getComposingTextStart", INVALID_TEXT_INDEX); 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); sGetInsertionMarkerFlagsMethod = sCursorAnchorInfoClass.getPrimitiveMethod( "getInsertionMarkerFlags", 0); } @UsedForTesting public boolean isAvailable() { return sCursorAnchorInfoClass.exists() && mInstance != null; } private Object mInstance; private CursorAnchorInfoCompatWrapper(final Object instance) { mInstance = instance; } @UsedForTesting public static CursorAnchorInfoCompatWrapper fromObject(final Object instance) { if (!sCursorAnchorInfoClass.exists()) { 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; private CursorAnchorInfoCompatWrapper() { // This class is not publicly instantiable. } @TargetApi(BuildCompatUtils.VERSION_CODES_LXX) @Nullable public static CursorAnchorInfoCompatWrapper wrap(@Nullable final CursorAnchorInfo instance) { if (Build.VERSION.SDK_INT < BuildCompatUtils.VERSION_CODES_LXX) { return null; } if (instance == null) { return null; } return new RealWrapper(instance); } public int getSelectionStart() { return sGetSelectionStartMethod.invoke(mInstance); throw new UnsupportedOperationException("not supported."); } public int getSelectionEnd() { return sGetSelectionEndMethod.invoke(mInstance); throw new UnsupportedOperationException("not supported."); } public CharSequence getComposingText() { return sGetComposingTextMethod.invoke(mInstance); throw new UnsupportedOperationException("not supported."); } public int getComposingTextStart() { return sGetComposingTextStartMethod.invoke(mInstance); throw new UnsupportedOperationException("not supported."); } public Matrix getMatrix() { return sGetMatrixMethod.invoke(mInstance); throw new UnsupportedOperationException("not supported."); } public RectF getCharacterBounds(final int index) { return sGetCharacterBoundsMethod.invoke(mInstance, index); throw new UnsupportedOperationException("not supported."); } public int getCharacterBoundsFlags(final int index) { return sGetCharacterBoundsFlagsMethod.invoke(mInstance, index); throw new UnsupportedOperationException("not supported."); } public float getInsertionMarkerBaseline() { return sGetInsertionMarkerBaselineMethod.invoke(mInstance); throw new UnsupportedOperationException("not supported."); } public float getInsertionMarkerBottom() { return sGetInsertionMarkerBottomMethod.invoke(mInstance); throw new UnsupportedOperationException("not supported."); } public float getInsertionMarkerHorizontal() { return sGetInsertionMarkerHorizontalMethod.invoke(mInstance); throw new UnsupportedOperationException("not supported."); } public float getInsertionMarkerTop() { return sGetInsertionMarkerTopMethod.invoke(mInstance); throw new UnsupportedOperationException("not supported."); } public int getInsertionMarkerFlags() { return sGetInsertionMarkerFlagsMethod.invoke(mInstance); throw new UnsupportedOperationException("not supported."); } @TargetApi(BuildCompatUtils.VERSION_CODES_LXX) private static final class RealWrapper extends CursorAnchorInfoCompatWrapper { @Nonnull private final CursorAnchorInfo mInstance; public RealWrapper(@Nonnull final CursorAnchorInfo info) { mInstance = info; } @Override public int getSelectionStart() { return mInstance.getSelectionStart(); } @Override public int getSelectionEnd() { return mInstance.getSelectionEnd(); } @Override public CharSequence getComposingText() { return mInstance.getComposingText(); } @Override public int getComposingTextStart() { return mInstance.getComposingTextStart(); } @Override public Matrix getMatrix() { return mInstance.getMatrix(); } @Override public RectF getCharacterBounds(final int index) { return mInstance.getCharacterBounds(index); } @Override public int getCharacterBoundsFlags(final int index) { return mInstance.getCharacterBoundsFlags(index); } @Override public float getInsertionMarkerBaseline() { return mInstance.getInsertionMarkerBaseline(); } @Override public float getInsertionMarkerBottom() { return mInstance.getInsertionMarkerBottom(); } @Override public float getInsertionMarkerHorizontal() { return mInstance.getInsertionMarkerHorizontal(); } @Override public float getInsertionMarkerTop() { return mInstance.getInsertionMarkerTop(); } @Override public int getInsertionMarkerFlags() { return mInstance.getInsertionMarkerFlags(); } } }
java/src/com/android/inputmethod/keyboard/TextDecorator.java +4 −2 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import com.android.inputmethod.compat.CursorAnchorInfoCompatWrapper; import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper; import javax.annotation.Nonnull; import javax.annotation.Nullable; /** * A controller class of the add-to-dictionary indicator (a.k.a. TextDecorator). This class Loading @@ -56,6 +57,7 @@ public class TextDecorator { private String mWaitingWord = null; private int mWaitingCursorStart = INVALID_CURSOR_INDEX; private int mWaitingCursorEnd = INVALID_CURSOR_INDEX; @Nullable private CursorAnchorInfoCompatWrapper mCursorAnchorInfoWrapper = null; @Nonnull Loading Loading @@ -150,7 +152,7 @@ public class TextDecorator { * mode.</p> * @param info the compatibility wrapper object for the received {@link CursorAnchorInfo}. */ public void onUpdateCursorAnchorInfo(final CursorAnchorInfoCompatWrapper info) { public void onUpdateCursorAnchorInfo(@Nullable final CursorAnchorInfoCompatWrapper info) { mCursorAnchorInfoWrapper = info; // Do not use layoutLater() to minimize the latency. layoutImmediately(); Loading Loading @@ -182,7 +184,7 @@ public class TextDecorator { private void layoutMain() { final CursorAnchorInfoCompatWrapper info = mCursorAnchorInfoWrapper; if (info == null || !info.isAvailable()) { if (info == null) { cancelLayoutInternalExpectedly("CursorAnchorInfo isn't available."); return; } Loading
java/src/com/android/inputmethod/latin/LatinIME.java +8 −14 Original line number Diff line number Diff line Loading @@ -795,22 +795,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { onExtractTextViewPreDraw(); return true; } }; private void onExtractTextViewPreDraw() { // CursorAnchorInfo is available on L and later. if (Build.VERSION.SDK_INT < Build.VERSION_CODES.L) { return; // CursorAnchorInfo is used on L and later. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.L) { if (isFullscreenMode() && mExtractEditText != null) { mInputLogic.onUpdateCursorAnchorInfo( CursorAnchorInfoUtils.extractFromTextView(mExtractEditText)); } if (!isFullscreenMode() || mExtractEditText == null) { return; } final CursorAnchorInfo info = CursorAnchorInfoUtils.getCursorAnchorInfo(mExtractEditText); mInputLogic.onUpdateCursorAnchorInfo(CursorAnchorInfoCompatWrapper.fromObject(info)); return true; } }; @Override public void setCandidatesView(final View view) { Loading Loading @@ -1094,7 +1088,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (isFullscreenMode()) { return; } mInputLogic.onUpdateCursorAnchorInfo(CursorAnchorInfoCompatWrapper.fromObject(info)); mInputLogic.onUpdateCursorAnchorInfo(CursorAnchorInfoCompatWrapper.wrap(info)); } /** Loading
java/src/com/android/inputmethod/latin/utils/CursorAnchorInfoUtils.java +29 −2 Original line number Diff line number Diff line Loading @@ -16,10 +16,12 @@ package com.android.inputmethod.latin.utils; import android.annotation.TargetApi; import android.graphics.Matrix; import android.graphics.Rect; import android.inputmethodservice.ExtractEditText; import android.inputmethodservice.InputMethodService; import android.os.Build; import android.text.Layout; import android.text.Spannable; import android.view.View; Loading @@ -27,6 +29,12 @@ import android.view.ViewParent; import android.view.inputmethod.CursorAnchorInfo; import android.widget.TextView; import com.android.inputmethod.compat.BuildCompatUtils; import com.android.inputmethod.compat.CursorAnchorInfoCompatWrapper; import javax.annotation.Nonnull; import javax.annotation.Nullable; /** * This class allows input methods to extract {@link CursorAnchorInfo} directly from the given * {@link TextView}. This is useful and even necessary to support full-screen mode where the default Loading Loading @@ -76,14 +84,33 @@ public final class CursorAnchorInfoUtils { return true; } /** * Extracts {@link CursorAnchorInfoCompatWrapper} from the given {@link TextView}. * @param textView the target text view from which {@link CursorAnchorInfoCompatWrapper} is to * be extracted. * @return the {@link CursorAnchorInfoCompatWrapper} object based on the current layout. * {@code null} if {@code Build.VERSION.SDK_INT} is 20 or prior or {@link TextView} is not * ready to provide layout information. */ @Nullable public static CursorAnchorInfoCompatWrapper extractFromTextView( @Nonnull final TextView textView) { if (Build.VERSION.SDK_INT < BuildCompatUtils.VERSION_CODES_LXX) { return null; } return CursorAnchorInfoCompatWrapper.wrap(extractFromTextViewInternal(textView)); } /** * Returns {@link CursorAnchorInfo} from the given {@link TextView}. * @param textView the target text view from which {@link CursorAnchorInfo} is to be extracted. * @return the {@link CursorAnchorInfo} object based on the current layout. {@code null} if it * is not feasible. */ public static CursorAnchorInfo getCursorAnchorInfo(final TextView textView) { Layout layout = textView.getLayout(); @TargetApi(BuildCompatUtils.VERSION_CODES_LXX) @Nullable private static CursorAnchorInfo extractFromTextViewInternal(@Nonnull final TextView textView) { final Layout layout = textView.getLayout(); if (layout == null) { return null; } Loading