Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(239)

Side by Side Diff: content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java

Issue 2650113004: [WIP] Add support for Android SuggestionSpans when editing text (Closed)
Patch Set: Uploading the latest version from my repo so I can reference it Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.content.browser.input; 5 package org.chromium.content.browser.input;
6 6
7 import android.content.res.Configuration; 7 import android.content.res.Configuration;
8 import android.os.Build; 8 import android.os.Build;
9 import android.os.ResultReceiver; 9 import android.os.ResultReceiver;
10 import android.os.SystemClock; 10 import android.os.SystemClock;
11 import android.text.SpannableString; 11 import android.text.SpannableString;
12 import android.text.TextUtils; 12 import android.text.TextUtils;
13 import android.text.style.BackgroundColorSpan; 13 import android.text.style.BackgroundColorSpan;
14 import android.text.style.CharacterStyle; 14 import android.text.style.CharacterStyle;
15 import android.text.style.SuggestionSpan;
15 import android.text.style.UnderlineSpan; 16 import android.text.style.UnderlineSpan;
16 import android.view.KeyCharacterMap; 17 import android.view.KeyCharacterMap;
17 import android.view.KeyEvent; 18 import android.view.KeyEvent;
18 import android.view.View; 19 import android.view.View;
19 import android.view.inputmethod.BaseInputConnection; 20 import android.view.inputmethod.BaseInputConnection;
20 import android.view.inputmethod.EditorInfo; 21 import android.view.inputmethod.EditorInfo;
21 import android.view.inputmethod.InputConnection; 22 import android.view.inputmethod.InputConnection;
22 23
23 import org.chromium.base.Log; 24 import org.chromium.base.Log;
24 import org.chromium.base.VisibleForTesting; 25 import org.chromium.base.VisibleForTesting;
(...skipping 26 matching lines...) Expand all
51 * Note that the native peer object does not take any strong reference onto the 52 * Note that the native peer object does not take any strong reference onto the
52 * instance of this java object, hence it is up to the client of this class (e.g . 53 * instance of this java object, hence it is up to the client of this class (e.g .
53 * the ViewEmbedder implementor) to hold a strong reference to it for the requir ed 54 * the ViewEmbedder implementor) to hold a strong reference to it for the requir ed
54 * lifetime of the object. 55 * lifetime of the object.
55 */ 56 */
56 @JNINamespace("content") 57 @JNINamespace("content")
57 public class ImeAdapter { 58 public class ImeAdapter {
58 private static final String TAG = "cr_Ime"; 59 private static final String TAG = "cr_Ime";
59 private static final boolean DEBUG_LOGS = false; 60 private static final boolean DEBUG_LOGS = false;
60 61
62 private static final int SUGGESTION_SPAN_UNDERLINE_COLOR = 0x88C8C8C8;
63
61 public static final int COMPOSITION_KEY_CODE = 229; 64 public static final int COMPOSITION_KEY_CODE = 229;
62 65
63 /** 66 /**
64 * Interface for the delegate that needs to be notified of IME changes. 67 * Interface for the delegate that needs to be notified of IME changes.
65 */ 68 */
66 public interface ImeAdapterDelegate { 69 public interface ImeAdapterDelegate {
67 /** 70 /**
68 * Called to notify the delegate about synthetic/real key events before sending to renderer. 71 * Called to notify the delegate about synthetic/real key events before sending to renderer.
69 */ 72 */
70 void onImeEvent(); 73 void onImeEvent();
(...skipping 27 matching lines...) Expand all
98 private ChromiumBaseInputConnection mInputConnection; 101 private ChromiumBaseInputConnection mInputConnection;
99 private ChromiumBaseInputConnection.Factory mInputConnectionFactory; 102 private ChromiumBaseInputConnection.Factory mInputConnectionFactory;
100 103
101 private final ImeAdapterDelegate mViewEmbedder; 104 private final ImeAdapterDelegate mViewEmbedder;
102 // This holds the information necessary for constructing CursorAnchorInfo, a nd notifies to 105 // This holds the information necessary for constructing CursorAnchorInfo, a nd notifies to
103 // InputMethodManager on appropriate timing, depending on how IME requested the information 106 // InputMethodManager on appropriate timing, depending on how IME requested the information
104 // via InputConnection. The update request is per InputConnection, hence for each time it is 107 // via InputConnection. The update request is per InputConnection, hence for each time it is
105 // re-created, the monitoring status will be reset. 108 // re-created, the monitoring status will be reset.
106 private final CursorAnchorInfoController mCursorAnchorInfoController; 109 private final CursorAnchorInfoController mCursorAnchorInfoController;
107 110
111 private SuggestionsPopupWindow mSuggestionsPopupWindow;
112
108 private int mTextInputType = TextInputType.NONE; 113 private int mTextInputType = TextInputType.NONE;
109 private int mTextInputFlags; 114 private int mTextInputFlags;
110 private int mTextInputMode = WebTextInputMode.kDefault; 115 private int mTextInputMode = WebTextInputMode.kDefault;
111 116
112 // Keep the current configuration to detect the change when onConfigurationC hanged() is called. 117 // Keep the current configuration to detect the change when onConfigurationC hanged() is called.
113 private Configuration mCurrentConfig; 118 private Configuration mCurrentConfig;
114 119
115 private int mLastSelectionStart; 120 private int mLastSelectionStart;
116 private int mLastSelectionEnd; 121 private int mLastSelectionEnd;
117 private String mLastText; 122 private String mLastText;
(...skipping 10 matching lines...) Expand all
128 * @param wrapper InputMethodManagerWrapper that should receive all the call directed to 133 * @param wrapper InputMethodManagerWrapper that should receive all the call directed to
129 * InputMethodManager. 134 * InputMethodManager.
130 * @param embedder The view that is used for callbacks from ImeAdapter. 135 * @param embedder The view that is used for callbacks from ImeAdapter.
131 */ 136 */
132 public ImeAdapter(Configuration initialConfiguration, WebContents webContent s, 137 public ImeAdapter(Configuration initialConfiguration, WebContents webContent s,
133 InputMethodManagerWrapper wrapper, ImeAdapterDelegate embedder) { 138 InputMethodManagerWrapper wrapper, ImeAdapterDelegate embedder) {
134 mInputMethodManagerWrapper = wrapper; 139 mInputMethodManagerWrapper = wrapper;
135 mViewEmbedder = embedder; 140 mViewEmbedder = embedder;
136 // Deep copy newConfig so that we can notice the difference. 141 // Deep copy newConfig so that we can notice the difference.
137 mCurrentConfig = new Configuration(initialConfiguration); 142 mCurrentConfig = new Configuration(initialConfiguration);
138 // CursorAnchroInfo is supported only after L. 143 // CursorAnchorInfo is supported only after L.
139 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 144 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
140 mCursorAnchorInfoController = CursorAnchorInfoController.create(wrap per, 145 mCursorAnchorInfoController = CursorAnchorInfoController.create(
141 new CursorAnchorInfoController.ComposingTextDelegate() { 146 wrapper, new CursorAnchorInfoController.ComposingTextDelegat e() {
142 @Override 147 @Override
143 public CharSequence getText() { 148 public CharSequence getText() {
144 return mLastText; 149 return mLastText;
145 } 150 }
146 @Override 151 @Override
147 public int getSelectionStart() { 152 public int getSelectionStart() {
148 return mLastSelectionStart; 153 return mLastSelectionStart;
149 } 154 }
150 @Override 155 @Override
151 public int getSelectionEnd() { 156 public int getSelectionEnd() {
(...skipping 585 matching lines...) Expand 10 before | Expand all | Expand 10 after
737 insertionMarkerBottom, mViewEmbedder.getAttachedView()); 742 insertionMarkerBottom, mViewEmbedder.getAttachedView());
738 } 743 }
739 744
740 @CalledByNative 745 @CalledByNative
741 private void populateUnderlinesFromSpans(CharSequence text, long underlines) { 746 private void populateUnderlinesFromSpans(CharSequence text, long underlines) {
742 if (DEBUG_LOGS) { 747 if (DEBUG_LOGS) {
743 Log.i(TAG, "populateUnderlinesFromSpans: text [%s], underlines [%d]" , text, underlines); 748 Log.i(TAG, "populateUnderlinesFromSpans: text [%s], underlines [%d]" , text, underlines);
744 } 749 }
745 if (!(text instanceof SpannableString)) return; 750 if (!(text instanceof SpannableString)) return;
746 751
747 SpannableString spannableString = ((SpannableString) text); 752 SpannableString spannableString = (SpannableString) text;
748 CharacterStyle spans[] = 753 CharacterStyle spans[] =
749 spannableString.getSpans(0, text.length(), CharacterStyle.class) ; 754 spannableString.getSpans(0, text.length(), CharacterStyle.class) ;
750 for (CharacterStyle span : spans) { 755 for (CharacterStyle span : spans) {
751 if (span instanceof BackgroundColorSpan) { 756 if (span instanceof BackgroundColorSpan) {
752 nativeAppendBackgroundColorSpan(underlines, spannableString.getS panStart(span), 757 nativeAppendBackgroundColorSpan(underlines, spannableString.getS panStart(span),
753 spannableString.getSpanEnd(span), 758 spannableString.getSpanEnd(span),
754 ((BackgroundColorSpan) span).getBackgroundColor()); 759 ((BackgroundColorSpan) span).getBackgroundColor());
760 } else if (span instanceof SuggestionSpan) {
761 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
762 // The suggestion menu is only supported on Lollipop and new er
763 continue;
764 }
765
766 SuggestionSpan suggestionSpan = (SuggestionSpan) span;
767 nativeAppendSuggestionSpan(underlines, spannableString.getSpanSt art(suggestionSpan),
768 spannableString.getSpanEnd(suggestionSpan), SUGGESTION_S PAN_UNDERLINE_COLOR,
769 suggestionSpan.getFlags(), suggestionSpan.getSuggestions ());
770
755 } else if (span instanceof UnderlineSpan) { 771 } else if (span instanceof UnderlineSpan) {
756 nativeAppendUnderlineSpan(underlines, spannableString.getSpanSta rt(span), 772 nativeAppendUnderlineSpan(underlines, spannableString.getSpanSta rt(span),
757 spannableString.getSpanEnd(span)); 773 spannableString.getSpanEnd(span));
758 } 774 }
759 } 775 }
760 } 776 }
761 777
762 @CalledByNative 778 @CalledByNative
763 private void cancelComposition() { 779 private void cancelComposition() {
764 if (DEBUG_LOGS) Log.i(TAG, "cancelComposition"); 780 if (DEBUG_LOGS) Log.i(TAG, "cancelComposition");
765 if (mInputConnection != null) restartInput(); 781 if (mInputConnection != null) restartInput();
766 } 782 }
767 783
768 @CalledByNative 784 @CalledByNative
769 private void setCharacterBounds(float[] characterBounds) { 785 private void setCharacterBounds(float[] characterBounds) {
770 if (mCursorAnchorInfoController == null) return; 786 if (mCursorAnchorInfoController == null) return;
771 mCursorAnchorInfoController.setCompositionCharacterBounds(characterBound s, 787 mCursorAnchorInfoController.setCompositionCharacterBounds(characterBound s,
772 mViewEmbedder.getAttachedView()); 788 mViewEmbedder.getAttachedView());
773 } 789 }
774 790
775 @CalledByNative 791 @CalledByNative
776 private void onConnectedToRenderProcess() { 792 private void onConnectedToRenderProcess() {
777 if (DEBUG_LOGS) Log.i(TAG, "onConnectedToRenderProcess"); 793 if (DEBUG_LOGS) Log.i(TAG, "onConnectedToRenderProcess");
778 mIsConnected = true; 794 mIsConnected = true;
779 createInputConnectionFactory(); 795 createInputConnectionFactory();
780 resetAndHideKeyboard(); 796 resetAndHideKeyboard();
781 } 797 }
782 798
799 @CalledByNative
800 private void showSuggestionMenu(SuggestionInfo[] suggestionInfos) {
801 if (mSuggestionsPopupWindow == null) {
802 mSuggestionsPopupWindow =
803 new SuggestionsPopupWindow(mInputMethodManagerWrapper.getCon text(), this,
804 mViewEmbedder.getAttachedView(), mCursorAnchorInfoCo ntroller);
805 }
806
807 mSuggestionsPopupWindow.setSuggestionInfos(suggestionInfos);
808 mSuggestionsPopupWindow.show();
809 }
810
811 public void applySuggestionReplacement(long suggestionMarkerID, int suggesti onIndex) {
812 nativeApplySuggestionReplacement(
813 mNativeImeAdapterAndroid, suggestionMarkerID, suggestionIndex);
814 }
815
816 public void deleteSuggestionHighlight() {
817 nativeDeleteSuggestionHighlight(mNativeImeAdapterAndroid);
818 }
819
820 public void suggestionMenuClosed() {
821 nativeSuggestionMenuClosed(mNativeImeAdapterAndroid);
822 }
823
783 private native long nativeInit(WebContents webContents); 824 private native long nativeInit(WebContents webContents);
784 private native boolean nativeSendKeyEvent(long nativeImeAdapterAndroid, KeyE vent event, 825 private native boolean nativeSendKeyEvent(long nativeImeAdapterAndroid, KeyE vent event,
785 int type, int modifiers, long timestampMs, int keyCode, int scanCode , 826 int type, int modifiers, long timestampMs, int keyCode, int scanCode ,
786 boolean isSystemKey, int unicodeChar); 827 boolean isSystemKey, int unicodeChar);
787 private static native void nativeAppendUnderlineSpan(long underlinePtr, int start, int end);
788 private static native void nativeAppendBackgroundColorSpan(long underlinePtr , int start, 828 private static native void nativeAppendBackgroundColorSpan(long underlinePtr , int start,
789 int end, int backgroundColor); 829 int end, int backgroundColor);
830 private static native void nativeAppendSuggestionSpan(long underlinePtr, int start, int end,
831 int underlineColor, int flags, String[] suggestions);
832 private static native void nativeAppendUnderlineSpan(long underlinePtr, int start, int end);
790 private native void nativeSetComposingText(long nativeImeAdapterAndroid, Cha rSequence text, 833 private native void nativeSetComposingText(long nativeImeAdapterAndroid, Cha rSequence text,
791 String textStr, int newCursorPosition); 834 String textStr, int newCursorPosition);
792 private native void nativeCommitText( 835 private native void nativeCommitText(
793 long nativeImeAdapterAndroid, CharSequence text, String textStr, int newCursorPosition); 836 long nativeImeAdapterAndroid, CharSequence text, String textStr, int newCursorPosition);
794 private native void nativeFinishComposingText(long nativeImeAdapterAndroid); 837 private native void nativeFinishComposingText(long nativeImeAdapterAndroid);
795 private native void nativeSetEditableSelectionOffsets(long nativeImeAdapterA ndroid, 838 private native void nativeSetEditableSelectionOffsets(long nativeImeAdapterA ndroid,
796 int start, int end); 839 int start, int end);
797 private native void nativeSetComposingRegion(long nativeImeAdapterAndroid, i nt start, int end); 840 private native void nativeSetComposingRegion(long nativeImeAdapterAndroid, i nt start, int end);
798 private native void nativeDeleteSurroundingText(long nativeImeAdapterAndroid , 841 private native void nativeDeleteSurroundingText(long nativeImeAdapterAndroid ,
799 int before, int after); 842 int before, int after);
800 private native void nativeDeleteSurroundingTextInCodePoints( 843 private native void nativeDeleteSurroundingTextInCodePoints(
801 long nativeImeAdapterAndroid, int before, int after); 844 long nativeImeAdapterAndroid, int before, int after);
802 private native boolean nativeRequestTextInputStateUpdate(long nativeImeAdapt erAndroid); 845 private native boolean nativeRequestTextInputStateUpdate(long nativeImeAdapt erAndroid);
803 private native void nativeRequestCursorUpdate(long nativeImeAdapterAndroid, 846 private native void nativeRequestCursorUpdate(long nativeImeAdapterAndroid,
804 boolean immediateRequest, boolean monitorRequest); 847 boolean immediateRequest, boolean monitorRequest);
848 private native void nativeApplySuggestionReplacement(
849 long nativeImeAdapterAndroid, long suggestionMarkerID, int suggestio nIndex);
850 private native void nativeDeleteSuggestionHighlight(long nativeImeAdapterAnd roid);
851 private native void nativeSuggestionMenuClosed(long nativeImeAdapterAndroid) ;
805 } 852 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698