29 /**
30 SDL Activity
31 */
37 // Handle the state of the native layer
40 }
47 /** If shared libraries (e.g. SDL or the native application) could not be loaded. */
50 // If we want to separate mouse and touch events.
51 // This is only toggled in native code when a hint is set!
54 // Main components
63 // This is what SDL runs in. It invokes SDL_main(), eventually
66 /**
67 * This method returns the name of the shared object with the application entry point
68 * It can be overridden by derived classes.
69 */
71 String library;
77 }
79 }
81 /**
82 * This method returns the name of the application entry point
83 * It can be overridden by derived classes.
84 */
87 }
89 /**
90 * This method is called by SDL before loading the native shared libraries.
91 * It can be overridden to provide names of shared libraries to be loaded.
92 * The default implementation returns the defaults. It never returns null.
93 * An array returned by a new implementation must at least contain "SDL2".
94 * Also keep in mind that the order the libraries are loaded may matter.
95 * @return names of shared libraries to be loaded (e.g. "SDL2", "main").
96 */
100 // "SDL2_image",
101 // "SDL2_mixer",
102 // "SDL2_net",
103 // "SDL2_ttf",
104 "main"
105 };
106 }
108 // Load the .so
112 }
113 }
115 /**
116 * This method is called by SDL before starting the native application thread.
117 * It can be overridden to provide the arguments after the application name.
118 * The default implementation returns an empty array. It never returns null.
119 * @return arguments for the native application.
120 */
123 }
126 // The static nature of the singleton and Android quirkyness force us to initialize everything here
127 // Otherwise, when exiting the app and returning to it, these variables *keep* their pre exit values
141 }
143 // Setup
144 @Override
151 // Load shared libraries
163 }
166 {
168 dlgAlert.setMessage("An error occurred while trying to start the application. Please try again and/or reinstall."
175 @Override
177 // if this button is clicked, close current activity
179 }
180 });
185 }
187 // Set up JNI
190 // Initialize state
193 // So we can call stuff from static callbacks
200 /* Before API 11, no clipboard notification (eg no SDL_CLIPBOARDUPDATE) */
202 }
204 // Set up the surface
212 // Get filename from "Open with" of another application
219 }
220 }
221 }
223 // Events
224 @Override
233 }
236 }
238 @Override
247 }
250 }
253 @Override
260 }
267 }
270 }
272 @Override
279 }
282 }
284 @Override
290 // Reset everything in case the user re opens the app
293 }
298 // Send a quit message to the application
302 // Now wait for the SDL thread to quit
308 }
311 //Log.v(TAG, "Finished waiting for SDL thread");
312 }
316 // Reset everything in case the user re opens the app
318 }
320 @Override
325 }
328 // Ignore certain special keys so they're handled by Android
334 ) {
336 }
338 }
340 /* Transition to next state */
344 // Already in same state, discard.
346 }
348 // Try a transition to init state
353 }
355 // Try a transition to paused state
361 }
363 // Try a transition to resumed state
367 // This is the entry point to the C app.
368 // Start up the C app thread and enable sensor input for the first time
369 // FIXME: Why aren't we enabling sensor input at start?
375 // Set up a listener thread to catch when the native thread ends
377 @Override
382 // Ignore any exception
384 // Native thread has finished
387 }
388 }
389 }
393 }
398 }
399 }
400 }
402 /* The native thread has finished */
406 }
409 // Messages from the SDLMain thread
417 /**
418 * This method is called by SDL if SDL did not handle a message itself.
419 * This happens if a received message contains an unsupported command.
420 * Method can be overwritten to handle Messages in a different class.
421 * @param command the command of the message.
422 * @param param the parameter of the message. May be null.
423 * @return if the message was handled in overridden method.
424 */
427 }
429 /**
430 * A Handler class for Messages from native SDL applications.
431 * It uses current Activities as target (e.g. for the title).
432 * static to prevent implicit references to enclosing object.
433 */
435 @Override
441 }
448 }
452 // Note: On some devices setting view to GONE creates a flicker in landscape.
453 // Setting the View's sizes to 0 is similar to GONE but without the flicker.
454 // The sizes will be set to useful values when the keyboard is shown again.
457 InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
461 }
464 {
472 }
473 }
474 }
476 }
478 if ((context instanceof SDLActivity) && !((SDLActivity) context).onUnhandledMessage(msg.arg1, msg.obj)) {
480 }
481 }
482 }
483 }
485 // Handler for the messages
488 // Send a message from the SDLMain thread
494 }
496 // C functions we call
518 /**
519 * This method is called by SDL using JNI.
520 */
522 // Called from SDLMain() thread and can't directly affect the view
524 }
526 /**
527 * This method is called by SDL using JNI.
528 * This is a static method for JNI convenience, it calls a non-static method
529 * so that is can be overridden
530 */
532 {
535 }
536 }
538 /**
539 * This can be overridden
540 */
542 {
558 }
559 }
561 /* no valid hint */
564 /* no fixed orientation */
570 }
571 }
572 }
574 Log.v("SDL", "setOrientation() orientation=" + orientation + " width=" + w +" height="+ h +" resizable=" + resizable + " hint=" + hint);
577 }
578 }
581 /**
582 * This method is called by SDL using JNI.
583 */
585 {
588 }
592 }
594 InputMethodManager imm = (InputMethodManager) SDL.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
597 }
599 /**
600 * This method is called by SDL using JNI.
601 */
605 }
607 }
609 /**
610 * This method is called by SDL using JNI.
611 */
614 }
617 /*
618 * This is used to regulate the pan&scan method to have some offset from
619 * the bottom edge of the input region and the top edge of an input
620 * method (soft keyboard)
621 */
631 }
633 @Override
645 }
650 InputMethodManager imm = (InputMethodManager) SDL.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
654 }
655 }
657 /**
658 * This method is called by SDL using JNI.
659 */
661 // Transfer the task to the main thread as a Runnable
663 }
667 // Key pressed with Ctrl should be sent as SDL_KEYDOWN/SDL_KEYUP and not SDL_TEXTINPUT
671 }
672 }
675 }
677 /**
678 * This method is called by SDL using JNI.
679 */
683 }
685 }
687 // Input
689 /**
690 * This method is called by SDL using JNI.
691 * @return an array which may be empty but is never null.
692 */
701 }
702 }
704 }
706 // APK expansion files support
708 /** com.android.vending.expansion.zipfile.ZipResourceFile object or null. */
711 /** com.android.vending.expansion.zipfile.ZipResourceFile's getInputStream() or null. */
714 /**
715 * This method is called by SDL using JNI.
716 * @return an InputStream on success or null if no expansion file was used.
717 * @throws IOException on errors. Message is set for the SDL error message.
718 */
720 // Get a ZipResourceFile representing a merger of both the main and patch files
725 }
729 }
731 Integer mainVersion;
732 Integer patchVersion;
739 }
742 // To avoid direct dependency on Google APK expansion library that is
743 // not a part of Android SDK we access it using reflection
755 }
756 }
758 // Get an input stream for a known file inside the expansion file ZIPs
759 InputStream fileStream;
763 // calling "getInputStream" failed
766 }
769 // calling "getInputStream" was successful but null was returned
771 }
774 }
776 // Messagebox
778 /** Result of current messagebox. Also used for blocking the calling thread. */
781 /** Id of current dialog. */
784 /**
785 * This method is called by SDL using JNI.
786 * Shows the messagebox from UI thread and block calling thread.
787 * buttonFlags, buttonIds and buttonTexts must have same length.
788 * @param buttonFlags array containing flags for every button.
789 * @param buttonIds array containing id for every button.
790 * @param buttonTexts array containing text for every button.
791 * @param colors null for default or array of length 5 containing colors.
792 * @return button id or -1.
793 */
805 // sanity checks
809 }
811 // collect arguments for Dialog
822 // trigger Dialog creation on UI thread
825 @Override
828 }
829 });
831 // block the calling thread
839 }
840 }
842 // return selected value
845 }
847 @Override
850 // TODO set values from "flags" to messagebox dialog
852 // get colors
873 }
875 // create dialog with title and a listener to wake up calling thread
881 @Override
885 }
886 }
887 });
889 // create text
896 }
898 // create buttons
913 @Override
917 }
918 });
920 // see SDL_messagebox.h
923 }
926 }
927 }
931 }
933 // TODO set color for border of messagebox button
934 }
938 // setting the color this way removes the style
941 // setting the color this way keeps the style (gradient, padding, etc.)
943 }
944 }
946 // TODO set color for selected messagebox button
947 }
949 }
951 // create content
959 }
961 // add content to dialog and return
965 @Override
971 }
973 }
975 }
976 });
979 }
981 /**
982 * This method is called by SDL using JNI.
983 */
986 }
988 /**
989 * This method is called by SDL using JNI.
990 */
993 }
995 /**
996 * This method is called by SDL using JNI.
997 */
1000 }
1002 }
1004 /**
1005 Simple runnable to start the SDL application
1006 */
1008 @Override
1010 // Runs SDL_main()
1019 }
1020 }
1023 /**
1024 SDLSurface. This is what we draw on, so we need to know when it's created
1025 in order to do anything useful.
1027 Because of this, that's where we set up the SDL thread
1028 */
1032 // Sensors
1036 // Keep track of the surface size to normalize touch events
1039 // Startup
1050 mDisplay = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
1055 }
1057 // Some arbitrary defaults to avoid a potential division by zero
1060 }
1064 }
1073 }
1077 }
1079 // Called when we have a valid drawing surface
1080 @Override
1084 }
1086 // Called when we lose the surface
1087 @Override
1091 // Transition to pause, if needed
1097 }
1099 // Called when the surface is resized
1100 @Override
1142 // Not sure this is right, maybe SDL_PIXELFORMAT_RGB24 instead?
1148 }
1160 {
1161 // Accept any
1162 }
1163 else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT)
1164 {
1167 }
1168 } else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE || requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
1171 }
1172 }
1174 // Special Patch for Square Resolution: Black Berry Passport
1182 }
1183 }
1189 }
1191 /* Surface is ready */
1194 /* If the surface has been previously destroyed by onNativeSurfaceDestroyed, recreate it here */
1198 }
1200 // Key events
1201 @Override
1203 // Dispatch the different events depending on where they come from
1204 // Some SOURCE_JOYSTICK, SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD
1205 // So, we try to process them as JOYSTICK/DPAD/GAMEPAD events first, if that fails we try them as KEYBOARD
1206 //
1207 // Furthermore, it's possible a game controller has SOURCE_KEYBOARD and
1208 // SOURCE_JOYSTICK, while its key events arrive from the keyboard source
1209 // So, retrieve the device itself and check all of its sources
1211 // Note that we process events with specific key codes here
1215 }
1219 }
1220 }
1221 }
1225 //Log.v("SDL", "key down: " + keyCode);
1228 }
1230 //Log.v("SDL", "key up: " + keyCode);
1233 }
1234 }
1237 // on some devices key events are sent for mouse BUTTON_BACK/FORWARD presses
1238 // they are ignored here because sending them as mouse input to SDL is messy
1243 // mark the event as handled or it will be handled by system
1244 // handling KEYCODE_BACK by system will call onBackPressed()
1246 }
1247 }
1248 }
1251 }
1253 // Touch events
1254 @Override
1256 /* Ref: http://developer.android.com/training/gestures/multi.html */
1265 // !!! FIXME: dump this SDK check after 2.0.4 ships and require API14.
1274 }
1275 }
1286 // may be larger than 1.0f on some devices
1287 // see the documentation of getPressure(i)
1289 }
1291 }
1296 // Primary pointer up/down, the index is always zero
1300 // Non primary pointer up/down
1303 }
1310 // may be larger than 1.0f on some devices
1311 // see the documentation of getPressure(i)
1313 }
1324 // may be larger than 1.0f on some devices
1325 // see the documentation of getPressure(i)
1327 }
1329 }
1334 }
1335 }
1338 }
1340 // Sensor events
1342 // TODO: This uses getDefaultSensor - what if we have >1 accels?
1350 }
1351 }
1353 @Override
1355 // TODO
1356 }
1358 @Override
1379 }
1383 }
1384 }
1385 }
1387 /* This is a fake invisible editor view that receives the input and defines the
1388 * pan&scan region
1389 */
1391 InputConnection ic;
1398 }
1400 @Override
1403 }
1405 @Override
1407 /*
1408 * This handles the hardware keyboard input
1409 */
1413 }
1419 }
1421 }
1423 //
1424 @Override
1426 // As seen on StackOverflow: http://stackoverflow.com/questions/7634346/keyboard-hide-event
1427 // FIXME: Discussion at http://bugzilla.libsdl.org/show_bug.cgi?id=1639
1428 // FIXME: This is not a 100% effective solution to the problem of detecting if the keyboard is showing or not
1429 // FIXME: A more effective solution would be to assume our Layout to be RelativeLayout or LinearLayout
1430 // FIXME: And determine the keyboard presence doing this: http://stackoverflow.com/questions/2150078/how-to-check-visibility-of-software-keyboard-in-android
1431 // FIXME: An even more effective way would be if Android provided this out of the box, but where would the fun be in that :)
1435 }
1436 }
1438 }
1440 @Override
1444 outAttrs.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
1449 }
1450 }
1457 }
1459 @Override
1461 /*
1462 * This handles the keycodes from soft keyboard (and IME-translated input from hardkeyboard)
1463 */
1468 }
1474 }
1476 }
1478 @Override
1484 }
1486 @Override
1492 }
1498 @Override
1500 // Workaround to capture backspace key. Ref: http://stackoverflow.com/questions/14560344/android-backspace-in-webview-baseinputconnection
1501 // and https://bugzilla.libsdl.org/show_bug.cgi?id=2265
1504 // backspace(s)
1509 }
1511 }
1514 }
1515 }
1523 }
1527 SDLClipboardHandler,
1533 mClipMgr = (android.content.ClipboardManager) SDL.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
1535 }
1537 @Override
1540 }
1542 @Override
1544 CharSequence text;
1548 }
1550 }
1552 @Override
1557 }
1559 @Override
1562 }
1564 }
1567 SDLClipboardHandler {
1572 mClipMgrOld = (android.text.ClipboardManager) SDL.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
1573 }
1575 @Override
1578 }
1580 @Override
1582 CharSequence text;
1586 }
1588 }
1590 @Override
1593 }
1594 }