OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |