28 /**
29 SDL Activity
30 */
36 // Handle the state of the native layer
39 }
46 /** If shared libraries (e.g. SDL or the native application) could not be loaded. */
49 // If we want to separate mouse and touch events.
50 // This is only toggled in native code when a hint is set!
53 // Main components
62 // This is what SDL runs in. It invokes SDL_main(), eventually
65 /**
66 * This method returns the name of the shared object with the application entry point
67 * It can be overridden by derived classes.
68 */
70 String library;
76 }
78 }
80 /**
81 * This method returns the name of the application entry point
82 * It can be overridden by derived classes.
83 */
86 }
88 /**
89 * This method is called by SDL before loading the native shared libraries.
90 * It can be overridden to provide names of shared libraries to be loaded.
91 * The default implementation returns the defaults. It never returns null.
92 * An array returned by a new implementation must at least contain "SDL2".
93 * Also keep in mind that the order the libraries are loaded may matter.
94 * @return names of shared libraries to be loaded (e.g. "SDL2", "main").
95 */
99 // "SDL2_image",
100 // "SDL2_mixer",
101 // "SDL2_net",
102 // "SDL2_ttf",
103 "main"
104 };
105 }
107 // Load the .so
111 }
112 }
114 /**
115 * This method is called by SDL before starting the native application thread.
116 * It can be overridden to provide the arguments after the application name.
117 * The default implementation returns an empty array. It never returns null.
118 * @return arguments for the native application.
119 */
122 }
125 // The static nature of the singleton and Android quirkyness force us to initialize everything here
126 // Otherwise, when exiting the app and returning to it, these variables *keep* their pre exit values
140 }
142 // Setup
143 @Override
150 // Load shared libraries
162 }
165 {
167 dlgAlert.setMessage("An error occurred while trying to start the application. Please try again and/or reinstall."
174 @Override
176 // if this button is clicked, close current activity
178 }
179 });
184 }
186 // Set up JNI
189 // Initialize state
192 // So we can call stuff from static callbacks
199 /* Before API 11, no clipboard notification (eg no SDL_CLIPBOARDUPDATE) */
201 }
203 // Set up the surface
211 // Get filename from "Open with" of another application
218 }
219 }
222 }
224 // Events
225 @Override
234 }
237 }
239 @Override
250 }
253 }
256 @Override
263 }
270 }
273 }
275 @Override
282 }
285 }
287 @Override
293 // Reset everything in case the user re opens the app
296 }
301 // Send a quit message to the application
305 // Now wait for the SDL thread to quit
311 }
314 //Log.v(TAG, "Finished waiting for SDL thread");
315 }
319 // Reset everything in case the user re opens the app
321 }
323 @Override
328 }
331 // Ignore certain special keys so they're handled by Android
337 ) {
339 }
341 }
343 /* Transition to next state */
347 // Already in same state, discard.
349 }
351 // Try a transition to init state
356 }
358 // Try a transition to paused state
364 }
366 // Try a transition to resumed state
370 // This is the entry point to the C app.
371 // Start up the C app thread and enable sensor input for the first time
372 // FIXME: Why aren't we enabling sensor input at start?
378 // Set up a listener thread to catch when the native thread ends
380 @Override
385 // Ignore any exception
387 // Native thread has finished
390 }
391 }
392 }
396 }
401 }
402 }
403 }
405 /* The native thread has finished */
409 }
412 // Messages from the SDLMain thread
420 /**
421 * This method is called by SDL if SDL did not handle a message itself.
422 * This happens if a received message contains an unsupported command.
423 * Method can be overwritten to handle Messages in a different class.
424 * @param command the command of the message.
425 * @param param the parameter of the message. May be null.
426 * @return if the message was handled in overridden method.
427 */
430 }
432 /**
433 * A Handler class for Messages from native SDL applications.
434 * It uses current Activities as target (e.g. for the title).
435 * static to prevent implicit references to enclosing object.
436 */
438 @Override
444 }
451 }
455 // Note: On some devices setting view to GONE creates a flicker in landscape.
456 // Setting the View's sizes to 0 is similar to GONE but without the flicker.
457 // The sizes will be set to useful values when the keyboard is shown again.
460 InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
466 }
469 {
477 }
478 }
479 }
481 }
483 if ((context instanceof SDLActivity) && !((SDLActivity) context).onUnhandledMessage(msg.arg1, msg.obj)) {
485 }
486 }
487 }
488 }
490 // Handler for the messages
493 // Send a message from the SDLMain thread
499 }
501 // C functions we call
523 /**
524 * This method is called by SDL using JNI.
525 */
527 // Called from SDLMain() thread and can't directly affect the view
529 }
531 /**
532 * This method is called by SDL using JNI.
533 * This is a static method for JNI convenience, it calls a non-static method
534 * so that is can be overridden
535 */
537 {
540 }
541 }
543 /**
544 * This can be overridden
545 */
547 {
563 }
564 }
566 /* no valid hint */
569 /* no fixed orientation */
575 }
576 }
577 }
579 Log.v("SDL", "setOrientation() orientation=" + orientation + " width=" + w +" height="+ h +" resizable=" + resizable + " hint=" + hint);
582 }
583 }
586 /**
587 * This method is called by SDL using JNI.
588 */
590 {
593 }
597 }
599 InputMethodManager imm = (InputMethodManager) SDL.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
602 }
604 /**
605 * This method is called by SDL using JNI.
606 */
610 }
612 }
614 /**
615 * This method is called by SDL using JNI.
616 */
619 }
622 /*
623 * This is used to regulate the pan&scan method to have some offset from
624 * the bottom edge of the input region and the top edge of an input
625 * method (soft keyboard)
626 */
636 }
638 @Override
650 }
655 InputMethodManager imm = (InputMethodManager) SDL.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
659 }
660 }
662 /**
663 * This method is called by SDL using JNI.
664 */
666 // Transfer the task to the main thread as a Runnable
668 }
672 // Key pressed with Ctrl should be sent as SDL_KEYDOWN/SDL_KEYUP and not SDL_TEXTINPUT
676 }
677 }
680 }
682 /**
683 * This method is called by SDL using JNI.
684 */
688 }
690 }
692 // Input
694 /**
695 * This method is called by SDL using JNI.
696 * @return an array which may be empty but is never null.
697 */
706 }
707 }
709 }
711 // APK expansion files support
713 /** com.android.vending.expansion.zipfile.ZipResourceFile object or null. */
716 /** com.android.vending.expansion.zipfile.ZipResourceFile's getInputStream() or null. */
719 /**
720 * This method is called by SDL using JNI.
721 * @return an InputStream on success or null if no expansion file was used.
722 * @throws IOException on errors. Message is set for the SDL error message.
723 */
725 // Get a ZipResourceFile representing a merger of both the main and patch files
730 }
734 }
736 Integer mainVersion;
737 Integer patchVersion;
744 }
747 // To avoid direct dependency on Google APK expansion library that is
748 // not a part of Android SDK we access it using reflection
760 }
761 }
763 // Get an input stream for a known file inside the expansion file ZIPs
764 InputStream fileStream;
768 // calling "getInputStream" failed
771 }
774 // calling "getInputStream" was successful but null was returned
776 }
779 }
781 // Messagebox
783 /** Result of current messagebox. Also used for blocking the calling thread. */
786 /** Id of current dialog. */
789 /**
790 * This method is called by SDL using JNI.
791 * Shows the messagebox from UI thread and block calling thread.
792 * buttonFlags, buttonIds and buttonTexts must have same length.
793 * @param buttonFlags array containing flags for every button.
794 * @param buttonIds array containing id for every button.
795 * @param buttonTexts array containing text for every button.
796 * @param colors null for default or array of length 5 containing colors.
797 * @return button id or -1.
798 */
810 // sanity checks
814 }
816 // collect arguments for Dialog
827 // trigger Dialog creation on UI thread
830 @Override
833 }
834 });
836 // block the calling thread
844 }
845 }
847 // return selected value
850 }
858 }
859 }
861 @Override
864 // TODO set values from "flags" to messagebox dialog
866 // get colors
887 }
889 // create dialog with title and a listener to wake up calling thread
895 @Override
899 }
900 }
901 });
903 // create text
910 }
912 // create buttons
927 @Override
931 }
932 });
934 // see SDL_messagebox.h
937 }
940 }
941 }
945 }
947 // TODO set color for border of messagebox button
948 }
952 // setting the color this way removes the style
955 // setting the color this way keeps the style (gradient, padding, etc.)
957 }
958 }
960 // TODO set color for selected messagebox button
961 }
963 }
965 // create content
973 }
975 // add content to dialog and return
979 @Override
985 }
987 }
989 }
990 });
993 }
995 /**
996 * This method is called by SDL using JNI.
997 */
1000 }
1002 /**
1003 * This method is called by SDL using JNI.
1004 */
1007 }
1009 /**
1010 * This method is called by SDL using JNI.
1011 */
1014 }
1016 }
1018 /**
1019 Simple runnable to start the SDL application
1020 */
1022 @Override
1024 // Runs SDL_main()
1033 }
1034 }
1037 /**
1038 SDLSurface. This is what we draw on, so we need to know when it's created
1039 in order to do anything useful.
1041 Because of this, that's where we set up the SDL thread
1042 */
1046 // Sensors
1050 // Keep track of the surface size to normalize touch events
1053 // Startup
1064 mDisplay = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
1069 }
1071 // Some arbitrary defaults to avoid a potential division by zero
1074 }
1078 }
1087 }
1091 }
1093 // Called when we have a valid drawing surface
1094 @Override
1098 }
1100 // Called when we lose the surface
1101 @Override
1105 // Transition to pause, if needed
1111 }
1113 // Called when the surface is resized
1114 @Override
1156 // Not sure this is right, maybe SDL_PIXELFORMAT_RGB24 instead?
1162 }
1174 {
1175 // Accept any
1176 }
1177 else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT)
1178 {
1181 }
1182 } else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE || requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
1185 }
1186 }
1188 // Special Patch for Square Resolution: Black Berry Passport
1196 }
1197 }
1203 }
1205 /* Surface is ready */
1208 /* If the surface has been previously destroyed by onNativeSurfaceDestroyed, recreate it here */
1212 }
1214 // Key events
1215 @Override
1217 // Dispatch the different events depending on where they come from
1218 // Some SOURCE_JOYSTICK, SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD
1219 // So, we try to process them as JOYSTICK/DPAD/GAMEPAD events first, if that fails we try them as KEYBOARD
1220 //
1221 // Furthermore, it's possible a game controller has SOURCE_KEYBOARD and
1222 // SOURCE_JOYSTICK, while its key events arrive from the keyboard source
1223 // So, retrieve the device itself and check all of its sources
1225 // Note that we process events with specific key codes here
1229 }
1233 }
1234 }
1235 }
1239 //Log.v("SDL", "key down: " + keyCode);
1242 }
1244 //Log.v("SDL", "key up: " + keyCode);
1247 }
1248 }
1251 // on some devices key events are sent for mouse BUTTON_BACK/FORWARD presses
1252 // they are ignored here because sending them as mouse input to SDL is messy
1257 // mark the event as handled or it will be handled by system
1258 // handling KEYCODE_BACK by system will call onBackPressed()
1260 }
1261 }
1262 }
1265 }
1267 // Touch events
1268 @Override
1270 /* Ref: http://developer.android.com/training/gestures/multi.html */
1279 // !!! FIXME: dump this SDK check after 2.0.4 ships and require API14.
1288 }
1289 }
1300 // may be larger than 1.0f on some devices
1301 // see the documentation of getPressure(i)
1303 }
1305 }
1310 // Primary pointer up/down, the index is always zero
1314 // Non primary pointer up/down
1317 }
1324 // may be larger than 1.0f on some devices
1325 // see the documentation of getPressure(i)
1327 }
1338 // may be larger than 1.0f on some devices
1339 // see the documentation of getPressure(i)
1341 }
1343 }
1348 }
1349 }
1352 }
1354 // Sensor events
1356 // TODO: This uses getDefaultSensor - what if we have >1 accels?
1364 }
1365 }
1367 @Override
1369 // TODO
1370 }
1372 @Override
1393 }
1397 }
1398 }
1399 }
1401 /* This is a fake invisible editor view that receives the input and defines the
1402 * pan&scan region
1403 */
1405 InputConnection ic;
1412 }
1414 @Override
1417 }
1419 @Override
1421 /*
1422 * This handles the hardware keyboard input
1423 */
1427 }
1433 }
1435 }
1437 //
1438 @Override
1440 // As seen on StackOverflow: http://stackoverflow.com/questions/7634346/keyboard-hide-event
1441 // FIXME: Discussion at http://bugzilla.libsdl.org/show_bug.cgi?id=1639
1442 // FIXME: This is not a 100% effective solution to the problem of detecting if the keyboard is showing or not
1443 // FIXME: A more effective solution would be to assume our Layout to be RelativeLayout or LinearLayout
1444 // FIXME: And determine the keyboard presence doing this: http://stackoverflow.com/questions/2150078/how-to-check-visibility-of-software-keyboard-in-android
1445 // FIXME: An even more effective way would be if Android provided this out of the box, but where would the fun be in that :)
1449 }
1450 }
1452 }
1454 @Override
1458 outAttrs.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
1463 }
1464 }
1471 }
1473 @Override
1475 /*
1476 * This handles the keycodes from soft keyboard (and IME-translated input from hardkeyboard)
1477 */
1482 }
1488 }
1490 }
1492 @Override
1498 }
1500 @Override
1506 }
1512 @Override
1514 // Workaround to capture backspace key. Ref: http://stackoverflow.com/questions/14560344/android-backspace-in-webview-baseinputconnection
1515 // and https://bugzilla.libsdl.org/show_bug.cgi?id=2265
1518 // backspace(s)
1523 }
1525 }
1528 }
1529 }
1537 }
1541 SDLClipboardHandler,
1547 mClipMgr = (android.content.ClipboardManager) SDL.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
1549 }
1551 @Override
1554 }
1556 @Override
1558 CharSequence text;
1562 }
1564 }
1566 @Override
1571 }
1573 @Override
1576 }
1578 }
1581 SDLClipboardHandler {
1586 mClipMgrOld = (android.text.ClipboardManager) SDL.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
1587 }
1589 @Override
1592 }
1594 @Override
1596 CharSequence text;
1600 }
1602 }
1604 @Override
1607 }
1608 }