Bug 746142 - Part 2 - Use inputmode attribute to vary the virtual keyboard on Android. f=mounir r=cpeterson

This commit is contained in:
Zoe Bellot 2012-08-26 23:16:22 -03:00
parent e96e9dacf5
commit 5d63eeebbb
13 changed files with 62 additions and 15 deletions

View File

@ -322,6 +322,8 @@ nsIMEStateManager::SetIMEState(const IMEState &aState,
aContent->Tag() == nsGkAtoms::textarea)) { aContent->Tag() == nsGkAtoms::textarea)) {
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type,
context.mHTMLInputType); context.mHTMLInputType);
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::inputmode,
context.mHTMLInputInputmode);
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::moz_action_hint, aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::moz_action_hint,
context.mActionHint); context.mActionHint);

View File

@ -161,6 +161,7 @@ parent:
SetInputContext(int32_t IMEEnabled, SetInputContext(int32_t IMEEnabled,
int32_t IMEOpen, int32_t IMEOpen,
nsString type, nsString type,
nsString inputmode,
nsString actionHint, nsString actionHint,
int32_t cause, int32_t cause,
int32_t focusChange); int32_t focusChange);

View File

@ -684,6 +684,7 @@ bool
TabParent::RecvSetInputContext(const int32_t& aIMEEnabled, TabParent::RecvSetInputContext(const int32_t& aIMEEnabled,
const int32_t& aIMEOpen, const int32_t& aIMEOpen,
const nsString& aType, const nsString& aType,
const nsString& aInputmode,
const nsString& aActionHint, const nsString& aActionHint,
const int32_t& aCause, const int32_t& aCause,
const int32_t& aFocusChange) const int32_t& aFocusChange)
@ -701,6 +702,7 @@ TabParent::RecvSetInputContext(const int32_t& aIMEEnabled,
context.mIMEState.mEnabled = static_cast<IMEState::Enabled>(aIMEEnabled); context.mIMEState.mEnabled = static_cast<IMEState::Enabled>(aIMEEnabled);
context.mIMEState.mOpen = static_cast<IMEState::Open>(aIMEOpen); context.mIMEState.mOpen = static_cast<IMEState::Open>(aIMEOpen);
context.mHTMLInputType.Assign(aType); context.mHTMLInputType.Assign(aType);
context.mHTMLInputInputmode.Assign(aInputmode);
context.mActionHint.Assign(aActionHint); context.mActionHint.Assign(aActionHint);
InputContextAction action( InputContextAction action(
static_cast<InputContextAction::Cause>(aCause), static_cast<InputContextAction::Cause>(aCause),

View File

@ -98,6 +98,7 @@ public:
virtual bool RecvSetInputContext(const int32_t& aIMEEnabled, virtual bool RecvSetInputContext(const int32_t& aIMEEnabled,
const int32_t& aIMEOpen, const int32_t& aIMEOpen,
const nsString& aType, const nsString& aType,
const nsString& aInputmode,
const nsString& aActionHint, const nsString& aActionHint,
const int32_t& aCause, const int32_t& aCause,
const int32_t& aFocusChange); const int32_t& aFocusChange);

View File

@ -539,7 +539,7 @@ public class GeckoAppShell
} }
} }
public static void notifyIMEEnabled(int state, String typeHint, public static void notifyIMEEnabled(int state, String typeHint, String modeHint,
String actionHint, boolean landscapeFS) String actionHint, boolean landscapeFS)
{ {
if (GeckoApp.surfaceView == null) if (GeckoApp.surfaceView == null)
@ -549,6 +549,7 @@ public class GeckoAppShell
In addition, the IME UI is hidden */ In addition, the IME UI is hidden */
GeckoApp.surfaceView.mIMEState = state; GeckoApp.surfaceView.mIMEState = state;
GeckoApp.surfaceView.mIMETypeHint = typeHint; GeckoApp.surfaceView.mIMETypeHint = typeHint;
GeckoApp.surfaceView.mIMEModeHint = modeHint;
GeckoApp.surfaceView.mIMEActionHint = actionHint; GeckoApp.surfaceView.mIMEActionHint = actionHint;
GeckoApp.surfaceView.mIMELandscapeFS = landscapeFS; GeckoApp.surfaceView.mIMELandscapeFS = landscapeFS;
IMEStateUpdater.enableIME(); IMEStateUpdater.enableIME();

View File

@ -63,6 +63,7 @@ class GeckoSurfaceView
initEditable(""); initEditable("");
mIMEState = IME_STATE_DISABLED; mIMEState = IME_STATE_DISABLED;
mIMETypeHint = ""; mIMETypeHint = "";
mIMEModeHint = "";
mIMEActionHint = ""; mIMEActionHint = "";
} }
@ -502,6 +503,20 @@ class GeckoSurfaceView
else if (mIMETypeHint.equalsIgnoreCase("time")) else if (mIMETypeHint.equalsIgnoreCase("time"))
outAttrs.inputType = InputType.TYPE_CLASS_DATETIME | outAttrs.inputType = InputType.TYPE_CLASS_DATETIME |
InputType.TYPE_DATETIME_VARIATION_TIME; InputType.TYPE_DATETIME_VARIATION_TIME;
else if (mIMEModeHint.equalsIgnoreCase("numeric"))
outAttrs.inputType = InputType.TYPE_CLASS_NUMBER |
InputType.TYPE_NUMBER_FLAG_SIGNED |
InputType.TYPE_NUMBER_FLAG_DECIMAL;
else if (mIMEModeHint.equalsIgnoreCase("digit"))
outAttrs.inputType = InputType.TYPE_CLASS_NUMBER;
else if (mIMEModeHint.equalsIgnoreCase("uppercase"))
outAttrs.inputType |= InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS;
else if (mIMEModeHint.equalsIgnoreCase("lowercase"))
outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
else if (mIMEModeHint.equalsIgnoreCase("titlecase"))
outAttrs.inputType |= InputType.TYPE_TEXT_FLAG_CAP_WORDS;
else if (mIMEModeHint.equalsIgnoreCase("autocapitalized"))
outAttrs.inputType |= InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
if (mIMEActionHint.equalsIgnoreCase("go")) if (mIMEActionHint.equalsIgnoreCase("go"))
outAttrs.imeOptions = EditorInfo.IME_ACTION_GO; outAttrs.imeOptions = EditorInfo.IME_ACTION_GO;
@ -748,6 +763,7 @@ class GeckoSurfaceView
Editable.Factory mEditableFactory; Editable.Factory mEditableFactory;
int mIMEState; int mIMEState;
String mIMETypeHint; String mIMETypeHint;
String mIMEModeHint;
String mIMEActionHint; String mIMEActionHint;
boolean mIMELandscapeFS; boolean mIMELandscapeFS;

View File

@ -585,12 +585,12 @@ public class GeckoAppShell
mInputConnection.notifyIME(type, state); mInputConnection.notifyIME(type, state);
} }
public static void notifyIMEEnabled(int state, String typeHint, public static void notifyIMEEnabled(int state, String typeHint, String modeHint,
String actionHint, boolean landscapeFS) { String actionHint, boolean landscapeFS) {
// notifyIMEEnabled() still needs the landscapeFS parameter because it is called from JNI // notifyIMEEnabled() still needs the landscapeFS parameter because it is called from JNI
// code that assumes it has the same signature as XUL Fennec's (which does use landscapeFS). // code that assumes it has the same signature as XUL Fennec's (which does use landscapeFS).
if (mInputConnection != null) if (mInputConnection != null)
mInputConnection.notifyIMEEnabled(state, typeHint, actionHint); mInputConnection.notifyIMEEnabled(state, typeHint, modeHint, actionHint);
} }
public static void notifyIMEChange(String text, int start, int end, int newEnd) { public static void notifyIMEChange(String text, int start, int end, int newEnd) {

View File

@ -86,6 +86,7 @@ class GeckoInputConnection
private static final Timer mIMETimer = new Timer("GeckoInputConnection Timer"); private static final Timer mIMETimer = new Timer("GeckoInputConnection Timer");
private static int mIMEState; private static int mIMEState;
private static String mIMETypeHint = ""; private static String mIMETypeHint = "";
private static String mIMEModeHint = "";
private static String mIMEActionHint = ""; private static String mIMEActionHint = "";
private String mCurrentInputMethod; private String mCurrentInputMethod;
@ -804,6 +805,20 @@ class GeckoInputConnection
else if (mIMETypeHint.equalsIgnoreCase("time")) else if (mIMETypeHint.equalsIgnoreCase("time"))
outAttrs.inputType = InputType.TYPE_CLASS_DATETIME outAttrs.inputType = InputType.TYPE_CLASS_DATETIME
| InputType.TYPE_DATETIME_VARIATION_TIME; | InputType.TYPE_DATETIME_VARIATION_TIME;
else if (mIMEModeHint.equalsIgnoreCase("numeric"))
outAttrs.inputType = InputType.TYPE_CLASS_NUMBER |
InputType.TYPE_NUMBER_FLAG_SIGNED |
InputType.TYPE_NUMBER_FLAG_DECIMAL;
else if (mIMEModeHint.equalsIgnoreCase("digit"))
outAttrs.inputType = InputType.TYPE_CLASS_NUMBER;
else if (mIMEModeHint.equalsIgnoreCase("uppercase"))
outAttrs.inputType |= InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS;
else if (mIMEModeHint.equalsIgnoreCase("lowercase"))
outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
else if (mIMEModeHint.equalsIgnoreCase("titlecase"))
outAttrs.inputType |= InputType.TYPE_TEXT_FLAG_CAP_WORDS;
else if (mIMEModeHint.equalsIgnoreCase("autocapitalized"))
outAttrs.inputType |= InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
if (mIMEActionHint.equalsIgnoreCase("go")) if (mIMEActionHint.equalsIgnoreCase("go"))
outAttrs.imeOptions = EditorInfo.IME_ACTION_GO; outAttrs.imeOptions = EditorInfo.IME_ACTION_GO;
@ -1030,7 +1045,7 @@ class GeckoInputConnection
}); });
} }
public void notifyIMEEnabled(final int state, final String typeHint, final String actionHint) { public void notifyIMEEnabled(final int state, final String typeHint, final String modeHint, final String actionHint) {
postToUiThread(new Runnable() { postToUiThread(new Runnable() {
public void run() { public void run() {
View v = getView(); View v = getView();
@ -1041,6 +1056,7 @@ class GeckoInputConnection
In addition, the IME UI is hidden */ In addition, the IME UI is hidden */
mIMEState = state; mIMEState = state;
mIMETypeHint = (typeHint == null) ? "" : typeHint; mIMETypeHint = (typeHint == null) ? "" : typeHint;
mIMEModeHint = (modeHint == null) ? "" : modeHint;
mIMEActionHint = (actionHint == null) ? "" : actionHint; mIMEActionHint = (actionHint == null) ? "" : actionHint;
IMEStateUpdater.enableIME(); IMEStateUpdater.enableIME();
} }
@ -1441,13 +1457,14 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
} }
@Override @Override
public void notifyIMEEnabled(int state, String typeHint, String actionHint) { public void notifyIMEEnabled(int state, String typeHint, String modeHint, String actionHint) {
Log.d(LOGTAG, "IME: >notifyIMEEnabled(state=" + state + ", typeHint=\"" + typeHint Log.d(LOGTAG, "IME: >notifyIMEEnabled(state=" + state + ", typeHint=\"" + typeHint
+ "\", actionHint=\"" + actionHint + "\""); + "\", modeHint=\"" + modeHint + "\", actionHint=\""
+ actionHint + "\"");
GeckoApp.assertOnGeckoThread(); GeckoApp.assertOnGeckoThread();
if (state < IME_STATE_DISABLED || state > IME_STATE_PLUGIN) if (state < IME_STATE_DISABLED || state > IME_STATE_PLUGIN)
throw new IllegalArgumentException("Unexpected IMEState=" + state); throw new IllegalArgumentException("Unexpected IMEState=" + state);
super.notifyIMEEnabled(state, typeHint, actionHint); super.notifyIMEEnabled(state, typeHint, modeHint, actionHint);
} }
} }

View File

@ -99,7 +99,7 @@ AndroidBridge::Init(JNIEnv *jEnv,
mGeckoAppShellClass = (jclass) jEnv->NewGlobalRef(jGeckoAppShellClass); mGeckoAppShellClass = (jclass) jEnv->NewGlobalRef(jGeckoAppShellClass);
jNotifyIME = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIME", "(II)V"); jNotifyIME = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIME", "(II)V");
jNotifyIMEEnabled = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEEnabled", "(ILjava/lang/String;Ljava/lang/String;Z)V"); jNotifyIMEEnabled = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEEnabled", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)V");
jNotifyIMEChange = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEChange", "(Ljava/lang/String;III)V"); jNotifyIMEChange = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEChange", "(Ljava/lang/String;III)V");
jNotifyScreenShot = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyScreenShot", "(Ljava/nio/ByteBuffer;IIIIIIII)V"); jNotifyScreenShot = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyScreenShot", "(Ljava/nio/ByteBuffer;IIIIIIII)V");
jAcknowledgeEventSync = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "acknowledgeEventSync", "()V"); jAcknowledgeEventSync = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "acknowledgeEventSync", "()V");
@ -263,7 +263,7 @@ jstring NewJavaString(AutoLocalJNIFrame* frame, const PRUnichar* string, uint32_
void void
AndroidBridge::NotifyIMEEnabled(int aState, const nsAString& aTypeHint, AndroidBridge::NotifyIMEEnabled(int aState, const nsAString& aTypeHint,
const nsAString& aActionHint) const nsAString& aModeHint, const nsAString& aActionHint)
{ {
ALOG_BRIDGE("AndroidBridge::NotifyIMEEnabled"); ALOG_BRIDGE("AndroidBridge::NotifyIMEEnabled");
if (!sBridge) if (!sBridge)
@ -275,18 +275,20 @@ AndroidBridge::NotifyIMEEnabled(int aState, const nsAString& aTypeHint,
AutoLocalJNIFrame jniFrame(env); AutoLocalJNIFrame jniFrame(env);
nsPromiseFlatString typeHint(aTypeHint); nsPromiseFlatString typeHint(aTypeHint);
nsPromiseFlatString modeHint(aModeHint);
nsPromiseFlatString actionHint(aActionHint); nsPromiseFlatString actionHint(aActionHint);
jvalue args[4]; jvalue args[5];
args[0].i = aState; args[0].i = aState;
args[1].l = NewJavaString(&jniFrame, typeHint.get(), typeHint.Length()); args[1].l = NewJavaString(&jniFrame, typeHint.get(), typeHint.Length());
args[2].l = NewJavaString(&jniFrame, actionHint.get(), actionHint.Length()); args[2].l = env->NewString(modeHint.get(), modeHint.Length());
args[3].z = false; args[3].l = env->NewString(actionHint.get(), actionHint.Length());
args[4].z = false;
int32_t landscapeFS; int32_t landscapeFS;
if (NS_SUCCEEDED(Preferences::GetInt(IME_FULLSCREEN_PREF, &landscapeFS))) { if (NS_SUCCEEDED(Preferences::GetInt(IME_FULLSCREEN_PREF, &landscapeFS))) {
if (landscapeFS == 1) { if (landscapeFS == 1) {
args[3].z = true; args[4].z = true;
} else if (landscapeFS == -1){ } else if (landscapeFS == -1){
if (NS_SUCCEEDED( if (NS_SUCCEEDED(
Preferences::GetInt(IME_FULLSCREEN_THRESHOLD_PREF, Preferences::GetInt(IME_FULLSCREEN_THRESHOLD_PREF,
@ -295,7 +297,7 @@ AndroidBridge::NotifyIMEEnabled(int aState, const nsAString& aTypeHint,
// threshold to pixels and multiply the height by 100 // threshold to pixels and multiply the height by 100
if (nsWindow::GetAndroidScreenBounds().height * 100 < if (nsWindow::GetAndroidScreenBounds().height * 100 <
landscapeFS * Bridge()->GetDPI()) { landscapeFS * Bridge()->GetDPI()) {
args[3].z = true; args[4].z = true;
} }
} }

View File

@ -142,7 +142,7 @@ public:
static void NotifyIME(int aType, int aState); static void NotifyIME(int aType, int aState);
static void NotifyIMEEnabled(int aState, const nsAString& aTypeHint, static void NotifyIMEEnabled(int aState, const nsAString& aTypeHint,
const nsAString& aActionHint); const nsAString& aModeHint, const nsAString& aActionHint);
static void NotifyIMEChange(const PRUnichar *aText, uint32_t aTextLen, int aStart, int aEnd, int aNewEnd); static void NotifyIMEChange(const PRUnichar *aText, uint32_t aTextLen, int aStart, int aEnd, int aNewEnd);

View File

@ -2115,6 +2115,7 @@ nsWindow::SetInputContext(const InputContext& aContext,
AndroidBridge::NotifyIMEEnabled(enabled, AndroidBridge::NotifyIMEEnabled(enabled,
aContext.mHTMLInputType, aContext.mHTMLInputType,
aContext.mHTMLInputInputmode,
aContext.mActionHint); aContext.mActionHint);
} }

View File

@ -281,6 +281,9 @@ struct InputContext {
/* The type of the input if the input is a html input field */ /* The type of the input if the input is a html input field */
nsString mHTMLInputType; nsString mHTMLInputType;
/* The type of the inputmode */
nsString mHTMLInputInputmode;
/* A hint for the action that is performed when the input is submitted */ /* A hint for the action that is performed when the input is submitted */
nsString mActionHint; nsString mActionHint;
}; };

View File

@ -363,6 +363,7 @@ PuppetWidget::SetInputContext(const InputContext& aContext,
static_cast<int32_t>(aContext.mIMEState.mEnabled), static_cast<int32_t>(aContext.mIMEState.mEnabled),
static_cast<int32_t>(aContext.mIMEState.mOpen), static_cast<int32_t>(aContext.mIMEState.mOpen),
aContext.mHTMLInputType, aContext.mHTMLInputType,
aContext.mHTMLInputInputmode,
aContext.mActionHint, aContext.mActionHint,
static_cast<int32_t>(aAction.mCause), static_cast<int32_t>(aAction.mCause),
static_cast<int32_t>(aAction.mFocusChange)); static_cast<int32_t>(aAction.mFocusChange));