We are currently migrating Bugzilla to GitHub issues.
Any changes made to the bug tracker now will be lost, so please do not post new bugs or make changes to them.
When we're done, all bug URLs will redirect to their equivalent location on the new bug tracker.

Bug 3439 - [Android] [patch] support display DPI reading
Summary: [Android] [patch] support display DPI reading
Status: RESOLVED FIXED
Alias: None
Product: SDL
Classification: Unclassified
Component: video (show other bugs)
Version: HG 2.1
Hardware: All Android (All)
: P2 normal
Assignee: Sam Lantinga
QA Contact: Sam Lantinga
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-10-02 14:27 UTC by Daniel Sobe
Modified: 2017-11-01 07:58 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Daniel Sobe 2016-10-02 14:27:23 UTC
The following patch adds support for reading display DPI from Android devices.

Please ignore the additional lines at the beginning of the patch.

The trustworthiness of the values depend on the manufacturer of the device, but over time this has improved.

I did not know how to fill the "diagonal DPI", so I put the "densityDPI" value in FWIW.

-------------------------------------------------------------------------------------------------


--- SDL_snapshot/src/core/android/SDL_android.c	2016-10-02 09:27:31.000000000 +0200
+++ SDL_patches/src/core/android/SDL_android.c	2016-10-02 11:49:15.985195517 +0200
@@ -421,6 +421,32 @@
     return result;
 }
 
+void Android_JNI_HintCallback(void *userdata, const char *name, const char *oldValue, const char *newValue) {
+    JNIEnv *env = Android_JNI_GetEnv();
+
+    jobject callback = (jobject)userdata;
+   jclass cls = (*env)->GetObjectClass(env, callback);
+    jmethodID method = (*env)->GetMethodID(env, cls, "callback", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
+
+    jstring javaName     = (*env)->NewStringUTF(env, name);
+    jstring javaOldValue = (*env)->NewStringUTF(env, oldValue);
+    jstring javaNewValue = (*env)->NewStringUTF(env, newValue);
+
+    (*env)->CallVoidMethod(env, callback, method, javaName, javaOldValue, javaNewValue);
+
+    (*env)->DeleteLocalRef(env, javaName);
+    (*env)->DeleteLocalRef(env, javaOldValue);
+    (*env)->DeleteLocalRef(env, javaNewValue);
+}
+
+void Java_org_libsdl_app_SDLActivity_nativeAddHintCallback(JNIEnv* env, jclass cls, jstring name, jobject callback) {
+    const char *utfname = (*env)->GetStringUTFChars(env, name, NULL);
+
+    SDL_AddHintCallback(utfname, Android_JNI_HintCallback, (*env)->NewGlobalRef(env, callback));
+
+    (*env)->ReleaseStringUTFChars(env, name, utfname);    
+}
+
 /*******************************************************************************
              Functions called by SDL into Java
 *******************************************************************************/
@@ -1770,6 +1796,63 @@
     return mActivityClass;
 }
 
+int Android_JNI_GetDisplayMetrics(float *density, int *densityDpi, float *xdpi, float *ydpi)
+{
+    jmethodID mid;
+    jobject   context;
+    jclass    contextClass;
+    jobject   resources;
+    jclass    resourcesClass;
+    jobject   displayMetrics;
+    jclass    displayMetricsClass;
+    jfieldID  IDdensity;
+    jfieldID  IDdensityDpi;
+    jfieldID  IDxdpi;
+    jfieldID  IDydpi;
+
+    struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__);
+
+    JNIEnv *env = Android_JNI_GetEnv();
+
+    if (!LocalReferenceHolder_Init(&refs, env)) {
+        LocalReferenceHolder_Cleanup(&refs);
+        return -1;
+    }
+
+    /* context = SDLActivity.getContext(); */
+    mid = (*env)->GetStaticMethodID(env, mActivityClass,
+            "getContext","()Landroid/content/Context;");
+    context = (*env)->CallStaticObjectMethod(env, mActivityClass, mid);
+    contextClass = (*env)->GetObjectClass(env, context);
+
+    mid = (*env)->GetMethodID(env, contextClass,
+    		"getResources", "()Landroid/content/res/Resources;");
+    resources = (*env)->CallObjectMethod(env, context, mid);
+
+    resourcesClass = (*env)->GetObjectClass(env, resources);
+    mid = (*env)->GetMethodID(env, resourcesClass,
+    		"getDisplayMetrics", "()Landroid/util/DisplayMetrics;");
+    displayMetrics = (*env)->CallObjectMethod(env, resources, mid);
+
+    displayMetricsClass = (*env)->GetObjectClass(env, displayMetrics);
+
+    IDdensity    = (*env)->GetFieldID(env, displayMetricsClass, "density", "F");
+    IDdensityDpi = (*env)->GetFieldID(env, displayMetricsClass, "densityDpi", "I");
+    IDxdpi       = (*env)->GetFieldID(env, displayMetricsClass, "xdpi", "F");
+    IDydpi       = (*env)->GetFieldID(env, displayMetricsClass, "ydpi", "F");
+
+    *density    = (float) ((*env)->GetFloatField  (env, displayMetrics, IDdensity));
+    *densityDpi = (int)   ((*env)->GetIntField  (env, displayMetrics, IDdensityDpi));
+    *xdpi       = (float) ((*env)->GetFloatField(env, displayMetrics, IDxdpi));
+    *ydpi       = (float) ((*env)->GetFloatField(env, displayMetrics, IDydpi));
+
+    __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL display density: dens=%.2f dpi=%d x=%.2f y=%.2f!", *density, *densityDpi, *xdpi, *ydpi);
+
+    LocalReferenceHolder_Cleanup(&refs);
+
+    return 0;
+}
+
 #endif /* __ANDROID__ */
 
 /* vi: set ts=4 sw=4 expandtab: */
diff -aur SDL_snapshot/src/core/android/SDL_android.h SDL_patches/src/core/android/SDL_android.h
--- SDL_snapshot/src/core/android/SDL_android.h	2016-10-02 09:27:31.000000000 +0200
+++ SDL_patches/src/core/android/SDL_android.h	2016-10-02 11:50:39.825776984 +0200
@@ -69,6 +69,7 @@
 
 /* Video */
 void Android_JNI_SuspendScreenSaver(SDL_bool suspend);
+int Android_JNI_GetDisplayMetrics(float *density, int *densityDpi, float *xdpi, float *ydpi);
 
 /* Touch support */
 int Android_JNI_GetTouchDeviceIds(int **ids);

--- SDL_snapshot/src/video/android/SDL_androidvideo.c	2016-10-02 09:27:31.000000000 +0200
+++ SDL_patches/src/video/android/SDL_androidvideo.c	2016-10-02 12:12:25.658772321 +0200
@@ -45,6 +45,7 @@
 /* Initialization/Query functions */
 static int Android_VideoInit(_THIS);
 static void Android_VideoQuit(_THIS);
+static int Android_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi);
 
 #include "../SDL_egl_c.h"
 /* GL functions (SDL_androidgl.c) */
@@ -122,6 +123,7 @@
     device->SetWindowTitle = Android_SetWindowTitle;
     device->DestroyWindow = Android_DestroyWindow;
     device->GetWindowWMInfo = Android_GetWindowWMInfo;
+    device->GetDisplayDPI = Android_GetDisplayDPI;
 
     device->free = Android_DeleteDevice;
 
@@ -223,6 +225,21 @@
     }
 }
 
+static int Android_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi)
+{
+	float density;
+	int densityDpi;
+
+	if (Android_JNI_GetDisplayMetrics(&density, &densityDpi, hdpi, vdpi) == -1)
+	{
+		return -1;
+	}
+
+    *ddpi = (float) densityDpi;
+
+    return 0;
+}
+
 #endif /* SDL_VIDEO_DRIVER_ANDROID */
 
 /* vi: set ts=4 sw=4 expandtab: */
Comment 1 Alex Szpakowski 2016-10-02 14:49:05 UTC
Here's some info from a Unity employee about how reliable Android's xdpi / ydpi / densityDpi are: https://forum.unity3d.com/threads/screen-dpi-on-android.414014/
Comment 2 Daniel Sobe 2016-10-02 19:16:23 UTC
I have only tested about 15 devices, but it did not look as bad as described in the post. Maybe the situation improved over the years (the post is from 2013)? I only found 2 faulty devices, one of them had a Cyanogenmod with improper values, the other one was an older phone, whose values were off a bit, but not completely wrong. 

All other values were correct with a tolerance of 1..2mm physical screen size.

Anyway, invalid values from device manufacturers would not really be SDL's fault.

Finally, considering to simply do the same that Unity does is not a bad idea either.
Comment 3 Alex Szpakowski 2016-10-02 19:17:55 UTC
(In reply to Daniel Sobe from comment #2)
> the post is from 2013

June 2016, actually.
Comment 4 Daniel Sobe 2016-10-02 19:19:23 UTC
Ooops, yes, you're right.
Comment 5 Sylvain 2017-11-01 07:58:59 UTC
Fixed by https://hg.libsdl.org/SDL/rev/a996f135cc81