summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormvglasow <michael -at- vonglasow.com>2016-01-19 17:02:07 +0100
committermvglasow <michael -at- vonglasow.com>2016-02-02 09:58:31 +0100
commit2309b377da6e89f1fc35bef42577b8de7a80ef85 (patch)
treeb06de7bb910ea65c530e6df45bf72787a7958c87
parent97e493aaacf25e4a56cb9c8dae8b4e90615ca2c9 (diff)
downloadnavit-2309b377da6e89f1fc35bef42577b8de7a80ef85.tar.gz
Add:graphics_android:Implement padding for areas obstructed by system UI
Signed-off-by: mvglasow <michael -at- vonglasow.com>
-rw-r--r--navit/android.c8
-rw-r--r--navit/android/src/org/navitproject/navit/Navit.java46
-rw-r--r--navit/android/src/org/navitproject/navit/NavitGraphics.java86
-rw-r--r--navit/graphics.h15
-rw-r--r--navit/graphics/android/graphics_android.c35
5 files changed, 180 insertions, 10 deletions
diff --git a/navit/android.c b/navit/android.c
index d35c105cf..6e62da1b3 100644
--- a/navit/android.c
+++ b/navit/android.c
@@ -118,6 +118,14 @@ Java_org_navitproject_navit_NavitGraphics_SizeChangedCallback( JNIEnv* env, jobj
}
JNIEXPORT void JNICALL
+Java_org_navitproject_navit_NavitGraphics_PaddingChangedCallback(JNIEnv* env, jobject thiz, int id, int left, int top, int right, int bottom)
+{
+ dbg(lvl_debug,"enter %p %d %d %d %d\n",(struct callback *)id, left, top, right, bottom);
+ if (id)
+ callback_call_4((struct callback *)id, left, top, right, bottom);
+}
+
+JNIEXPORT void JNICALL
Java_org_navitproject_navit_NavitGraphics_ButtonCallback( JNIEnv* env, jobject thiz, int id, int pressed, int button, int x, int y)
{
dbg(lvl_debug,"enter %p %d %d\n",(struct callback *)id,pressed,button);
diff --git a/navit/android/src/org/navitproject/navit/Navit.java b/navit/android/src/org/navitproject/navit/Navit.java
index d33425a76..920b79a98 100644
--- a/navit/android/src/org/navitproject/navit/Navit.java
+++ b/navit/android/src/org/navitproject/navit/Navit.java
@@ -34,6 +34,7 @@ import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ActivityManager.TaskDescription;
import android.app.AlertDialog;
@@ -48,12 +49,15 @@ import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
+import android.graphics.Point;
import android.media.AudioManager;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Message;
@@ -83,6 +87,11 @@ public class Navit extends Activity
private NavitActivityResult ActivityResults[];
public static InputMethodManager mgr = null;
public static DisplayMetrics metrics = null;
+ public static int status_bar_height = 0;
+ public static int action_bar_default_height = 0;
+ public static int navigation_bar_height = 0;
+ public static int navigation_bar_height_landscape= 0;
+ public static int navigation_bar_width = 0;
public static Boolean show_soft_keyboard = false;
public static Boolean show_soft_keyboard_now_showing = false;
public static long last_pressed_menu_key = 0L;
@@ -105,6 +114,7 @@ public class Navit extends Activity
static final String NAVIT_DATA_SHARE_DIR = NAVIT_DATA_DIR + "/share";
static final String FIRST_STARTUP_FILE = NAVIT_DATA_SHARE_DIR + "/has_run_once.txt";
public static final String NAVIT_PREFS = "NavitPrefs";
+ Boolean isFullscreen = false;
public void removeFileIfExists(String source) {
File file = new File(source);
@@ -281,6 +291,23 @@ public class Navit extends Activity
NavitNotification.flags|=Notification.FLAG_ONGOING_EVENT; // Ensure that the notification appears in Ongoing
nm.notify(R.string.app_name, NavitNotification); // Set the notification
+ // Status and navigation bar sizes
+ // These are platform defaults and do not change with rotation, but we have to figure out which ones apply
+ // (is the navigation bar visible? on the side or at the bottom?)
+ Resources resources = getResources();
+ int shid = resources.getIdentifier("status_bar_height", "dimen", "android");
+ int adhid = resources.getIdentifier("action_bar_default_height", "dimen", "android");
+ int nhid = resources.getIdentifier("navigation_bar_height", "dimen", "android");
+ int nhlid = resources.getIdentifier("navigation_bar_height_landscape", "dimen", "android");
+ int nwid = resources.getIdentifier("navigation_bar_width", "dimen", "android");
+ status_bar_height = (shid > 0) ? resources.getDimensionPixelSize(shid) : 0;
+ action_bar_default_height = (adhid > 0) ? resources.getDimensionPixelSize(adhid) : 0;
+ navigation_bar_height = (nhid > 0) ? resources.getDimensionPixelSize(nhid) : 0;
+ navigation_bar_height_landscape = (nhid > 0) ? resources.getDimensionPixelSize(nhlid) : 0;
+ navigation_bar_width = (nwid > 0) ? resources.getDimensionPixelSize(nwid) : 0;
+ Log.d(TAG, String.format("status_bar_height=%d, action_bar_default_height=%d, navigation_bar_height=%d, navigation_bar_height_landscape=%d, navigation_bar_width=%d",
+ status_bar_height, action_bar_default_height, navigation_bar_height, navigation_bar_height_landscape, navigation_bar_width));
+
// get the local language -------------
Locale locale = java.util.Locale.getDefault();
String lang = locale.getLanguage();
@@ -607,6 +634,7 @@ public class Navit extends Activity
}
}
+
/**
* @brief Shows the Options menu.
*
@@ -717,7 +745,10 @@ public class Navit extends Activity
}
public void fullscreen(int fullscreen) {
- if(fullscreen != 0) {
+ int w, h;
+
+ isFullscreen = (fullscreen != 0);
+ if (isFullscreen) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
}
@@ -725,6 +756,19 @@ public class Navit extends Activity
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
+
+ Display display_ = getWindowManager().getDefaultDisplay();
+ if (Build.VERSION.SDK_INT < 17) {
+ w = display_.getWidth();
+ h = display_.getHeight();
+ } else {
+ Point size = new Point();
+ display_.getRealSize(size);
+ w = size.x;
+ h = size.y;
+ }
+ Log.d(TAG, String.format("Toggle fullscreen, w=%d, h=%d", w, h));
+ N_NavitGraphics.handleResize(w, h);
}
public void disableSuspend()
diff --git a/navit/android/src/org/navitproject/navit/NavitGraphics.java b/navit/android/src/org/navitproject/navit/NavitGraphics.java
index 08f4fbe3e..a0bdafed2 100644
--- a/navit/android/src/org/navitproject/navit/NavitGraphics.java
+++ b/navit/android/src/org/navitproject/navit/NavitGraphics.java
@@ -25,6 +25,8 @@ import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
@@ -199,11 +201,8 @@ public class NavitGraphics
Log.e("Navit", "NavitGraphics -> onSizeChanged scaledDensity="
+ Navit.metrics.scaledDensity);
super.onSizeChanged(w, h, oldw, oldh);
- draw_bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
- draw_canvas = new Canvas(draw_bitmap);
- bitmap_w = w;
- bitmap_h = h;
- SizeChangedCallback(SizeChangedCallbackID, w, h);
+
+ handleResize(w, h);
}
public void do_longpress_action()
@@ -783,6 +782,7 @@ public class NavitGraphics
};
public native void SizeChangedCallback(int id, int x, int y);
+ public native void PaddingChangedCallback(int id, int left, int right, int top, int bottom);
public native void KeypressCallback(int id, String s);
public native int CallbackMessageChannel(int i, String s);
public native void ButtonCallback(int id, int pressed, int button, int x, int y);
@@ -791,8 +791,74 @@ public class NavitGraphics
public static native String[][] GetAllCountries();
private Canvas draw_canvas;
private Bitmap draw_bitmap;
- private int SizeChangedCallbackID, ButtonCallbackID, MotionCallbackID, KeypressCallbackID;
+ private int SizeChangedCallbackID, PaddingChangedCallbackID, ButtonCallbackID, MotionCallbackID, KeypressCallbackID;
// private int count;
+
+ /**
+ * @brief Handles resize events.
+ *
+ * This method is called whenever the main View is resized in any way. This is the case when its
+ * {@code onSizeChanged()} event handler fires or when toggling Fullscreen mode.
+ *
+ * It (re-)evaluates if and where the navigation bar is going to be shown, and calculates the
+ * padding for objects which should not be obstructed.
+ */
+ public void handleResize(int w, int h) {
+ if (this.parent_graphics != null)
+ this.parent_graphics.handleResize(w, h);
+ else {
+ Log.d("NavitGraphics", String.format("handleResize w=%d h=%d", w, h));
+ /*
+ * The code would work on API14+ but is meaningful only on API17+
+ */
+ if (Build.VERSION.SDK_INT >= 17) {
+ Navit navit = null;
+ if (activity instanceof Navit) {
+ navit = (Navit) activity;
+ /*
+ * Determine visibility of status bar.
+ * The status bar is always visible unless we are in fullscreen mode.
+ */
+ Boolean isStatusShowing = !navit.isFullscreen;
+
+ /*
+ * Determine visibility of navigation bar.
+ * This logic is based on the presence of a hardware menu button and is known to work on
+ * devices which allow switching between hw and sw buttons (OnePlus One running CyanogenMod).
+ */
+ Boolean isNavShowing = !ViewConfiguration.get(navit.getApplication()).hasPermanentMenuKey();
+
+ Log.d("NavitGraphics", String.format("isStatusShowing=%b isNavShowing=%b", isStatusShowing, isNavShowing));
+
+ /*
+ * Determine where the navigation bar would be displayed.
+ * Logic is taken from AOSP RenderSessionImpl.findNavigationBar()
+ * (platform/frameworks/base/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java)
+ */
+ Boolean isLandscape = (navit.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
+ Boolean isNavAtBottom = (!isLandscape) || (navit.getResources().getConfiguration().smallestScreenWidthDp >= 600);
+ Log.d("NavitGraphics", String.format("isNavAtBottom=%b (Configuration.smallestScreenWidthDp=%d, isLandscape=%b)",
+ isNavAtBottom, navit.getResources().getConfiguration().smallestScreenWidthDp, isLandscape));
+
+ int left = 0;
+ int top = isStatusShowing ? Navit.status_bar_height : 0;
+ int right = (isNavShowing && !isNavAtBottom) ? Navit.navigation_bar_width : 0;
+ int bottom = (!(isNavShowing && isNavAtBottom)) ? 0 : isLandscape ? Navit.navigation_bar_height_landscape : Navit.navigation_bar_height;
+
+ Log.d("NavitGraphics", String.format("Padding left=%d top=%d right=%d bottom=%d", left, top, right, bottom));
+
+ PaddingChangedCallback(PaddingChangedCallbackID, left, top, right, bottom);
+ } else
+ Log.e("NavitGraphics", "Main Activity is not a Navit instance, cannot update padding");
+ }
+
+ draw_bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+ draw_canvas = new Canvas(draw_bitmap);
+ bitmap_w = w;
+ bitmap_h = h;
+ SizeChangedCallback(SizeChangedCallbackID, w, h);
+ }
+ }
/**
* @brief Returns whether the device has a hardware menu button.
@@ -802,6 +868,10 @@ public class NavitGraphics
* this method will always return {@code true}, as these Android versions relied on devices having a physical
* Menu button. On API levels 11 through 13 (Honeycomb releases), this method will always return
* {@code false}, as Honeycomb was a tablet-only release and did not require devices to have a Menu button.
+ *
+ * Note that this method is not aware of non-standard mechanisms on some customized builds of Android. For
+ * example, CyanogenMod has an option to add a menu button to the navigation bar. Even with that option,
+ * this method will still return `false`.
*/
public boolean hasMenuButton() {
if (Build.VERSION.SDK_INT <= 10)
@@ -816,6 +886,10 @@ public class NavitGraphics
{
SizeChangedCallbackID = id;
}
+ public void setPaddingChangedCallback(int id)
+ {
+ PaddingChangedCallbackID = id;
+ }
public void setButtonCallback(int id)
{
ButtonCallbackID = id;
diff --git a/navit/graphics.h b/navit/graphics.h
index fb18347cf..44bd6c919 100644
--- a/navit/graphics.h
+++ b/navit/graphics.h
@@ -74,6 +74,21 @@ struct graphics_image_buffer {
* @see graphics_gtk_drawing_area#plugin_init()
* @see graphics_android#plugin_init()
*/
+
+/**
+ * Describes areas at each edge of the application window which may be obstructed by the system UI.
+ *
+ * This allows the map to use all available space, including areas which may be obscured by system UI
+ * elements, while constraining other elements such as OSDs or UI controls to an area that is guaranteed
+ * to be visible as long as Navit is in the foreground.
+ */
+struct padding {
+ int left;
+ int top;
+ int right;
+ int bottom;
+};
+
struct graphics_methods {
void (*graphics_destroy)(struct graphics_priv *gr);
void (*draw_mode)(struct graphics_priv *gr, enum draw_mode_num mode);
diff --git a/navit/graphics/android/graphics_android.c b/navit/graphics/android/graphics_android.c
index 2bfbacab4..2ef9400b4 100644
--- a/navit/graphics/android/graphics_android.c
+++ b/navit/graphics/android/graphics_android.c
@@ -64,6 +64,7 @@ struct graphics_priv {
struct callback_list *cbl;
struct window win;
+ struct padding *padding;
};
struct graphics_font_priv {
@@ -419,9 +420,11 @@ static struct graphics_priv * overlay_new(struct graphics_priv *gr, struct graph
static void *
get_data(struct graphics_priv *this, const char *type)
{
- if (strcmp(type,"window"))
- return NULL;
- return &this->win;
+ if (!strcmp(type,"padding"))
+ return this->padding;
+ if (!strcmp(type,"window"))
+ return &this->win;
+ return NULL;
}
static void image_free(struct graphics_priv *gr, struct graphics_image_priv *priv)
@@ -496,10 +499,21 @@ static void
resize_callback(struct graphics_priv *gra, int w, int h)
{
dbg(lvl_debug,"w=%d h=%d ok\n",w,h);
+ dbg(lvl_debug,"gra=%p, %d callbacks in list\n", gra, g_list_length(gra->cbl));
callback_list_call_attr_2(gra->cbl, attr_resize, (void *)w, (void *)h);
}
static void
+padding_callback(struct graphics_priv *gra, int left, int top, int right, int bottom)
+{
+ dbg(lvl_debug, "win.padding left=%d top=%d right=%d bottom=%d ok\n", left, top, right, bottom);
+ gra->padding->left = left;
+ gra->padding->top = top;
+ gra->padding->right = right;
+ gra->padding->bottom = bottom;
+}
+
+static void
motion_callback(struct graphics_priv *gra, int x, int y)
{
struct point p;
@@ -569,6 +583,8 @@ graphics_android_init(struct graphics_priv *ret, struct graphics_priv *parent, s
jmethodID cid, Context_getPackageName;
dbg(lvl_debug,"at 2 jnienv=%p\n",jnienv);
+ if (parent)
+ ret->padding = parent->padding;
if (!find_class_global("android/graphics/Paint", &ret->PaintClass))
return 0;
if (!find_method(ret->PaintClass, "<init>", "(I)V", &ret->Paint_init))
@@ -644,6 +660,14 @@ graphics_android_init(struct graphics_priv *ret, struct graphics_priv *parent, s
cb=callback_new_1(callback_cast(resize_callback), ret);
(*jnienv)->CallVoidMethod(jnienv, ret->NavitGraphics, cid, (int)cb);
+ cid = (*jnienv)->GetMethodID(jnienv, ret->NavitGraphicsClass, "setPaddingChangedCallback", "(I)V");
+ if (cid == NULL) {
+ dbg(lvl_error,"no SetPaddingCallback method found\n");
+ return 0; /* exception thrown */
+ }
+ cb=callback_new_1(callback_cast(padding_callback), ret);
+ (*jnienv)->CallVoidMethod(jnienv, ret->NavitGraphics, cid, (int)cb);
+
cid = (*jnienv)->GetMethodID(jnienv, ret->NavitGraphicsClass, "setButtonCallback", "(I)V");
if (cid == NULL) {
dbg(lvl_error,"no SetButtonCallback method found\n");
@@ -801,6 +825,11 @@ graphics_android_new(struct navit *nav, struct graphics_methods *meth, struct at
ret->win.priv=ret;
ret->win.fullscreen=graphics_android_fullscreen;
ret->win.disable_suspend=graphics_android_disable_suspend;
+ ret->padding = g_new0(struct padding, 1);
+ ret->padding->left = 0;
+ ret->padding->top = 0;
+ ret->padding->right = 0;
+ ret->padding->bottom = 0;
if ((attr=attr_search(attrs, NULL, attr_use_camera))) {
use_camera=attr->u.num;
}