diff options
-rw-r--r-- | navit/android.c | 8 | ||||
-rw-r--r-- | navit/android/src/org/navitproject/navit/Navit.java | 46 | ||||
-rw-r--r-- | navit/android/src/org/navitproject/navit/NavitGraphics.java | 86 | ||||
-rw-r--r-- | navit/graphics.h | 15 | ||||
-rw-r--r-- | navit/graphics/android/graphics_android.c | 35 |
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; } |