1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.inputmethodservice; 18 19 import android.content.Context; 20 import android.util.AttributeSet; 21 import android.view.inputmethod.ExtractedText; 22 import android.view.inputmethod.InputMethodManager; 23 import android.widget.EditText; 24 25 /*** 26 * Specialization of {@link EditText} for showing and interacting with the 27 * extracted text in a full-screen input method. 28 */ 29 public class ExtractEditText extends EditText { 30 private InputMethodService mIME; 31 private int mSettingExtractedText; 32 ExtractEditText(Context context)33 public ExtractEditText(Context context) { 34 super(context, null); 35 } 36 ExtractEditText(Context context, AttributeSet attrs)37 public ExtractEditText(Context context, AttributeSet attrs) { 38 super(context, attrs, com.android.internal.R.attr.editTextStyle); 39 } 40 ExtractEditText(Context context, AttributeSet attrs, int defStyleAttr)41 public ExtractEditText(Context context, AttributeSet attrs, int defStyleAttr) { 42 this(context, attrs, defStyleAttr, 0); 43 } 44 ExtractEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)45 public ExtractEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 46 super(context, attrs, defStyleAttr, defStyleRes); 47 } 48 setIME(InputMethodService ime)49 void setIME(InputMethodService ime) { 50 mIME = ime; 51 } 52 53 /** 54 * Start making changes that will not be reported to the client. That 55 * is, {@link #onSelectionChanged(int, int)} will not result in sending 56 * the new selection to the client 57 */ startInternalChanges()58 public void startInternalChanges() { 59 mSettingExtractedText += 1; 60 } 61 62 /** 63 * Finish making changes that will not be reported to the client. That 64 * is, {@link #onSelectionChanged(int, int)} will not result in sending 65 * the new selection to the client 66 */ finishInternalChanges()67 public void finishInternalChanges() { 68 mSettingExtractedText -= 1; 69 } 70 71 /** 72 * Implement just to keep track of when we are setting text from the 73 * client (vs. seeing changes in ourself from the user). 74 */ setExtractedText(ExtractedText text)75 @Override public void setExtractedText(ExtractedText text) { 76 try { 77 mSettingExtractedText++; 78 super.setExtractedText(text); 79 } finally { 80 mSettingExtractedText--; 81 } 82 } 83 84 /** 85 * Report to the underlying text editor about selection changes. 86 */ onSelectionChanged(int selStart, int selEnd)87 @Override protected void onSelectionChanged(int selStart, int selEnd) { 88 if (mSettingExtractedText == 0 && mIME != null && selStart >= 0 && selEnd >= 0) { 89 mIME.onExtractedSelectionChanged(selStart, selEnd); 90 } 91 } 92 93 /** 94 * Redirect clicks to the IME for handling there. First allows any 95 * on click handler to run, though. 96 */ performClick()97 @Override public boolean performClick() { 98 if (!super.performClick() && mIME != null) { 99 mIME.onExtractedTextClicked(); 100 return true; 101 } 102 return false; 103 } 104 onTextContextMenuItem(int id)105 @Override public boolean onTextContextMenuItem(int id) { 106 if (mIME != null && mIME.onExtractTextContextMenuItem(id)) { 107 // Mode was started on Extracted, needs to be stopped here. 108 // Cut and paste will change the text, which stops selection mode. 109 if (id == android.R.id.copy) stopSelectionActionMode(); 110 return true; 111 } 112 return super.onTextContextMenuItem(id); 113 } 114 115 /** 116 * We are always considered to be an input method target. 117 */ 118 @Override isInputMethodTarget()119 public boolean isInputMethodTarget() { 120 return true; 121 } 122 123 /** 124 * Return true if the edit text is currently showing a scroll bar. 125 */ hasVerticalScrollBar()126 public boolean hasVerticalScrollBar() { 127 return computeVerticalScrollRange() > computeVerticalScrollExtent(); 128 } 129 130 /** 131 * Pretend like the window this view is in always has focus, so its 132 * highlight and cursor will be displayed. 133 */ hasWindowFocus()134 @Override public boolean hasWindowFocus() { 135 return this.isEnabled(); 136 } 137 138 /** 139 * Pretend like this view always has focus, so its 140 * highlight and cursor will be displayed. 141 */ isFocused()142 @Override public boolean isFocused() { 143 return this.isEnabled(); 144 } 145 146 /** 147 * Pretend like this view always has focus, so its 148 * highlight and cursor will be displayed. 149 */ hasFocus()150 @Override public boolean hasFocus() { 151 return this.isEnabled(); 152 } 153 154 /** 155 * @hide 156 */ viewClicked(InputMethodManager imm)157 @Override protected void viewClicked(InputMethodManager imm) { 158 // As an instance of this class is supposed to be owned by IMS, 159 // and it has a reference to the IMS (the current IME), 160 // we just need to call back its onViewClicked() here. 161 // It should be good to avoid unnecessary IPCs by doing this as well. 162 if (mIME != null) { 163 mIME.onViewClicked(false); 164 } 165 } 166 167 /** 168 * {@inheritDoc} 169 * @hide 170 */ 171 @Override deleteText_internal(int start, int end)172 protected void deleteText_internal(int start, int end) { 173 // Do not call the super method. 174 // This will change the source TextView instead, which will update the ExtractTextView. 175 mIME.onExtractedDeleteText(start, end); 176 } 177 178 /** 179 * {@inheritDoc} 180 * @hide 181 */ 182 @Override replaceText_internal(int start, int end, CharSequence text)183 protected void replaceText_internal(int start, int end, CharSequence text) { 184 // Do not call the super method. 185 // This will change the source TextView instead, which will update the ExtractTextView. 186 mIME.onExtractedReplaceText(start, end, text); 187 } 188 189 /** 190 * {@inheritDoc} 191 * @hide 192 */ 193 @Override setSpan_internal(Object span, int start, int end, int flags)194 protected void setSpan_internal(Object span, int start, int end, int flags) { 195 // Do not call the super method. 196 // This will change the source TextView instead, which will update the ExtractTextView. 197 mIME.onExtractedSetSpan(span, start, end, flags); 198 } 199 200 /** 201 * {@inheritDoc} 202 * @hide 203 */ 204 @Override setCursorPosition_internal(int start, int end)205 protected void setCursorPosition_internal(int start, int end) { 206 // Do not call the super method. 207 // This will change the source TextView instead, which will update the ExtractTextView. 208 mIME.onExtractedSelectionChanged(start, end); 209 } 210 } 211