summaryrefslogtreecommitdiffstats
path: root/core/java/android/inputmethodservice/InputMethodService.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/inputmethodservice/InputMethodService.java')
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java177
1 files changed, 159 insertions, 18 deletions
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 9ebf127..0588bea 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -48,6 +48,132 @@ import android.widget.FrameLayout;
* which final implementations can derive from and customize. See the
* base class {@link AbstractInputMethodService} and the {@link InputMethod}
* interface for more information on the basics of writing input methods.
+ *
+ * <p>An input method has significant discretion in how it goes about its
+ * work: the {@link android.inputmethodservice.InputMethodService} provides
+ * a basic framework for standard UI elements (input view, candidates view,
+ * and running in fullscreen mode), but it is up to a particular implementor
+ * to decide how to use them. For example, one input method could implement
+ * an input area with a keyboard, another could allow the user to draw text,
+ * while a third could have no input area (and thus not be visible to the
+ * user) but instead listen to audio and perform text to speech conversion.</p>
+ *
+ * <p>In the implementation provided here, all of these elements are placed
+ * together in a single window managed by the InputMethodService. It will
+ * execute callbacks as it needs information about them, and provides APIs for
+ * programmatic control over them. They layout of these elements is explicitly
+ * defined:</p>
+ *
+ * <ul>
+ * <li>The soft input view, if available, is placed at the bottom of the
+ * screen.
+ * <li>The candidates view, if currently shown, is placed above the soft
+ * input view.
+ * <li>If not running fullscreen, the application is moved or resized to be
+ * above these views; if running fullscreen, the window will completely cover
+ * the application and its top part will contain the extract text of what is
+ * currently being edited by the application.
+ * </ul>
+ *
+ *
+ * <a name="SoftInputView"></a>
+ * <h3>Soft Input View</h3>
+ *
+ * <p>Central to most input methods is the soft input view. This is where most
+ * user interaction occurs: pressing on soft keys, drawing characters, or
+ * however else your input method wants to generate text. Most implementations
+ * will simply have their own view doing all of this work, and return a new
+ * instance of it when {@link #onCreateInputView()} is called. At that point,
+ * as long as the input view is visible, you will see user interaction in
+ * that view and can call back on the InputMethodService to interact with the
+ * application as appropriate.</p>
+ *
+ * <p>There are some situations where you want to decide whether or not your
+ * soft input view should be shown to the user. This is done by implementing
+ * the {@link #onEvaluateInputViewShown()} to return true or false based on
+ * whether it should be shown in the current environment. If any of your
+ * state has changed that may impact this, call
+ * {@link #updateInputViewShown()} to have it re-evaluated. The default
+ * implementation always shows the input view unless there is a hard
+ * keyboard available, which is the appropriate behavior for most input
+ * methods.</p>
+ *
+ *
+ * <a name="CandidatesView"></a>
+ * <h3>Candidates View</h3>
+ *
+ * <p>Often while the user is generating raw text, an input method wants to
+ * provide them with a list of possible interpretations of that text that can
+ * be selected for use. This is accomplished with the candidates view, and
+ * like the soft input view you implement {@link #onCreateCandidatesView()}
+ * to instantiate your own view implementing your candidates UI.</p>
+ *
+ * <p>Management of the candidates view is a little different than the input
+ * view, because the candidates view tends to be more transient, being shown
+ * only when there are possible candidates for the current text being entered
+ * by the user. To control whether the candidates view is shown, you use
+ * {@link #setCandidatesViewShown(boolean)}. Note that because the candidate
+ * view tends to be shown and hidden a lot, it does not impact the application
+ * UI in the same way as the soft input view: it will never cause application
+ * windows to resize, only cause them to be panned if needed for the user to
+ * see the current focus.</p>
+ *
+ *
+ * <a name="FullscreenMode"></a>
+ * <h3>Fullscreen Mode</h3>
+ *
+ * <p>Sometimes your input method UI is too large to integrate with the
+ * application UI, so you just want to take over the screen. This is
+ * accomplished by switching to full-screen mode, causing the input method
+ * window to fill the entire screen and add its own "extracted text" editor
+ * showing the user the text that is being typed. Unlike the other UI elements,
+ * there is a standard implementation for the extract editor that you should
+ * not need to change. The editor is placed at the top of the IME, above the
+ * input and candidates views.</p>
+ *
+ * <p>Similar to the input view, you control whether the IME is running in
+ * fullscreen mode by implementing {@link #onEvaluateFullscreenMode()}
+ * to return true or false based on
+ * whether it should be fullscreen in the current environment. If any of your
+ * state has changed that may impact this, call
+ * {@link #updateFullscreenMode()} to have it re-evaluated. The default
+ * implementation selects fullscreen mode when the screen is in a landscape
+ * orientation, which is appropriate behavior for most input methods that have
+ * a significant input area.</p>
+ *
+ * <p>When in fullscreen mode, you have some special requirements because the
+ * user can not see the application UI. In particular, you should implement
+ * {@link #onDisplayCompletions(CompletionInfo[])} to show completions
+ * generated by your application, typically in your candidates view like you
+ * would normally show candidates.
+ *
+ *
+ * <a name="GeneratingText"></a>
+ * <h3>Generating Text</h3>
+ *
+ * <p>The key part of an IME is of course generating text for the application.
+ * This is done through calls to the
+ * {@link android.view.inputmethod.InputConnection} interface to the
+ * application, which can be retrieved from {@link #getCurrentInputConnection()}.
+ * This interface allows you to generate raw key events or, if the target
+ * supports it, directly edit in strings of candidates and committed text.</p>
+ *
+ * <p>Information about what the target is expected and supports can be found
+ * through the {@link android.view.inputmethod.EditorInfo} class, which is
+ * retrieved with {@link #getCurrentInputEditorInfo()} method. The most
+ * important part of this is {@link android.view.inputmethod.EditorInfo#inputType
+ * EditorInfo.inputType}; in particular, if this is
+ * {@link android.view.inputmethod.EditorInfo#TYPE_NULL EditorInfo.TYPE_NULL},
+ * then the target does not support complex edits and you need to only deliver
+ * raw key events to it. An input method will also want to look at other
+ * values here, to for example detect password mode, auto complete text views,
+ * phone number entry, etc.</p>
+ *
+ * <p>When the user switches between input targets, you will receive calls to
+ * {@link #onFinishInput()} and {@link #onStartInput(EditorInfo, boolean)}.
+ * You can use these to reset and initialize your input state for the current
+ * target. For example, you will often want to clear any input state, and
+ * update a soft keyboard to be appropriate for the new inputType.</p>
*/
public class InputMethodService extends AbstractInputMethodService {
static final String TAG = "InputMethodService";
@@ -68,7 +194,7 @@ public class InputMethodService extends AbstractInputMethodService {
InputBinding mInputBinding;
InputConnection mInputConnection;
boolean mInputStarted;
- EditorInfo mInputInfo;
+ EditorInfo mInputEditorInfo;
boolean mShowInputRequested;
boolean mShowCandidatesRequested;
@@ -210,12 +336,13 @@ public class InputMethodService extends AbstractInputMethodService {
* InputMethodService.onUpdateSelection()}.
*/
public void updateSelection(int oldSelStart, int oldSelEnd,
- int newSelStart, int newSelEnd) {
+ int newSelStart, int newSelEnd,
+ int candidatesStart, int candidatesEnd) {
if (!isEnabled()) {
return;
}
InputMethodService.this.onUpdateSelection(oldSelStart, oldSelEnd,
- newSelStart, newSelEnd);
+ newSelStart, newSelEnd, candidatesStart, candidatesEnd);
}
/**
@@ -303,6 +430,7 @@ public class InputMethodService extends AbstractInputMethodService {
Context.LAYOUT_INFLATER_SERVICE);
mWindow = new SoftInputWindow(this);
initViews();
+ mWindow.getWindow().setLayout(FILL_PARENT, WRAP_CONTENT);
}
void initViews() {
@@ -384,8 +512,8 @@ public class InputMethodService extends AbstractInputMethodService {
return mInputStarted;
}
- public EditorInfo getCurrentInputInfo() {
- return mInputInfo;
+ public EditorInfo getCurrentInputEditorInfo() {
+ return mInputEditorInfo;
}
/**
@@ -459,14 +587,14 @@ public class InputMethodService extends AbstractInputMethodService {
int[] loc = mTmpLocation;
if (mInputFrame.getVisibility() == View.VISIBLE) {
mInputFrame.getLocationInWindow(loc);
- outInsets.contentTopInsets = loc[1];
+ } else {
+ loc[1] = 0;
}
+ outInsets.contentTopInsets = loc[1];
if (mCandidatesFrame.getVisibility() == View.VISIBLE) {
mCandidatesFrame.getLocationInWindow(loc);
- outInsets.visibleTopInsets = loc[1];
- } else {
- outInsets.visibleTopInsets = loc[1];
}
+ outInsets.visibleTopInsets = loc[1];
outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_VISIBLE;
}
@@ -712,7 +840,7 @@ public class InputMethodService extends AbstractInputMethodService {
if (doShowInput) {
if (mInputStarted) {
if (DEBUG) Log.v(TAG, "showWindow: starting input view");
- onStartInputView(mInputInfo, false);
+ onStartInputView(mInputEditorInfo, false);
}
startExtractingText();
}
@@ -744,11 +872,11 @@ public class InputMethodService extends AbstractInputMethodService {
void doStartInput(EditorInfo attribute, boolean restarting) {
mInputStarted = true;
- mInputInfo = attribute;
+ mInputEditorInfo = attribute;
onStartInput(attribute, restarting);
if (mWindowVisible) {
if (mWindowCreated) {
- onStartInputView(mInputInfo, restarting);
+ onStartInputView(mInputEditorInfo, restarting);
}
startExtractingText();
}
@@ -795,7 +923,8 @@ public class InputMethodService extends AbstractInputMethodService {
* the extract text, if it is being shown.
*/
public void onUpdateSelection(int oldSelStart, int oldSelEnd,
- int newSelStart, int newSelEnd) {
+ int newSelStart, int newSelEnd,
+ int candidatesStart, int candidatesEnd) {
if (mExtractEditText != null && mExtractedText != null) {
final int off = mExtractedText.startOffset;
mExtractEditText.setSelection(newSelStart-off, newSelEnd-off);
@@ -821,10 +950,22 @@ public class InputMethodService extends AbstractInputMethodService {
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (mWindowVisible && event.getKeyCode() == KeyEvent.KEYCODE_BACK
+ if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
&& event.getRepeatCount() == 0) {
- dismissSoftInput();
- return true;
+ if (mShowInputRequested) {
+ // If the soft input area is shown, back closes it and we
+ // consume the back key.
+ dismissSoftInput();
+ return true;
+ }
+ if (mShowCandidatesRequested) {
+ // If the candidates are shown, we just want to make sure
+ // they are now hidden but otherwise let the app execute
+ // the back.
+ // XXX this needs better interaction with the soft input
+ // implementation.
+ //setCandidatesViewShown(false);
+ }
}
return false;
}
@@ -857,8 +998,8 @@ public class InputMethodService extends AbstractInputMethodService {
if (mExtractedText != null) {
mExtractEditText.setExtractedText(mExtractedText);
}
- mExtractEditText.setInputType(getCurrentInputInfo().inputType);
- mExtractEditText.setHint(mInputInfo.hintText);
+ mExtractEditText.setInputType(getCurrentInputEditorInfo().inputType);
+ mExtractEditText.setHint(mInputEditorInfo.hintText);
}
}
}