summaryrefslogtreecommitdiff
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.java245
1 files changed, 170 insertions, 75 deletions
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index d3509d5eb289..301e48c4a990 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -346,6 +346,13 @@ public class InputMethodService extends AbstractInputMethodService {
*/
public static final int IME_VISIBLE = 0x2;
+ /**
+ * @hide
+ * The IME is active and ready with views but set invisible.
+ * This flag cannot be combined with {@link #IME_VISIBLE}.
+ */
+ public static final int IME_INVISIBLE = 0x4;
+
// Min and max values for back disposition.
private static final int BACK_DISPOSITION_MIN = BACK_DISPOSITION_DEFAULT;
private static final int BACK_DISPOSITION_MAX = BACK_DISPOSITION_ADJUST_NOTHING;
@@ -362,10 +369,19 @@ public class InputMethodService extends AbstractInputMethodService {
View mRootView;
SoftInputWindow mWindow;
boolean mInitialized;
- boolean mWindowCreated;
- boolean mWindowVisible;
- boolean mWindowWasVisible;
+ boolean mViewsCreated;
+ // IME views visibility.
+ boolean mDecorViewVisible;
+ boolean mDecorViewWasVisible;
boolean mInShowWindow;
+ // True if pre-rendering of IME views/window is supported.
+ boolean mCanPreRender;
+ // If IME is pre-rendered.
+ boolean mIsPreRendered;
+ // IME window visibility.
+ // Use (mDecorViewVisible && mWindowVisible) to check if IME is visible to the user.
+ boolean mWindowVisible;
+
ViewGroup mFullscreenArea;
FrameLayout mExtractFrame;
FrameLayout mCandidatesFrame;
@@ -552,15 +568,18 @@ public class InputMethodService extends AbstractInputMethodService {
*/
@MainThread
@Override
- public void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
+ public final void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
@NonNull EditorInfo editorInfo, boolean restarting,
- @NonNull IBinder startInputToken) {
+ @NonNull IBinder startInputToken, boolean shouldPreRenderIme) {
mPrivOps.reportStartInput(startInputToken);
- // This needs to be dispatched to interface methods rather than doStartInput().
- // Otherwise IME developers who have overridden those interface methods will lose
- // notifications.
- super.dispatchStartInputWithToken(inputConnection, editorInfo, restarting,
- startInputToken);
+ mCanPreRender = shouldPreRenderIme;
+ if (DEBUG) Log.v(TAG, "Will Pre-render IME: " + mCanPreRender);
+
+ if (restarting) {
+ restartInput(inputConnection, editorInfo);
+ } else {
+ startInput(inputConnection, editorInfo);
+ }
}
/**
@@ -570,14 +589,27 @@ public class InputMethodService extends AbstractInputMethodService {
@Override
public void hideSoftInput(int flags, ResultReceiver resultReceiver) {
if (DEBUG) Log.v(TAG, "hideSoftInput()");
- boolean wasVis = isInputViewShown();
- mShowInputFlags = 0;
- mShowInputRequested = false;
- doHideWindow();
+ final boolean wasVisible = mIsPreRendered
+ ? mDecorViewVisible && mWindowVisible : isInputViewShown();
+ if (mIsPreRendered) {
+ // TODO: notify visibility to insets consumer.
+ if (DEBUG) {
+ Log.v(TAG, "Making IME window invisible");
+ }
+ setImeWindowStatus(IME_ACTIVE | IME_INVISIBLE, mBackDisposition);
+ onPreRenderedWindowVisibilityChanged(false /* setVisible */);
+ } else {
+ mShowInputFlags = 0;
+ mShowInputRequested = false;
+ doHideWindow();
+ }
+ final boolean isVisible = mIsPreRendered
+ ? mDecorViewVisible && mWindowVisible : isInputViewShown();
+ final boolean visibilityChanged = isVisible != wasVisible;
if (resultReceiver != null) {
- resultReceiver.send(wasVis != isInputViewShown()
+ resultReceiver.send(visibilityChanged
? InputMethodManager.RESULT_HIDDEN
- : (wasVis ? InputMethodManager.RESULT_UNCHANGED_SHOWN
+ : (wasVisible ? InputMethodManager.RESULT_UNCHANGED_SHOWN
: InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
}
}
@@ -589,17 +621,28 @@ public class InputMethodService extends AbstractInputMethodService {
@Override
public void showSoftInput(int flags, ResultReceiver resultReceiver) {
if (DEBUG) Log.v(TAG, "showSoftInput()");
- boolean wasVis = isInputViewShown();
+ final boolean wasVisible = mIsPreRendered
+ ? mDecorViewVisible && mWindowVisible : isInputViewShown();
if (dispatchOnShowInputRequested(flags, false)) {
- showWindow(true);
+ if (mIsPreRendered) {
+ // TODO: notify visibility to insets consumer.
+ if (DEBUG) {
+ Log.v(TAG, "Making IME window visible");
+ }
+ onPreRenderedWindowVisibilityChanged(true /* setVisible */);
+ } else {
+ showWindow(true);
+ }
}
// If user uses hard keyboard, IME button should always be shown.
- setImeWindowStatus(mapToImeWindowStatus(isInputViewShown()), mBackDisposition);
-
+ setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
+ final boolean isVisible = mIsPreRendered
+ ? mDecorViewVisible && mWindowVisible : isInputViewShown();
+ final boolean visibilityChanged = isVisible != wasVisible;
if (resultReceiver != null) {
- resultReceiver.send(wasVis != isInputViewShown()
+ resultReceiver.send(visibilityChanged
? InputMethodManager.RESULT_SHOWN
- : (wasVis ? InputMethodManager.RESULT_UNCHANGED_SHOWN
+ : (wasVisible ? InputMethodManager.RESULT_UNCHANGED_SHOWN
: InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
}
}
@@ -972,7 +1015,7 @@ public class InputMethodService extends AbstractInputMethodService {
void initViews() {
mInitialized = false;
- mWindowCreated = false;
+ mViewsCreated = false;
mShowInputRequested = false;
mShowInputFlags = 0;
@@ -1046,7 +1089,7 @@ public class InputMethodService extends AbstractInputMethodService {
}
private void resetStateForNewConfiguration() {
- boolean visible = mWindowVisible;
+ boolean visible = mDecorViewVisible;
int showFlags = mShowInputFlags;
boolean showingInput = mShowInputRequested;
CompletionInfo[] completions = mCurCompletions;
@@ -1129,7 +1172,7 @@ public class InputMethodService extends AbstractInputMethodService {
return;
}
mBackDisposition = disposition;
- setImeWindowStatus(mapToImeWindowStatus(isInputViewShown()), mBackDisposition);
+ setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
}
/**
@@ -1380,7 +1423,7 @@ public class InputMethodService extends AbstractInputMethodService {
mExtractFrame.setVisibility(View.GONE);
}
updateCandidatesVisibility(mCandidatesVisibility == View.VISIBLE);
- if (mWindowWasVisible && mFullscreenArea.getVisibility() != vis) {
+ if (mDecorViewWasVisible && mFullscreenArea.getVisibility() != vis) {
int animRes = mThemeAttrs.getResourceId(vis == View.VISIBLE
? com.android.internal.R.styleable.InputMethodService_imeExtractEnterAnimation
: com.android.internal.R.styleable.InputMethodService_imeExtractExitAnimation,
@@ -1439,7 +1482,7 @@ public class InputMethodService extends AbstractInputMethodService {
*/
public void updateInputViewShown() {
boolean isShown = mShowInputRequested && onEvaluateInputViewShown();
- if (mIsInputViewShown != isShown && mWindowVisible) {
+ if (mIsInputViewShown != isShown && mDecorViewVisible) {
mIsInputViewShown = isShown;
mInputFrame.setVisibility(isShown ? View.VISIBLE : View.GONE);
if (mInputView == null) {
@@ -1458,14 +1501,14 @@ public class InputMethodService extends AbstractInputMethodService {
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;
+ return mCanPreRender ? mWindowVisible : mIsInputViewShown && mDecorViewVisible;
}
/**
@@ -1499,7 +1542,7 @@ public class InputMethodService extends AbstractInputMethodService {
*/
public void setCandidatesViewShown(boolean shown) {
updateCandidatesVisibility(shown);
- if (!mShowInputRequested && mWindowVisible != shown) {
+ if (!mShowInputRequested && mDecorViewVisible != 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.
@@ -1804,7 +1847,8 @@ public class InputMethodService extends AbstractInputMethodService {
public void showWindow(boolean showInput) {
if (DEBUG) Log.v(TAG, "Showing window: showInput=" + showInput
+ " mShowInputRequested=" + mShowInputRequested
- + " mWindowCreated=" + mWindowCreated
+ + " mViewsCreated=" + mViewsCreated
+ + " mDecorViewVisible=" + mDecorViewVisible
+ " mWindowVisible=" + mWindowVisible
+ " mInputStarted=" + mInputStarted
+ " mShowInputFlags=" + mShowInputFlags);
@@ -1814,18 +1858,42 @@ public class InputMethodService extends AbstractInputMethodService {
return;
}
- mWindowWasVisible = mWindowVisible;
+ mDecorViewWasVisible = mDecorViewVisible;
mInShowWindow = true;
- showWindowInner(showInput);
- mWindowWasVisible = true;
+ boolean isPreRenderedAndInvisible = mIsPreRendered && !mWindowVisible;
+ final int previousImeWindowStatus =
+ (mDecorViewVisible ? IME_ACTIVE : 0) | (isInputViewShown()
+ ? (isPreRenderedAndInvisible ? IME_INVISIBLE : IME_VISIBLE) : 0);
+ startViews(prepareWindow(showInput));
+ final int nextImeWindowStatus = mapToImeWindowStatus();
+ if (previousImeWindowStatus != nextImeWindowStatus) {
+ setImeWindowStatus(nextImeWindowStatus, mBackDisposition);
+ }
+
+ // compute visibility
+ onWindowShown();
+ mIsPreRendered = mCanPreRender;
+ if (mIsPreRendered) {
+ onPreRenderedWindowVisibilityChanged(true /* setVisible */);
+ } else {
+ // Pre-rendering not supported.
+ if (DEBUG) Log.d(TAG, "No pre-rendering supported");
+ mWindowVisible = true;
+ }
+
+ // request draw for the IME surface.
+ // When IME is not pre-rendered, this will actually show the IME.
+ if ((previousImeWindowStatus & IME_ACTIVE) == 0) {
+ if (DEBUG) Log.v(TAG, "showWindow: draw decorView!");
+ mWindow.show();
+ }
+ mDecorViewWasVisible = true;
mInShowWindow = false;
}
- void showWindowInner(boolean showInput) {
+ private boolean prepareWindow(boolean showInput) {
boolean doShowInput = false;
- final int previousImeWindowStatus =
- (mWindowVisible ? IME_ACTIVE : 0) | (isInputViewShown() ? IME_VISIBLE : 0);
- mWindowVisible = true;
+ mDecorViewVisible = true;
if (!mShowInputRequested && mInputStarted && showInput) {
doShowInput = true;
mShowInputRequested = true;
@@ -1836,8 +1904,8 @@ public class InputMethodService extends AbstractInputMethodService {
updateFullscreenMode();
updateInputViewShown();
- if (!mWindowCreated) {
- mWindowCreated = true;
+ if (!mViewsCreated) {
+ mViewsCreated = true;
initialize();
if (DEBUG) Log.v(TAG, "CALL: onCreateCandidatesView");
View v = onCreateCandidatesView();
@@ -1846,6 +1914,10 @@ public class InputMethodService extends AbstractInputMethodService {
setCandidatesView(v);
}
}
+ return doShowInput;
+ }
+
+ private void startViews(boolean doShowInput) {
if (mShowInputRequested) {
if (!mInputViewStarted) {
if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
@@ -1857,29 +1929,26 @@ public class InputMethodService extends AbstractInputMethodService {
mCandidatesViewStarted = true;
onStartCandidatesView(mInputEditorInfo, false);
}
-
- if (doShowInput) {
- startExtractingText(false);
- }
+ if (doShowInput) startExtractingText(false);
+ }
- final int nextImeWindowStatus = mapToImeWindowStatus(isInputViewShown());
- if (previousImeWindowStatus != nextImeWindowStatus) {
- setImeWindowStatus(nextImeWindowStatus, mBackDisposition);
- }
- if ((previousImeWindowStatus & IME_ACTIVE) == 0) {
- if (DEBUG) Log.v(TAG, "showWindow: showing!");
+ private void onPreRenderedWindowVisibilityChanged(boolean setVisible) {
+ mWindowVisible = setVisible;
+ mShowInputFlags = setVisible ? mShowInputFlags : 0;
+ mShowInputRequested = setVisible;
+ mDecorViewVisible = setVisible;
+ if (setVisible) {
onWindowShown();
- mWindow.show();
}
}
- private void finishViews() {
+ private void finishViews(boolean finishingInput) {
if (mInputViewStarted) {
if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
- onFinishInputView(false);
+ onFinishInputView(finishingInput);
} else if (mCandidatesViewStarted) {
if (DEBUG) Log.v(TAG, "CALL: onFinishCandidatesView");
- onFinishCandidatesView(false);
+ onFinishCandidatesView(finishingInput);
}
mInputViewStarted = false;
mCandidatesViewStarted = false;
@@ -1891,12 +1960,15 @@ public class InputMethodService extends AbstractInputMethodService {
}
public void hideWindow() {
- finishViews();
- if (mWindowVisible) {
+ if (DEBUG) Log.v(TAG, "CALL: hideWindow");
+ mIsPreRendered = false;
+ mWindowVisible = false;
+ finishViews(false /* finishingInput */);
+ if (mDecorViewVisible) {
mWindow.hide();
- mWindowVisible = false;
+ mDecorViewVisible = false;
onWindowHidden();
- mWindowWasVisible = false;
+ mDecorViewWasVisible = false;
}
updateFullscreenMode();
}
@@ -1956,15 +2028,8 @@ public class InputMethodService extends AbstractInputMethodService {
}
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 (DEBUG) Log.v(TAG, "CALL: doFinishInput");
+ finishViews(true /* finishingInput */);
if (mInputStarted) {
if (DEBUG) Log.v(TAG, "CALL: onFinishInput");
onFinishInput();
@@ -1984,7 +2049,7 @@ public class InputMethodService extends AbstractInputMethodService {
initialize();
if (DEBUG) Log.v(TAG, "CALL: onStartInput");
onStartInput(attribute, restarting);
- if (mWindowVisible) {
+ if (mDecorViewVisible) {
if (mShowInputRequested) {
if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
mInputViewStarted = true;
@@ -1995,6 +2060,31 @@ public class InputMethodService extends AbstractInputMethodService {
mCandidatesViewStarted = true;
onStartCandidatesView(mInputEditorInfo, restarting);
}
+ } else if (mCanPreRender && mInputEditorInfo != null && mStartedInputConnection != null) {
+ // Pre-render IME views and window when real EditorInfo is available.
+ // pre-render IME window and keep it invisible.
+ if (DEBUG) Log.v(TAG, "Pre-Render IME for " + mInputEditorInfo.fieldName);
+ if (mInShowWindow) {
+ Log.w(TAG, "Re-entrance in to showWindow");
+ return;
+ }
+
+ mDecorViewWasVisible = mDecorViewVisible;
+ mInShowWindow = true;
+ startViews(prepareWindow(true /* showInput */));
+
+ // compute visibility
+ mIsPreRendered = true;
+ onPreRenderedWindowVisibilityChanged(false /* setVisible */);
+
+ // request draw for the IME surface.
+ // When IME is not pre-rendered, this will actually show the IME.
+ if (DEBUG) Log.v(TAG, "showWindow: draw decorView!");
+ mWindow.show();
+ mDecorViewWasVisible = true;
+ mInShowWindow = false;
+ } else {
+ mIsPreRendered = false;
}
}
@@ -2146,7 +2236,7 @@ public class InputMethodService extends AbstractInputMethodService {
// consume the back key.
if (doIt) requestHideSelf(0);
return true;
- } else if (mWindowVisible) {
+ } else if (mDecorViewVisible) {
if (mCandidatesVisibility == View.VISIBLE) {
// If we are showing candidates even if no input area, then
// hide them.
@@ -2173,7 +2263,6 @@ public class InputMethodService extends AbstractInputMethodService {
return mExtractEditText;
}
-
/**
* Called back when a {@link KeyEvent} is forwarded from the target application.
*
@@ -2886,8 +2975,11 @@ public class InputMethodService extends AbstractInputMethodService {
inputContentInfo.setUriToken(uriToken);
}
- private static int mapToImeWindowStatus(boolean isInputViewShown) {
- return IME_ACTIVE | (isInputViewShown ? IME_VISIBLE : 0);
+ private int mapToImeWindowStatus() {
+ return IME_ACTIVE
+ | (isInputViewShown()
+ ? (mCanPreRender ? (mWindowVisible ? IME_VISIBLE : IME_INVISIBLE)
+ : IME_VISIBLE) : 0);
}
/**
@@ -2897,9 +2989,10 @@ public class InputMethodService extends AbstractInputMethodService {
@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);
- p.println(" mWindowVisible=" + mWindowVisible
- + " mWindowWasVisible=" + mWindowWasVisible
+ p.println(" mViewsCreated=" + mViewsCreated);
+ p.println(" mDecorViewVisible=" + mDecorViewVisible
+ + " mDecorViewWasVisible=" + mDecorViewWasVisible
+ + " mWindowVisible=" + mWindowVisible
+ " mInShowWindow=" + mInShowWindow);
p.println(" Configuration=" + getResources().getConfiguration());
p.println(" mToken=" + mToken);
@@ -2919,6 +3012,8 @@ public class InputMethodService extends AbstractInputMethodService {
p.println(" mShowInputRequested=" + mShowInputRequested
+ " mLastShowInputRequested=" + mLastShowInputRequested
+ + " mCanPreRender=" + mCanPreRender
+ + " mIsPreRendered=" + mIsPreRendered
+ " mShowInputFlags=0x" + Integer.toHexString(mShowInputFlags));
p.println(" mCandidatesVisibility=" + mCandidatesVisibility
+ " mFullscreenApplied=" + mFullscreenApplied