/
SDL_android.c
2801 lines (2334 loc) · 101 KB
1
2
/*
Simple DirectMedia Layer
3
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
22
23
24
#include "SDL_stdinc.h"
#include "SDL_assert.h"
25
#include "SDL_atomic.h"
26
#include "SDL_hints.h"
27
#include "SDL_main.h"
28
#include "SDL_timer.h"
29
30
31
32
33
34
#ifdef __ANDROID__
#include "SDL_system.h"
#include "SDL_android.h"
35
36
#include "keyinfotable.h"
37
38
39
40
41
42
43
#include "../../events/SDL_events_c.h"
#include "../../video/android/SDL_androidkeyboard.h"
#include "../../video/android/SDL_androidmouse.h"
#include "../../video/android/SDL_androidtouch.h"
#include "../../video/android/SDL_androidvideo.h"
#include "../../video/android/SDL_androidwindow.h"
#include "../../joystick/android/SDL_sysjoystick_c.h"
44
#include "../../haptic/android/SDL_syshaptic_c.h"
45
46
#include <android/log.h>
47
#include <sys/system_properties.h>
48
49
50
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
51
#include <dlfcn.h>
52
53
54
55
56
#define SDL_JAVA_PREFIX org_libsdl_app
#define CONCAT1(prefix, class, function) CONCAT2(prefix, class, function)
#define CONCAT2(prefix, class, function) Java_ ## prefix ## _ ## class ## _ ## function
#define SDL_JAVA_INTERFACE(function) CONCAT1(SDL_JAVA_PREFIX, SDLActivity, function)
57
58
#define SDL_JAVA_AUDIO_INTERFACE(function) CONCAT1(SDL_JAVA_PREFIX, SDLAudioManager, function)
#define SDL_JAVA_CONTROLLER_INTERFACE(function) CONCAT1(SDL_JAVA_PREFIX, SDLControllerManager, function)
59
60
#define SDL_JAVA_INTERFACE_INPUT_CONNECTION(function) CONCAT1(SDL_JAVA_PREFIX, SDLInputConnection, function)
61
62
63
64
/* Audio encoding definitions */
#define ENCODING_PCM_8BIT 3
#define ENCODING_PCM_16BIT 2
#define ENCODING_PCM_FLOAT 4
65
66
/* Java class SDLActivity */
67
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(
68
JNIEnv *env, jclass cls);
69
70
JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeRunMain)(
71
JNIEnv *env, jclass cls,
72
73
jstring library, jstring function, jobject array);
74
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeDropFile)(
75
JNIEnv *env, jclass jcls,
76
77
jstring filename);
78
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetScreenResolution)(
79
JNIEnv *env, jclass jcls,
80
jint surfaceWidth, jint surfaceHeight,
81
jint deviceWidth, jint deviceHeight, jint format, jfloat rate);
82
83
84
85
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeResize)(
JNIEnv *env, jclass cls);
86
87
88
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceCreated)(
JNIEnv *env, jclass jcls);
89
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceChanged)(
90
JNIEnv *env, jclass jcls);
91
92
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceDestroyed)(
93
JNIEnv *env, jclass jcls);
94
95
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeKeyDown)(
96
JNIEnv *env, jclass jcls,
97
98
99
jint keycode);
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeKeyUp)(
100
JNIEnv *env, jclass jcls,
101
102
jint keycode);
103
104
105
JNIEXPORT jboolean JNICALL SDL_JAVA_INTERFACE(onNativeSoftReturnKey)(
JNIEnv *env, jclass jcls);
106
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeKeyboardFocusLost)(
107
JNIEnv *env, jclass jcls);
108
109
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeTouch)(
110
JNIEnv *env, jclass jcls,
111
112
113
114
jint touch_device_id_in, jint pointer_finger_id_in,
jint action, jfloat x, jfloat y, jfloat p);
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeMouse)(
115
JNIEnv *env, jclass jcls,
116
jint button, jint action, jfloat x, jfloat y, jboolean relative);
117
118
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeAccel)(
119
JNIEnv *env, jclass jcls,
120
121
jfloat x, jfloat y, jfloat z);
122
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeClipboardChanged)(
123
JNIEnv *env, jclass jcls);
124
125
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeLowMemory)(
126
JNIEnv *env, jclass cls);
127
128
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSendQuit)(
129
JNIEnv *env, jclass cls);
130
131
132
133
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeQuit)(
JNIEnv *env, jclass cls);
134
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativePause)(
135
JNIEnv *env, jclass cls);
136
137
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeResume)(
138
JNIEnv *env, jclass cls);
139
140
141
142
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeFocusChanged)(
JNIEnv *env, jclass cls, jboolean hasFocus);
143
JNIEXPORT jstring JNICALL SDL_JAVA_INTERFACE(nativeGetHint)(
144
JNIEnv *env, jclass cls,
145
146
jstring name);
147
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetenv)(
148
JNIEnv *env, jclass cls,
149
150
jstring name, jstring value);
151
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeOrientationChanged)(
152
JNIEnv *env, jclass cls,
153
154
jint orientation);
155
156
157
158
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeAddTouch)(
JNIEnv* env, jclass cls,
jint touchId, jstring name);
159
160
161
162
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativePermissionResult)(
JNIEnv* env, jclass cls,
jint requestCode, jboolean result);
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
static JNINativeMethod SDLActivity_tab[] = {
{ "nativeSetupJNI", "()I", SDL_JAVA_INTERFACE(nativeSetupJNI) },
{ "nativeRunMain", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)I", SDL_JAVA_INTERFACE(nativeRunMain) },
{ "onNativeDropFile", "(Ljava/lang/String;)V", SDL_JAVA_INTERFACE(onNativeDropFile) },
{ "nativeSetScreenResolution", "(IIIIIF)V", SDL_JAVA_INTERFACE(nativeSetScreenResolution) },
{ "onNativeResize", "()V", SDL_JAVA_INTERFACE(onNativeResize) },
{ "onNativeSurfaceCreated", "()V", SDL_JAVA_INTERFACE(onNativeSurfaceCreated) },
{ "onNativeSurfaceChanged", "()V", SDL_JAVA_INTERFACE(onNativeSurfaceChanged) },
{ "onNativeSurfaceDestroyed", "()V", SDL_JAVA_INTERFACE(onNativeSurfaceDestroyed) },
{ "onNativeKeyDown", "(I)V", SDL_JAVA_INTERFACE(onNativeKeyDown) },
{ "onNativeKeyUp", "(I)V", SDL_JAVA_INTERFACE(onNativeKeyUp) },
{ "onNativeSoftReturnKey", "()Z", SDL_JAVA_INTERFACE(onNativeSoftReturnKey) },
{ "onNativeKeyboardFocusLost", "()V", SDL_JAVA_INTERFACE(onNativeKeyboardFocusLost) },
{ "onNativeTouch", "(IIIFFF)V", SDL_JAVA_INTERFACE(onNativeTouch) },
{ "onNativeMouse", "(IIFFZ)V", SDL_JAVA_INTERFACE(onNativeMouse) },
{ "onNativeAccel", "(FFF)V", SDL_JAVA_INTERFACE(onNativeAccel) },
{ "onNativeClipboardChanged", "()V", SDL_JAVA_INTERFACE(onNativeClipboardChanged) },
{ "nativeLowMemory", "()V", SDL_JAVA_INTERFACE(nativeLowMemory) },
{ "nativeSendQuit", "()V", SDL_JAVA_INTERFACE(nativeSendQuit) },
{ "nativeQuit", "()V", SDL_JAVA_INTERFACE(nativeQuit) },
{ "nativePause", "()V", SDL_JAVA_INTERFACE(nativePause) },
{ "nativeResume", "()V", SDL_JAVA_INTERFACE(nativeResume) },
{ "nativeFocusChanged", "(Z)V", SDL_JAVA_INTERFACE(nativeFocusChanged) },
{ "nativeGetHint", "(Ljava/lang/String;)Ljava/lang/String;", SDL_JAVA_INTERFACE(nativeGetHint) },
{ "nativeSetenv", "(Ljava/lang/String;Ljava/lang/String;)V", SDL_JAVA_INTERFACE(nativeSetenv) },
{ "onNativeOrientationChanged", "(I)V", SDL_JAVA_INTERFACE(onNativeOrientationChanged) },
189
190
{ "nativeAddTouch", "(ILjava/lang/String;)V", SDL_JAVA_INTERFACE(nativeAddTouch) },
{ "nativePermissionResult", "(IZ)V", SDL_JAVA_INTERFACE(nativePermissionResult) }
191
192
};
193
194
/* Java class SDLInputConnection */
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeCommitText)(
195
JNIEnv *env, jclass cls,
196
197
jstring text, jint newCursorPosition);
198
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeGenerateScancodeForUnichar)(
199
JNIEnv *env, jclass cls,
200
201
jchar chUnicode);
202
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeSetComposingText)(
203
JNIEnv *env, jclass cls,
204
205
jstring text, jint newCursorPosition);
206
207
208
209
210
211
static JNINativeMethod SDLInputConnection_tab[] = {
{ "nativeCommitText", "(Ljava/lang/String;I)V", SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeCommitText) },
{ "nativeGenerateScancodeForUnichar", "(C)V", SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeGenerateScancodeForUnichar) },
{ "nativeSetComposingText", "(Ljava/lang/String;I)V", SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeSetComposingText) }
};
212
213
214
215
/* Java class SDLAudioManager */
JNIEXPORT void JNICALL SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI)(
JNIEnv *env, jclass jcls);
216
217
218
219
static JNINativeMethod SDLAudioManager_tab[] = {
{ "nativeSetupJNI", "()I", SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI) }
};
220
221
222
223
224
/* Java class SDLControllerManager */
JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI)(
JNIEnv *env, jclass jcls);
JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativePadDown)(
225
JNIEnv *env, jclass jcls,
226
227
228
jint device_id, jint keycode);
JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativePadUp)(
229
JNIEnv *env, jclass jcls,
230
231
232
jint device_id, jint keycode);
JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativeJoy)(
233
JNIEnv *env, jclass jcls,
234
235
236
jint device_id, jint axis, jfloat value);
JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativeHat)(
237
JNIEnv *env, jclass jcls,
238
239
240
jint device_id, jint hat_id, jint x, jint y);
JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick)(
241
JNIEnv *env, jclass jcls,
242
243
jint device_id, jstring device_name, jstring device_desc, jint vendor_id, jint product_id,
jboolean is_accelerometer, jint button_mask, jint naxes, jint nhats, jint nballs);
244
245
JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveJoystick)(
246
JNIEnv *env, jclass jcls,
247
248
249
jint device_id);
JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddHaptic)(
250
JNIEnv *env, jclass jcls,
251
252
253
jint device_id, jstring device_name);
JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveHaptic)(
254
JNIEnv *env, jclass jcls,
255
256
jint device_id);
257
258
259
260
261
262
263
264
265
266
267
static JNINativeMethod SDLControllerManager_tab[] = {
{ "nativeSetupJNI", "()I", SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI) },
{ "onNativePadDown", "(II)I", SDL_JAVA_CONTROLLER_INTERFACE(onNativePadDown) },
{ "onNativePadUp", "(II)I", SDL_JAVA_CONTROLLER_INTERFACE(onNativePadUp) },
{ "onNativeJoy", "(IIF)V", SDL_JAVA_CONTROLLER_INTERFACE(onNativeJoy) },
{ "onNativeHat", "(IIII)V", SDL_JAVA_CONTROLLER_INTERFACE(onNativeHat) },
{ "nativeAddJoystick", "(ILjava/lang/String;Ljava/lang/String;IIZIIII)I", SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick) },
{ "nativeRemoveJoystick", "(I)I", SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveJoystick) },
{ "nativeAddHaptic", "(ILjava/lang/String;)I", SDL_JAVA_CONTROLLER_INTERFACE(nativeAddHaptic) },
{ "nativeRemoveHaptic", "(I)I", SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveHaptic) }
};
268
269
270
271
272
/* Uncomment this to log messages entering and exiting methods in this file */
/* #define DEBUG_JNI */
273
static void checkJNIReady(void);
274
275
276
277
278
279
280
281
282
283
284
/*******************************************************************************
This file links the Java side of Android with libsdl
*******************************************************************************/
#include <jni.h>
/*******************************************************************************
Globals
*******************************************************************************/
static pthread_key_t mThreadKey;
285
286
static pthread_once_t key_once = PTHREAD_ONCE_INIT;
static JavaVM *mJavaVM = NULL;
287
288
289
290
291
/* Main activity */
static jclass mActivityClass;
/* method signatures */
292
293
294
295
static jmethodID midClipboardGetText;
static jmethodID midClipboardHasText;
static jmethodID midClipboardSetText;
static jmethodID midCreateCustomCursor;
296
static jmethodID midGetContext;
297
298
299
300
static jmethodID midGetDisplayDPI;
static jmethodID midGetManifestEnvironmentVariables;
static jmethodID midGetNativeSurface;
static jmethodID midInitTouch;
301
static jmethodID midIsAndroidTV;
302
static jmethodID midIsChromebook;
303
static jmethodID midIsDeXMode;
304
static jmethodID midIsScreenKeyboardShown;
305
306
307
static jmethodID midIsTablet;
static jmethodID midManualBackButton;
static jmethodID midMinimizeWindow;
308
static jmethodID midOpenAPKExpansionInputStream;
309
310
311
static jmethodID midRequestPermission;
static jmethodID midSendMessage;
static jmethodID midSetActivityTitle;
312
static jmethodID midSetCustomCursor;
313
314
315
static jmethodID midSetOrientation;
static jmethodID midSetRelativeMouseEnabled;
static jmethodID midSetSurfaceViewFormat;
316
static jmethodID midSetSystemCursor;
317
318
319
static jmethodID midSetWindowStyle;
static jmethodID midShouldMinimizeOnFocusLoss;
static jmethodID midShowTextInput;
320
static jmethodID midSupportsRelativeMouse;
321
322
323
324
325
326
327
/* audio manager */
static jclass mAudioManagerClass;
/* method signatures */
static jmethodID midAudioOpen;
static jmethodID midAudioWriteByteBuffer;
328
329
static jmethodID midAudioWriteShortBuffer;
static jmethodID midAudioWriteFloatBuffer;
330
331
332
static jmethodID midAudioClose;
static jmethodID midCaptureOpen;
static jmethodID midCaptureReadByteBuffer;
333
334
static jmethodID midCaptureReadShortBuffer;
static jmethodID midCaptureReadFloatBuffer;
335
static jmethodID midCaptureClose;
336
static jmethodID midAudioSetThreadPriority;
337
338
339
340
341
342
343
344
/* controller manager */
static jclass mControllerManagerClass;
/* method signatures */
static jmethodID midPollInputDevices;
static jmethodID midPollHapticDevices;
static jmethodID midHapticRun;
345
static jmethodID midHapticStop;
346
347
/* Accelerometer data storage */
348
static SDL_DisplayOrientation displayOrientation;
349
350
351
static float fLastAccelerometer[3];
static SDL_bool bHasNewData;
352
353
354
355
static SDL_bool bHasEnvironmentVariables;
static SDL_atomic_t bPermissionRequestPending;
static SDL_bool bPermissionRequestResult;
356
357
358
359
360
/*******************************************************************************
Functions called by JNI
*******************************************************************************/
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
/* From http://developer.android.com/guide/practices/jni.html
* All threads are Linux threads, scheduled by the kernel.
* They're usually started from managed code (using Thread.start), but they can also be created elsewhere and then
* attached to the JavaVM. For example, a thread started with pthread_create can be attached with the
* JNI AttachCurrentThread or AttachCurrentThreadAsDaemon functions. Until a thread is attached, it has no JNIEnv,
* and cannot make JNI calls.
* Attaching a natively-created thread causes a java.lang.Thread object to be constructed and added to the "main"
* ThreadGroup, making it visible to the debugger. Calling AttachCurrentThread on an already-attached thread
* is a no-op.
* Note: You can call this function any number of times for the same thread, there's no harm in it
*/
/* From http://developer.android.com/guide/practices/jni.html
* Threads attached through JNI must call DetachCurrentThread before they exit. If coding this directly is awkward,
* in Android 2.0 (Eclair) and higher you can use pthread_key_create to define a destructor function that will be
* called before the thread exits, and call DetachCurrentThread from there. (Use that key with pthread_setspecific
* to store the JNIEnv in thread-local-storage; that way it'll be passed into your destructor as the argument.)
* Note: The destructor is not called unless the stored value is != NULL
* Note: You can call this function any number of times for the same thread, there's no harm in it
* (except for some lost CPU cycles)
*/
/* Set local storage value */
static int
Android_JNI_SetEnv(JNIEnv *env) {
int status = pthread_setspecific(mThreadKey, env);
if (status < 0) {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "Failed pthread_setspecific() in Android_JNI_SetEnv() (err=%d)", status);
}
return status;
}
/* Get local storage value */
JNIEnv* Android_JNI_GetEnv(void)
{
/* Get JNIEnv from the Thread local storage */
JNIEnv *env = pthread_getspecific(mThreadKey);
if (env == NULL) {
399
/* If it fails, try to attach ! (e.g the thread isn't created with SDL_CreateThread() */
400
401
402
403
404
int status;
/* There should be a JVM */
if (mJavaVM == NULL) {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "Failed, there is no JavaVM");
405
return NULL;
406
407
408
409
410
411
412
413
414
415
416
417
418
419
}
/* Attach the current thread to the JVM and get a JNIEnv.
* It will be detached by pthread_create destructor 'Android_JNI_ThreadDestroyed' */
status = (*mJavaVM)->AttachCurrentThread(mJavaVM, &env, NULL);
if (status < 0) {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "Failed to attach current thread (err=%d)", status);
return NULL;
}
/* Save JNIEnv into the Thread local storage */
if (Android_JNI_SetEnv(env) < 0) {
return NULL;
}
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
}
return env;
}
/* Set up an external thread for using JNI with Android_JNI_GetEnv() */
int Android_JNI_SetupThread(void)
{
JNIEnv *env;
int status;
/* There should be a JVM */
if (mJavaVM == NULL) {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "Failed, there is no JavaVM");
return 0;
}
/* Attach the current thread to the JVM and get a JNIEnv.
* It will be detached by pthread_create destructor 'Android_JNI_ThreadDestroyed' */
status = (*mJavaVM)->AttachCurrentThread(mJavaVM, &env, NULL);
if (status < 0) {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "Failed to attach current thread (err=%d)", status);
return 0;
}
/* Save JNIEnv into the Thread local storage */
if (Android_JNI_SetEnv(env) < 0) {
return 0;
}
return 1;
}
/* Destructor called for each thread where mThreadKey is not NULL */
static void
Android_JNI_ThreadDestroyed(void *value)
{
/* The thread is being destroyed, detach it from the Java VM and set the mThreadKey value to NULL as required */
JNIEnv *env = (JNIEnv *) value;
if (env != NULL) {
(*mJavaVM)->DetachCurrentThread(mJavaVM);
Android_JNI_SetEnv(NULL);
}
}
/* Creation of local storage mThreadKey */
466
static void
467
Android_JNI_CreateKey(void)
468
469
470
471
472
473
474
{
int status = pthread_key_create(&mThreadKey, Android_JNI_ThreadDestroyed);
if (status < 0) {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "Error initializing mThreadKey with pthread_key_create() (err=%d)", status);
}
}
475
static void
476
Android_JNI_CreateKey_once(void)
477
478
479
480
481
482
483
{
int status = pthread_once(&key_once, Android_JNI_CreateKey);
if (status < 0) {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "Error initializing mThreadKey with pthread_once() (err=%d)", status);
}
}
484
static void
485
register_methods(JNIEnv *env, const char *classname, JNINativeMethod *methods, int nb)
486
487
488
489
490
491
492
493
{
jclass clazz = (*env)->FindClass(env, classname);
if (clazz == NULL || (*env)->RegisterNatives(env, clazz, methods, nb) < 0) {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "Failed to register methods of %s", classname);
return;
}
}
494
/* Library init */
495
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
496
497
{
mJavaVM = vm;
498
499
500
501
502
503
504
JNIEnv *env = NULL;
if ((*mJavaVM)->GetEnv(mJavaVM, (void **)&env, JNI_VERSION_1_4) != JNI_OK) {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "Failed to get JNI Env");
return JNI_VERSION_1_4;
}
505
register_methods(env, "org/libsdl/app/SDLActivity", SDLActivity_tab, SDL_arraysize(SDLActivity_tab));
506
507
508
register_methods(env, "org/libsdl/app/SDLInputConnection", SDLInputConnection_tab, SDL_arraysize(SDLInputConnection_tab));
register_methods(env, "org/libsdl/app/SDLAudioManager", SDLAudioManager_tab, SDL_arraysize(SDLAudioManager_tab));
register_methods(env, "org/libsdl/app/SDLControllerManager", SDLControllerManager_tab, SDL_arraysize(SDLControllerManager_tab));
509
510
511
512
return JNI_VERSION_1_4;
}
513
void checkJNIReady(void)
514
515
{
if (!mActivityClass || !mAudioManagerClass || !mControllerManagerClass) {
516
/* We aren't fully initialized, let's just return. */
517
518
519
return;
}
520
SDL_SetMainReady();
521
522
523
}
/* Activity initialization -- called before SDL_main() to initialize JNI bindings */
524
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cls)
525
{
526
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeSetupJNI()");
527
528
529
530
531
532
533
534
535
536
537
538
539
540
/*
* Create mThreadKey so we can keep track of the JNIEnv assigned to each thread
* Refer to http://developer.android.com/guide/practices/design/jni.html for the rationale behind this
*/
Android_JNI_CreateKey_once();
/* Save JNIEnv of SDLActivity */
Android_JNI_SetEnv(env);
if (mJavaVM == NULL) {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "failed to found a JavaVM");
}
541
/* Use a mutex to prevent concurrency issues between Java Activity and Native thread code, when using 'Android_Window'.
542
543
* (Eg. Java sending Touch events, while native code is destroying the main SDL_Window. )
*/
544
545
if (Android_ActivityMutex == NULL) {
Android_ActivityMutex = SDL_CreateMutex(); /* Could this be created twice if onCreate() is called a second time ? */
546
547
}
548
if (Android_ActivityMutex == NULL) {
549
__android_log_print(ANDROID_LOG_ERROR, "SDL", "failed to create Android_ActivityMutex mutex");
550
551
}
552
553
554
555
556
557
558
559
560
561
562
Android_PauseSem = SDL_CreateSemaphore(0);
if (Android_PauseSem == NULL) {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "failed to create Android_PauseSem semaphore");
}
Android_ResumeSem = SDL_CreateSemaphore(0);
if (Android_ResumeSem == NULL) {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "failed to create Android_ResumeSem semaphore");
}
563
mActivityClass = (jclass)((*env)->NewGlobalRef(env, cls));
564
565
566
567
midClipboardGetText = (*env)->GetStaticMethodID(env, mActivityClass, "clipboardGetText", "()Ljava/lang/String;");
midClipboardHasText = (*env)->GetStaticMethodID(env, mActivityClass, "clipboardHasText", "()Z");
midClipboardSetText = (*env)->GetStaticMethodID(env, mActivityClass, "clipboardSetText", "(Ljava/lang/String;)V");
568
midCreateCustomCursor = (*env)->GetStaticMethodID(env, mActivityClass, "createCustomCursor", "([IIIII)I");
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
midGetContext = (*env)->GetStaticMethodID(env, mActivityClass, "getContext","()Landroid/content/Context;");
midGetDisplayDPI = (*env)->GetStaticMethodID(env, mActivityClass, "getDisplayDPI", "()Landroid/util/DisplayMetrics;");
midGetManifestEnvironmentVariables = (*env)->GetStaticMethodID(env, mActivityClass, "getManifestEnvironmentVariables", "()Z");
midGetNativeSurface = (*env)->GetStaticMethodID(env, mActivityClass, "getNativeSurface","()Landroid/view/Surface;");
midInitTouch = (*env)->GetStaticMethodID(env, mActivityClass, "initTouch", "()V");
midIsAndroidTV = (*env)->GetStaticMethodID(env, mActivityClass, "isAndroidTV","()Z");
midIsChromebook = (*env)->GetStaticMethodID(env, mActivityClass, "isChromebook", "()Z");
midIsDeXMode = (*env)->GetStaticMethodID(env, mActivityClass, "isDeXMode", "()Z");
midIsScreenKeyboardShown = (*env)->GetStaticMethodID(env, mActivityClass, "isScreenKeyboardShown","()Z");
midIsTablet = (*env)->GetStaticMethodID(env, mActivityClass, "isTablet", "()Z");
midManualBackButton = (*env)->GetStaticMethodID(env, mActivityClass, "manualBackButton", "()V");
midMinimizeWindow = (*env)->GetStaticMethodID(env, mActivityClass, "minimizeWindow","()V");
midOpenAPKExpansionInputStream = (*env)->GetStaticMethodID(env, mActivityClass, "openAPKExpansionInputStream", "(Ljava/lang/String;)Ljava/io/InputStream;");
midRequestPermission = (*env)->GetStaticMethodID(env, mActivityClass, "requestPermission", "(Ljava/lang/String;I)V");
midSendMessage = (*env)->GetStaticMethodID(env, mActivityClass, "sendMessage", "(II)Z");
midSetActivityTitle = (*env)->GetStaticMethodID(env, mActivityClass, "setActivityTitle","(Ljava/lang/String;)Z");
585
midSetCustomCursor = (*env)->GetStaticMethodID(env, mActivityClass, "setCustomCursor", "(I)Z");
586
587
588
midSetOrientation = (*env)->GetStaticMethodID(env, mActivityClass, "setOrientation","(IIZLjava/lang/String;)V");
midSetRelativeMouseEnabled = (*env)->GetStaticMethodID(env, mActivityClass, "setRelativeMouseEnabled", "(Z)Z");
midSetSurfaceViewFormat = (*env)->GetStaticMethodID(env, mActivityClass, "setSurfaceViewFormat","(I)V");
589
midSetSystemCursor = (*env)->GetStaticMethodID(env, mActivityClass, "setSystemCursor", "(I)Z");
590
591
592
midSetWindowStyle = (*env)->GetStaticMethodID(env, mActivityClass, "setWindowStyle","(Z)V");
midShouldMinimizeOnFocusLoss = (*env)->GetStaticMethodID(env, mActivityClass, "shouldMinimizeOnFocusLoss","()Z");
midShowTextInput = (*env)->GetStaticMethodID(env, mActivityClass, "showTextInput", "(IIII)Z");
593
midSupportsRelativeMouse = (*env)->GetStaticMethodID(env, mActivityClass, "supportsRelativeMouse", "()Z");
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
if (!midClipboardGetText ||
!midClipboardHasText ||
!midClipboardSetText ||
!midCreateCustomCursor ||
!midGetContext ||
!midGetDisplayDPI ||
!midGetManifestEnvironmentVariables ||
!midGetNativeSurface ||
!midInitTouch ||
!midIsAndroidTV ||
!midIsChromebook ||
!midIsDeXMode ||
!midIsScreenKeyboardShown ||
!midIsTablet ||
!midManualBackButton ||
!midMinimizeWindow ||
!midOpenAPKExpansionInputStream ||
!midRequestPermission ||
!midSendMessage ||
!midSetActivityTitle ||
!midSetCustomCursor ||
!midSetOrientation ||
!midSetRelativeMouseEnabled ||
!midSetSurfaceViewFormat ||
!midSetSystemCursor ||
!midSetWindowStyle ||
!midShouldMinimizeOnFocusLoss ||
!midShowTextInput ||
!midSupportsRelativeMouse) {
624
__android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLActivity.java?");
625
}
626
627
628
629
630
checkJNIReady();
}
/* Audio initialization -- called before SDL_main() to initialize JNI bindings */
631
JNIEXPORT void JNICALL SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cls)
632
633
634
{
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "AUDIO nativeSetupJNI()");
635
mAudioManagerClass = (jclass)((*env)->NewGlobalRef(env, cls));
636
637
midAudioOpen = (*env)->GetStaticMethodID(env, mAudioManagerClass,
638
"audioOpen", "(IIII)[I");
639
midAudioWriteByteBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
640
"audioWriteByteBuffer", "([B)V");
641
midAudioWriteShortBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
642
"audioWriteShortBuffer", "([S)V");
643
midAudioWriteFloatBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
644
"audioWriteFloatBuffer", "([F)V");
645
midAudioClose = (*env)->GetStaticMethodID(env, mAudioManagerClass,
646
"audioClose", "()V");
647
midCaptureOpen = (*env)->GetStaticMethodID(env, mAudioManagerClass,
648
"captureOpen", "(IIII)[I");
649
midCaptureReadByteBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
650
"captureReadByteBuffer", "([BZ)I");
651
midCaptureReadShortBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
652
"captureReadShortBuffer", "([SZ)I");
653
midCaptureReadFloatBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
654
"captureReadFloatBuffer", "([FZ)I");
655
midCaptureClose = (*env)->GetStaticMethodID(env, mAudioManagerClass,
656
"captureClose", "()V");
657
midAudioSetThreadPriority = (*env)->GetStaticMethodID(env, mAudioManagerClass,
658
"audioSetThreadPriority", "(ZI)V");
659
660
if (!midAudioOpen || !midAudioWriteByteBuffer || !midAudioWriteShortBuffer || !midAudioWriteFloatBuffer || !midAudioClose ||
661
!midCaptureOpen || !midCaptureReadByteBuffer || !midCaptureReadShortBuffer || !midCaptureReadFloatBuffer || !midCaptureClose || !midAudioSetThreadPriority) {
662
663
664
665
666
667
668
__android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLAudioManager.java?");
}
checkJNIReady();
}
/* Controller initialization -- called before SDL_main() to initialize JNI bindings */
669
JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cls)
670
671
672
{
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "CONTROLLER nativeSetupJNI()");
673
mControllerManagerClass = (jclass)((*env)->NewGlobalRef(env, cls));
674
675
midPollInputDevices = (*env)->GetStaticMethodID(env, mControllerManagerClass,
676
"pollInputDevices", "()V");
677
midPollHapticDevices = (*env)->GetStaticMethodID(env, mControllerManagerClass,
678
"pollHapticDevices", "()V");
679
midHapticRun = (*env)->GetStaticMethodID(env, mControllerManagerClass,
680
"hapticRun", "(IFI)V");
681
midHapticStop = (*env)->GetStaticMethodID(env, mControllerManagerClass,
682
"hapticStop", "(I)V");
683
684
if (!midPollInputDevices || !midPollHapticDevices || !midHapticRun || !midHapticStop) {
685
686
687
688
__android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLControllerManager.java?");
}
checkJNIReady();
689
690
691
692
693
694
}
/* SDL main function prototype */
typedef int (*SDL_main_func)(int argc, char *argv[]);
/* Start up the SDL app */
695
JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeRunMain)(JNIEnv *env, jclass cls, jstring library, jstring function, jobject array)
696
697
698
699
700
{
int status = -1;
const char *library_file;
void *library_handle;
701
702
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeRunMain()");
703
704
705
/* Save JNIEnv of SDLThread */
Android_JNI_SetEnv(env);
706
707
library_file = (*env)->GetStringUTFChars(env, library, NULL);
library_handle = dlopen(library_file, RTLD_GLOBAL);
708
709
710
711
712
713
714
715
716
717
718
if (!library_handle) {
/* When deploying android app bundle format uncompressed native libs may not extract from apk to filesystem.
In this case we should use lib name without path. https://bugzilla.libsdl.org/show_bug.cgi?id=4739 */
const char *library_name = SDL_strrchr(library_file, '/');
if (library_name && *library_name) {
library_name += 1;
library_handle = dlopen(library_name, RTLD_GLOBAL);
}
}
719
720
721
722
723
724
725
726
727
728
729
if (library_handle) {
const char *function_name;
SDL_main_func SDL_main;
function_name = (*env)->GetStringUTFChars(env, function, NULL);
SDL_main = (SDL_main_func)dlsym(library_handle, function_name);
if (SDL_main) {
int i;
int argc;
int len;
char **argv;
730
SDL_bool isstack;
731
732
733
/* Prepare the arguments. */
len = (*env)->GetArrayLength(env, array);
734
argv = SDL_small_alloc(char *, 1 + len + 1, &isstack); /* !!! FIXME: check for NULL */
735
736
737
738
739
740
argc = 0;
/* Use the name "app_process" so PHYSFS_platformCalcBaseDir() works.
https://bitbucket.org/MartinFelis/love-android-sdl2/issue/23/release-build-crash-on-start
*/
argv[argc++] = SDL_strdup("app_process");
for (i = 0; i < len; ++i) {
741
742
const char *utf;
char *arg = NULL;
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
jstring string = (*env)->GetObjectArrayElement(env, array, i);
if (string) {
utf = (*env)->GetStringUTFChars(env, string, 0);
if (utf) {
arg = SDL_strdup(utf);
(*env)->ReleaseStringUTFChars(env, string, utf);
}
(*env)->DeleteLocalRef(env, string);
}
if (!arg) {
arg = SDL_strdup("");
}
argv[argc++] = arg;
}
argv[argc] = NULL;
/* Run the application. */
status = SDL_main(argc, argv);
/* Release the arguments. */
for (i = 0; i < argc; ++i) {
SDL_free(argv[i]);
}
767
SDL_small_free(argv, isstack);
768
769
770
771
772
773
774
775
776
777
} else {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "nativeRunMain(): Couldn't find function %s in library %s", function_name, library_file);
}
(*env)->ReleaseStringUTFChars(env, function, function_name);
dlclose(library_handle);
} else {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "nativeRunMain(): Couldn't load library %s", library_file);
778
}
779
780
(*env)->ReleaseStringUTFChars(env, library, library_file);
781
/* This is a Java thread, it doesn't need to be Detached from the JVM.
782
783
784
* Set to mThreadKey value to NULL not to call pthread_create destructor 'Android_JNI_ThreadDestroyed' */
Android_JNI_SetEnv(NULL);
785
786
/* Do not issue an exit or the whole application will terminate instead of just the SDL thread */
/* exit(status); */
787
788
return status;
789
790
791
}
/* Drop file */
792
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeDropFile)(
793
JNIEnv *env, jclass jcls,
794
795
796
jstring filename)
{
const char *path = (*env)->GetStringUTFChars(env, filename, NULL);
797
SDL_SendDropFile(NULL, path);
798
(*env)->ReleaseStringUTFChars(env, filename, path);
799
SDL_SendDropComplete(NULL);
800
801
}
802
803
804
805
806
807
808
809
810
/* Lock / Unlock Mutex */
void Android_ActivityMutex_Lock() {
SDL_LockMutex(Android_ActivityMutex);
}
void Android_ActivityMutex_Unlock() {
SDL_UnlockMutex(Android_ActivityMutex);
}
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
/* Lock the Mutex when the Activity is in its 'Running' state */
void Android_ActivityMutex_Lock_Running() {
int pauseSignaled = 0;
int resumeSignaled = 0;
retry:
SDL_LockMutex(Android_ActivityMutex);
pauseSignaled = SDL_SemValue(Android_PauseSem);
resumeSignaled = SDL_SemValue(Android_ResumeSem);
if (pauseSignaled > resumeSignaled) {
SDL_UnlockMutex(Android_ActivityMutex);
SDL_Delay(50);
goto retry;
}
}
830
831
/* Set screen resolution */
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetScreenResolution)(
832
JNIEnv *env, jclass jcls,
833
jint surfaceWidth, jint surfaceHeight,
834
jint deviceWidth, jint deviceHeight, jint format, jfloat rate)
835
{
836
SDL_LockMutex(Android_ActivityMutex);
837
838
839
840
841
842
843
844
845
846
847
848
849
850
Android_SetScreenResolution(surfaceWidth, surfaceHeight, deviceWidth, deviceHeight, format, rate);
SDL_UnlockMutex(Android_ActivityMutex);
}
/* Resize */
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeResize)(
JNIEnv *env, jclass jcls)
{
SDL_LockMutex(Android_ActivityMutex);
if (Android_Window)
{
851
Android_SendResize(Android_Window);
852
}
853
854
SDL_UnlockMutex(Android_ActivityMutex);
855
856
}
857
858
859
860
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeOrientationChanged)(
JNIEnv *env, jclass jcls,
jint orientation)
{
861
862
SDL_LockMutex(Android_ActivityMutex);
863
displayOrientation = (SDL_DisplayOrientation)orientation;
864
865
866
867
868
869
if (Android_Window)
{
SDL_VideoDisplay *display = SDL_GetDisplay(0);
SDL_SendDisplayEvent(display, SDL_DISPLAYEVENT_ORIENTATION, orientation);
}
870
871
SDL_UnlockMutex(Android_ActivityMutex);
872
873
}
874
875
876
877
878
879
880
881
882
883
884
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeAddTouch)(
JNIEnv* env, jclass cls,
jint touchId, jstring name)
{
const char *utfname = (*env)->GetStringUTFChars(env, name, NULL);
SDL_AddTouch((SDL_TouchID) touchId, SDL_TOUCH_DEVICE_DIRECT, utfname);
(*env)->ReleaseStringUTFChars(env, name, utfname);
}
885
886
887
888
889
890
891
892
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativePermissionResult)(
JNIEnv* env, jclass cls,
jint requestCode, jboolean result)
{
bPermissionRequestResult = result;
SDL_AtomicSet(&bPermissionRequestPending, SDL_FALSE);
}
893
/* Paddown */
894
JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativePadDown)(
895
JNIEnv *env, jclass jcls,
896
897
898
899
900
901
jint device_id, jint keycode)
{
return Android_OnPadDown(device_id, keycode);
}
/* Padup */
902
JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativePadUp)(
903
JNIEnv *env, jclass jcls,
904
jint device_id, jint keycode)
905
906
907
908
909
{
return Android_OnPadUp(device_id, keycode);
}
/* Joy */
910
JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativeJoy)(
911
JNIEnv *env, jclass jcls,
912
913
914
915
916
917
jint device_id, jint axis, jfloat value)
{
Android_OnJoy(device_id, axis, value);
}
/* POV Hat */
918
JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativeHat)(
919
JNIEnv *env, jclass jcls,
920
921
922
923
924
925
jint device_id, jint hat_id, jint x, jint y)
{
Android_OnHat(device_id, hat_id, x, y);
}
926
JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick)(
927
JNIEnv *env, jclass jcls,
928
929
930
jint device_id, jstring device_name, jstring device_desc,
jint vendor_id, jint product_id, jboolean is_accelerometer,
jint button_mask, jint naxes, jint nhats, jint nballs)
931
932
933
{
int retval;
const char *name = (*env)->GetStringUTFChars(env, device_name, NULL);
934
const char *desc = (*env)->GetStringUTFChars(env, device_desc, NULL);
935
936
retval = Android_AddJoystick(device_id, name, desc, vendor_id, product_id, is_accelerometer ? SDL_TRUE : SDL_FALSE, button_mask, naxes, nhats, nballs);
937
938
(*env)->ReleaseStringUTFChars(env, device_name, name);
939
(*env)->ReleaseStringUTFChars(env, device_desc, desc);
940
941
942
943
return retval;
}
944
JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveJoystick)(
945
JNIEnv *env, jclass jcls,
946
jint device_id)
947
948
949
950
{
return Android_RemoveJoystick(device_id);
}
951
JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddHaptic)(
952
JNIEnv *env, jclass jcls, jint device_id, jstring device_name)
953
954
955
956
957
958
959
960
961
962
963
{
int retval;
const char *name = (*env)->GetStringUTFChars(env, device_name, NULL);
retval = Android_AddHaptic(device_id, name);
(*env)->ReleaseStringUTFChars(env, device_name, name);
return retval;
}
964
JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveHaptic)(
965
JNIEnv *env, jclass jcls, jint device_id)
966
967
968
969
{
return Android_RemoveHaptic(device_id);
}
970
971
972
973
974
/* Called from surfaceCreated() */
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceCreated)(JNIEnv *env, jclass jcls)
{
SDL_LockMutex(Android_ActivityMutex);
975
if (Android_Window)
976
977
978
979
980
981
982
983
984
985
986
{
SDL_WindowData *data = (SDL_WindowData *) Android_Window->driverdata;
data->native_window = Android_JNI_GetNativeWindow();
if (data->native_window == NULL) {
SDL_SetError("Could not fetch native window from UI thread");
}
}
SDL_UnlockMutex(Android_ActivityMutex);
}
987
988
/* Called from surfaceChanged() */
989
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceChanged)(JNIEnv *env, jclass jcls)
990
{
991
SDL_LockMutex(Android_ActivityMutex);
992
993
if (Android_Window)
994
995
996
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
SDL_WindowData *data = (SDL_WindowData *) Android_Window->driverdata;
997
998
999
1000
/* If the surface has been previously destroyed by onNativeSurfaceDestroyed, recreate it here */
if (data->egl_surface == EGL_NO_SURFACE) {
data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->native_window);