summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormvglasow <michael -at- vonglasow.com>2015-11-15 23:05:24 +0100
committermvglasow <michael -at- vonglasow.com>2016-02-24 09:43:46 +0100
commit0c0697760bb9b78013812ee816a30c7af148520d (patch)
treea6f237d502db69ace0fe65611474c5f4a66db8e7
parent6e8450f7ce39f4c713bcbd8368e1b25d32f98283 (diff)
downloadnavit-0c0697760bb9b78013812ee816a30c7af148520d.tar.gz
Fix:gui_internal:Further native keyboard refinements
Allow graphics plugin to specify size occupied by keyboard Create placeholder for Android keyboard Show Android keyboard in landscape mode Skip keyboard logic if hardware keyboard is present on Android Add some documentation and comments Signed-off-by: mvglasow <michael -at- vonglasow.com>
-rw-r--r--navit/android/src/org/navitproject/navit/Navit.java70
-rw-r--r--navit/android/src/org/navitproject/navit/NavitGraphics.java1
-rw-r--r--navit/graphics.c62
-rw-r--r--navit/graphics.h19
-rw-r--r--navit/graphics/android/graphics_android.c18
-rw-r--r--navit/gui/internal/gui_internal_keyboard.c37
6 files changed, 167 insertions, 40 deletions
diff --git a/navit/android/src/org/navitproject/navit/Navit.java b/navit/android/src/org/navitproject/navit/Navit.java
index 78476758c..0242d95bf 100644
--- a/navit/android/src/org/navitproject/navit/Navit.java
+++ b/navit/android/src/org/navitproject/navit/Navit.java
@@ -116,6 +116,20 @@ public class Navit extends Activity
public static final String NAVIT_PREFS = "NavitPrefs";
Boolean isFullscreen = false;
+
+ /**
+ * @brief A Runnable to restore soft input when the user returns to the activity.
+ *
+ * An instance of this class can be passed to the main message queue in the Activity's
+ * {@code onRestore()} method.
+ */
+ private class SoftInputRestorer implements Runnable {
+ public void run() {
+ Navit.this.showNativeKeyboard();
+ }
+ }
+
+
public void removeFileIfExists(String source) {
File file = new File(source);
@@ -445,6 +459,21 @@ public class Navit extends Activity
Log.e("Navit", "timestamp for navigate_to expired! not using data");
}
}
+ Log.d(TAG, "onResume");
+ /* FIXME this doesn't work */
+ if (show_soft_keyboard_now_showing)
+ this.showNativeKeyboard();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ Log.d(TAG, "onPause");
+ if (show_soft_keyboard_now_showing) {
+ Log.d(TAG, "onPause:hiding soft input");
+ this.hideNativeKeyboard();
+ show_soft_keyboard_now_showing = true;
+ }
}
private void parseNavigationURI(String schemeSpecificPart) {
@@ -651,10 +680,38 @@ public class Navit extends Activity
*
* @return {@code true} if an input method is going to be displayed, {@code false} if not
*/
- public boolean showNativeKeyboard() {
- // TODO determine if we need on-screen input
- mgr.showSoftInput(getCurrentFocus(), InputMethodManager.SHOW_IMPLICIT);
- return true;
+ public int showNativeKeyboard() {
+ /*
+ * Apologies for the huge mess that this function is, but Android's soft input API is a big
+ * nightmare. Its devs have mercifully given us an option to show or hide the keyboard, but
+ * there is no reliable way to figure out if it is actually showing, let alone how much of the
+ * screen it occupies, so our best bet is guesswork.
+ */
+ Configuration config = getResources().getConfiguration();
+ if ((config.keyboard == Configuration.KEYBOARD_QWERTY) && (config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO))
+ /* physical keyboard present, exit */
+ return 0;
+
+ /* Use SHOW_FORCED here, else keyboard won't show in landscape mode */
+ mgr.showSoftInput(getCurrentFocus(), InputMethodManager.SHOW_FORCED);
+ show_soft_keyboard_now_showing = true;
+
+ /*
+ * Crude way to estimate the height occupied by the keyboard: for AOSP on KitKat and Lollipop it
+ * is about 62-63% of available screen width (in portrait mode) but no more than slightly above
+ * 46% of height (in landscape mode).
+ */
+ Display display_ = getWindowManager().getDefaultDisplay();
+ int width_ = display_.getWidth();
+ int height_ = display_.getHeight();
+ int maxHeight = height_ * 47 / 100;
+ int inputHeight = width_ * 63 / 100;
+ if (inputHeight > (maxHeight))
+ inputHeight = maxHeight;
+
+ /* the receiver isn't going to fire before the UI thread becomes idle, well after this method returns */
+ Log.d(TAG, "showNativeKeyboard:return (assuming true)");
+ return inputHeight;
}
@@ -662,10 +719,11 @@ public class Navit extends Activity
* @brief Hides the native keyboard or other input method.
*/
public void hideNativeKeyboard() {
- mgr.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY);
+ mgr.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
+ show_soft_keyboard_now_showing = false;
}
-
+
void setDestination(float latitude, float longitude, String address) {
Toast.makeText( getApplicationContext(),getString(R.string.address_search_set_destination) + "\n" + address, Toast.LENGTH_LONG).show(); //TRANS
diff --git a/navit/android/src/org/navitproject/navit/NavitGraphics.java b/navit/android/src/org/navitproject/navit/NavitGraphics.java
index 005f79bf2..de7c41863 100644
--- a/navit/android/src/org/navitproject/navit/NavitGraphics.java
+++ b/navit/android/src/org/navitproject/navit/NavitGraphics.java
@@ -738,6 +738,7 @@ public class NavitGraphics
frameLayout.addView(statusTintView);
activity.setContentView(frameLayout);
+
view.requestFocus();
}
else
diff --git a/navit/graphics.c b/navit/graphics.c
index 829acd1b8..5c6f9e5b3 100644
--- a/navit/graphics.c
+++ b/navit/graphics.c
@@ -1074,22 +1074,76 @@ graphics_background_gc(struct graphics *this_, struct graphics_gc *gc)
/**
* @brief Shows the native on-screen keyboard or other input method
*
- * This method is just a wrapper which calls the respective method of the graphics plugin.
+ * This method is a wrapper around the respective method of the graphics plugin.
+ *
+ * The caller should populate the {@code kbd} argument with appropriate {@code mode} and {@code lang}
+ * members so the graphics plugin can determine the best matching layout.
+ *
+ * If an input method is shown, the graphics plugin should try to select the configuration which best
+ * matches the specified {@code mode}. For example, if {@code mode} specifies a numeric layout, the
+ * graphics plugin should select a numeric keyboard layout (if available), or the equivalent for another
+ * input method (such as setting stroke recognition to identify strokes as numbers). Likewise, when an
+ * alphanumeric-uppercase mode is requested, it should switch to uppercase input.
+ *
+ * Implementations should, however, consider that Navit's internal keyboard allows the user to switch
+ * modes at will (the only exception being degree mode) and thus must not "lock" the user into a limited
+ * layout with no means to switch to a general-purpose one. For example, house number entry in an
+ * address search dialog may default to numeric mode, but since some house numbers may contain
+ * non-numeric characters, a pure numeric keyboard is suitable only if the user has the option to switch
+ * to an alphanumeric layout.
+ *
+ * When multiple alphanumeric layouts are available, the graphics plugin should use the {@code lang}
+ * argument to determine the best layout.
+ *
+ * When selecting an input method, preference should always be given to the default or last selected
+ * input method and configuration if it matches the requested {@code mode} and {@code lang}.
+ *
+ * If the native input method is going to obstruct parts of Navit's UI, the graphics plugin should set
+ * {@code kbd->w} and {@code kbd->h} to the height and width to the appropriate value in pixels. A value
+ * of -1 indicates that the input method fills the entire available width or height of the space
+ * available to Navit. On windowed platforms, where the on-screen input method and Navit's window may be
+ * moved relative to each other as needed and can be displayed alongside each other, the graphics plugin
+ * should report 0 for both dimensions.
+ *
+ * @param this_ The graphics instance
+ * @param kbd The keyboard instance
*
* @return 1 if the native keyboard is going to be displayed, 0 if not, -1 if the method is not
* supported by the plugin
*/
int graphics_show_native_keyboard (struct graphics *this_, struct graphics_keyboard *kbd) {
+ int ret;
if (!this_->meth.show_native_keyboard)
- return -1;
- return this_->meth.show_native_keyboard(kbd);
+ ret = -1;
+ else
+ ret = this_->meth.show_native_keyboard(kbd);
+ dbg(lvl_debug, "return %d\n", ret);
+ return ret;
}
/**
* @brief Hides the native on-screen keyboard or other input method
*
- * This method is just a wrapper which calls the respective method of the graphics plugin.
+ * This method is a wrapper around the respective method of the graphics plugin.
+ *
+ * A call to this function indicates that Navit no longer needs the input method and is about to reclaim
+ * any screen real estate it may have previously reserved for the input method.
+ *
+ * On platforms that don't support overlapping windows this means that the on-screen input method should
+ * be hidden, as it may otherwise obstruct parts of Navit's UI.
+ *
+ * On windowed platforms, where on-screen input methods can be displayed alongside Navit or moved around
+ * as needed, the graphics driver should instead notify the on-screen method that it is no longer
+ * expecting user input, allowing the input method to take the appropriate action.
+ *
+ * The graphics plugin must free any data it has stored in {@code kbd->gra_priv} and reset the pointer
+ * to {@code NULL} to indicate it has done so.
+ *
+ * The caller may free {@code kbd} after this function returns.
+ *
+ * @param this The graphics instance
+ * @param kbd The keyboard instance
*
* @return True if the call was successfully passed to the plugin, false if the method is not supported
* by the plugin
diff --git a/navit/graphics.h b/navit/graphics.h
index ae6e8b629..2ffbd9ab0 100644
--- a/navit/graphics.h
+++ b/navit/graphics.h
@@ -70,10 +70,23 @@ struct graphics_keyboard_priv;
* Describes an instance of the native on-screen keyboard or other input method.
*/
struct graphics_keyboard {
- // TODO complete
+ int w; /**< The width of the area obscured by the keyboard (-1 for full width) */
+ int h; /**< The height of the area obscured by the keyboard (-1 for full height) */
+ /* TODO mode is currently a copy of the respective value in the internal GUI and uses the same values.
+ * This may need to be changed to something with globally available enum, possibly with revised values.
+ * The Android implementation (the first to support a native on-screen keyboard) does not use this field
+ * due to limitations of the platform. */
+ int mode; /**< Mode flags for the keyboard */
char *lang; /**< The preferred language for text input, may be {@code NULL}. */
- void *gui_priv; /**< Private data determined by the GUI */
- struct graphics_keyboard_priv *gra_priv; /**< Private data determined by the graphics plugin */
+ void *gui_priv; /**< Private data determined by the GUI. The GUI may store
+ * a pointer to a data structure of its choice here. It is
+ * the responsibility of the GUI to free the data structure
+ * when it is no longer needed. The graphics plugin should
+ * not access this member. */
+ struct graphics_keyboard_priv *gra_priv; /**< Private data determined by the graphics plugin. The
+ * graphics plugin is responsible for its management. If it
+ * uses this member, it must free the associated data in
+ * its {@code hide_native_keyboard} method. */
};
/** Magic value for unset/unspecified width/height. */
diff --git a/navit/graphics/android/graphics_android.c b/navit/graphics/android/graphics_android.c
index c88ee11fd..41f441c96 100644
--- a/navit/graphics/android/graphics_android.c
+++ b/navit/graphics/android/graphics_android.c
@@ -1136,7 +1136,7 @@ event_android_new(struct event_methods *meth)
Navit_showMenu = (*jnienv)->GetMethodID(jnienv, NavitClass, "showMenu", "()V");
if (Navit_showMenu == NULL)
return NULL;
- Navit_showNativeKeyboard = (*jnienv)->GetMethodID(jnienv, NavitClass, "showNativeKeyboard", "()Z");
+ Navit_showNativeKeyboard = (*jnienv)->GetMethodID(jnienv, NavitClass, "showNativeKeyboard", "()I");
Navit_hideNativeKeyboard = (*jnienv)->GetMethodID(jnienv, NavitClass, "hideNativeKeyboard", "()V");
dbg(lvl_debug,"ok\n");
@@ -1152,18 +1152,28 @@ event_android_new(struct event_methods *meth)
* displayed. A typical case in which there is no need for an on-screen input method is if a hardware
* keyboard is present.
*
+ * Note that the Android platform lacks reliable means of determining whether an on-screen input method
+ * is going to be displayed or how much screen space it is going to occupy. Therefore this method tries
+ * to guess these values. They have been tested and found to work correctly with the AOSP keyboard, and
+ * are thus expected to be compatible with most on-screen keyboards found on the market, but results may
+ * be unexpected with other input methods.
+ *
* @param kbd A {@code struct graphics_keyboard} which describes the requirements for the input method
* and will be populated with the data of the input method before the function returns.
*
- * @return True if the input method is displayed, false if not.
+ * @return True if the input method is going to be displayed, false if not.
*/
int show_native_keyboard (struct graphics_keyboard *kbd) {
- // TODO populate kbd with values
+ kbd->w = -1;
if (Navit_showNativeKeyboard == NULL) {
dbg(lvl_error, "method Navit.showNativeKeyboard() not found, cannot display keyboard\n");
return 0;
}
- return (*jnienv)->CallBooleanMethod(jnienv, android_activity, Navit_showNativeKeyboard);
+ kbd->h = (*jnienv)->CallIntMethod(jnienv, android_activity, Navit_showNativeKeyboard);
+ dbg(lvl_error, "keyboard size is %d x %d px\n", kbd->w, kbd->h);
+ dbg(lvl_error, "return\n");
+ /* zero height means we're not showing a keyboard, therefore normalize height to boolean */
+ return !!(kbd->h);
}
diff --git a/navit/gui/internal/gui_internal_keyboard.c b/navit/gui/internal/gui_internal_keyboard.c
index 92ccc339d..313768371 100644
--- a/navit/gui/internal/gui_internal_keyboard.c
+++ b/navit/gui/internal/gui_internal_keyboard.c
@@ -449,12 +449,7 @@ gui_internal_keyboard_init_mode(char *lang)
* its placeholder widget. Navit will subsequently reclaim any screen real estate it may have previously
* reserved for the input method.
*
- * On platforms that don't support overlapping windows this means that the on-screen input method should
- * be hidden, as it may otherwise obstruct parts of Navit's UI.
- *
- * On windowed platforms, where on-screen input methods can be displayed alongside Navit or moved around
- * as needed, the graphics driver should instead notify the on-screen method that it is no longer
- * expecting user input, allowing the input method to take the appropriate action.
+ * This function will free the {@code struct graphics_keyboard} pointed to by {@code w->data}
*
* @param this The internal GUI instance
* @param w The placeholder widget
@@ -478,21 +473,9 @@ void gui_internal_keyboard_hide_native(struct gui_priv *this_, struct widget *w)
* This method is a wrapper around the corresponding method of the graphics plugin, which takes care of
* all platform-specific details. In particular, it is up to the graphics plugin to determine how to
* handle the request: it may show its on-screen keyboard or another input method (such as stroke
- * recognition). It may also simply ignore the request, which will typically occur when a hardware
+ * recognition). It may choose to simply ignore the request, which will typically occur when a hardware
* keyboard (or other hardware input) is available.
*
- * If an input method is shown, the graphics plugin should try to select the configuration which best
- * matches the specified {@code mode}. For example, if {@code mode} specifies a numeric layout, the
- * graphics plugin should select a numeric keyboard layout (if available), or the equivalent for another
- * input method (such as setting stroke recognition to identify strokes as numbers). Likewise, when an
- * alphanumeric-uppercase mode is requested, it should switch to uppercase input.
- *
- * When multiple alphanumeric layouts are available, the graphics plugin should use the {@code lang}
- * argument to determine the best layout.
- *
- * When selecting an input method, preference should always be given to the default or last selected
- * input method and configuration if it matches the requested {@code mode} and {@code lang}.
- *
* The platform's native input method may obstruct parts of Navit's UI. To prevent parts of the UI from
* becoming unreachable, this method will insert an empty box widget in the appropriate size at the
* appropriate position, provided the graphics plugin reports the correct values. Otherwise a zero-size
@@ -532,11 +515,19 @@ struct widget * gui_internal_keyboard_show_native(struct gui_priv *this, struct
md->keyboard = ret;
md->keyboard_mode=mode;
ret->wfree = gui_internal_keyboard_hide_native;
- /* TODO
- * set ret dimensions
- */
+ if (kbd->h < 0) {
+ ret->h = w->h;
+ ret->hmin = w->hmin;
+ } else
+ ret->h = kbd->h;
+ if (kbd->w < 0) {
+ ret->w = w->w;
+ ret->wmin = w->wmin;
+ } else
+ ret->w = kbd->w;
+ dbg(lvl_error, "ret->w=%d, ret->h=%d\n", ret->w, ret->h);
ret->data = (void *) kbd;
gui_internal_widget_append(w, ret);
- /* FIXME do we need to render anything? */
+ dbg(lvl_error, "return\n");
return ret;
}