summaryrefslogtreecommitdiffstats
path: root/core/java/android/inputmethodservice/InputMethodService.java
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:45 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:45 -0800
commitd83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /core/java/android/inputmethodservice/InputMethodService.java
parent076357b8567458d4b6dfdcf839ef751634cd2bfb (diff)
downloadframeworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.zip
frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.gz
frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'core/java/android/inputmethodservice/InputMethodService.java')
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java1636
1 files changed, 0 insertions, 1636 deletions
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
deleted file mode 100644
index 4be1fc7..0000000
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ /dev/null
@@ -1,1636 +0,0 @@
-/*
- * Copyright (C) 2007-2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package android.inputmethodservice;
-
-import static android.view.ViewGroup.LayoutParams.FILL_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-
-import android.app.Dialog;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.provider.Settings;
-import android.text.Layout;
-import android.text.Spannable;
-import android.text.method.MovementMethod;
-import android.util.Log;
-import android.util.PrintWriterPrinter;
-import android.util.Printer;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.inputmethod.CompletionInfo;
-import android.view.inputmethod.ExtractedText;
-import android.view.inputmethod.ExtractedTextRequest;
-import android.view.inputmethod.InputBinding;
-import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputMethod;
-import android.view.inputmethod.InputMethodManager;
-import android.view.inputmethod.EditorInfo;
-import android.widget.FrameLayout;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * InputMethodService provides a standard implementation of an InputMethod,
- * 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>In addition to the normal Service lifecycle methods, this class
- * introduces some new specific callbacks that most subclasses will want
- * to make use of:</p>
- * <ul>
- * <li> {@link #onInitializeInterface()} for user-interface initialization,
- * in particular to deal with configuration changes while the service is
- * running.
- * <li> {@link #onBindInput} to find out about switching to a new client.
- * <li> {@link #onStartInput} to deal with an input session starting with
- * the client.
- * <li> {@link #onCreateInputView()}, {@link #onCreateCandidatesView()},
- * and {@link #onCreateExtractTextView()} for non-demand generation of the UI.
- * <li> {@link #onStartInputView(EditorInfo, boolean)} to deal with input
- * starting within the input area of the IME.
- * </ul>
- *
- * <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";
- static final boolean DEBUG = false;
-
- InputMethodManager mImm;
-
- LayoutInflater mInflater;
- View mRootView;
- SoftInputWindow mWindow;
- boolean mInitialized;
- boolean mWindowCreated;
- boolean mWindowAdded;
- boolean mWindowVisible;
- FrameLayout mExtractFrame;
- FrameLayout mCandidatesFrame;
- FrameLayout mInputFrame;
-
- IBinder mToken;
-
- InputBinding mInputBinding;
- InputConnection mInputConnection;
- boolean mInputStarted;
- boolean mInputViewStarted;
- boolean mCandidatesViewStarted;
- InputConnection mStartedInputConnection;
- EditorInfo mInputEditorInfo;
-
- int mShowInputFlags;
- boolean mShowInputRequested;
- boolean mLastShowInputRequested;
- int mCandidatesVisibility;
- CompletionInfo[] mCurCompletions;
-
- boolean mShowInputForced;
-
- boolean mFullscreenApplied;
- boolean mIsFullscreen;
- View mExtractView;
- ExtractEditText mExtractEditText;
- ExtractedText mExtractedText;
- int mExtractedToken;
-
- View mInputView;
- boolean mIsInputViewShown;
-
- int mStatusIcon;
-
- final Insets mTmpInsets = new Insets();
- final int[] mTmpLocation = new int[2];
-
- final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer =
- new ViewTreeObserver.OnComputeInternalInsetsListener() {
- public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
- if (isFullscreenMode()) {
- // In fullscreen mode, we just say the window isn't covering
- // any content so we don't impact whatever is behind.
- View decor = getWindow().getWindow().getDecorView();
- info.contentInsets.top = info.visibleInsets.top
- = decor.getHeight();
- info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
- } else {
- onComputeInsets(mTmpInsets);
- info.contentInsets.top = mTmpInsets.contentTopInsets;
- info.visibleInsets.top = mTmpInsets.visibleTopInsets;
- info.setTouchableInsets(mTmpInsets.touchableInsets);
- }
- }
- };
-
- /**
- * Concrete implementation of
- * {@link AbstractInputMethodService.AbstractInputMethodImpl} that provides
- * all of the standard behavior for an input method.
- */
- public class InputMethodImpl extends AbstractInputMethodImpl {
- /**
- * Take care of attaching the given window token provided by the system.
- */
- public void attachToken(IBinder token) {
- if (mToken == null) {
- mToken = token;
- mWindow.setToken(token);
- }
- }
-
- /**
- * Handle a new input binding, calling
- * {@link InputMethodService#onBindInput InputMethodService.onBindInput()}
- * when done.
- */
- public void bindInput(InputBinding binding) {
- mInputBinding = binding;
- mInputConnection = binding.getConnection();
- if (DEBUG) Log.v(TAG, "bindInput(): binding=" + binding
- + " ic=" + mInputConnection);
- InputConnection ic = getCurrentInputConnection();
- if (ic != null) ic.reportFullscreenMode(mIsFullscreen);
- initialize();
- onBindInput();
- }
-
- /**
- * Clear the current input binding.
- */
- public void unbindInput() {
- if (DEBUG) Log.v(TAG, "unbindInput(): binding=" + mInputBinding
- + " ic=" + mInputConnection);
- onUnbindInput();
- mInputStarted = false;
- mInputBinding = null;
- mInputConnection = null;
- }
-
- public void startInput(InputConnection ic, EditorInfo attribute) {
- if (DEBUG) Log.v(TAG, "startInput(): editor=" + attribute);
- doStartInput(ic, attribute, false);
- }
-
- public void restartInput(InputConnection ic, EditorInfo attribute) {
- if (DEBUG) Log.v(TAG, "restartInput(): editor=" + attribute);
- doStartInput(ic, attribute, true);
- }
-
- /**
- * Handle a request by the system to hide the soft input area.
- */
- public void hideSoftInput() {
- if (DEBUG) Log.v(TAG, "hideSoftInput()");
- mShowInputFlags = 0;
- mShowInputRequested = false;
- mShowInputForced = false;
- hideWindow();
- }
-
- /**
- * Handle a request by the system to show the soft input area.
- */
- public void showSoftInput(int flags) {
- if (DEBUG) Log.v(TAG, "showSoftInput()");
- mShowInputFlags = 0;
- if (onShowInputRequested(flags, false)) {
- showWindow(true);
- }
- }
- }
-
- /**
- * Concrete implementation of
- * {@link AbstractInputMethodService.AbstractInputMethodSessionImpl} that provides
- * all of the standard behavior for an input method session.
- */
- public class InputMethodSessionImpl extends AbstractInputMethodSessionImpl {
- public void finishInput() {
- if (!isEnabled()) {
- return;
- }
- if (DEBUG) Log.v(TAG, "finishInput() in " + this);
- doFinishInput();
- }
-
- /**
- * Call {@link InputMethodService#onDisplayCompletions
- * InputMethodService.onDisplayCompletions()}.
- */
- public void displayCompletions(CompletionInfo[] completions) {
- if (!isEnabled()) {
- return;
- }
- mCurCompletions = completions;
- onDisplayCompletions(completions);
- }
-
- /**
- * Call {@link InputMethodService#onUpdateExtractedText
- * InputMethodService.onUpdateExtractedText()}.
- */
- public void updateExtractedText(int token, ExtractedText text) {
- if (!isEnabled()) {
- return;
- }
- onUpdateExtractedText(token, text);
- }
-
- /**
- * Call {@link InputMethodService#onUpdateSelection
- * InputMethodService.onUpdateSelection()}.
- */
- public void updateSelection(int oldSelStart, int oldSelEnd,
- int newSelStart, int newSelEnd,
- int candidatesStart, int candidatesEnd) {
- if (!isEnabled()) {
- return;
- }
- InputMethodService.this.onUpdateSelection(oldSelStart, oldSelEnd,
- newSelStart, newSelEnd, candidatesStart, candidatesEnd);
- }
-
- /**
- * Call {@link InputMethodService#onUpdateCursor
- * InputMethodService.onUpdateCursor()}.
- */
- public void updateCursor(Rect newCursor) {
- if (!isEnabled()) {
- return;
- }
- InputMethodService.this.onUpdateCursor(newCursor);
- }
-
- /**
- * Call {@link InputMethodService#onAppPrivateCommand
- * InputMethodService.onAppPrivateCommand()}.
- */
- public void appPrivateCommand(String action, Bundle data) {
- if (!isEnabled()) {
- return;
- }
- InputMethodService.this.onAppPrivateCommand(action, data);
- }
- }
-
- /**
- * Information about where interesting parts of the input method UI appear.
- */
- public static final class Insets {
- /**
- * This is the top part of the UI that is the main content. It is
- * used to determine the basic space needed, to resize/pan the
- * application behind. It is assumed that this inset does not
- * change very much, since any change will cause a full resize/pan
- * of the application behind. This value is relative to the top edge
- * of the input method window.
- */
- public int contentTopInsets;
-
- /**
- * This is the top part of the UI that is visibly covering the
- * application behind it. This provides finer-grained control over
- * visibility, allowing you to change it relatively frequently (such
- * as hiding or showing candidates) without disrupting the underlying
- * UI too much. For example, this will never resize the application
- * UI, will only pan if needed to make the current focus visible, and
- * will not aggressively move the pan position when this changes unless
- * needed to make the focus visible. This value is relative to the top edge
- * of the input method window.
- */
- public int visibleTopInsets;
-
- /**
- * Option for {@link #touchableInsets}: the entire window frame
- * can be touched.
- */
- public static final int TOUCHABLE_INSETS_FRAME
- = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
-
- /**
- * Option for {@link #touchableInsets}: the area inside of
- * the content insets can be touched.
- */
- public static final int TOUCHABLE_INSETS_CONTENT
- = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
-
- /**
- * Option for {@link #touchableInsets}: the area inside of
- * the visible insets can be touched.
- */
- public static final int TOUCHABLE_INSETS_VISIBLE
- = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
-
- /**
- * Determine which area of the window is touchable by the user. May
- * be one of: {@link #TOUCHABLE_INSETS_FRAME},
- * {@link #TOUCHABLE_INSETS_CONTENT}, or {@link #TOUCHABLE_INSETS_VISIBLE}.
- */
- public int touchableInsets;
- }
-
- @Override public void onCreate() {
- super.onCreate();
- mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
- mInflater = (LayoutInflater)getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
- mWindow = new SoftInputWindow(this);
- initViews();
- mWindow.getWindow().setLayout(FILL_PARENT, WRAP_CONTENT);
- }
-
- /**
- * This is a hook that subclasses can use to perform initialization of
- * their interface. It is called for you prior to any of your UI objects
- * being created, both after the service is first created and after a
- * configuration change happens.
- */
- public void onInitializeInterface() {
- }
-
- void initialize() {
- if (!mInitialized) {
- mInitialized = true;
- onInitializeInterface();
- }
- }
-
- void initViews() {
- mInitialized = false;
- mWindowCreated = false;
- mShowInputRequested = false;
- mShowInputForced = false;
-
- mRootView = mInflater.inflate(
- com.android.internal.R.layout.input_method, null);
- mWindow.setContentView(mRootView);
- mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
- if (Settings.System.getInt(getContentResolver(),
- Settings.System.FANCY_IME_ANIMATIONS, 0) != 0) {
- mWindow.getWindow().setWindowAnimations(
- com.android.internal.R.style.Animation_InputMethodFancy);
- }
- mExtractFrame = (FrameLayout)mRootView.findViewById(android.R.id.extractArea);
- mExtractView = null;
- mExtractEditText = null;
- mFullscreenApplied = false;
-
- mCandidatesFrame = (FrameLayout)mRootView.findViewById(android.R.id.candidatesArea);
- mInputFrame = (FrameLayout)mRootView.findViewById(android.R.id.inputArea);
- mInputView = null;
- mIsInputViewShown = false;
-
- mExtractFrame.setVisibility(View.GONE);
- mCandidatesVisibility = getCandidatesHiddenVisibility();
- mCandidatesFrame.setVisibility(mCandidatesVisibility);
- mInputFrame.setVisibility(View.GONE);
- }
-
- @Override public void onDestroy() {
- super.onDestroy();
- mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
- mInsetsComputer);
- if (mWindowAdded) {
- mWindow.dismiss();
- }
- }
-
- /**
- * Take care of handling configuration changes. Subclasses of
- * InputMethodService generally don't need to deal directly with
- * this on their own; the standard implementation here takes care of
- * regenerating the input method UI as a result of the configuration
- * change, so you can rely on your {@link #onCreateInputView} and
- * other methods being called as appropriate due to a configuration change.
- *
- * <p>When a configuration change does happen,
- * {@link #onInitializeInterface()} is guaranteed to be called the next
- * time prior to any of the other input or UI creation callbacks. The
- * following will be called immediately depending if appropriate for current
- * state: {@link #onStartInput} if input is active, and
- * {@link #onCreateInputView} and {@link #onStartInputView} and related
- * appropriate functions if the UI is displayed.
- */
- @Override public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
-
- boolean visible = mWindowVisible;
- int showFlags = mShowInputFlags;
- boolean showingInput = mShowInputRequested;
- CompletionInfo[] completions = mCurCompletions;
- initViews();
- mInputViewStarted = false;
- mCandidatesViewStarted = false;
- if (mInputStarted) {
- doStartInput(getCurrentInputConnection(),
- getCurrentInputEditorInfo(), true);
- }
- if (visible) {
- if (showingInput) {
- // If we were last showing the soft keyboard, try to do so again.
- if (onShowInputRequested(showFlags, true)) {
- showWindow(true);
- if (completions != null) {
- mCurCompletions = completions;
- onDisplayCompletions(completions);
- }
- } else {
- hideWindow();
- }
- } else if (mCandidatesVisibility == View.VISIBLE) {
- // If the candidates are currently visible, make sure the
- // window is shown for them.
- showWindow(false);
- } else {
- // Otherwise hide the window.
- hideWindow();
- }
- }
- }
-
- /**
- * Implement to return our standard {@link InputMethodImpl}. Subclasses
- * can override to provide their own customized version.
- */
- public AbstractInputMethodImpl onCreateInputMethodInterface() {
- return new InputMethodImpl();
- }
-
- /**
- * Implement to return our standard {@link InputMethodSessionImpl}. Subclasses
- * can override to provide their own customized version.
- */
- public AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface() {
- return new InputMethodSessionImpl();
- }
-
- public LayoutInflater getLayoutInflater() {
- return mInflater;
- }
-
- public Dialog getWindow() {
- return mWindow;
- }
-
- /**
- * Return the maximum width, in pixels, available the input method.
- * Input methods are positioned at the bottom of the screen and, unless
- * running in fullscreen, will generally want to be as short as possible
- * so should compute their height based on their contents. However, they
- * can stretch as much as needed horizontally. The function returns to
- * you the maximum amount of space available horizontally, which you can
- * use if needed for UI placement.
- *
- * <p>In many cases this is not needed, you can just rely on the normal
- * view layout mechanisms to position your views within the full horizontal
- * space given to the input method.
- *
- * <p>Note that this value can change dynamically, in particular when the
- * screen orientation changes.
- */
- public int getMaxWidth() {
- WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
- return wm.getDefaultDisplay().getWidth();
- }
-
- /**
- * Return the currently active InputBinding for the input method, or
- * null if there is none.
- */
- public InputBinding getCurrentInputBinding() {
- return mInputBinding;
- }
-
- /**
- * Retrieve the currently active InputConnection that is bound to
- * the input method, or null if there is none.
- */
- public InputConnection getCurrentInputConnection() {
- InputConnection ic = mStartedInputConnection;
- if (ic != null) {
- return ic;
- }
- return mInputConnection;
- }
-
- public boolean getCurrentInputStarted() {
- return mInputStarted;
- }
-
- public EditorInfo getCurrentInputEditorInfo() {
- return mInputEditorInfo;
- }
-
- /**
- * Re-evaluate whether the input method should be running in fullscreen
- * mode, and update its UI if this has changed since the last time it
- * was evaluated. This will call {@link #onEvaluateFullscreenMode()} to
- * determine whether it should currently run in fullscreen mode. You
- * can use {@link #isFullscreenMode()} to determine if the input method
- * is currently running in fullscreen mode.
- */
- public void updateFullscreenMode() {
- boolean isFullscreen = mShowInputRequested && onEvaluateFullscreenMode();
- boolean changed = mLastShowInputRequested != mShowInputRequested;
- if (mIsFullscreen != isFullscreen || !mFullscreenApplied) {
- changed = true;
- mIsFullscreen = isFullscreen;
- InputConnection ic = getCurrentInputConnection();
- if (ic != null) ic.reportFullscreenMode(isFullscreen);
- mFullscreenApplied = true;
- initialize();
- Drawable bg = onCreateBackgroundDrawable();
- if (bg == null) {
- // We need to give the window a real drawable, so that it
- // correctly sets its mode.
- bg = getResources().getDrawable(android.R.color.transparent);
- }
- mWindow.getWindow().setBackgroundDrawable(bg);
- mExtractFrame.setVisibility(isFullscreen ? View.VISIBLE : View.GONE);
- if (isFullscreen) {
- if (mExtractView == null) {
- View v = onCreateExtractTextView();
- if (v != null) {
- setExtractView(v);
- }
- }
- startExtractingText();
- }
- }
-
- if (changed) {
- onConfigureWindow(mWindow.getWindow(), isFullscreen,
- !mShowInputRequested);
- mLastShowInputRequested = mShowInputRequested;
- }
- }
-
- /**
- * Update the given window's parameters for the given mode. This is called
- * when the window is first displayed and each time the fullscreen or
- * candidates only mode changes.
- *
- * <p>The default implementation makes the layout for the window
- * FILL_PARENT x FILL_PARENT when in fullscreen mode, and
- * FILL_PARENT x WRAP_CONTENT when in non-fullscreen mode.
- *
- * @param win The input method's window.
- * @param isFullscreen If true, the window is running in fullscreen mode
- * and intended to cover the entire application display.
- * @param isCandidatesOnly If true, the window is only showing the
- * candidates view and none of the rest of its UI. This is mutually
- * exclusive with fullscreen mode.
- */
- public void onConfigureWindow(Window win, boolean isFullscreen,
- boolean isCandidatesOnly) {
- if (isFullscreen) {
- mWindow.getWindow().setLayout(FILL_PARENT, FILL_PARENT);
- } else {
- mWindow.getWindow().setLayout(FILL_PARENT, WRAP_CONTENT);
- }
- }
-
- /**
- * Return whether the input method is <em>currently</em> running in
- * fullscreen mode. This is the mode that was last determined and
- * applied by {@link #updateFullscreenMode()}.
- */
- public boolean isFullscreenMode() {
- return mIsFullscreen;
- }
-
- /**
- * Override this to control when the input method should run in
- * fullscreen mode. The default implementation runs in fullsceen only
- * when the screen is in landscape mode. If you change what
- * this returns, you will need to call {@link #updateFullscreenMode()}
- * yourself whenever the returned value may have changed to have it
- * re-evaluated and applied.
- */
- public boolean onEvaluateFullscreenMode() {
- Configuration config = getResources().getConfiguration();
- return config.orientation == Configuration.ORIENTATION_LANDSCAPE;
- }
-
- /**
- * Compute the interesting insets into your UI. The default implementation
- * uses the top of the candidates frame for the visible insets, and the
- * top of the input frame for the content insets. The default touchable
- * insets are {@link Insets#TOUCHABLE_INSETS_VISIBLE}.
- *
- * <p>Note that this method is not called when in fullscreen mode, since
- * in that case the application is left as-is behind the input method and
- * not impacted by anything in its UI.
- *
- * @param outInsets Fill in with the current UI insets.
- */
- public void onComputeInsets(Insets outInsets) {
- int[] loc = mTmpLocation;
- if (mInputFrame.getVisibility() == View.VISIBLE) {
- mInputFrame.getLocationInWindow(loc);
- } else {
- loc[1] = 0;
- }
- outInsets.contentTopInsets = loc[1];
- if (mCandidatesFrame.getVisibility() == View.VISIBLE) {
- mCandidatesFrame.getLocationInWindow(loc);
- }
- outInsets.visibleTopInsets = loc[1];
- outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_VISIBLE;
- }
-
- /**
- * Re-evaluate whether the soft input area should currently be shown, and
- * update its UI if this has changed since the last time it
- * was evaluated. This will call {@link #onEvaluateInputViewShown()} to
- * determine whether the input view should currently be shown. You
- * can use {@link #isInputViewShown()} to determine if the input view
- * is currently shown.
- */
- public void updateInputViewShown() {
- boolean isShown = mShowInputRequested && onEvaluateInputViewShown();
- if (mIsInputViewShown != isShown && mWindowVisible) {
- mIsInputViewShown = isShown;
- mInputFrame.setVisibility(isShown ? View.VISIBLE : View.GONE);
- if (mInputView == null) {
- initialize();
- View v = onCreateInputView();
- if (v != null) {
- setInputView(v);
- }
- }
- }
- }
-
- /**
- * Returns true if we have been asked to show our input view.
- */
- public boolean isShowInputRequested() {
- return mShowInputRequested;
- }
-
- /**
- * Return whether the soft input view is <em>currently</em> shown to the
- * user. This is the state that was last determined and
- * applied by {@link #updateInputViewShown()}.
- */
- public boolean isInputViewShown() {
- return mIsInputViewShown && mWindowVisible;
- }
-
- /**
- * Override this to control when the soft input area should be shown to
- * the user. The default implementation only shows the input view when
- * there is no hard keyboard or the keyboard is hidden. If you change what
- * this returns, you will need to call {@link #updateInputViewShown()}
- * yourself whenever the returned value may have changed to have it
- * re-evalauted and applied.
- */
- public boolean onEvaluateInputViewShown() {
- Configuration config = getResources().getConfiguration();
- return config.keyboard == Configuration.KEYBOARD_NOKEYS
- || config.hardKeyboardHidden == Configuration.KEYBOARDHIDDEN_YES;
- }
-
- /**
- * Controls the visibility of the candidates display area. By default
- * it is hidden.
- */
- public void setCandidatesViewShown(boolean shown) {
- int vis = shown ? View.VISIBLE : getCandidatesHiddenVisibility();
- if (mCandidatesVisibility != vis) {
- mCandidatesFrame.setVisibility(vis);
- mCandidatesVisibility = vis;
- }
- if (!mShowInputRequested && mWindowVisible != shown) {
- // If we are being asked to show the candidates view while the app
- // has not asked for the input view to be shown, then we need
- // to update whether the window is shown.
- if (shown) {
- showWindow(false);
- } else {
- hideWindow();
- }
- }
- }
-
- /**
- * Returns the visibility mode (either {@link View#INVISIBLE View.INVISIBLE}
- * or {@link View#GONE View.GONE}) of the candidates view when it is not
- * shown. The default implementation returns GONE when in fullscreen mode,
- * otherwise VISIBLE. Be careful if you change this to return GONE in
- * other situations -- if showing or hiding the candidates view causes
- * your window to resize, this can cause temporary drawing artifacts as
- * the resize takes place.
- */
- public int getCandidatesHiddenVisibility() {
- return isFullscreenMode() ? View.GONE : View.INVISIBLE;
- }
-
- public void showStatusIcon(int iconResId) {
- mStatusIcon = iconResId;
- mImm.showStatusIcon(mToken, getPackageName(), iconResId);
- }
-
- public void hideStatusIcon() {
- mStatusIcon = 0;
- mImm.hideStatusIcon(mToken);
- }
-
- /**
- * Force switch to a new input method, as identified by <var>id</var>. This
- * input method will be destroyed, and the requested one started on the
- * current input field.
- *
- * @param id Unique identifier of the new input method ot start.
- */
- public void switchInputMethod(String id) {
- mImm.setInputMethod(mToken, id);
- }
-
- public void setExtractView(View view) {
- mExtractFrame.removeAllViews();
- mExtractFrame.addView(view, new FrameLayout.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.FILL_PARENT));
- mExtractView = view;
- if (view != null) {
- mExtractEditText = (ExtractEditText)view.findViewById(
- com.android.internal.R.id.inputExtractEditText);
- mExtractEditText.setIME(this);
- startExtractingText();
- } else {
- mExtractEditText = null;
- }
- }
-
- /**
- * Replaces the current candidates view with a new one. You only need to
- * call this when dynamically changing the view; normally, you should
- * implement {@link #onCreateCandidatesView()} and create your view when
- * first needed by the input method.
- */
- public void setCandidatesView(View view) {
- mCandidatesFrame.removeAllViews();
- mCandidatesFrame.addView(view, new FrameLayout.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
- }
-
- /**
- * Replaces the current input view with a new one. You only need to
- * call this when dynamically changing the view; normally, you should
- * implement {@link #onCreateInputView()} and create your view when
- * first needed by the input method.
- */
- public void setInputView(View view) {
- mInputFrame.removeAllViews();
- mInputFrame.addView(view, new FrameLayout.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
- mInputView = view;
- }
-
- /**
- * Called by the framework to create a Drawable for the background of
- * the input method window. May return null for no background. The default
- * implementation returns a non-null standard background only when in
- * fullscreen mode. This is called each time the fullscreen mode changes.
- */
- public Drawable onCreateBackgroundDrawable() {
- if (isFullscreenMode()) {
- return getResources().getDrawable(
- com.android.internal.R.drawable.input_method_fullscreen_background);
- }
- return null;
- }
-
- /**
- * Called by the framework to create the layout for showing extacted text.
- * Only called when in fullscreen mode. The returned view hierarchy must
- * have an {@link ExtractEditText} whose ID is
- * {@link android.R.id#inputExtractEditText}.
- */
- public View onCreateExtractTextView() {
- return mInflater.inflate(
- com.android.internal.R.layout.input_method_extract_view, null);
- }
-
- /**
- * Create and return the view hierarchy used to show candidates. This will
- * be called once, when the candidates are first displayed. You can return
- * null to have no candidates view; the default implementation returns null.
- *
- * <p>To control when the candidates view is displayed, use
- * {@link #setCandidatesViewShown(boolean)}.
- * To change the candidates view after the first one is created by this
- * function, use {@link #setCandidatesView(View)}.
- */
- public View onCreateCandidatesView() {
- return null;
- }
-
- /**
- * Create and return the view hierarchy used for the input area (such as
- * a soft keyboard). This will be called once, when the input area is
- * first displayed. You can return null to have no input area; the default
- * implementation returns null.
- *
- * <p>To control when the input view is displayed, implement
- * {@link #onEvaluateInputViewShown()}.
- * To change the input view after the first one is created by this
- * function, use {@link #setInputView(View)}.
- */
- public View onCreateInputView() {
- return null;
- }
-
- /**
- * Called when the input view is being shown and input has started on
- * a new editor. This will always be called after {@link #onStartInput},
- * allowing you to do your general setup there and just view-specific
- * setup here. You are guaranteed that {@link #onCreateInputView()} will
- * have been called some time before this function is called.
- *
- * @param info Description of the type of text being edited.
- * @param restarting Set to true if we are restarting input on the
- * same text field as before.
- */
- public void onStartInputView(EditorInfo info, boolean restarting) {
- }
-
- /**
- * Called when the input view is being hidden from the user. This will
- * be called either prior to hiding the window, or prior to switching to
- * another target for editing.
- *
- * <p>The default
- * implementation uses the InputConnection to clear any active composing
- * text; you can override this (not calling the base class implementation)
- * to perform whatever behavior you would like.
- *
- * @boolean finishingInput If true, {@link #onFinishInput} will be
- * called immediately after.
- */
- public void onFinishInputView(boolean finishingInput) {
- if (!finishingInput) {
- InputConnection ic = getCurrentInputConnection();
- if (ic != null) {
- ic.finishComposingText();
- }
- }
- }
-
- /**
- * Called when only the candidates view has been shown for showing
- * processing as the user enters text through a hard keyboard.
- * This will always be called after {@link #onStartInput},
- * allowing you to do your general setup there and just view-specific
- * setup here. You are guaranteed that {@link #onCreateCandidatesView()}
- * will have been called some time before this function is called.
- *
- * <p>Note that this will <em>not</em> be called when the input method
- * is running in full editing mode, and thus receiving
- * {@link #onStartInputView} to initiate that operation. This is only
- * for the case when candidates are being shown while the input method
- * editor is hidden but wants to show its candidates UI as text is
- * entered through some other mechanism.
- *
- * @param info Description of the type of text being edited.
- * @param restarting Set to true if we are restarting input on the
- * same text field as before.
- */
- public void onStartCandidatesView(EditorInfo info, boolean restarting) {
- }
-
- /**
- * Called when the candidates view is being hidden from the user. This will
- * be called either prior to hiding the window, or prior to switching to
- * another target for editing.
- *
- * <p>The default
- * implementation uses the InputConnection to clear any active composing
- * text; you can override this (not calling the base class implementation)
- * to perform whatever behavior you would like.
- *
- * @boolean finishingInput If true, {@link #onFinishInput} will be
- * called immediately after.
- */
- public void onFinishCandidatesView(boolean finishingInput) {
- if (!finishingInput) {
- InputConnection ic = getCurrentInputConnection();
- if (ic != null) {
- ic.finishComposingText();
- }
- }
- }
-
- /**
- * The system has decided that it may be time to show your input method.
- * This is called due to a corresponding call to your
- * {@link InputMethod#showSoftInput(int) InputMethod.showSoftInput(int)}
- * method. The default implementation uses
- * {@link #onEvaluateInputViewShown()}, {@link #onEvaluateFullscreenMode()},
- * and the current configuration to decide whether the input view should
- * be shown at this point.
- *
- * @param flags Provides additional information about the show request,
- * as per {@link InputMethod#showSoftInput(int) InputMethod.showSoftInput(int)}.
- * @param configChange This is true if we are re-showing due to a
- * configuration change.
- * @return Returns true to indicate that the window should be shown.
- */
- public boolean onShowInputRequested(int flags, boolean configChange) {
- if (!onEvaluateInputViewShown()) {
- return false;
- }
- if ((flags&InputMethod.SHOW_EXPLICIT) == 0) {
- if (!configChange && onEvaluateFullscreenMode()) {
- // Don't show if this is not explicitly requested by the user and
- // the input method is fullscreen. That would be too disruptive.
- // However, we skip this change for a config change, since if
- // the IME is already shown we do want to go into fullscreen
- // mode at this point.
- return false;
- }
- Configuration config = getResources().getConfiguration();
- if (config.keyboard != Configuration.KEYBOARD_NOKEYS) {
- // And if the device has a hard keyboard, even if it is
- // currently hidden, don't show the input method implicitly.
- // These kinds of devices don't need it that much.
- return false;
- }
- }
- if ((flags&InputMethod.SHOW_FORCED) != 0) {
- mShowInputForced = true;
- }
- return true;
- }
-
- public void showWindow(boolean showInput) {
- if (DEBUG) Log.v(TAG, "Showing window: showInput=" + showInput
- + " mShowInputRequested=" + mShowInputRequested
- + " mWindowAdded=" + mWindowAdded
- + " mWindowCreated=" + mWindowCreated
- + " mWindowVisible=" + mWindowVisible
- + " mInputStarted=" + mInputStarted);
- boolean doShowInput = false;
- boolean wasVisible = mWindowVisible;
- mWindowVisible = true;
- if (!mShowInputRequested) {
- if (mInputStarted) {
- if (showInput) {
- doShowInput = true;
- mShowInputRequested = true;
- }
- }
- } else {
- showInput = true;
- }
-
- if (DEBUG) Log.v(TAG, "showWindow: updating UI");
- initialize();
- updateFullscreenMode();
- updateInputViewShown();
-
- if (!mWindowAdded || !mWindowCreated) {
- mWindowAdded = true;
- mWindowCreated = true;
- initialize();
- if (DEBUG) Log.v(TAG, "CALL: onCreateCandidatesView");
- View v = onCreateCandidatesView();
- if (DEBUG) Log.v(TAG, "showWindow: candidates=" + v);
- if (v != null) {
- setCandidatesView(v);
- }
- }
- if (mShowInputRequested) {
- if (!mInputViewStarted) {
- if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
- mInputViewStarted = true;
- onStartInputView(mInputEditorInfo, false);
- }
- } else if (!mCandidatesViewStarted) {
- if (DEBUG) Log.v(TAG, "CALL: onStartCandidatesView");
- mCandidatesViewStarted = true;
- onStartCandidatesView(mInputEditorInfo, false);
- }
-
- if (doShowInput) {
- startExtractingText();
- }
-
- if (!wasVisible) {
- if (DEBUG) Log.v(TAG, "showWindow: showing!");
- onWindowShown();
- mWindow.show();
- }
- }
-
- public void hideWindow() {
- if (mInputViewStarted) {
- if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
- onFinishInputView(false);
- } else if (mCandidatesViewStarted) {
- if (DEBUG) Log.v(TAG, "CALL: onFinishCandidatesView");
- onFinishCandidatesView(false);
- }
- mInputViewStarted = false;
- mCandidatesViewStarted = false;
- if (mWindowVisible) {
- mWindow.hide();
- mWindowVisible = false;
- onWindowHidden();
- }
- }
-
- /**
- * Called when the input method window has been shown to the user, after
- * previously not being visible. This is done after all of the UI setup
- * for the window has occurred (creating its views etc).
- */
- public void onWindowShown() {
- }
-
- /**
- * Called when the input method window has been hidden from the user,
- * after previously being visible.
- */
- public void onWindowHidden() {
- }
-
- /**
- * Called when a new client has bound to the input method. This
- * may be followed by a series of {@link #onStartInput(EditorInfo, boolean)}
- * and {@link #onFinishInput()} calls as the user navigates through its
- * UI. Upon this call you know that {@link #getCurrentInputBinding}
- * and {@link #getCurrentInputConnection} return valid objects.
- */
- public void onBindInput() {
- }
-
- /**
- * Called when the previous bound client is no longer associated
- * with the input method. After returning {@link #getCurrentInputBinding}
- * and {@link #getCurrentInputConnection} will no longer return
- * valid objects.
- */
- public void onUnbindInput() {
- }
-
- /**
- * Called to inform the input method that text input has started in an
- * editor. You should use this callback to initialize the state of your
- * input to match the state of the editor given to it.
- *
- * @param attribute The attributes of the editor that input is starting
- * in.
- * @param restarting Set to true if input is restarting in the same
- * editor such as because the application has changed the text in
- * the editor. Otherwise will be false, indicating this is a new
- * session with the editor.
- */
- public void onStartInput(EditorInfo attribute, boolean restarting) {
- }
-
- void doFinishInput() {
- if (mInputViewStarted) {
- if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
- onFinishInputView(true);
- } else if (mCandidatesViewStarted) {
- if (DEBUG) Log.v(TAG, "CALL: onFinishCandidatesView");
- onFinishCandidatesView(true);
- }
- mInputViewStarted = false;
- mCandidatesViewStarted = false;
- if (mInputStarted) {
- if (DEBUG) Log.v(TAG, "CALL: onFinishInput");
- onFinishInput();
- }
- mInputStarted = false;
- mStartedInputConnection = null;
- mCurCompletions = null;
- }
-
- void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) {
- if (!restarting) {
- doFinishInput();
- }
- mInputStarted = true;
- mStartedInputConnection = ic;
- mInputEditorInfo = attribute;
- initialize();
- if (DEBUG) Log.v(TAG, "CALL: onStartInput");
- onStartInput(attribute, restarting);
- if (mWindowVisible) {
- if (mShowInputRequested) {
- if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
- mInputViewStarted = true;
- onStartInputView(mInputEditorInfo, restarting);
- startExtractingText();
- } else if (mCandidatesVisibility == View.VISIBLE) {
- if (DEBUG) Log.v(TAG, "CALL: onStartCandidatesView");
- mCandidatesViewStarted = true;
- onStartCandidatesView(mInputEditorInfo, restarting);
- }
- }
- }
-
- /**
- * Called to inform the input method that text input has finished in
- * the last editor. At this point there may be a call to
- * {@link #onStartInput(EditorInfo, boolean)} to perform input in a
- * new editor, or the input method may be left idle. This method is
- * <em>not</em> called when input restarts in the same editor.
- *
- * <p>The default
- * implementation uses the InputConnection to clear any active composing
- * text; you can override this (not calling the base class implementation)
- * to perform whatever behavior you would like.
- */
- public void onFinishInput() {
- InputConnection ic = getCurrentInputConnection();
- if (ic != null) {
- ic.finishComposingText();
- }
- }
-
- /**
- * Called when the application has reported auto-completion candidates that
- * it would like to have the input method displayed. Typically these are
- * only used when an input method is running in full-screen mode, since
- * otherwise the user can see and interact with the pop-up window of
- * completions shown by the application.
- *
- * <p>The default implementation here does nothing.
- */
- public void onDisplayCompletions(CompletionInfo[] completions) {
- }
-
- /**
- * Called when the application has reported new extracted text to be shown
- * due to changes in its current text state. The default implementation
- * here places the new text in the extract edit text, when the input
- * method is running in fullscreen mode.
- */
- public void onUpdateExtractedText(int token, ExtractedText text) {
- if (mExtractedToken != token) {
- return;
- }
- if (mExtractEditText != null && text != null) {
- mExtractedText = text;
- mExtractEditText.setExtractedText(text);
- }
- }
-
- /**
- * Called when the application has reported a new selection region of
- * the text. This is called whether or not the input method has requested
- * extracted text updates, although if so it will not receive this call
- * if the extracted text has changed as well.
- *
- * <p>The default implementation takes care of updating the cursor in
- * the extract text, if it is being shown.
- */
- public void onUpdateSelection(int oldSelStart, int oldSelEnd,
- int newSelStart, int newSelEnd,
- int candidatesStart, int candidatesEnd) {
- final ExtractEditText eet = mExtractEditText;
- if (eet != null && mExtractedText != null) {
- final int off = mExtractedText.startOffset;
- eet.startInternalChanges();
- eet.setSelection(newSelStart-off, newSelEnd-off);
- eet.finishInternalChanges();
- }
- }
-
- /**
- * Called when the application has reported a new location of its text
- * cursor. This is only called if explicitly requested by the input method.
- * The default implementation does nothing.
- */
- public void onUpdateCursor(Rect newCursor) {
- }
-
- /**
- * Close this input method's soft input area, removing it from the display.
- * The input method will continue running, but the user can no longer use
- * it to generate input by touching the screen.
- * @param flags Provides additional operating flags. Currently may be
- * 0 or have the {@link InputMethodManager#HIDE_IMPLICIT_ONLY
- * InputMethodManager.HIDE_IMPLICIT_ONLY} bit set.
- */
- public void dismissSoftInput(int flags) {
- mImm.hideSoftInputFromInputMethod(mToken, flags);
- }
-
- /**
- * Override this to intercept key down events before they are processed by the
- * application. If you return true, the application will not itself
- * process the event. If you return true, the normal application processing
- * will occur as if the IME had not seen the event at all.
- *
- * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK
- * KeyEvent.KEYCODE_BACK} to hide the current IME UI if it is shown. In
- * additional, in fullscreen mode only, it will consume DPAD movement
- * events to move the cursor in the extracted text view, not allowing
- * them to perform navigation in the underlying application.
- */
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
- && event.getRepeatCount() == 0) {
- if (mShowInputRequested) {
- // If the soft input area is shown, back closes it and we
- // consume the back key.
- dismissSoftInput(0);
- return true;
- } else if (mWindowVisible) {
- if (mCandidatesVisibility == View.VISIBLE) {
- // If we are showing candidates even if no input area, then
- // hide them.
- setCandidatesViewShown(false);
- return true;
- } else {
- // If we have the window visible for some other reason --
- // most likely to show candidates -- then just get rid
- // of it. This really shouldn't happen, but just in case...
- hideWindow();
- return true;
- }
- }
- }
-
- return doMovementKey(keyCode, event, MOVEMENT_DOWN);
- }
-
- /**
- * Override this to intercept special key multiple events before they are
- * processed by the
- * application. If you return true, the application will not itself
- * process the event. If you return true, the normal application processing
- * will occur as if the IME had not seen the event at all.
- *
- * <p>The default implementation always returns false, except when
- * in fullscreen mode, where it will consume DPAD movement
- * events to move the cursor in the extracted text view, not allowing
- * them to perform navigation in the underlying application.
- */
- public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
- return doMovementKey(keyCode, event, count);
- }
-
- /**
- * Override this to intercept key up events before they are processed by the
- * application. If you return true, the application will not itself
- * process the event. If you return true, the normal application processing
- * will occur as if the IME had not seen the event at all.
- *
- * <p>The default implementation always returns false, except when
- * in fullscreen mode, where it will consume DPAD movement
- * events to move the cursor in the extracted text view, not allowing
- * them to perform navigation in the underlying application.
- */
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- return doMovementKey(keyCode, event, MOVEMENT_UP);
- }
-
- public boolean onTrackballEvent(MotionEvent event) {
- return false;
- }
-
- public void onAppPrivateCommand(String action, Bundle data) {
- }
-
- static final int MOVEMENT_DOWN = -1;
- static final int MOVEMENT_UP = -2;
-
- boolean doMovementKey(int keyCode, KeyEvent event, int count) {
- final ExtractEditText eet = mExtractEditText;
- if (isFullscreenMode() && isInputViewShown() && eet != null) {
- // If we are in fullscreen mode, the cursor will move around
- // the extract edit text, but should NOT cause focus to move
- // to other fields.
- MovementMethod movement = eet.getMovementMethod();
- Layout layout = eet.getLayout();
- if (movement != null && layout != null) {
- // We want our own movement method to handle the key, so the
- // cursor will properly move in our own word wrapping.
- if (count == MOVEMENT_DOWN) {
- if (movement.onKeyDown(eet,
- (Spannable)eet.getText(), keyCode, event)) {
- return true;
- }
- } else if (count == MOVEMENT_UP) {
- if (movement.onKeyUp(eet,
- (Spannable)eet.getText(), keyCode, event)) {
- return true;
- }
- } else {
- if (!movement.onKeyOther(eet, (Spannable)eet.getText(), event)) {
- KeyEvent down = new KeyEvent(event, KeyEvent.ACTION_DOWN);
- if (movement.onKeyDown(eet,
- (Spannable)eet.getText(), keyCode, down)) {
- KeyEvent up = new KeyEvent(event, KeyEvent.ACTION_UP);
- movement.onKeyUp(eet,
- (Spannable)eet.getText(), keyCode, up);
- while (--count > 0) {
- movement.onKeyDown(eet,
- (Spannable)eet.getText(), keyCode, down);
- movement.onKeyUp(eet,
- (Spannable)eet.getText(), keyCode, up);
- }
- }
- }
- }
- }
- // Regardless of whether the movement method handled the key,
- // we never allow DPAD navigation to the application.
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_LEFT:
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- case KeyEvent.KEYCODE_DPAD_UP:
- case KeyEvent.KEYCODE_DPAD_DOWN:
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * This is called when the user has moved the cursor in the extracted
- * text view, when running in fullsreen mode. The default implementation
- * performs the corresponding selection change on the underlying text
- * editor.
- */
- public void onExtractedSelectionChanged(int start, int end) {
- InputConnection conn = getCurrentInputConnection();
- if (conn != null) {
- conn.setSelection(start, end);
- }
- }
-
- /**
- * This is called when the user has clicked on the extracted text view,
- * when running in fullscreen mode. The default implementation hides
- * the candidates view when this happens. Re-implement this to provide
- * whatever behavior you want.
- */
- public void onExtractedTextClicked() {
- setCandidatesViewShown(false);
- }
-
- /**
- * This is called when the user has selected a context menu item from the
- * extracted text view, when running in fullscreen mode. The default
- * implementation sends this action to the current InputConnection's
- * {@link InputConnection#performContextMenuAction(int)}, for it
- * to be processed in underlying "real" editor. Re-implement this to
- * provide whatever behavior you want.
- */
- public boolean onExtractTextContextMenuItem(int id) {
- InputConnection ic = getCurrentInputConnection();
- if (ic != null) {
- ic.performContextMenuAction(id);
- }
- return true;
- }
-
- void startExtractingText() {
- final ExtractEditText eet = mExtractEditText;
- if (eet != null && getCurrentInputStarted()
- && isFullscreenMode()) {
- mExtractedToken++;
- ExtractedTextRequest req = new ExtractedTextRequest();
- req.token = mExtractedToken;
- req.flags = InputConnection.GET_TEXT_WITH_STYLES;
- req.hintMaxLines = 10;
- req.hintMaxChars = 10000;
- mExtractedText = getCurrentInputConnection().getExtractedText(req,
- InputConnection.GET_EXTRACTED_TEXT_MONITOR);
- try {
- eet.startInternalChanges();
- int inputType = getCurrentInputEditorInfo().inputType;
- if ((inputType&EditorInfo.TYPE_MASK_CLASS)
- == EditorInfo.TYPE_CLASS_TEXT) {
- if ((inputType&EditorInfo.TYPE_TEXT_FLAG_IME_MULTI_LINE) != 0) {
- inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
- }
- }
- eet.setInputType(inputType);
- eet.setHint(mInputEditorInfo.hintText);
- if (mExtractedText != null) {
- eet.setEnabled(true);
- eet.setExtractedText(mExtractedText);
- } else {
- eet.setEnabled(false);
- eet.setText("");
- }
- } finally {
- eet.finishInternalChanges();
- }
- }
- }
-
- /**
- * Performs a dump of the InputMethodService's internal state. Override
- * to add your own information to the dump.
- */
- @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
- final Printer p = new PrintWriterPrinter(fout);
- p.println("Input method service state for " + this + ":");
- p.println(" mWindowCreated=" + mWindowCreated
- + " mWindowAdded=" + mWindowAdded
- + " mWindowVisible=" + mWindowVisible);
- p.println(" Configuration=" + getResources().getConfiguration());
- p.println(" mToken=" + mToken);
- p.println(" mInputBinding=" + mInputBinding);
- p.println(" mInputConnection=" + mInputConnection);
- p.println(" mStartedInputConnection=" + mStartedInputConnection);
- p.println(" mInputStarted=" + mInputStarted
- + " mInputViewStarted=" + mInputViewStarted
- + " mCandidatesViewStarted=" + mCandidatesViewStarted);
-
- if (mInputEditorInfo != null) {
- p.println(" mInputEditorInfo:");
- mInputEditorInfo.dump(p, " ");
- } else {
- p.println(" mInputEditorInfo: null");
- }
-
- p.println(" mShowInputRequested=" + mShowInputRequested
- + " mLastShowInputRequested=" + mLastShowInputRequested
- + " mShowInputForced=" + mShowInputForced
- + " mShowInputFlags=0x" + Integer.toHexString(mShowInputFlags));
- p.println(" mCandidatesVisibility=" + mCandidatesVisibility
- + " mFullscreenApplied=" + mFullscreenApplied
- + " mIsFullscreen=" + mIsFullscreen);
-
- if (mExtractedText != null) {
- p.println(" mExtractedText:");
- p.println(" text=" + mExtractedText.text.length() + " chars"
- + " startOffset=" + mExtractedText.startOffset);
- p.println(" selectionStart=" + mExtractedText.selectionStart
- + " selectionEnd=" + mExtractedText.selectionEnd
- + " flags=0x" + Integer.toHexString(mExtractedText.flags));
- } else {
- p.println(" mExtractedText: null");
- }
- p.println(" mExtractedToken=" + mExtractedToken);
- p.println(" mIsInputViewShown=" + mIsInputViewShown
- + " mStatusIcon=" + mStatusIcon);
- p.println("Last computed insets:");
- p.println(" contentTopInsets=" + mTmpInsets.contentTopInsets
- + " visibleTopInsets=" + mTmpInsets.visibleTopInsets
- + " touchableInsets=" + mTmpInsets.touchableInsets);
- }
-}