am 97b46504: am ead70974: am 27ccbeb4: am cd119050: Support CursorAnchorInfo in the full-screen mode
* commit '97b465044fb6e0dfece02e7bd6c639ded295a547': Support CursorAnchorInfo in the full-screen modemain
commit
41175b7364
|
@ -24,7 +24,6 @@ import android.os.Message;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.inputmethod.CursorAnchorInfo;
|
|
||||||
|
|
||||||
import com.android.inputmethod.annotations.UsedForTesting;
|
import com.android.inputmethod.annotations.UsedForTesting;
|
||||||
import com.android.inputmethod.compat.CursorAnchorInfoCompatWrapper;
|
import com.android.inputmethod.compat.CursorAnchorInfoCompatWrapper;
|
||||||
|
@ -154,13 +153,11 @@ public class TextDecorator {
|
||||||
* {@code false} is the input method is finishing the full screen mode.
|
* {@code false} is the input method is finishing the full screen mode.
|
||||||
*/
|
*/
|
||||||
public void notifyFullScreenMode(final boolean fullScreenMode) {
|
public void notifyFullScreenMode(final boolean fullScreenMode) {
|
||||||
final boolean currentFullScreenMode = mIsFullScreenMode;
|
final boolean fullScreenModeChanged = (mIsFullScreenMode != fullScreenMode);
|
||||||
if (!currentFullScreenMode && fullScreenMode) {
|
|
||||||
// Currently full screen mode is not supported.
|
|
||||||
// TODO: Support full screen mode.
|
|
||||||
mUiOperator.hideUi();
|
|
||||||
}
|
|
||||||
mIsFullScreenMode = fullScreenMode;
|
mIsFullScreenMode = fullScreenMode;
|
||||||
|
if (fullScreenModeChanged) {
|
||||||
|
layoutLater();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -183,11 +180,6 @@ public class TextDecorator {
|
||||||
* @param info the compatibility wrapper object for the received {@link CursorAnchorInfo}.
|
* @param info the compatibility wrapper object for the received {@link CursorAnchorInfo}.
|
||||||
*/
|
*/
|
||||||
public void onUpdateCursorAnchorInfo(final CursorAnchorInfoCompatWrapper info) {
|
public void onUpdateCursorAnchorInfo(final CursorAnchorInfoCompatWrapper info) {
|
||||||
if (mIsFullScreenMode) {
|
|
||||||
// TODO: Consider to call InputConnection#requestCursorAnchorInfo to disable the
|
|
||||||
// event callback to suppress unnecessary event callbacks.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mCursorAnchorInfoWrapper = info;
|
mCursorAnchorInfoWrapper = info;
|
||||||
// Do not use layoutLater() to minimize the latency.
|
// Do not use layoutLater() to minimize the latency.
|
||||||
layoutImmediately();
|
layoutImmediately();
|
||||||
|
@ -240,11 +232,6 @@ public class TextDecorator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void layoutMain() {
|
private void layoutMain() {
|
||||||
if (mIsFullScreenMode) {
|
|
||||||
cancelLayoutInternalUnexpectedly("Full screen mode isn't yet supported.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mMode != MODE_COMMIT && mMode != MODE_ADD_TO_DICTIONARY) {
|
if (mMode != MODE_COMMIT && mMode != MODE_ADD_TO_DICTIONARY) {
|
||||||
if (mMode == MODE_NONE) {
|
if (mMode == MODE_NONE) {
|
||||||
cancelLayoutInternalExpectedly("Not ready for layouting.");
|
cancelLayoutInternalExpectedly("Not ready for layouting.");
|
||||||
|
@ -328,7 +315,7 @@ public class TextDecorator {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!TextUtils.isEmpty(composingText)) {
|
if (!mIsFullScreenMode && !TextUtils.isEmpty(composingText)) {
|
||||||
// This is an unexpected case.
|
// This is an unexpected case.
|
||||||
// TODO: Document this.
|
// TODO: Document this.
|
||||||
mUiOperator.hideUi();
|
mUiOperator.hideUi();
|
||||||
|
|
|
@ -46,6 +46,7 @@ import android.view.Gravity;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup.LayoutParams;
|
import android.view.ViewGroup.LayoutParams;
|
||||||
|
import android.view.ViewTreeObserver;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.view.inputmethod.CompletionInfo;
|
import android.view.inputmethod.CompletionInfo;
|
||||||
|
@ -53,6 +54,7 @@ import android.view.inputmethod.CursorAnchorInfo;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.view.inputmethod.InputMethod;
|
import android.view.inputmethod.InputMethod;
|
||||||
import android.view.inputmethod.InputMethodSubtype;
|
import android.view.inputmethod.InputMethodSubtype;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.android.inputmethod.accessibility.AccessibilityUtils;
|
import com.android.inputmethod.accessibility.AccessibilityUtils;
|
||||||
import com.android.inputmethod.annotations.UsedForTesting;
|
import com.android.inputmethod.annotations.UsedForTesting;
|
||||||
|
@ -85,6 +87,7 @@ import com.android.inputmethod.latin.suggestions.SuggestionStripView;
|
||||||
import com.android.inputmethod.latin.suggestions.SuggestionStripViewAccessor;
|
import com.android.inputmethod.latin.suggestions.SuggestionStripViewAccessor;
|
||||||
import com.android.inputmethod.latin.utils.ApplicationUtils;
|
import com.android.inputmethod.latin.utils.ApplicationUtils;
|
||||||
import com.android.inputmethod.latin.utils.CapsModeUtils;
|
import com.android.inputmethod.latin.utils.CapsModeUtils;
|
||||||
|
import com.android.inputmethod.latin.utils.CursorAnchorInfoUtils;
|
||||||
import com.android.inputmethod.latin.utils.CoordinateUtils;
|
import com.android.inputmethod.latin.utils.CoordinateUtils;
|
||||||
import com.android.inputmethod.latin.utils.DialogUtils;
|
import com.android.inputmethod.latin.utils.DialogUtils;
|
||||||
import com.android.inputmethod.latin.utils.DistracterFilterCheckingExactMatchesAndSuggestions;
|
import com.android.inputmethod.latin.utils.DistracterFilterCheckingExactMatchesAndSuggestions;
|
||||||
|
@ -152,6 +155,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
// TODO: Move these {@link View}s to {@link KeyboardSwitcher}.
|
// TODO: Move these {@link View}s to {@link KeyboardSwitcher}.
|
||||||
private View mInputView;
|
private View mInputView;
|
||||||
private SuggestionStripView mSuggestionStripView;
|
private SuggestionStripView mSuggestionStripView;
|
||||||
|
private TextView mExtractEditText;
|
||||||
|
|
||||||
private RichInputMethodManager mRichImm;
|
private RichInputMethodManager mRichImm;
|
||||||
@UsedForTesting final KeyboardSwitcher mKeyboardSwitcher;
|
@UsedForTesting final KeyboardSwitcher mKeyboardSwitcher;
|
||||||
|
@ -755,6 +759,49 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
mInputLogic.setTextDecoratorUi(new TextDecoratorUi(this, view));
|
mInputLogic.setTextDecoratorUi(new TextDecoratorUi(this, view));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setExtractView(final View view) {
|
||||||
|
final TextView prevExtractEditText = mExtractEditText;
|
||||||
|
super.setExtractView(view);
|
||||||
|
TextView nextExtractEditText = null;
|
||||||
|
if (view != null) {
|
||||||
|
final View extractEditText = view.findViewById(android.R.id.inputExtractEditText);
|
||||||
|
if (extractEditText instanceof TextView) {
|
||||||
|
nextExtractEditText = (TextView)extractEditText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (prevExtractEditText == nextExtractEditText) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK && prevExtractEditText != null) {
|
||||||
|
prevExtractEditText.getViewTreeObserver().removeOnPreDrawListener(
|
||||||
|
mExtractTextViewPreDrawListener);
|
||||||
|
}
|
||||||
|
mExtractEditText = nextExtractEditText;
|
||||||
|
if (ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK && mExtractEditText != null) {
|
||||||
|
mExtractEditText.getViewTreeObserver().addOnPreDrawListener(
|
||||||
|
mExtractTextViewPreDrawListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ViewTreeObserver.OnPreDrawListener mExtractTextViewPreDrawListener =
|
||||||
|
new ViewTreeObserver.OnPreDrawListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreDraw() {
|
||||||
|
onExtractTextViewPreDraw();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private void onExtractTextViewPreDraw() {
|
||||||
|
if (!ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK || !isFullscreenMode()
|
||||||
|
|| mExtractEditText == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final CursorAnchorInfo info = CursorAnchorInfoUtils.getCursorAnchorInfo(mExtractEditText);
|
||||||
|
mInputLogic.onUpdateCursorAnchorInfo(CursorAnchorInfoCompatWrapper.fromObject(info));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCandidatesView(final View view) {
|
public void setCandidatesView(final View view) {
|
||||||
// To ensure that CandidatesView will never be set.
|
// To ensure that CandidatesView will never be set.
|
||||||
|
@ -1023,9 +1070,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
// We cannot mark this method as @Override until new SDK becomes publicly available.
|
// We cannot mark this method as @Override until new SDK becomes publicly available.
|
||||||
// @Override
|
// @Override
|
||||||
public void onUpdateCursorAnchorInfo(final CursorAnchorInfo info) {
|
public void onUpdateCursorAnchorInfo(final CursorAnchorInfo info) {
|
||||||
if (ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK) {
|
if (!ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK || isFullscreenMode()) {
|
||||||
mInputLogic.onUpdateCursorAnchorInfo(CursorAnchorInfoCompatWrapper.fromObject(info));
|
return;
|
||||||
}
|
}
|
||||||
|
mInputLogic.onUpdateCursorAnchorInfo(CursorAnchorInfoCompatWrapper.fromObject(info));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,236 @@
|
||||||
|
/*
|
||||||
|
* 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.latin.utils;
|
||||||
|
|
||||||
|
import android.graphics.Matrix;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.inputmethodservice.ExtractEditText;
|
||||||
|
import android.inputmethodservice.InputMethodService;
|
||||||
|
import android.text.Layout;
|
||||||
|
import android.text.Spannable;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewParent;
|
||||||
|
import android.view.inputmethod.CursorAnchorInfo;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* {@link InputMethodService#onUpdateCursorAnchorInfo(CursorAnchorInfo)} event callback must be
|
||||||
|
* ignored because it reports the character locations of the target application rather than
|
||||||
|
* characters on {@link ExtractEditText}.
|
||||||
|
*/
|
||||||
|
public final class CursorAnchorInfoUtils {
|
||||||
|
private CursorAnchorInfoUtils() {
|
||||||
|
// This helper class is not instantiable.
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isPositionVisible(final View view, final float positionX,
|
||||||
|
final float positionY) {
|
||||||
|
final float[] position = new float[] { positionX, positionY };
|
||||||
|
View currentView = view;
|
||||||
|
|
||||||
|
while (currentView != null) {
|
||||||
|
if (currentView != view) {
|
||||||
|
// Local scroll is already taken into account in positionX/Y
|
||||||
|
position[0] -= currentView.getScrollX();
|
||||||
|
position[1] -= currentView.getScrollY();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (position[0] < 0 || position[1] < 0 ||
|
||||||
|
position[0] > currentView.getWidth() || position[1] > currentView.getHeight()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!currentView.getMatrix().isIdentity()) {
|
||||||
|
currentView.getMatrix().mapPoints(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
position[0] += currentView.getLeft();
|
||||||
|
position[1] += currentView.getTop();
|
||||||
|
|
||||||
|
final ViewParent parent = currentView.getParent();
|
||||||
|
if (parent instanceof View) {
|
||||||
|
currentView = (View) parent;
|
||||||
|
} else {
|
||||||
|
// We've reached the ViewRoot, stop iterating
|
||||||
|
currentView = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We've been able to walk up the view hierarchy and the position was never clipped
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
if (layout == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final CursorAnchorInfo.Builder builder = new CursorAnchorInfo.Builder();
|
||||||
|
|
||||||
|
final int selectionStart = textView.getSelectionStart();
|
||||||
|
builder.setSelectionRange(selectionStart, textView.getSelectionEnd());
|
||||||
|
|
||||||
|
// Construct transformation matrix from view local coordinates to screen coordinates.
|
||||||
|
final Matrix viewToScreenMatrix = new Matrix(textView.getMatrix());
|
||||||
|
final int[] viewOriginInScreen = new int[2];
|
||||||
|
textView.getLocationOnScreen(viewOriginInScreen);
|
||||||
|
viewToScreenMatrix.postTranslate(viewOriginInScreen[0], viewOriginInScreen[1]);
|
||||||
|
builder.setMatrix(viewToScreenMatrix);
|
||||||
|
|
||||||
|
if (layout.getLineCount() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final Rect lineBoundsWithoutOffset = new Rect();
|
||||||
|
final Rect lineBoundsWithOffset = new Rect();
|
||||||
|
layout.getLineBounds(0, lineBoundsWithoutOffset);
|
||||||
|
textView.getLineBounds(0, lineBoundsWithOffset);
|
||||||
|
final float viewportToContentHorizontalOffset = lineBoundsWithOffset.left
|
||||||
|
- lineBoundsWithoutOffset.left - textView.getScrollX();
|
||||||
|
final float viewportToContentVerticalOffset = lineBoundsWithOffset.top
|
||||||
|
- lineBoundsWithoutOffset.top - textView.getScrollY();
|
||||||
|
|
||||||
|
final CharSequence text = textView.getText();
|
||||||
|
if (text instanceof Spannable) {
|
||||||
|
// Here we assume that the composing text is marked as SPAN_COMPOSING flag. This is not
|
||||||
|
// necessarily true, but basically works.
|
||||||
|
int composingTextStart = text.length();
|
||||||
|
int composingTextEnd = 0;
|
||||||
|
final Spannable spannable = (Spannable) text;
|
||||||
|
final Object[] spans = spannable.getSpans(0, text.length(), Object.class);
|
||||||
|
for (Object span : spans) {
|
||||||
|
final int spanFlag = spannable.getSpanFlags(span);
|
||||||
|
if ((spanFlag & Spannable.SPAN_COMPOSING) != 0) {
|
||||||
|
composingTextStart = Math.min(composingTextStart,
|
||||||
|
spannable.getSpanStart(span));
|
||||||
|
composingTextEnd = Math.max(composingTextEnd, spannable.getSpanEnd(span));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean hasComposingText =
|
||||||
|
(0 <= composingTextStart) && (composingTextStart < composingTextEnd);
|
||||||
|
if (hasComposingText) {
|
||||||
|
final CharSequence composingText = text.subSequence(composingTextStart,
|
||||||
|
composingTextEnd);
|
||||||
|
builder.setComposingText(composingTextStart, composingText);
|
||||||
|
|
||||||
|
final int minLine = layout.getLineForOffset(composingTextStart);
|
||||||
|
final int maxLine = layout.getLineForOffset(composingTextEnd - 1);
|
||||||
|
for (int line = minLine; line <= maxLine; ++line) {
|
||||||
|
final int lineStart = layout.getLineStart(line);
|
||||||
|
final int lineEnd = layout.getLineEnd(line);
|
||||||
|
final int offsetStart = Math.max(lineStart, composingTextStart);
|
||||||
|
final int offsetEnd = Math.min(lineEnd, composingTextEnd);
|
||||||
|
final boolean ltrLine =
|
||||||
|
layout.getParagraphDirection(line) == Layout.DIR_LEFT_TO_RIGHT;
|
||||||
|
final float[] widths = new float[offsetEnd - offsetStart];
|
||||||
|
layout.getPaint().getTextWidths(text, offsetStart, offsetEnd, widths);
|
||||||
|
final float top = layout.getLineTop(line);
|
||||||
|
final float bottom = layout.getLineBottom(line);
|
||||||
|
for (int offset = offsetStart; offset < offsetEnd; ++offset) {
|
||||||
|
final float charWidth = widths[offset - offsetStart];
|
||||||
|
final boolean isRtl = layout.isRtlCharAt(offset);
|
||||||
|
final float primary = layout.getPrimaryHorizontal(offset);
|
||||||
|
final float secondary = layout.getSecondaryHorizontal(offset);
|
||||||
|
// TODO: This doesn't work perfectly for text with custom styles and TAB
|
||||||
|
// chars.
|
||||||
|
final float left;
|
||||||
|
final float right;
|
||||||
|
if (ltrLine) {
|
||||||
|
if (isRtl) {
|
||||||
|
left = secondary - charWidth;
|
||||||
|
right = secondary;
|
||||||
|
} else {
|
||||||
|
left = primary;
|
||||||
|
right = primary + charWidth;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!isRtl) {
|
||||||
|
left = secondary;
|
||||||
|
right = secondary + charWidth;
|
||||||
|
} else {
|
||||||
|
left = primary - charWidth;
|
||||||
|
right = primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: Check top-right and bottom-left as well.
|
||||||
|
final float localLeft = left + viewportToContentHorizontalOffset;
|
||||||
|
final float localRight = right + viewportToContentHorizontalOffset;
|
||||||
|
final float localTop = top + viewportToContentVerticalOffset;
|
||||||
|
final float localBottom = bottom + viewportToContentVerticalOffset;
|
||||||
|
final boolean isTopLeftVisible = isPositionVisible(textView,
|
||||||
|
localLeft, localTop);
|
||||||
|
final boolean isBottomRightVisible =
|
||||||
|
isPositionVisible(textView, localRight, localBottom);
|
||||||
|
int characterBoundsFlags = 0;
|
||||||
|
if (isTopLeftVisible || isBottomRightVisible) {
|
||||||
|
characterBoundsFlags |= CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
|
||||||
|
}
|
||||||
|
if (!isTopLeftVisible || !isTopLeftVisible) {
|
||||||
|
characterBoundsFlags |= CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION;
|
||||||
|
}
|
||||||
|
if (isRtl) {
|
||||||
|
characterBoundsFlags |= CursorAnchorInfo.FLAG_IS_RTL;
|
||||||
|
}
|
||||||
|
// Here offset is the index in Java chars.
|
||||||
|
builder.addCharacterBounds(offset, localLeft, localTop, localRight,
|
||||||
|
localBottom, characterBoundsFlags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Treat selectionStart as the insertion point.
|
||||||
|
if (0 <= selectionStart) {
|
||||||
|
final int offset = selectionStart;
|
||||||
|
final int line = layout.getLineForOffset(offset);
|
||||||
|
final float insertionMarkerX = layout.getPrimaryHorizontal(offset)
|
||||||
|
+ viewportToContentHorizontalOffset;
|
||||||
|
final float insertionMarkerTop = layout.getLineTop(line)
|
||||||
|
+ viewportToContentVerticalOffset;
|
||||||
|
final float insertionMarkerBaseline = layout.getLineBaseline(line)
|
||||||
|
+ viewportToContentVerticalOffset;
|
||||||
|
final float insertionMarkerBottom = layout.getLineBottom(line)
|
||||||
|
+ viewportToContentVerticalOffset;
|
||||||
|
final boolean isTopVisible =
|
||||||
|
isPositionVisible(textView, insertionMarkerX, insertionMarkerTop);
|
||||||
|
final boolean isBottomVisible =
|
||||||
|
isPositionVisible(textView, insertionMarkerX, insertionMarkerBottom);
|
||||||
|
int insertionMarkerFlags = 0;
|
||||||
|
if (isTopVisible || isBottomVisible) {
|
||||||
|
insertionMarkerFlags |= CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
|
||||||
|
}
|
||||||
|
if (!isTopVisible || !isBottomVisible) {
|
||||||
|
insertionMarkerFlags |= CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION;
|
||||||
|
}
|
||||||
|
if (layout.isRtlCharAt(offset)) {
|
||||||
|
insertionMarkerFlags |= CursorAnchorInfo.FLAG_IS_RTL;
|
||||||
|
}
|
||||||
|
builder.setInsertionMarkerLocation(insertionMarkerX, insertionMarkerTop,
|
||||||
|
insertionMarkerBaseline, insertionMarkerBottom, insertionMarkerFlags);
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue