Skip to content
Permalink
Browse files

Add IMS#BACK_DISPOSITION_ADJUST_NOTHING

This is a follow up CL to our previous attempt [1] to make
InputMethodService#setBackDisposition() work and make sense.

Based on the feedback from several IME developers, we learned that
InputMethodService#setBackDisposition() is still confusing.

My conclusion is that trying to reuse existing flags was a mistake.
Here are the rationale for deprecating those two flags.

 * BACK_DISPOSITION_WILL_NOT_DISMISS

   This flag had never been used until we started using it in our
   previous CL [1].  However, it turns out that what this flag means
   is hard to understand because its JavaDoc only says
      "This input method will not consume the back key."
   To address the original goal of Bug 38513361, we can (and should)
   introduce a new flag rather than reusing this confusing flag.
   Deprecating this flag should have no impact because it had never
   been used.

 * BACK_DISPOSITION_WILL_DISMISS

   On pre-P devices IME could abuse this flag to override the back
   button to "dismiss" mode even after IME lost the focus.  On the
   other hand, as far as we know there is no good use case for this
   flag.  Hence rather than trying to fix such an abuse scenario, we
   should just deprecate this flag.

Instead, a newly introduced flag BACK_DISPOSITION_ADJUST_NOTHING
should be sufficient to achieve the original goal of Bug 38513361.
This flag does not rely on the concept "dismiss" and key event
handling hence it would be much easier to maintain.

 [1]: I99e7c413fe1a93f8d8cff897b5c5f0947690d2c0
      3fecef1

Fix: 74403102
Test: atest CtsInputMethodTestCases
Change-Id: I064209c40da79fffb2627e8f580818a793017b1f
  • Loading branch information...
yukawa committed Mar 14, 2018
1 parent dcf12d4 commit 386f50e04f6e93894a38951cf9e946e9fa952af8
@@ -21245,9 +21245,10 @@ package android.inputmethodservice {
method public final boolean switchToPreviousInputMethod();
method public void updateFullscreenMode();
method public void updateInputViewShown();
field public static final int BACK_DISPOSITION_ADJUST_NOTHING = 3; // 0x3
field public static final int BACK_DISPOSITION_DEFAULT = 0; // 0x0
field public static final int BACK_DISPOSITION_WILL_DISMISS = 2; // 0x2
field public static final int BACK_DISPOSITION_WILL_NOT_DISMISS = 1; // 0x1
field public static final deprecated int BACK_DISPOSITION_WILL_DISMISS = 2; // 0x2
field public static final deprecated int BACK_DISPOSITION_WILL_NOT_DISMISS = 1; // 0x1
}

public class InputMethodService.InputMethodImpl extends android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodImpl {
@@ -20,6 +20,8 @@
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;

import static java.lang.annotation.RetentionPolicy.SOURCE;

import android.annotation.CallSuper;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
@@ -239,19 +241,89 @@
static final boolean DEBUG = false;

/**
* The back button will close the input window.
* Allows the system to optimize the back button affordance based on the presence of software
* keyboard.
*
* <p>For instance, on devices that have navigation bar and software-rendered back button, the
* system may use a different icon while {@link #isInputViewShown()} returns {@code true}, to
* indicate that the back button has "dismiss" affordance.</p>
*
* <p>Note that {@link KeyEvent#KEYCODE_BACK} events continue to be sent to
* {@link #onKeyDown(int, KeyEvent)} even when this mode is specified. The default
* implementation of {@link #onKeyDown(int, KeyEvent)} for {@link KeyEvent#KEYCODE_BACK} does
* not take this mode into account.</p>
*
* <p>For API level {@link android.os.Build.VERSION_CODES#O_MR1} and lower devices, this is the
* only mode you can safely specify without worrying about the compatibility.</p>
*
* @see #setBackDisposition(int)
*/
public static final int BACK_DISPOSITION_DEFAULT = 0; // based on window
public static final int BACK_DISPOSITION_DEFAULT = 0;

/**
* This input method will not consume the back key.
* Deprecated flag.
*
* <p>To avoid compatibility issues, IME developers should not use this flag.</p>
*
* @deprecated on {@link android.os.Build.VERSION_CODES#P} and later devices, this flag is
* handled as a synonym of {@link #BACK_DISPOSITION_DEFAULT}. On
* {@link android.os.Build.VERSION_CODES#O_MR1} and prior devices, expected behavior
* of this mode had not been well defined. Most likely the end result would be the
* same as {@link #BACK_DISPOSITION_DEFAULT}. Either way it is not recommended to
* use this mode
* @see #setBackDisposition(int)
*/
public static final int BACK_DISPOSITION_WILL_NOT_DISMISS = 1; // back
@Deprecated
public static final int BACK_DISPOSITION_WILL_NOT_DISMISS = 1;

/**
* This input method will consume the back key.
* Deprecated flag.
*
* <p>To avoid compatibility issues, IME developers should not use this flag.</p>
*
* @deprecated on {@link android.os.Build.VERSION_CODES#P} and later devices, this flag is
* handled as a synonym of {@link #BACK_DISPOSITION_DEFAULT}. On
* {@link android.os.Build.VERSION_CODES#O_MR1} and prior devices, expected behavior
* of this mode had not been well defined. In AOSP implementation running on devices
* that have navigation bar, specifying this flag could change the software back
* button to "Dismiss" icon no matter whether the software keyboard is shown or not,
* but there would be no easy way to restore the icon state even after IME lost the
* connection to the application. To avoid user confusions, do not specify this mode
* anyway
* @see #setBackDisposition(int)
*/
public static final int BACK_DISPOSITION_WILL_DISMISS = 2; // down
@Deprecated
public static final int BACK_DISPOSITION_WILL_DISMISS = 2;

/**
* Asks the system to not adjust the back button affordance even when the software keyboard is
* shown.
*
* <p>This mode is useful for UI modes where IME's main soft input window is used for some
* supplemental UI, such as floating candidate window for languages such as Chinese and
* Japanese, where users expect the back button is, or at least looks to be, handled by the
* target application rather than the UI shown by the IME even while {@link #isInputViewShown()}
* returns {@code true}.</p>
*
* <p>Note that {@link KeyEvent#KEYCODE_BACK} events continue to be sent to
* {@link #onKeyDown(int, KeyEvent)} even when this mode is specified. The default
* implementation of {@link #onKeyDown(int, KeyEvent)} for {@link KeyEvent#KEYCODE_BACK} does
* not take this mode into account.</p>
*
* @see #setBackDisposition(int)
*/
public static final int BACK_DISPOSITION_ADJUST_NOTHING = 3;

/**
* Enum flag to be used for {@link #setBackDisposition(int)}.
*
* @hide
*/
@Retention(SOURCE)
@IntDef(value = {BACK_DISPOSITION_DEFAULT, BACK_DISPOSITION_WILL_NOT_DISMISS,
BACK_DISPOSITION_WILL_DISMISS, BACK_DISPOSITION_ADJUST_NOTHING},
prefix = "BACK_DISPOSITION_")
public @interface BackDispositionMode {}

/**
* @hide
@@ -267,7 +339,7 @@

// 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_WILL_DISMISS;
private static final int BACK_DISPOSITION_MAX = BACK_DISPOSITION_ADJUST_NOTHING;

InputMethodManager mImm;

@@ -331,6 +403,8 @@
boolean mIsInputViewShown;

int mStatusIcon;

@BackDispositionMode
int mBackDisposition;

/**
@@ -1015,8 +1089,19 @@ public LayoutInflater getLayoutInflater() {
public Dialog getWindow() {
return mWindow;
}

public void setBackDisposition(int disposition) {

/**
* Sets the disposition mode that indicates the expected affordance for the back button.
*
* <p>Keep in mind that specifying this flag does not change the the default behavior of
* {@link #onKeyDown(int, KeyEvent)}. It is IME developers' responsibility for making sure that
* their custom implementation of {@link #onKeyDown(int, KeyEvent)} is consistent with the mode
* specified to this API.</p>
*
* @see #getBackDisposition()
* @param disposition disposition mode to be set
*/
public void setBackDisposition(@BackDispositionMode int disposition) {
if (disposition == mBackDisposition) {
return;
}
@@ -1029,6 +1114,13 @@ public void setBackDisposition(int disposition) {
mBackDisposition);
}

/**
* Retrieves the current disposition mode that indicates the expected back button affordance.
*
* @see #setBackDisposition(int)
* @return currently selected disposition mode
*/
@BackDispositionMode
public int getBackDisposition() {
return mBackDisposition;
}
@@ -1894,7 +1986,6 @@ void doFinishInput() {
mInputStarted = false;
mStartedInputConnection = null;
mCurCompletions = null;
mBackDisposition = BACK_DISPOSITION_DEFAULT;
}

void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) {
@@ -2096,25 +2187,31 @@ private ExtractEditText getExtractEditTextIfVisible() {
return mExtractEditText;
}


/**
* Override this to intercept key down events before they are processed by the
* application. If you return true, the application will not
* process the event itself. If you return false, 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} if the IME is currently shown, to
* possibly hide it when the key goes up (if not canceled or long pressed). In
* addition, 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.
* Called back when a {@link KeyEvent} is forwarded from the target application.
*
* <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK} if the IME is
* currently shown , to possibly hide it when the key goes up (if not canceled or long pressed).
* In addition, 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.</p>
*
* <p>The default implementation does not take flags specified to
* {@link #setBackDisposition(int)} into account, even on API version
* {@link android.os.Build.VERSION_CODES#P} and later devices. IME developers are responsible
* for making sure that their special handling for {@link KeyEvent#KEYCODE_BACK} are consistent
* with the flag they specified to {@link #setBackDisposition(int)}.</p>
*
* @param keyCode The value in {@code event.getKeyCode()}
* @param event Description of the key event
*
* @return {@code true} if the event is consumed by the IME and the application no longer needs
* to consume it. Return {@code false} when the event should be handled as if the IME
* had not seen the event at all.
*/
public boolean onKeyDown(int keyCode, KeyEvent event) {

if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
if (mBackDisposition == BACK_DISPOSITION_WILL_NOT_DISMISS) {
return false;
}
final ExtractEditText eet = getExtractEditTextIfVisible();
if (eet != null && eet.handleBackInTextActionModeIfNeeded(event)) {
return true;
@@ -343,10 +343,19 @@ public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
boolean showImeSwitcher) {
boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
int hints = mNavigationIconHints;
if (imeShown && backDisposition != InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS) {
hints |= NAVIGATION_HINT_BACK_ALT;
} else {
hints &= ~NAVIGATION_HINT_BACK_ALT;
switch (backDisposition) {
case InputMethodService.BACK_DISPOSITION_DEFAULT:
case InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS:
case InputMethodService.BACK_DISPOSITION_WILL_DISMISS:
if (imeShown) {
hints |= NAVIGATION_HINT_BACK_ALT;
} else {
hints &= ~NAVIGATION_HINT_BACK_ALT;
}
break;
case InputMethodService.BACK_DISPOSITION_ADJUST_NOTHING:
hints &= ~NAVIGATION_HINT_BACK_ALT;
break;
}
if (showImeSwitcher) {
hints |= NAVIGATION_HINT_IME_SHOWN;

0 comments on commit 386f50e

Please sign in to comment.
You can’t perform that action at this time.