(inputMethod);
+ mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
}
public InputMethod getInternalInputMethod() {
@@ -151,7 +153,9 @@ class IInputMethodWrapper extends IInputMethod.Stub
IInputContext inputContext = (IInputContext)args.arg1;
InputConnection ic = inputContext != null
? new InputConnectionWrapper(inputContext) : null;
- inputMethod.startInput(ic, (EditorInfo)args.arg2);
+ EditorInfo info = (EditorInfo)args.arg2;
+ info.makeCompatible(mTargetSdkVersion);
+ inputMethod.startInput(ic, info);
return;
}
case DO_RESTART_INPUT: {
@@ -159,7 +163,9 @@ class IInputMethodWrapper extends IInputMethod.Stub
IInputContext inputContext = (IInputContext)args.arg1;
InputConnection ic = inputContext != null
? new InputConnectionWrapper(inputContext) : null;
- inputMethod.restartInput(ic, (EditorInfo)args.arg2);
+ EditorInfo info = (EditorInfo)args.arg2;
+ info.makeCompatible(mTargetSdkVersion);
+ inputMethod.restartInput(ic, info);
return;
}
case DO_CREATE_SESSION: {
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index c0743cfe32eda..a1f2b633347b0 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1945,6 +1945,8 @@ public class InputMethodService extends AbstractInputMethodService {
return getText(com.android.internal.R.string.ime_action_next);
case EditorInfo.IME_ACTION_DONE:
return getText(com.android.internal.R.string.ime_action_done);
+ case EditorInfo.IME_ACTION_PREVIOUS:
+ return getText(com.android.internal.R.string.ime_action_previous);
default:
return getText(com.android.internal.R.string.ime_action_default);
}
diff --git a/core/java/android/text/InputType.java b/core/java/android/text/InputType.java
index 859222168c4bf..7b8acd9c7186f 100644
--- a/core/java/android/text/InputType.java
+++ b/core/java/android/text/InputType.java
@@ -228,6 +228,28 @@ public interface InputType {
*/
public static final int TYPE_TEXT_VARIATION_PHONETIC = 0x000000c0;
+ /**
+ * Variation of {@link #TYPE_CLASS_TEXT}: entering e-mail address inside
+ * of a web form. This was added in
+ * {@link android.os.Build.VERSION_CODES#HONEYCOMB}. An IME must target
+ * this API version or later to see this input type; if it doesn't, a request
+ * for this type will be seen as {@link #TYPE_TEXT_VARIATION_EMAIL_ADDRESS}
+ * when passed through {@link android.view.inputmethod.EditorInfo#makeCompatible(int)
+ * EditorInfo.makeCompatible(int)}.
+ */
+ public static final int TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS = 0x000000d0;
+
+ /**
+ * Variation of {@link #TYPE_CLASS_TEXT}: entering password inside
+ * of a web form. This was added in
+ * {@link android.os.Build.VERSION_CODES#HONEYCOMB}. An IME must target
+ * this API version or later to see this input type; if it doesn't, a request
+ * for this type will be seen as {@link #TYPE_TEXT_VARIATION_PASSWORD}
+ * when passed through {@link android.view.inputmethod.EditorInfo#makeCompatible(int)
+ * EditorInfo.makeCompatible(int)}.
+ */
+ public static final int TYPE_TEXT_VARIATION_WEB_PASSWORD = 0x000000e0;
+
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 0b2d0f66b340f..e5f4b087e6fe8 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -762,6 +762,12 @@ public interface WindowManager extends ViewManager {
*/
public static final int SOFT_INPUT_ADJUST_PAN = 0x20;
+ /** Adjustment option for {@link #softInputMode}: set to have a window
+ * not adjust for a shown input method. The window will not be resized,
+ * and it will not be panned to make its focus visible.
+ */
+ public static final int SOFT_INPUT_ADJUST_NOTHING = 0x30;
+
/**
* Bit for {@link #softInputMode}: set when the user has navigated
* forward to the window. This is normally set automatically for
@@ -771,27 +777,6 @@ public interface WindowManager extends ViewManager {
*/
public static final int SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x100;
- /**
- * Default value for {@link #screenBrightness} and {@link #buttonBrightness}
- * indicating that the brightness value is not overridden for this window
- * and normal brightness policy should be used.
- */
- public static final float BRIGHTNESS_OVERRIDE_NONE = -1.0f;
-
- /**
- * Value for {@link #screenBrightness} and {@link #buttonBrightness}
- * indicating that the screen or button backlight brightness should be set
- * to the lowest value when this window is in front.
- */
- public static final float BRIGHTNESS_OVERRIDE_OFF = 0.0f;
-
- /**
- * Value for {@link #screenBrightness} and {@link #buttonBrightness}
- * indicating that the screen or button backlight brightness should be set
- * to the hightest value when this window is in front.
- */
- public static final float BRIGHTNESS_OVERRIDE_FULL = 1.0f;
-
/**
* Desired operating mode for any soft input area. May any combination
* of:
@@ -852,6 +837,27 @@ public interface WindowManager extends ViewManager {
* dim.
*/
public float dimAmount = 1.0f;
+
+ /**
+ * Default value for {@link #screenBrightness} and {@link #buttonBrightness}
+ * indicating that the brightness value is not overridden for this window
+ * and normal brightness policy should be used.
+ */
+ public static final float BRIGHTNESS_OVERRIDE_NONE = -1.0f;
+
+ /**
+ * Value for {@link #screenBrightness} and {@link #buttonBrightness}
+ * indicating that the screen or button backlight brightness should be set
+ * to the lowest value when this window is in front.
+ */
+ public static final float BRIGHTNESS_OVERRIDE_OFF = 0.0f;
+
+ /**
+ * Value for {@link #screenBrightness} and {@link #buttonBrightness}
+ * indicating that the screen or button backlight brightness should be set
+ * to the hightest value when this window is in front.
+ */
+ public static final float BRIGHTNESS_OVERRIDE_FULL = 1.0f;
/**
* This can be used to override the user's preferred brightness of
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index b98dcd2fa11ba..300e5d641fae9 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -93,6 +93,45 @@ public class EditorInfo implements InputType, Parcelable {
*/
public static final int IME_ACTION_DONE = 0x00000006;
+ /**
+ * Bits of {@link #IME_MASK_ACTION}: Like {@link #IME_ACTION_NEXT}, but
+ * for moving to the previous field. This will normally not be used to
+ * specify an action (since it precludes {@link #IME_ACTION_NEXT}, but
+ * can be returned to the app if it sets {@link #IME_FLAG_NAVIGATE_PREVIOUS}.
+ */
+ public static final int IME_ACTION_PREVIOUS = 0x00000007;
+
+ /**
+ * Flag of {@link #imeOptions}: used to request that the IME never go
+ * into fullscreen mode. Applications need to be aware that the flag is not
+ * a guarantee, and not all IMEs will respect it.
+ */
+ public static final int IME_FLAG_NO_FULLSCREEN = 0x2000000;
+
+ /**
+ * Flag of {@link #imeOptions}: like {@link #IME_FLAG_NAVIGATE_NEXT}, but
+ * specifies there is something interesting that a backward navigation
+ * can focus on. If the user selects the IME's facility to backward
+ * navigate, this will show up in the application as an {@link #IME_ACTION_PREVIOUS}
+ * at {@link InputConnection#performEditorAction(int)
+ * InputConnection.performEditorAction(int)}.
+ */
+ public static final int IME_FLAG_NAVIGATE_PREVIOUS = 0x4000000;
+
+ /**
+ * Flag of {@link #imeOptions}: used to specify that there is something
+ * interesting that a forward navigation can focus on. This is like using
+ * {@link #IME_ACTION_NEXT}, except allows the IME to be multiline (with
+ * an enter key) as well as provide forward navigation. Note that some
+ * IMEs may not be able to do this, especially when running on a small
+ * screen where there is little space. In that case it does not need to
+ * present a UI for this option. Like {@link #IME_ACTION_NEXT}, if the
+ * user selects the IME's facility to forward navigate, this will show up
+ * in the application at {@link InputConnection#performEditorAction(int)
+ * InputConnection.performEditorAction(int)}.
+ */
+ public static final int IME_FLAG_NAVIGATE_NEXT = 0x8000000;
+
/**
* Flag of {@link #imeOptions}: used to specify that the IME does not need
* to show its extracted text UI. For input methods that may be fullscreen,
@@ -128,14 +167,6 @@ public class EditorInfo implements InputType, Parcelable {
*/
public static final int IME_FLAG_NO_ENTER_ACTION = 0x40000000;
- /**
- * Flag of {@link #imeOptions}: used to request that the IME never go
- * into fullscreen mode. Applications need to be aware that the flag is not
- * a guarantee, and not all IMEs will respect it.
- * @hide
- */
- public static final int IME_FLAG_NO_FULLSCREEN = 0x80000000;
-
/**
* Generic unspecified type for {@link #imeOptions}.
*/
@@ -239,6 +270,34 @@ public class EditorInfo implements InputType, Parcelable {
*/
public Bundle extras;
+ /**
+ * Ensure that the data in this EditorInfo is compatible with an application
+ * that was developed against the given target API version. This can
+ * impact the following input types:
+ * {@link InputType#TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS},
+ * {@link InputType#TYPE_TEXT_VARIATION_WEB_PASSWORD}.
+ *
+ * This is called by the framework for input method implementations;
+ * you should not generally need to call it yourself.
+ *
+ * @param targetSdkVersion The API version number that the compatible
+ * application was developed against.
+ */
+ public final void makeCompatible(int targetSdkVersion) {
+ if (targetSdkVersion < android.os.Build.VERSION_CODES.HONEYCOMB) {
+ switch (inputType&(TYPE_MASK_CLASS|TYPE_MASK_VARIATION)) {
+ case TYPE_CLASS_TEXT|TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS:
+ inputType = TYPE_CLASS_TEXT|TYPE_TEXT_VARIATION_EMAIL_ADDRESS
+ | (inputType&(~TYPE_MASK_FLAGS));
+ break;
+ case TYPE_CLASS_TEXT|TYPE_TEXT_VARIATION_WEB_PASSWORD:
+ inputType = TYPE_CLASS_TEXT|TYPE_TEXT_VARIATION_PASSWORD
+ | (inputType&(~TYPE_MASK_FLAGS));
+ break;
+ }
+ }
+ }
+
/**
* Write debug output of this object.
*/
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index ef15f6f082c0f..9855d6e5d2472 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3229,7 +3229,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* for this text view. The default implementation will call your action
* listener supplied to {@link #setOnEditorActionListener}, or perform
* a standard operation for {@link EditorInfo#IME_ACTION_NEXT
- * EditorInfo.IME_ACTION_NEXT} or {@link EditorInfo#IME_ACTION_DONE
+ * EditorInfo.IME_ACTION_NEXT}, {@link EditorInfo#IME_ACTION_PREVIOUS
+ * EditorInfo.IME_ACTION_PREVIOUS}, or {@link EditorInfo#IME_ACTION_DONE
* EditorInfo.IME_ACTION_DONE}.
*
*
For backwards compatibility, if no IME options have been set and the
@@ -3266,6 +3267,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
return;
+ } else if (actionCode == EditorInfo.IME_ACTION_PREVIOUS) {
+ View v = focusSearch(FOCUS_UP);
+ if (v != null) {
+ if (!v.requestFocus(FOCUS_UP)) {
+ throw new IllegalStateException("focus search returned a view " +
+ "that wasn't able to take focus!");
+ }
+ }
+ return;
+
} else if (actionCode == EditorInfo.IME_ACTION_DONE) {
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) {
@@ -4680,9 +4691,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
} else {
outAttrs.imeOptions = EditorInfo.IME_NULL;
}
+ if (focusSearch(FOCUS_DOWN) != null) {
+ outAttrs.imeOptions |= EditorInfo.IME_FLAG_NAVIGATE_NEXT;
+ }
+ if (focusSearch(FOCUS_UP) != null) {
+ outAttrs.imeOptions |= EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS;
+ }
if ((outAttrs.imeOptions&EditorInfo.IME_MASK_ACTION)
== EditorInfo.IME_ACTION_UNSPECIFIED) {
- if (focusSearch(FOCUS_DOWN) != null) {
+ if ((outAttrs.imeOptions&EditorInfo.IME_FLAG_NAVIGATE_NEXT) != 0) {
// An action has not been set, but the enter key will move to
// the next focus, so set the action to that.
outAttrs.imeOptions |= EditorInfo.IME_ACTION_NEXT;
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 0cac7ebebb6a4..79131ba97f8f7 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -326,6 +326,9 @@
need to close the input area to get at and interact with
parts of the window. -->
+
+
+
+
+
+
@@ -811,6 +822,40 @@
Corresponds to
{@link android.view.inputmethod.EditorInfo#IME_ACTION_DONE}. -->
+
+
+
+
+
+
+
+
Done
+
+ Prev
+
Execute
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index cd1ad4ca23ce3..7f49da9039097 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -84,6 +84,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
@@ -1386,7 +1387,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- void setAttachedWindowFrames(WindowState win, int fl, int sim,
+ void setAttachedWindowFrames(WindowState win, int fl, int adjust,
WindowState attached, boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf) {
if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) {
// Here's a special case: if this attached window is a panel that is
@@ -1407,7 +1408,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// window is positioned within that content. Otherwise we can use
// the display frame and let the attached window take care of
// positioning its content appropriately.
- if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) {
+ if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
cf.set(attached.getDisplayFrameLw());
} else {
// If the window is resizing, then we want to base the content
@@ -1466,6 +1467,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
attrs.gravity = Gravity.BOTTOM;
mDockLayer = win.getSurfaceLayer();
} else {
+ final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
+
if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
== (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
// This is the case for a normal activity window: we want it
@@ -1481,7 +1484,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
pf.top = df.top = mScreenTop;
pf.right = df.right = mScreenLeft+mScreenWidth;
pf.bottom = df.bottom = mScreenTop+mScreenHeight;
- if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) {
+ if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
cf.left = mDockLeft;
cf.top = mDockTop;
cf.right = mDockRight;
@@ -1492,10 +1495,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
cf.right = mContentRight;
cf.bottom = mContentBottom;
}
- vf.left = mCurLeft;
- vf.top = mCurTop;
- vf.right = mCurRight;
- vf.bottom = mCurBottom;
+ if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
+ vf.left = mCurLeft;
+ vf.top = mCurTop;
+ vf.right = mCurRight;
+ vf.bottom = mCurBottom;
+ } else {
+ vf.set(cf);
+ }
}
} else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0) {
// A window that has requested to fill the entire screen just
@@ -1504,14 +1511,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
pf.top = df.top = cf.top = mScreenTop;
pf.right = df.right = cf.right = mScreenLeft+mScreenWidth;
pf.bottom = df.bottom = cf.bottom = mScreenTop+mScreenHeight;
- vf.left = mCurLeft;
- vf.top = mCurTop;
- vf.right = mCurRight;
- vf.bottom = mCurBottom;
+ if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
+ vf.left = mCurLeft;
+ vf.top = mCurTop;
+ vf.right = mCurRight;
+ vf.bottom = mCurBottom;
+ } else {
+ vf.set(cf);
+ }
} else if (attached != null) {
// A child window should be placed inside of the same visible
// frame that its parent had.
- setAttachedWindowFrames(win, fl, sim, attached, false, pf, df, cf, vf);
+ setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf);
} else {
// Otherwise, a normal window must be placed inside the content
// of all screen decorations.
@@ -1519,7 +1530,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
pf.top = mContentTop;
pf.right = mContentRight;
pf.bottom = mContentBottom;
- if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) {
+ if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
df.left = cf.left = mDockLeft;
df.top = cf.top = mDockTop;
df.right = cf.right = mDockRight;
@@ -1530,10 +1541,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
df.right = cf.right = mContentRight;
df.bottom = cf.bottom = mContentBottom;
}
- vf.left = mCurLeft;
- vf.top = mCurTop;
- vf.right = mCurRight;
- vf.bottom = mCurBottom;
+ if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
+ vf.left = mCurLeft;
+ vf.top = mCurTop;
+ vf.right = mCurRight;
+ vf.bottom = mCurBottom;
+ } else {
+ vf.set(cf);
+ }
}
}