| Summary: | [Android] [patch] support display DPI reading | ||
|---|---|---|---|
| Product: | SDL | Reporter: | Daniel Sobe <hardcoredaniel> |
| Component: | video | Assignee: | Sam Lantinga <slouken> |
| Status: | RESOLVED FIXED | QA Contact: | Sam Lantinga <slouken> |
| Severity: | normal | ||
| Priority: | P2 | CC: | amaranth72, sylvain.becker |
| Version: | HG 2.1 | ||
| Hardware: | All | ||
| OS: | Android (All) | ||
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/ 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. (In reply to Daniel Sobe from comment #2) > the post is from 2013 June 2016, actually. Ooops, yes, you're right. |
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: */