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 defStyle)41 public ExtractEditText(Context context, AttributeSet attrs, int defStyle) { 42 super(context, attrs, defStyle); 43 } 44 setIME(InputMethodService ime)45 void setIME(InputMethodService ime) { 46 mIME = ime; 47 } 48 49 /** 50 * Start making changes that will not be reported to the client. That 51 * is, {@link #onSelectionChanged(int, int)} will not result in sending 52 * the new selection to the client 53 */ startInternalChanges()54 public void startInternalChanges() { 55 mSettingExtractedText += 1; 56 } 57 58 /** 59 * Finish making changes that will not be reported to the client. That 60 * is, {@link #onSelectionChanged(int, int)} will not result in sending 61 * the new selection to the client 62 */ finishInternalChanges()63 public void finishInternalChanges() { 64 mSettingExtractedText -= 1; 65 } 66 67 /** 68 * Implement just to keep track of when we are setting text from the 69 * client (vs. seeing changes in ourself from the user). 70 */ setExtractedText(ExtractedText text)71 @Override public void setExtractedText(ExtractedText text) { 72 try { 73 mSettingExtractedText++; 74 super.setExtractedText(text); 75 } finally { 76 mSettingExtractedText--; 77 } 78 } 79 80 /** 81 * Report to the underlying text editor about selection changes. 82 */ onSelectionChanged(int selStart, int selEnd)83 @Override protected void onSelectionChanged(int selStart, int selEnd) { 84 if (mSettingExtractedText == 0 && mIME != null && selStart >= 0 && selEnd >= 0) { 85 mIME.onExtractedSelectionChanged(selStart, selEnd); 86 } 87 } 88 89 /** 90 * Redirect clicks to the IME for handling there. First allows any 91 * on click handler to run, though. 92 */ performClick()93 @Override public boolean performClick() { 94 if (!super.performClick() && mIME != null) { 95 mIME.onExtractedTextClicked(); 96 return true; 97 } 98 return false; 99 } 100 onTextContextMenuItem(int id)101 @Override public boolean onTextContextMenuItem(int id) { 102 if (mIME != null && mIME.onExtractTextContextMenuItem(id)) { 103 // Mode was started on Extracted, needs to be stopped here. 104 // Cut and paste will change the text, which stops selection mode. 105 if (id == android.R.id.copy) stopSelectionActionMode(); 106 return true; 107 } 108 return super.onTextContextMenuItem(id); 109 } 110 111 /** 112 * We are always considered to be an input method target. 113 */ 114 @Override isInputMethodTarget()115 public boolean isInputMethodTarget() { 116 return true; 117 } 118 119 /** 120 * Return true if the edit text is currently showing a scroll bar. 121 */ hasVerticalScrollBar()122 public boolean hasVerticalScrollBar() { 123 return computeVerticalScrollRange() > computeVerticalScrollExtent(); 124 } 125 126 /** 127 * Pretend like the window this view is in always has focus, so its 128 * highlight and cursor will be displayed. 129 */ hasWindowFocus()130 @Override public boolean hasWindowFocus() { 131 return this.isEnabled(); 132 } 133 134 /** 135 * Pretend like this view always has focus, so its 136 * highlight and cursor will be displayed. 137 */ isFocused()138 @Override public boolean isFocused() { 139 return this.isEnabled(); 140 } 141 142 /** 143 * Pretend like this view always has focus, so its 144 * highlight and cursor will be displayed. 145 */ hasFocus()146 @Override public boolean hasFocus() { 147 return this.isEnabled(); 148 } 149 150 /** 151 * @hide 152 */ viewClicked(InputMethodManager imm)153 @Override protected void viewClicked(InputMethodManager imm) { 154 // As an instance of this class is supposed to be owned by IMS, 155 // and it has a reference to the IMS (the current IME), 156 // we just need to call back its onViewClicked() here. 157 // It should be good to avoid unnecessary IPCs by doing this as well. 158 if (mIME != null) { 159 mIME.onViewClicked(false); 160 } 161 } 162 163 /** 164 * {@inheritDoc} 165 * @hide 166 */ 167 @Override deleteText_internal(int start, int end)168 protected void deleteText_internal(int start, int end) { 169 // Do not call the super method. 170 // This will change the source TextView instead, which will update the ExtractTextView. 171 mIME.onExtractedDeleteText(start, end); 172 } 173 174 /** 175 * {@inheritDoc} 176 * @hide 177 */ 178 @Override replaceText_internal(int start, int end, CharSequence text)179 protected void replaceText_internal(int start, int end, CharSequence text) { 180 // Do not call the super method. 181 // This will change the source TextView instead, which will update the ExtractTextView. 182 mIME.onExtractedReplaceText(start, end, text); 183 } 184 185 /** 186 * {@inheritDoc} 187 * @hide 188 */ 189 @Override setSpan_internal(Object span, int start, int end, int flags)190 protected void setSpan_internal(Object span, int start, int end, int flags) { 191 // Do not call the super method. 192 // This will change the source TextView instead, which will update the ExtractTextView. 193 mIME.onExtractedSetSpan(span, start, end, flags); 194 } 195 196 /** 197 * {@inheritDoc} 198 * @hide 199 */ 200 @Override setCursorPosition_internal(int start, int end)201 protected void setCursorPosition_internal(int start, int end) { 202 // Do not call the super method. 203 // This will change the source TextView instead, which will update the ExtractTextView. 204 mIME.onExtractedSelectionChanged(start, end); 205 } 206 } 207