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 // Select all and Replace text shouldn't be handled by the original edit text, but by the 107 // extracted one. 108 if (id == android.R.id.selectAll || id == android.R.id.replaceText) { 109 return super.onTextContextMenuItem(id); 110 } 111 if (mIME != null && mIME.onExtractTextContextMenuItem(id)) { 112 // Mode was started on Extracted, needs to be stopped here. 113 // Cut will change the text, which stops selection mode. 114 if (id == android.R.id.copy || id == android.R.id.paste) stopTextActionMode(); 115 return true; 116 } 117 return super.onTextContextMenuItem(id); 118 } 119 120 /** 121 * We are always considered to be an input method target. 122 */ 123 @Override isInputMethodTarget()124 public boolean isInputMethodTarget() { 125 return true; 126 } 127 128 /** 129 * Return true if the edit text is currently showing a scroll bar. 130 */ hasVerticalScrollBar()131 public boolean hasVerticalScrollBar() { 132 return computeVerticalScrollRange() > computeVerticalScrollExtent(); 133 } 134 135 /** 136 * Pretend like the window this view is in always has focus, so its 137 * highlight and cursor will be displayed. 138 */ hasWindowFocus()139 @Override public boolean hasWindowFocus() { 140 return this.isEnabled(); 141 } 142 143 /** 144 * Pretend like this view always has focus, so its 145 * highlight and cursor will be displayed. 146 */ isFocused()147 @Override public boolean isFocused() { 148 return this.isEnabled(); 149 } 150 151 /** 152 * Pretend like this view always has focus, so its 153 * highlight and cursor will be displayed. 154 */ hasFocus()155 @Override public boolean hasFocus() { 156 return this.isEnabled(); 157 } 158 159 /** 160 * @hide 161 */ viewClicked(InputMethodManager imm)162 @Override protected void viewClicked(InputMethodManager imm) { 163 // As an instance of this class is supposed to be owned by IMS, 164 // and it has a reference to the IMS (the current IME), 165 // we just need to call back its onViewClicked() here. 166 // It should be good to avoid unnecessary IPCs by doing this as well. 167 if (mIME != null) { 168 mIME.onViewClicked(false); 169 } 170 } 171 172 /** 173 * @hide 174 */ 175 @Override isInExtractedMode()176 public boolean isInExtractedMode() { 177 return true; 178 } 179 180 /** 181 * {@inheritDoc} 182 * @hide 183 */ 184 @Override deleteText_internal(int start, int end)185 protected void deleteText_internal(int start, int end) { 186 // Do not call the super method. 187 // This will change the source TextView instead, which will update the ExtractTextView. 188 mIME.onExtractedDeleteText(start, end); 189 } 190 191 /** 192 * {@inheritDoc} 193 * @hide 194 */ 195 @Override replaceText_internal(int start, int end, CharSequence text)196 protected void replaceText_internal(int start, int end, CharSequence text) { 197 // Do not call the super method. 198 // This will change the source TextView instead, which will update the ExtractTextView. 199 mIME.onExtractedReplaceText(start, end, text); 200 } 201 202 /** 203 * {@inheritDoc} 204 * @hide 205 */ 206 @Override setSpan_internal(Object span, int start, int end, int flags)207 protected void setSpan_internal(Object span, int start, int end, int flags) { 208 // Do not call the super method. 209 // This will change the source TextView instead, which will update the ExtractTextView. 210 mIME.onExtractedSetSpan(span, start, end, flags); 211 } 212 213 /** 214 * {@inheritDoc} 215 * @hide 216 */ 217 @Override setCursorPosition_internal(int start, int end)218 protected void setCursorPosition_internal(int start, int end) { 219 // Do not call the super method. 220 // This will change the source TextView instead, which will update the ExtractTextView. 221 mIME.onExtractedSelectionChanged(start, end); 222 } 223 } 224