static bool Sys_Android_CheckBrowserAvailability( void ) { JNIEnv *env = Sys_Android_GetJNIEnv(); jobject intent, list; jstring str; bool available; { jclass intentClass; jmethodID init, addCategory; jobject intentRef; intentClass = (*env)->FindClass( env, "android/content/Intent" ); init = (*env)->GetMethodID( env, intentClass, "<init>", "(Ljava/lang/String;)V" ); addCategory = (*env)->GetMethodID( env, intentClass, "addCategory", "(Ljava/lang/String;)Landroid/content/Intent;" ); str = (*env)->NewStringUTF( env, "android.intent.action.MAIN" ); intent = (*env)->NewObject( env, intentClass, init, str ); (*env)->DeleteLocalRef( env, str ); (*env)->DeleteLocalRef( env, intentClass ); str = (*env)->NewStringUTF( env, "android.intent.category.APP_BROWSER" ); intentRef = (*env)->CallObjectMethod( env, intent, addCategory, str ); (*env)->DeleteLocalRef( env, str ); (*env)->DeleteLocalRef( env, intentRef ); } { jobject pm; jmethodID getPackageManager; jclass pmClass; jmethodID queryIntentActivities; getPackageManager = (*env)->GetMethodID( env, sys_android_activityClass, "getPackageManager", "()Landroid/content/pm/PackageManager;" ); pm = (*env)->CallObjectMethod( env, sys_android_app->activity->clazz, getPackageManager ); pmClass = (*env)->FindClass( env, "android/content/pm/PackageManager" ); queryIntentActivities = (*env)->GetMethodID( env, pmClass, "queryIntentActivities", "(Landroid/content/Intent;I)Ljava/util/List;" ); (*env)->DeleteLocalRef( env, pmClass ); list = (*env)->CallObjectMethod( env, pm, queryIntentActivities, intent, 0x00010000 ); (*env)->DeleteLocalRef( env, intent ); (*env)->DeleteLocalRef( env, pm ); } { jclass listClass; jmethodID isEmpty; listClass = (*env)->FindClass( env, "java/util/List" ); isEmpty = (*env)->GetMethodID( env, listClass, "isEmpty", "()Z" ); (*env)->DeleteLocalRef( env, listClass ); available = ( (*env)->CallBooleanMethod( env, list, isEmpty ) == JNI_FALSE ); (*env)->DeleteLocalRef( env, list ); } return available; }
/* * IN_Android_KeyEvent2UCS */ static wchar_t IN_Android_KeyEvent2UCS( const AInputEvent *event ) { JNIEnv *env = Sys_Android_GetJNIEnv(); static jclass mapClass; static jmethodID load, get; jobject map; unsigned int ucs; if( !mapClass ) { jclass mapClassRef; mapClassRef = (*env)->FindClass( env, "android/view/KeyCharacterMap" ); mapClass = (*env)->NewGlobalRef( env, mapClassRef ); load = (*env)->GetStaticMethodID( env, mapClass, "load", "(I)Landroid/view/KeyCharacterMap;" ); get = (*env)->GetMethodID( env, mapClass, "get", "(II)I" ); (*env)->DeleteLocalRef( env, mapClassRef ); } map = (*env)->CallStaticObjectMethod( env, mapClass, load, AInputEvent_getDeviceId( event ) ); ucs = (*env)->CallIntMethod( env, map, get, AKeyEvent_getKeyCode( event ), AKeyEvent_getMetaState( event ) ); (*env)->DeleteLocalRef( env, map ); return ucs; }
bool VID_GetDefaultMode( int *width, int *height ) { int i, modeWidth, modeHeight, lastWidth = 0, lastHeight = 0; static int maxWidth; if( !maxWidth ) { JNIEnv *env = Sys_Android_GetJNIEnv(); jstring name; jobject activityManager; jclass activityManagerClass; jmethodID getDeviceConfigurationInfo; jobject configurationInfo; jclass configurationInfoClass; jfieldID reqGlEsVersion; name = (*env)->NewStringUTF( env, "activity" ); activityManager = (*env)->CallObjectMethod( env, sys_android_app->activity->clazz, sys_android_getSystemService, name ); (*env)->DeleteLocalRef( env, name ); activityManagerClass = (*env)->FindClass( env, "android/app/ActivityManager" ); getDeviceConfigurationInfo = (*env)->GetMethodID( env, activityManagerClass, "getDeviceConfigurationInfo", "()Landroid/content/pm/ConfigurationInfo;" ); (*env)->DeleteLocalRef( env, activityManagerClass ); configurationInfo = (*env)->CallObjectMethod( env, activityManager, getDeviceConfigurationInfo ); (*env)->DeleteLocalRef( env, activityManager ); configurationInfoClass = (*env)->FindClass( env, "android/content/pm/ConfigurationInfo" ); reqGlEsVersion = (*env)->GetFieldID( env, configurationInfoClass, "reqGlEsVersion", "I" ); (*env)->DeleteLocalRef( env, configurationInfoClass ); // Use full HD as the default on GPUs that support OpenGL ES 3.1, created in 2014 or later, such as NVIDIA Tegra K1. maxWidth = ( ( (*env)->GetIntField( env, configurationInfo, reqGlEsVersion ) >= 0x30001 ) ? 1920 : 1280 ); (*env)->DeleteLocalRef( env, configurationInfo ); } for( i = 0; VID_GetModeInfo( &modeWidth, &modeHeight, i ); i++ ) { if( modeWidth > maxWidth ) break; lastWidth = modeWidth; lastHeight = modeHeight; } assert( lastWidth && lastHeight ); // this function may be called only after vid mode initialization *width = lastWidth; *height = lastHeight; return true; }
void Sys_ReleaseWakeLock( void *wl ) { JNIEnv *env = Sys_Android_GetJNIEnv(); static jmethodID release; if( !release ) { jclass wlClass = (*env)->GetObjectClass( env, wl ); release = (*env)->GetMethodID( env, wlClass, "release", "()V" ); (*env)->DeleteLocalRef( env, wlClass ); } (*env)->CallVoidMethod( env, wl, release ); }
void Sys_OpenURLInBrowser( const char *url ) { JNIEnv *env = Sys_Android_GetJNIEnv(); jobject uri, intent; jstring str; { jclass uriClass; jmethodID parse; uriClass = (*env)->FindClass( env, "android/net/Uri" ); parse = (*env)->GetStaticMethodID( env, uriClass, "parse", "(Ljava/lang/String;)Landroid/net/Uri;" ); str = (*env)->NewStringUTF( env, url ); uri = (*env)->CallStaticObjectMethod( env, uriClass, parse, str ); (*env)->DeleteLocalRef( env, str ); (*env)->DeleteLocalRef( env, uriClass ); } if( !uri ) return; { jclass intentClass; jmethodID init, setData; jobject intentRef; intentClass = (*env)->FindClass( env, "android/content/Intent" ); init = (*env)->GetMethodID( env, intentClass, "<init>", "(Ljava/lang/String;)V" ); setData = (*env)->GetMethodID( env, intentClass, "setData", "(Landroid/net/Uri;)Landroid/content/Intent;" ); str = (*env)->NewStringUTF( env, "android.intent.action.VIEW" ); intent = (*env)->NewObject( env, intentClass, init, str ); (*env)->DeleteLocalRef( env, str ); (*env)->DeleteLocalRef( env, intentClass ); intentRef = (*env)->CallObjectMethod( env, intent, setData, uri ); (*env)->DeleteLocalRef( env, uri ); (*env)->DeleteLocalRef( env, intentRef ); } { jmethodID startActivity; startActivity = (*env)->GetMethodID( env, sys_android_activityClass, "startActivity", "(Landroid/content/Intent;)V" ); (*env)->CallVoidMethod( env, sys_android_app->activity->clazz, startActivity, intent ); (*env)->DeleteLocalRef( env, intent ); } }
void *Sys_AcquireWakeLock( void ) { JNIEnv *env = Sys_Android_GetJNIEnv(); static jmethodID acquire; if( !acquire ) { jclass wlClass = (*env)->GetObjectClass( env, sys_android_wakeLock ); acquire = (*env)->GetMethodID( env, wlClass, "acquire", "()V" ); (*env)->DeleteLocalRef( env, wlClass ); } (*env)->CallVoidMethod( env, sys_android_wakeLock, acquire ); return sys_android_wakeLock; }
static void Sys_Android_ExecuteIntent( void ) { JNIEnv *env = Sys_Android_GetJNIEnv(); static jmethodID getIntentCommand; jstring cmdJS; const char *cmd; if( !getIntentCommand ) getIntentCommand = (*env)->GetMethodID( env, sys_android_activityClass, "getIntentCommand", "()Ljava/lang/String;" ); cmdJS = (*env)->CallObjectMethod( env, sys_android_app->activity->clazz, getIntentCommand ); if( !cmdJS ) return; cmd = (*env)->GetStringUTFChars( env, cmdJS, NULL ); Cbuf_AddText( cmd ); (*env)->ReleaseStringUTFChars( env, cmdJS, cmd ); (*env)->DeleteLocalRef( env, cmdJS ); }
void Sys_ReleaseWakeLock( void *wl ) { JNIEnv *env = Sys_Android_GetJNIEnv(); static jmethodID releaseWakeLock, releaseWifiLock; jclass wlClass; if( !releaseWakeLock ) { wlClass = (*env)->GetObjectClass( env, sys_android_wakeLock ); releaseWakeLock = (*env)->GetMethodID( env, wlClass, "release", "()V" ); (*env)->DeleteLocalRef( env, wlClass ); } if( !releaseWifiLock ) { wlClass = (*env)->GetObjectClass( env, sys_android_wifiLock ); releaseWifiLock = (*env)->GetMethodID( env, wlClass, "release", "()V" ); (*env)->DeleteLocalRef( env, wlClass ); } (*env)->CallVoidMethod( env, sys_android_wakeLock, releaseWakeLock ); (*env)->CallVoidMethod( env, sys_android_wifiLock, releaseWifiLock ); }
/* * Sys_FS_AddFileToMedia */ void Sys_FS_AddFileToMedia( const char *filename ) { #ifdef __ANDROID__ ANativeActivity *activity = sys_android_app->activity; JNIEnv *env = Sys_Android_GetJNIEnv(); char path[PATH_MAX]; jobject file, uri, intent; if( !realpath( filename, path ) ) return; { jclass fileClass; jmethodID ctor; jstring pathname; fileClass = (*env)->FindClass( env, "java/io/File" ); ctor = (*env)->GetMethodID( env, fileClass, "<init>", "(Ljava/lang/String;)V" ); pathname = (*env)->NewStringUTF( env, path ); file = (*env)->NewObject( env, fileClass, ctor, pathname ); (*env)->DeleteLocalRef( env, pathname ); (*env)->DeleteLocalRef( env, fileClass ); } if( !file ) return; { jclass uriClass; jmethodID fromFile; uriClass = (*env)->FindClass( env, "android/net/Uri" ); fromFile = (*env)->GetStaticMethodID( env, uriClass, "fromFile", "(Ljava/io/File;)Landroid/net/Uri;" ); uri = (*env)->CallStaticObjectMethod( env, uriClass, fromFile, file ); (*env)->DeleteLocalRef( env, file ); (*env)->DeleteLocalRef( env, uriClass ); } if( !uri ) return; { jclass intentClass; jmethodID ctor, setData; jstring action; jobject intentRef; intentClass = (*env)->FindClass( env, "android/content/Intent" ); ctor = (*env)->GetMethodID( env, intentClass, "<init>", "(Ljava/lang/String;)V" ); action = (*env)->NewStringUTF( env, "android.intent.action.MEDIA_SCANNER_SCAN_FILE" ); intent = (*env)->NewObject( env, intentClass, ctor, action ); (*env)->DeleteLocalRef( env, action ); setData = (*env)->GetMethodID( env, intentClass, "setData", "(Landroid/net/Uri;)Landroid/content/Intent;" ); intentRef = (*env)->CallObjectMethod( env, intent, setData, uri ); (*env)->DeleteLocalRef( env, uri ); (*env)->DeleteLocalRef( env, intentRef ); (*env)->DeleteLocalRef( env, intentClass ); } { jmethodID sendBroadcast; sendBroadcast = (*env)->GetMethodID( env, sys_android_activityClass, "sendBroadcast", "(Landroid/content/Intent;)V" ); (*env)->CallVoidMethod( env, activity->clazz, sendBroadcast, intent ); (*env)->DeleteLocalRef( env, intent ); } #endif }
/* * Sys_FS_GetMediaDirectory */ const char *Sys_FS_GetMediaDirectory( fs_mediatype_t type ) { #ifdef __ANDROID__ static char paths[FS_MEDIA_NUM_TYPES][PATH_MAX]; static int pathsChecked; const char *publicDir; JNIEnv *env; jclass envClass; jmethodID getPublicDirectory; jstring js; jobject file; jclass fileClass; jmethodID getAbsolutePath; const char *pathUTF; if( paths[type][0] ) return paths[type]; if( pathsChecked & ( 1 << type ) ) return NULL; switch( type ) { case FS_MEDIA_IMAGES: publicDir = "Pictures"; break; default: return NULL; } pathsChecked |= 1 << type; env = Sys_Android_GetJNIEnv(); envClass = (*env)->FindClass( env, "android/os/Environment" ); getPublicDirectory = (*env)->GetStaticMethodID( env, envClass, "getExternalStoragePublicDirectory", "(Ljava/lang/String;)Ljava/io/File;" ); js = (*env)->NewStringUTF( env, publicDir ); file = (*env)->CallStaticObjectMethod( env, envClass, getPublicDirectory, js ); (*env)->DeleteLocalRef( env, js ); (*env)->DeleteLocalRef( env, envClass ); if( !file ) return NULL; fileClass = (*env)->FindClass( env, "java/io/File" ); getAbsolutePath = (*env)->GetMethodID( env, fileClass, "getAbsolutePath", "()Ljava/lang/String;" ); js = (*env)->CallObjectMethod( env, file, getAbsolutePath ); (*env)->DeleteLocalRef( env, file ); (*env)->DeleteLocalRef( env, fileClass ); pathUTF = (*env)->GetStringUTFChars( env, js, NULL ); Q_strncpyz( paths[type], pathUTF, sizeof( paths[0] ) ); (*env)->ReleaseStringUTFChars( env, js, pathUTF ); (*env)->DeleteLocalRef( env, js ); return paths[type]; #else return NULL; #endif }
static void Sys_Android_Init( void ) { struct android_app *app = sys_android_app; JNIEnv *env; jobject activity = app->activity->clazz; // Set signal handlers. signal( SIGTERM, Sys_Android_SignalHandler ); signal( SIGINT, Sys_Android_SignalHandler ); // Set working directory to external data path. { char externalDataPath[PATH_MAX]; Q_snprintfz( externalDataPath, sizeof( externalDataPath ), "%s/%d.%d", app->activity->externalDataPath, APP_VERSION_MAJOR, APP_VERSION_MINOR ); FS_CreateAbsolutePath( externalDataPath ); Sys_FS_CreateDirectory( externalDataPath ); if( chdir( externalDataPath ) ) Sys_Error( "Failed to change working directory" ); } // Initialize JNI. if( pthread_key_create( &sys_android_jniEnvKey, Sys_Android_JNIEnvDestructor ) ) Sys_Error( "Failed to create JNIEnv destructor" ); env = Sys_Android_GetJNIEnv(); // Activity class shortcut. { jclass activityClass = (*env)->GetObjectClass( env, activity ); sys_android_activityClass = (*env)->NewGlobalRef( env, activityClass ); sys_android_getSystemService = (*env)->GetMethodID( env, activityClass, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;" ); (*env)->DeleteLocalRef( env, activityClass ); } // Get package name. { jmethodID getPackageName; jstring packageNameJS; const char *packageNameUTF; getPackageName = (*env)->GetMethodID( env, sys_android_activityClass, "getPackageName", "()Ljava/lang/String;" ); packageNameJS = (*env)->CallObjectMethod( env, activity, getPackageName ); packageNameUTF = (*env)->GetStringUTFChars( env, packageNameJS, NULL ); Q_strncpyz( sys_android_packageName, packageNameUTF, sizeof( sys_android_packageName ) ); (*env)->ReleaseStringUTFChars( env, packageNameJS, packageNameUTF ); (*env)->DeleteLocalRef( env, packageNameJS ); } // Initialize the wake lock. { jstring name; jobject power; jclass powerClass; jmethodID newWakeLock; jstring tag; jobject wl; name = (*env)->NewStringUTF( env, "power" ); power = (*env)->CallObjectMethod( env, activity, sys_android_getSystemService, name ); (*env)->DeleteLocalRef( env, name ); powerClass = (*env)->FindClass( env, "android/os/PowerManager" ); newWakeLock = (*env)->GetMethodID( env, powerClass, "newWakeLock", "(ILjava/lang/String;)Landroid/os/PowerManager$WakeLock;" ); (*env)->DeleteLocalRef( env, powerClass ); tag = (*env)->NewStringUTF( env, "Qfusion" ); wl = (*env)->CallObjectMethod( env, power, newWakeLock, 1, tag ); (*env)->DeleteLocalRef( env, tag ); (*env)->DeleteLocalRef( env, power ); sys_android_wakeLock = (*env)->NewGlobalRef( env, wl ); (*env)->DeleteLocalRef( env, wl ); } // Set native app cmd handler to the actual one. app->onAppCmd = Sys_Android_OnAppCmd; // Check if browser links can be clicked. sys_android_browserAvailable = Sys_Android_CheckBrowserAvailability(); }
static void Sys_Android_Init( void ) { struct android_app *app = sys_android_app; JNIEnv *env; jobject activity = app->activity->clazz; // Resolve the app's internal storage root directory. { char relativePath[PATH_MAX]; Q_snprintfz( relativePath, sizeof( relativePath ), "%s/..", app->activity->internalDataPath ); realpath( relativePath, sys_android_internalDataPath ); } // Set working directory to external data path. { char externalDataPath[PATH_MAX]; Q_snprintfz( externalDataPath, sizeof( externalDataPath ), "%s/%d.%d/", // The trailing slash is here to make it a directory path, not a file path app->activity->externalDataPath, APP_VERSION_MAJOR, APP_VERSION_MINOR ); FS_CreateAbsolutePath( externalDataPath ); if( chdir( externalDataPath ) ) Sys_Error( "Failed to change working directory" ); } // Initialize JNI. if( pthread_key_create( &sys_android_jniEnvKey, Sys_Android_JNIEnvDestructor ) ) Sys_Error( "Failed to create JNIEnv destructor" ); env = Sys_Android_GetJNIEnv(); // Activity class shortcut. { jclass activityClass = (*env)->GetObjectClass( env, activity ); sys_android_activityClass = (*env)->NewGlobalRef( env, activityClass ); sys_android_getSystemService = (*env)->GetMethodID( env, activityClass, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;" ); (*env)->DeleteLocalRef( env, activityClass ); } // Get package name. { jmethodID getPackageName; jstring packageNameJS; const char *packageNameUTF; getPackageName = (*env)->GetMethodID( env, sys_android_activityClass, "getPackageName", "()Ljava/lang/String;" ); packageNameJS = (*env)->CallObjectMethod( env, activity, getPackageName ); packageNameUTF = (*env)->GetStringUTFChars( env, packageNameJS, NULL ); Q_strncpyz( sys_android_packageName, packageNameUTF, sizeof( sys_android_packageName ) ); (*env)->ReleaseStringUTFChars( env, packageNameJS, packageNameUTF ); (*env)->DeleteLocalRef( env, packageNameJS ); } // Initialize the wake lock. { jstring name; jobject power; jclass powerClass; jmethodID newWakeLock; jstring tag; jobject wakeLock; name = (*env)->NewStringUTF( env, "power" ); power = (*env)->CallObjectMethod( env, activity, sys_android_getSystemService, name ); (*env)->DeleteLocalRef( env, name ); powerClass = (*env)->FindClass( env, "android/os/PowerManager" ); newWakeLock = (*env)->GetMethodID( env, powerClass, "newWakeLock", "(ILjava/lang/String;)Landroid/os/PowerManager$WakeLock;" ); (*env)->DeleteLocalRef( env, powerClass ); tag = (*env)->NewStringUTF( env, "Qfusion" ); wakeLock = (*env)->CallObjectMethod( env, power, newWakeLock, 1 /* PARTIAL_WAKE_LOCK */, tag ); (*env)->DeleteLocalRef( env, tag ); (*env)->DeleteLocalRef( env, power ); sys_android_wakeLock = (*env)->NewGlobalRef( env, wakeLock ); (*env)->DeleteLocalRef( env, wakeLock ); } // Initialize the high-performance Wi-Fi lock. { jstring name; jobject wifi; jclass wifiClass; jmethodID createWifiLock; jstring tag; jobject wifiLock; name = (*env)->NewStringUTF( env, "wifi" ); wifi = (*env)->CallObjectMethod( env, activity, sys_android_getSystemService, name ); (*env)->DeleteLocalRef( env, name ); wifiClass = (*env)->FindClass( env, "android/net/wifi/WifiManager" ); createWifiLock = (*env)->GetMethodID( env, wifiClass, "createWifiLock", "(ILjava/lang/String;)Landroid/net/wifi/WifiManager$WifiLock;" ); (*env)->DeleteLocalRef( env, wifiClass ); tag = (*env)->NewStringUTF( env, "Qfusion" ); wifiLock = (*env)->CallObjectMethod( env, wifi, createWifiLock, 3 /* WIFI_MODE_FULL_HIGH_PERF */, tag ); (*env)->DeleteLocalRef( env, tag ); (*env)->DeleteLocalRef( env, wifi ); sys_android_wifiLock = (*env)->NewGlobalRef( env, wifiLock ); (*env)->DeleteLocalRef( env, wifiLock ); } // Set native app cmd handler to the actual one. app->onAppCmd = Sys_Android_OnAppCmd; // Check if browser links can be clicked. sys_android_browserAvailable = Sys_Android_CheckBrowserAvailability(); }