Loading core/java/android/view/inputmethod/InputMethodManager.java +6 −11 Original line number Original line Diff line number Diff line Loading @@ -541,7 +541,9 @@ public final class InputMethodManager { /** /** * The monitor mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}. * The monitor mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}. * @deprecated This is kept for {@link UnsupportedAppUsage}. Must not be used. */ */ @Deprecated private int mRequestUpdateCursorAnchorInfoMonitorMode = REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE; private int mRequestUpdateCursorAnchorInfoMonitorMode = REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE; /** /** Loading Loading @@ -2737,8 +2739,10 @@ public final class InputMethodManager { * Return true if the current input method wants to be notified when cursor/anchor location * Return true if the current input method wants to be notified when cursor/anchor location * is changed. * is changed. * * * @deprecated This method is kept for {@link UnsupportedAppUsage}. Must not be used. * @hide * @hide */ */ @Deprecated @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean isCursorAnchorInfoEnabled() { public boolean isCursorAnchorInfoEnabled() { synchronized (mH) { synchronized (mH) { Loading @@ -2753,8 +2757,10 @@ public final class InputMethodManager { /** /** * Set the requested mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}. * Set the requested mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}. * * * @deprecated This method is kept for {@link UnsupportedAppUsage}. Must not be used. * @hide * @hide */ */ @Deprecated @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void setUpdateCursorAnchorInfoMode(int flags) { public void setUpdateCursorAnchorInfoMode(int flags) { synchronized (mH) { synchronized (mH) { Loading @@ -2762,17 +2768,6 @@ public final class InputMethodManager { } } } } /** * Get the requested mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}. * * @hide */ public int getUpdateCursorAnchorInfoMode() { synchronized (mH) { return mRequestUpdateCursorAnchorInfoMonitorMode; } } /** /** * Report the current cursor location in its window. * Report the current cursor location in its window. * * Loading core/java/android/widget/Editor.java +15 −5 Original line number Original line Diff line number Diff line Loading @@ -4599,20 +4599,22 @@ public class Editor { return; return; } } // Skip if the IME has not requested the cursor/anchor position. // Skip if the IME has not requested the cursor/anchor position. if (!imm.isCursorAnchorInfoEnabled()) { final int knownCursorAnchorInfoModes = InputConnection.CURSOR_UPDATE_IMMEDIATE | InputConnection.CURSOR_UPDATE_MONITOR; if ((mInputMethodState.mUpdateCursorAnchorInfoMode & knownCursorAnchorInfoModes) == 0) { return; return; } } Layout layout = mTextView.getLayout(); Layout layout = mTextView.getLayout(); if (layout == null) { if (layout == null) { return; return; } } int mode = imm.getUpdateCursorAnchorInfoMode(); final int filter = mInputMethodState.mUpdateCursorAnchorInfoFilter; boolean includeEditorBounds = boolean includeEditorBounds = (mode & InputConnection.CURSOR_UPDATE_FILTER_EDITOR_BOUNDS) != 0; (filter & InputConnection.CURSOR_UPDATE_FILTER_EDITOR_BOUNDS) != 0; boolean includeCharacterBounds = boolean includeCharacterBounds = (mode & InputConnection.CURSOR_UPDATE_FILTER_CHARACTER_BOUNDS) != 0; (filter & InputConnection.CURSOR_UPDATE_FILTER_CHARACTER_BOUNDS) != 0; boolean includeInsertionMarker = boolean includeInsertionMarker = (mode & InputConnection.CURSOR_UPDATE_FILTER_INSERTION_MARKER) != 0; (filter & InputConnection.CURSOR_UPDATE_FILTER_INSERTION_MARKER) != 0; boolean includeAll = boolean includeAll = (!includeEditorBounds && !includeCharacterBounds && !includeInsertionMarker); (!includeEditorBounds && !includeCharacterBounds && !includeInsertionMarker); Loading Loading @@ -4713,6 +4715,10 @@ public class Editor { } } imm.updateCursorAnchorInfo(mTextView, builder.build()); imm.updateCursorAnchorInfo(mTextView, builder.build()); // Drop the immediate flag if any. mInputMethodState.mUpdateCursorAnchorInfoMode &= ~InputConnection.CURSOR_UPDATE_IMMEDIATE; } } } } Loading Loading @@ -7203,6 +7209,10 @@ public class Editor { boolean mSelectionModeChanged; boolean mSelectionModeChanged; boolean mContentChanged; boolean mContentChanged; int mChangedStart, mChangedEnd, mChangedDelta; int mChangedStart, mChangedEnd, mChangedDelta; @InputConnection.CursorUpdateMode int mUpdateCursorAnchorInfoMode; @InputConnection.CursorUpdateFilter int mUpdateCursorAnchorInfoFilter; } } /** /** Loading core/java/android/widget/TextView.java +30 −0 Original line number Original line Diff line number Diff line Loading @@ -9005,6 +9005,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public InputConnection onCreateInputConnection(EditorInfo outAttrs) { public InputConnection onCreateInputConnection(EditorInfo outAttrs) { if (onCheckIsTextEditor() && isEnabled()) { if (onCheckIsTextEditor() && isEnabled()) { mEditor.createInputMethodStateIfNeeded(); mEditor.createInputMethodStateIfNeeded(); mEditor.mInputMethodState.mUpdateCursorAnchorInfoMode = 0; mEditor.mInputMethodState.mUpdateCursorAnchorInfoFilter = 0; outAttrs.inputType = getInputType(); outAttrs.inputType = getInputType(); if (mEditor.mInputContentType != null) { if (mEditor.mInputContentType != null) { outAttrs.imeOptions = mEditor.mInputContentType.imeOptions; outAttrs.imeOptions = mEditor.mInputContentType.imeOptions; Loading Loading @@ -9060,6 +9063,33 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return null; return null; } } /** * Called back by the system to handle {@link InputConnection#requestCursorUpdates(int, int)}. * * @param cursorUpdateMode modes defined in {@link InputConnection.CursorUpdateMode}. * @param cursorUpdateFilter modes defined in {@link InputConnection.CursorUpdateFilter}. * * @hide */ public void onRequestCursorUpdatesInternal( @InputConnection.CursorUpdateMode int cursorUpdateMode, @InputConnection.CursorUpdateFilter int cursorUpdateFilter) { mEditor.mInputMethodState.mUpdateCursorAnchorInfoMode = cursorUpdateMode; mEditor.mInputMethodState.mUpdateCursorAnchorInfoFilter = cursorUpdateFilter; if ((cursorUpdateMode & InputConnection.CURSOR_UPDATE_IMMEDIATE) == 0) { return; } if (isInLayout()) { // In this case, the view hierarchy is currently undergoing a layout pass. // IMM#updateCursorAnchorInfo is supposed to be called soon after the layout // pass is finished. } else { // This will schedule a layout pass of the view tree, and the layout event // eventually triggers IMM#updateCursorAnchorInfo. requestLayout(); } } /** /** * If this TextView contains editable content, extract a portion of it * If this TextView contains editable content, extract a portion of it * based on the information in <var>request</var> in to <var>outText</var>. * based on the information in <var>request</var> in to <var>outText</var>. Loading core/java/com/android/internal/inputmethod/EditableInputConnection.java +11 −20 Original line number Original line Diff line number Diff line Loading @@ -215,13 +215,15 @@ public final class EditableInputConnection extends BaseInputConnection public boolean requestCursorUpdates(int cursorUpdateMode) { public boolean requestCursorUpdates(int cursorUpdateMode) { if (DEBUG) Log.v(TAG, "requestUpdateCursorAnchorInfo " + cursorUpdateMode); if (DEBUG) Log.v(TAG, "requestUpdateCursorAnchorInfo " + cursorUpdateMode); // It is possible that any other bit is used as a valid flag in a future release. final int knownModeFlags = InputConnection.CURSOR_UPDATE_IMMEDIATE // We should reject the entire request in such a case. | InputConnection.CURSOR_UPDATE_MONITOR; final int knownFlagMask = InputConnection.CURSOR_UPDATE_IMMEDIATE final int knownFilterFlags = InputConnection.CURSOR_UPDATE_FILTER_EDITOR_BOUNDS | InputConnection.CURSOR_UPDATE_MONITOR | InputConnection.CURSOR_UPDATE_FILTER_EDITOR_BOUNDS | InputConnection.CURSOR_UPDATE_FILTER_INSERTION_MARKER | InputConnection.CURSOR_UPDATE_FILTER_INSERTION_MARKER | InputConnection.CURSOR_UPDATE_FILTER_CHARACTER_BOUNDS; | InputConnection.CURSOR_UPDATE_FILTER_CHARACTER_BOUNDS; // It is possible that any other bit is used as a valid flag in a future release. // We should reject the entire request in such a case. final int knownFlagMask = knownModeFlags | knownFilterFlags; final int unknownFlags = cursorUpdateMode & ~knownFlagMask; final int unknownFlags = cursorUpdateMode & ~knownFlagMask; if (unknownFlags != 0) { if (unknownFlags != 0) { if (DEBUG) { if (DEBUG) { Loading @@ -237,21 +239,10 @@ public final class EditableInputConnection extends BaseInputConnection // CursorAnchorInfo is temporarily unavailable. // CursorAnchorInfo is temporarily unavailable. return false; return false; } } mIMM.setUpdateCursorAnchorInfoMode(cursorUpdateMode); mIMM.setUpdateCursorAnchorInfoMode(cursorUpdateMode); // for UnsupportedAppUsage if ((cursorUpdateMode & InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0) { if (mTextView != null) { if (mTextView == null) { mTextView.onRequestCursorUpdatesInternal(cursorUpdateMode & knownModeFlags, // In this case, FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE is silently ignored. cursorUpdateMode & knownFilterFlags); // TODO: Return some notification code for the input method that indicates // FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE is ignored. } else if (mTextView.isInLayout()) { // In this case, the view hierarchy is currently undergoing a layout pass. // IMM#updateCursorAnchorInfo is supposed to be called soon after the layout // pass is finished. } else { // This will schedule a layout pass of the view tree, and the layout event // eventually triggers IMM#updateCursorAnchorInfo. mTextView.requestLayout(); } } } return true; return true; } } Loading Loading
core/java/android/view/inputmethod/InputMethodManager.java +6 −11 Original line number Original line Diff line number Diff line Loading @@ -541,7 +541,9 @@ public final class InputMethodManager { /** /** * The monitor mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}. * The monitor mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}. * @deprecated This is kept for {@link UnsupportedAppUsage}. Must not be used. */ */ @Deprecated private int mRequestUpdateCursorAnchorInfoMonitorMode = REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE; private int mRequestUpdateCursorAnchorInfoMonitorMode = REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE; /** /** Loading Loading @@ -2737,8 +2739,10 @@ public final class InputMethodManager { * Return true if the current input method wants to be notified when cursor/anchor location * Return true if the current input method wants to be notified when cursor/anchor location * is changed. * is changed. * * * @deprecated This method is kept for {@link UnsupportedAppUsage}. Must not be used. * @hide * @hide */ */ @Deprecated @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean isCursorAnchorInfoEnabled() { public boolean isCursorAnchorInfoEnabled() { synchronized (mH) { synchronized (mH) { Loading @@ -2753,8 +2757,10 @@ public final class InputMethodManager { /** /** * Set the requested mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}. * Set the requested mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}. * * * @deprecated This method is kept for {@link UnsupportedAppUsage}. Must not be used. * @hide * @hide */ */ @Deprecated @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void setUpdateCursorAnchorInfoMode(int flags) { public void setUpdateCursorAnchorInfoMode(int flags) { synchronized (mH) { synchronized (mH) { Loading @@ -2762,17 +2768,6 @@ public final class InputMethodManager { } } } } /** * Get the requested mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}. * * @hide */ public int getUpdateCursorAnchorInfoMode() { synchronized (mH) { return mRequestUpdateCursorAnchorInfoMonitorMode; } } /** /** * Report the current cursor location in its window. * Report the current cursor location in its window. * * Loading
core/java/android/widget/Editor.java +15 −5 Original line number Original line Diff line number Diff line Loading @@ -4599,20 +4599,22 @@ public class Editor { return; return; } } // Skip if the IME has not requested the cursor/anchor position. // Skip if the IME has not requested the cursor/anchor position. if (!imm.isCursorAnchorInfoEnabled()) { final int knownCursorAnchorInfoModes = InputConnection.CURSOR_UPDATE_IMMEDIATE | InputConnection.CURSOR_UPDATE_MONITOR; if ((mInputMethodState.mUpdateCursorAnchorInfoMode & knownCursorAnchorInfoModes) == 0) { return; return; } } Layout layout = mTextView.getLayout(); Layout layout = mTextView.getLayout(); if (layout == null) { if (layout == null) { return; return; } } int mode = imm.getUpdateCursorAnchorInfoMode(); final int filter = mInputMethodState.mUpdateCursorAnchorInfoFilter; boolean includeEditorBounds = boolean includeEditorBounds = (mode & InputConnection.CURSOR_UPDATE_FILTER_EDITOR_BOUNDS) != 0; (filter & InputConnection.CURSOR_UPDATE_FILTER_EDITOR_BOUNDS) != 0; boolean includeCharacterBounds = boolean includeCharacterBounds = (mode & InputConnection.CURSOR_UPDATE_FILTER_CHARACTER_BOUNDS) != 0; (filter & InputConnection.CURSOR_UPDATE_FILTER_CHARACTER_BOUNDS) != 0; boolean includeInsertionMarker = boolean includeInsertionMarker = (mode & InputConnection.CURSOR_UPDATE_FILTER_INSERTION_MARKER) != 0; (filter & InputConnection.CURSOR_UPDATE_FILTER_INSERTION_MARKER) != 0; boolean includeAll = boolean includeAll = (!includeEditorBounds && !includeCharacterBounds && !includeInsertionMarker); (!includeEditorBounds && !includeCharacterBounds && !includeInsertionMarker); Loading Loading @@ -4713,6 +4715,10 @@ public class Editor { } } imm.updateCursorAnchorInfo(mTextView, builder.build()); imm.updateCursorAnchorInfo(mTextView, builder.build()); // Drop the immediate flag if any. mInputMethodState.mUpdateCursorAnchorInfoMode &= ~InputConnection.CURSOR_UPDATE_IMMEDIATE; } } } } Loading Loading @@ -7203,6 +7209,10 @@ public class Editor { boolean mSelectionModeChanged; boolean mSelectionModeChanged; boolean mContentChanged; boolean mContentChanged; int mChangedStart, mChangedEnd, mChangedDelta; int mChangedStart, mChangedEnd, mChangedDelta; @InputConnection.CursorUpdateMode int mUpdateCursorAnchorInfoMode; @InputConnection.CursorUpdateFilter int mUpdateCursorAnchorInfoFilter; } } /** /** Loading
core/java/android/widget/TextView.java +30 −0 Original line number Original line Diff line number Diff line Loading @@ -9005,6 +9005,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public InputConnection onCreateInputConnection(EditorInfo outAttrs) { public InputConnection onCreateInputConnection(EditorInfo outAttrs) { if (onCheckIsTextEditor() && isEnabled()) { if (onCheckIsTextEditor() && isEnabled()) { mEditor.createInputMethodStateIfNeeded(); mEditor.createInputMethodStateIfNeeded(); mEditor.mInputMethodState.mUpdateCursorAnchorInfoMode = 0; mEditor.mInputMethodState.mUpdateCursorAnchorInfoFilter = 0; outAttrs.inputType = getInputType(); outAttrs.inputType = getInputType(); if (mEditor.mInputContentType != null) { if (mEditor.mInputContentType != null) { outAttrs.imeOptions = mEditor.mInputContentType.imeOptions; outAttrs.imeOptions = mEditor.mInputContentType.imeOptions; Loading Loading @@ -9060,6 +9063,33 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return null; return null; } } /** * Called back by the system to handle {@link InputConnection#requestCursorUpdates(int, int)}. * * @param cursorUpdateMode modes defined in {@link InputConnection.CursorUpdateMode}. * @param cursorUpdateFilter modes defined in {@link InputConnection.CursorUpdateFilter}. * * @hide */ public void onRequestCursorUpdatesInternal( @InputConnection.CursorUpdateMode int cursorUpdateMode, @InputConnection.CursorUpdateFilter int cursorUpdateFilter) { mEditor.mInputMethodState.mUpdateCursorAnchorInfoMode = cursorUpdateMode; mEditor.mInputMethodState.mUpdateCursorAnchorInfoFilter = cursorUpdateFilter; if ((cursorUpdateMode & InputConnection.CURSOR_UPDATE_IMMEDIATE) == 0) { return; } if (isInLayout()) { // In this case, the view hierarchy is currently undergoing a layout pass. // IMM#updateCursorAnchorInfo is supposed to be called soon after the layout // pass is finished. } else { // This will schedule a layout pass of the view tree, and the layout event // eventually triggers IMM#updateCursorAnchorInfo. requestLayout(); } } /** /** * If this TextView contains editable content, extract a portion of it * If this TextView contains editable content, extract a portion of it * based on the information in <var>request</var> in to <var>outText</var>. * based on the information in <var>request</var> in to <var>outText</var>. Loading
core/java/com/android/internal/inputmethod/EditableInputConnection.java +11 −20 Original line number Original line Diff line number Diff line Loading @@ -215,13 +215,15 @@ public final class EditableInputConnection extends BaseInputConnection public boolean requestCursorUpdates(int cursorUpdateMode) { public boolean requestCursorUpdates(int cursorUpdateMode) { if (DEBUG) Log.v(TAG, "requestUpdateCursorAnchorInfo " + cursorUpdateMode); if (DEBUG) Log.v(TAG, "requestUpdateCursorAnchorInfo " + cursorUpdateMode); // It is possible that any other bit is used as a valid flag in a future release. final int knownModeFlags = InputConnection.CURSOR_UPDATE_IMMEDIATE // We should reject the entire request in such a case. | InputConnection.CURSOR_UPDATE_MONITOR; final int knownFlagMask = InputConnection.CURSOR_UPDATE_IMMEDIATE final int knownFilterFlags = InputConnection.CURSOR_UPDATE_FILTER_EDITOR_BOUNDS | InputConnection.CURSOR_UPDATE_MONITOR | InputConnection.CURSOR_UPDATE_FILTER_EDITOR_BOUNDS | InputConnection.CURSOR_UPDATE_FILTER_INSERTION_MARKER | InputConnection.CURSOR_UPDATE_FILTER_INSERTION_MARKER | InputConnection.CURSOR_UPDATE_FILTER_CHARACTER_BOUNDS; | InputConnection.CURSOR_UPDATE_FILTER_CHARACTER_BOUNDS; // It is possible that any other bit is used as a valid flag in a future release. // We should reject the entire request in such a case. final int knownFlagMask = knownModeFlags | knownFilterFlags; final int unknownFlags = cursorUpdateMode & ~knownFlagMask; final int unknownFlags = cursorUpdateMode & ~knownFlagMask; if (unknownFlags != 0) { if (unknownFlags != 0) { if (DEBUG) { if (DEBUG) { Loading @@ -237,21 +239,10 @@ public final class EditableInputConnection extends BaseInputConnection // CursorAnchorInfo is temporarily unavailable. // CursorAnchorInfo is temporarily unavailable. return false; return false; } } mIMM.setUpdateCursorAnchorInfoMode(cursorUpdateMode); mIMM.setUpdateCursorAnchorInfoMode(cursorUpdateMode); // for UnsupportedAppUsage if ((cursorUpdateMode & InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0) { if (mTextView != null) { if (mTextView == null) { mTextView.onRequestCursorUpdatesInternal(cursorUpdateMode & knownModeFlags, // In this case, FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE is silently ignored. cursorUpdateMode & knownFilterFlags); // TODO: Return some notification code for the input method that indicates // FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE is ignored. } else if (mTextView.isInLayout()) { // In this case, the view hierarchy is currently undergoing a layout pass. // IMM#updateCursorAnchorInfo is supposed to be called soon after the layout // pass is finished. } else { // This will schedule a layout pass of the view tree, and the layout event // eventually triggers IMM#updateCursorAnchorInfo. mTextView.requestLayout(); } } } return true; return true; } } Loading