1 package org.libsdl.app;
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.util.Arrays;
6 import java.util.Hashtable;
7 import java.lang.reflect.Method;
11 import android.content.*;
12 import android.content.res.Configuration;
13 import android.text.InputType;
14 import android.view.*;
15 import android.view.inputmethod.BaseInputConnection;
16 import android.view.inputmethod.EditorInfo;
17 import android.view.inputmethod.InputConnection;
18 import android.view.inputmethod.InputMethodManager;
19 import android.widget.RelativeLayout;
20 import android.widget.Button;
21 import android.widget.LinearLayout;
22 import android.widget.TextView;
24 import android.util.DisplayMetrics;
25 import android.util.Log;
26 import android.util.SparseArray;
27 import android.graphics.*;
28 import android.graphics.drawable.Drawable;
29 import android.hardware.*;
30 import android.content.pm.ActivityInfo;
31 import android.content.pm.PackageManager;
32 import android.content.pm.ApplicationInfo;
37 public class SDLActivity extends Activity implements View.OnSystemUiVisibilityChangeListener {
38 private static final String
TAG =
"SDL";
89 protected static Hashtable<Integer, Object>
mCursors;
98 if (mMotionListener == null) {
99 if (Build.VERSION.SDK_INT >= 26) {
100 mMotionListener =
new SDLGenericMotionListener_API26();
102 if (Build.VERSION.SDK_INT >= 24) {
103 mMotionListener =
new SDLGenericMotionListener_API24();
105 mMotionListener =
new SDLGenericMotionListener_API12();
119 if (libraries.length > 0) {
120 library =
"lib" + libraries[libraries.length - 1] +
".so";
122 library =
"libmain.so";
124 return getContext().getApplicationInfo().nativeLibraryDir +
"/" + library;
144 return new String[] {
168 return new String[0];
178 mClipboardHandler = null;
179 mCursors =
new Hashtable<Integer, Object>();
182 mExitCalledFromJava =
false;
183 mBrokenLibraries =
false;
184 mIsResumedCalled =
false;
185 mIsSurfaceReady =
false;
193 protected void onCreate(Bundle savedInstanceState) {
194 Log.v(TAG,
"Device: " + Build.DEVICE);
195 Log.v(TAG,
"Model: " + Build.MODEL);
196 Log.v(TAG,
"onCreate()");
197 super.onCreate(savedInstanceState);
200 String errorMsgBrokenLib =
"";
203 }
catch(UnsatisfiedLinkError
e) {
204 System.err.println(e.getMessage());
205 mBrokenLibraries =
true;
206 errorMsgBrokenLib = e.getMessage();
207 }
catch(Exception e) {
208 System.err.println(e.getMessage());
209 mBrokenLibraries =
true;
210 errorMsgBrokenLib = e.getMessage();
213 if (mBrokenLibraries)
216 AlertDialog.Builder dlgAlert =
new AlertDialog.Builder(
this);
217 dlgAlert.setMessage(
"An error occurred while trying to start the application. Please try again and/or reinstall." 218 + System.getProperty(
"line.separator")
219 + System.getProperty(
"line.separator")
220 +
"Error: " + errorMsgBrokenLib);
221 dlgAlert.setTitle(
"SDL Error");
222 dlgAlert.setPositiveButton(
"Exit",
223 new DialogInterface.OnClickListener() {
225 public void onClick(DialogInterface dialog,
int id) {
230 dlgAlert.setCancelable(
false);
231 dlgAlert.create().show();
246 if (Build.VERSION.SDK_INT >= 11) {
247 mClipboardHandler =
new SDLClipboardHandler_API11();
250 mClipboardHandler =
new SDLClipboardHandler_Old();
256 mSurface =
new SDLSurface(getApplication());
258 mLayout =
new RelativeLayout(
this);
259 mLayout.addView(mSurface);
265 setContentView(mLayout);
269 getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(
this);
272 Intent intent = getIntent();
273 if (intent != null && intent.getData() != null) {
274 String
filename = intent.getData().getPath();
275 if (filename != null) {
276 Log.v(TAG,
"Got filename: " + filename);
285 Log.v(TAG,
"onPause()");
288 mIsResumedCalled =
false;
294 if (mHIDDeviceManager != null) {
303 Log.v(TAG,
"onResume()");
306 mIsResumedCalled =
true;
312 if (mHIDDeviceManager != null) {
321 final Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
325 switch (display.getRotation()) {
326 case Surface.ROTATION_0:
330 case Surface.ROTATION_90:
334 case Surface.ROTATION_180:
338 case Surface.ROTATION_270:
348 super.onWindowFocusChanged(hasFocus);
349 Log.v(TAG,
"onWindowFocusChanged(): " + hasFocus);
368 Log.v(TAG,
"onLowMemory()");
380 Log.v(TAG,
"onDestroy()");
382 if (mHIDDeviceManager != null) {
384 mHIDDeviceManager = null;
405 }
catch(Exception
e) {
406 Log.v(TAG,
"Problem stopping thread: " + e);
427 if ((trapBack != null) && trapBack.equals(
"1")) {
433 super.onBackPressed();
443 runOnUiThread(
new Runnable() {
453 super.onBackPressed();
463 int keyCode =
event.getKeyCode();
465 if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
466 keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
467 keyCode == KeyEvent.KEYCODE_CAMERA ||
468 keyCode == KeyEvent.KEYCODE_ZOOM_IN ||
469 keyCode == KeyEvent.KEYCODE_ZOOM_OUT
473 return super.dispatchKeyEvent(event);
479 if (mNextNativeState == mCurrentNativeState) {
494 if (mSurface != null)
495 mSurface.handlePause();
502 if (mIsSurfaceReady && mHasFocus && mIsResumedCalled) {
503 if (mSDLThread == null) {
508 mSDLThread =
new Thread(
new SDLMain(),
"SDLThread");
509 mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER,
true);
514 mSurface.handleResume();
523 if (mSingleton != null) {
530 static final int COMMAND_CHANGE_TITLE = 1;
531 static final int COMMAND_CHANGE_WINDOW_STYLE = 2;
532 static final int COMMAND_TEXTEDIT_HIDE = 3;
533 static final int COMMAND_SET_KEEP_SCREEN_ON = 5;
560 if (context == null) {
561 Log.e(TAG,
"error handling message, getContext() returned null");
565 case COMMAND_CHANGE_TITLE:
566 if (context instanceof Activity) {
567 ((Activity) context).setTitle((String)msg.obj);
569 Log.e(TAG,
"error handling message, getContext() returned no Activity");
572 case COMMAND_CHANGE_WINDOW_STYLE:
573 if (Build.VERSION.SDK_INT < 19) {
577 if (context instanceof Activity) {
578 Window
window = ((Activity) context).getWindow();
579 if (window != null) {
580 if ((msg.obj instanceof Integer) && (((Integer) msg.obj).intValue() != 0)) {
581 int flags = View.SYSTEM_UI_FLAG_FULLSCREEN |
582 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
583 View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
584 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
585 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
586 View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.INVISIBLE;
587 window.getDecorView().setSystemUiVisibility(flags);
588 window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
589 window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
592 int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_VISIBLE;
593 window.getDecorView().setSystemUiVisibility(flags);
594 window.addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
595 window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
600 Log.e(TAG,
"error handling message, getContext() returned no Activity");
603 case COMMAND_TEXTEDIT_HIDE:
604 if (mTextEdit != null) {
608 mTextEdit.setLayoutParams(
new RelativeLayout.LayoutParams(0, 0));
610 InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
611 imm.hideSoftInputFromWindow(mTextEdit.getWindowToken(), 0);
613 mScreenKeyboardShown =
false;
616 case COMMAND_SET_KEEP_SCREEN_ON:
618 if (context instanceof Activity) {
619 Window
window = ((Activity) context).getWindow();
620 if (window != null) {
621 if ((msg.obj instanceof Integer) && (((Integer) msg.obj).intValue() != 0)) {
622 window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
624 window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
632 Log.e(TAG,
"error handling message, command is " + msg.arg1);
642 boolean sendCommand(
int command, Object
data) {
643 Message msg = commandHandler.obtainMessage();
646 boolean result = commandHandler.sendMessage(msg);
648 if ((Build.VERSION.SDK_INT >= 19) && (command == COMMAND_CHANGE_WINDOW_STYLE)) {
652 boolean bShouldWait =
false;
654 if (data instanceof Integer) {
656 Display display = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
657 android.util.DisplayMetrics realMetrics =
new android.util.DisplayMetrics();
658 display.getRealMetrics( realMetrics );
660 boolean bFullscreenLayout = ((realMetrics.widthPixels == mSurface.getWidth()) &&
661 (realMetrics.heightPixels == mSurface.getHeight()));
663 if (((Integer)
data).intValue() == 1) {
669 bShouldWait = !bFullscreenLayout;
675 bShouldWait = bFullscreenLayout;
693 catch (InterruptedException ie) {
694 ie.printStackTrace();
705 public static native
int nativeRunMain(String library, String
function, Object arguments);
711 public static native
void onNativeResize(
int surfaceWidth,
int surfaceHeight,
int deviceWidth,
int deviceHeight,
int format,
float rate);
716 public static native
void onNativeTouch(
int touchDevId,
int pointerFingerId,
719 public static native
void onNativeAccel(
float x,
float y,
float z);
732 return mSingleton.sendCommand(COMMAND_CHANGE_TITLE, title);
740 mSingleton.sendCommand(COMMAND_CHANGE_WINDOW_STYLE, fullscreen ? 1 : 0);
750 if (mSingleton != null) {
760 int orientation = -1;
762 if (hint.contains(
"LandscapeRight") && hint.contains(
"LandscapeLeft")) {
763 orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
764 }
else if (hint.contains(
"LandscapeRight")) {
765 orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
766 }
else if (hint.contains(
"LandscapeLeft")) {
767 orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
768 }
else if (hint.contains(
"Portrait") && hint.contains(
"PortraitUpsideDown")) {
769 orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
770 }
else if (hint.contains(
"Portrait")) {
771 orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
772 }
else if (hint.contains(
"PortraitUpsideDown")) {
773 orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
777 if (orientation == -1) {
782 orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
784 orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
789 Log.v(
"SDL",
"setOrientation() orientation=" + orientation +
" width=" + w +
" height="+ h +
" resizable=" + resizable +
" hint=" + hint);
790 if (orientation != -1) {
791 mSingleton.setRequestedOrientation(orientation);
800 if (mTextEdit == null) {
804 if (!mScreenKeyboardShown) {
808 InputMethodManager imm = (InputMethodManager)
SDL.
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
809 return imm.isAcceptingText();
830 if ((Build.VERSION.SDK_INT < 27) &&
isDeXMode()) {
853 if (mSingleton == null) {
856 return mSingleton.sendCommand(command, Integer.valueOf(param));
870 UiModeManager uiModeManager = (UiModeManager)
getContext().getSystemService(UI_MODE_SERVICE);
871 if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
874 if (Build.MANUFACTURER.equals(
"MINIX") && Build.MODEL.equals(
"NEO-U1")) {
877 if (Build.MANUFACTURER.equals(
"Amlogic") && Build.MODEL.equals(
"X96-W")) {
887 DisplayMetrics
metrics =
new DisplayMetrics();
889 activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
891 double dWidthInches = metrics.widthPixels / (double)metrics.xdpi;
892 double dHeightInches = metrics.heightPixels / (
double)metrics.ydpi;
894 double dDiagonal = Math.sqrt((dWidthInches * dWidthInches) + (dHeightInches * dHeightInches));
897 return (dDiagonal >= 7.0);
904 return getContext().getPackageManager().hasSystemFeature(
"org.chromium.arc.device_management");
911 if (Build.VERSION.SDK_INT < 24) {
915 final Configuration
config =
getContext().getResources().getConfiguration();
916 final Class configClass = config.getClass();
917 return configClass.getField(
"SEM_DESKTOP_MODE_ENABLED").getInt(configClass)
918 == configClass.getField(
"semDesktopModeEnabled").getInt(config);
919 }
catch(Exception ignored) {
928 return getContext().getResources().getDisplayMetrics();
936 ApplicationInfo applicationInfo =
getContext().getPackageManager().getApplicationInfo(
getContext().getPackageName(), PackageManager.GET_META_DATA);
937 Bundle bundle = applicationInfo.metaData;
938 if (bundle == null) {
941 String prefix =
"SDL_ENV.";
942 final int trimLength = prefix.length();
943 for (String
key : bundle.keySet()) {
944 if (
key.startsWith(prefix)) {
945 String name =
key.substring(trimLength);
946 String value = bundle.get(
key).toString();
952 }
catch (Exception
e) {
953 Log.v(
"SDL",
"exception " + e.toString());
964 static class ShowTextInputTask
implements Runnable {
970 static final int HEIGHT_PADDING = 15;
972 public int x,
y,
w,
h;
974 public ShowTextInputTask(
int x,
int y,
int w,
int h) {
983 RelativeLayout.LayoutParams
params =
new RelativeLayout.LayoutParams(w, h + HEIGHT_PADDING);
987 if (mTextEdit == null) {
990 mLayout.addView(mTextEdit,
params);
992 mTextEdit.setLayoutParams(
params);
995 mTextEdit.setVisibility(View.VISIBLE);
996 mTextEdit.requestFocus();
998 InputMethodManager imm = (InputMethodManager)
SDL.
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
999 imm.showSoftInput(mTextEdit, 0);
1001 mScreenKeyboardShown =
true;
1010 return mSingleton.commandHandler.post(
new ShowTextInputTask(x, y, w, h));
1016 if (Build.VERSION.SDK_INT >= 11) {
1017 if (event.isCtrlPressed()) {
1022 return event.isPrintingKey() ||
event.getKeyCode() == KeyEvent.KEYCODE_SPACE;
1042 int[]
ids = InputDevice.getDeviceIds();
1043 int[] filtered =
new int[ids.length];
1045 for (
int i = 0;
i < ids.length; ++
i) {
1046 InputDevice
device = InputDevice.getDevice(ids[
i]);
1047 if ((device != null) && ((device.getSources() &
sources) != 0)) {
1048 filtered[used++] = device.getId();
1051 return Arrays.copyOf(filtered, used);
1069 if (expansionFile == null) {
1070 String mainHint =
nativeGetHint(
"SDL_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION");
1071 if (mainHint == null) {
1074 String patchHint =
nativeGetHint(
"SDL_ANDROID_APK_EXPANSION_PATCH_FILE_VERSION");
1075 if (patchHint == null) {
1079 Integer mainVersion;
1080 Integer patchVersion;
1082 mainVersion = Integer.valueOf(mainHint);
1083 patchVersion = Integer.valueOf(patchHint);
1084 }
catch (NumberFormatException ex) {
1085 ex.printStackTrace();
1086 throw new IOException(
"No valid file versions set for APK expansion files", ex);
1092 expansionFile = Class.forName(
"com.android.vending.expansion.zipfile.APKExpansionSupport")
1093 .getMethod(
"getAPKExpansionZipFile", Context.class,
int.class,
int.class)
1096 expansionFileMethod = expansionFile.getClass()
1097 .getMethod(
"getInputStream", String.class);
1098 }
catch (Exception ex) {
1099 ex.printStackTrace();
1100 expansionFile = null;
1101 expansionFileMethod = null;
1102 throw new IOException(
"Could not access APK expansion support library", ex);
1107 InputStream fileStream;
1109 fileStream = (InputStream)expansionFileMethod.invoke(expansionFile, fileName);
1110 }
catch (Exception ex) {
1112 ex.printStackTrace();
1113 throw new IOException(
"Could not open stream from APK expansion file", ex);
1116 if (fileStream == null) {
1118 throw new IOException(
"Could not find path in APK expansion file");
1146 final int[] buttonFlags,
1147 final int[] buttonIds,
1148 final String[] buttonTexts,
1151 messageboxSelection[0] = -1;
1155 if ((buttonFlags.length != buttonIds.length) && (buttonIds.length != buttonTexts.length)) {
1161 final Bundle args =
new Bundle();
1162 args.putInt(
"flags", flags);
1163 args.putString(
"title", title);
1164 args.putString(
"message", message);
1165 args.putIntArray(
"buttonFlags", buttonFlags);
1166 args.putIntArray(
"buttonIds", buttonIds);
1167 args.putStringArray(
"buttonTexts", buttonTexts);
1168 args.putIntArray(
"colors", colors);
1172 runOnUiThread(
new Runnable() {
1175 showDialog(dialogs++, args);
1183 messageboxSelection.wait();
1184 }
catch (InterruptedException ex) {
1185 ex.printStackTrace();
1192 return messageboxSelection[0];
1202 int[]
colors = args.getIntArray(
"colors");
1203 int backgroundColor;
1205 int buttonBorderColor;
1206 int buttonBackgroundColor;
1207 int buttonSelectedColor;
1208 if (colors != null) {
1210 backgroundColor = colors[++
i];
1211 textColor = colors[++
i];
1212 buttonBorderColor = colors[++
i];
1213 buttonBackgroundColor = colors[++
i];
1214 buttonSelectedColor = colors[++
i];
1216 backgroundColor = Color.TRANSPARENT;
1217 textColor = Color.TRANSPARENT;
1218 buttonBorderColor = Color.TRANSPARENT;
1219 buttonBackgroundColor = Color.TRANSPARENT;
1220 buttonSelectedColor = Color.TRANSPARENT;
1225 final Dialog dialog =
new Dialog(
this);
1226 dialog.setTitle(args.getString(
"title"));
1227 dialog.setCancelable(
false);
1228 dialog.setOnDismissListener(
new DialogInterface.OnDismissListener() {
1230 public void onDismiss(DialogInterface unused) {
1232 messageboxSelection.notify();
1239 TextView
message =
new TextView(
this);
1240 message.setGravity(Gravity.CENTER);
1241 message.setText(args.getString(
"message"));
1242 if (textColor != Color.TRANSPARENT) {
1243 message.setTextColor(textColor);
1248 int[] buttonFlags = args.getIntArray(
"buttonFlags");
1249 int[] buttonIds = args.getIntArray(
"buttonIds");
1250 String[] buttonTexts = args.getStringArray(
"buttonTexts");
1252 final SparseArray<Button>
mapping =
new SparseArray<Button>();
1254 LinearLayout
buttons =
new LinearLayout(
this);
1255 buttons.setOrientation(LinearLayout.HORIZONTAL);
1256 buttons.setGravity(Gravity.CENTER);
1257 for (
int i = 0;
i < buttonTexts.length; ++
i) {
1258 Button button =
new Button(
this);
1259 final int id = buttonIds[
i];
1260 button.setOnClickListener(
new View.OnClickListener() {
1262 public void onClick(View
v) {
1263 messageboxSelection[0] =
id;
1267 if (buttonFlags[
i] != 0) {
1269 if ((buttonFlags[
i] & 0x00000001) != 0) {
1270 mapping.put(KeyEvent.KEYCODE_ENTER, button);
1272 if ((buttonFlags[
i] & 0x00000002) != 0) {
1273 mapping.put(KeyEvent.KEYCODE_ESCAPE, button);
1276 button.setText(buttonTexts[
i]);
1277 if (textColor != Color.TRANSPARENT) {
1278 button.setTextColor(textColor);
1280 if (buttonBorderColor != Color.TRANSPARENT) {
1283 if (buttonBackgroundColor != Color.TRANSPARENT) {
1284 Drawable drawable = button.getBackground();
1285 if (drawable == null) {
1287 button.setBackgroundColor(buttonBackgroundColor);
1290 drawable.setColorFilter(buttonBackgroundColor, PorterDuff.Mode.MULTIPLY);
1293 if (buttonSelectedColor != Color.TRANSPARENT) {
1296 buttons.addView(button);
1301 LinearLayout content =
new LinearLayout(
this);
1302 content.setOrientation(LinearLayout.VERTICAL);
1303 content.addView(message);
1304 content.addView(buttons);
1305 if (backgroundColor != Color.TRANSPARENT) {
1306 content.setBackgroundColor(backgroundColor);
1311 dialog.setContentView(content);
1312 dialog.setOnKeyListener(
new Dialog.OnKeyListener() {
1314 public boolean onKey(DialogInterface
d,
int keyCode, KeyEvent
event) {
1315 Button button = mapping.get(keyCode);
1316 if (button != null) {
1317 if (event.getAction() == KeyEvent.ACTION_UP) {
1318 button.performClick();
1332 int flags = View.SYSTEM_UI_FLAG_FULLSCREEN |
1333 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
1334 View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
1335 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
1336 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
1337 View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.INVISIBLE;
1339 SDLActivity.this.getWindow().getDecorView().setSystemUiVisibility(flags);
1346 Handler handler = getWindow().getDecorView().getHandler();
1347 if (handler != null) {
1348 handler.removeCallbacks(rehideSystemUi);
1349 handler.postDelayed(rehideSystemUi, 2000);
1359 return mClipboardHandler.clipboardHasText();
1366 return mClipboardHandler.clipboardGetText();
1373 mClipboardHandler.clipboardSetText(
string);
1380 Bitmap
bitmap = Bitmap.createBitmap(colors, width, height, Bitmap.Config.ARGB_8888);
1384 Class PointerIconClass = Class.forName(
"android.view.PointerIcon");
1385 Class[] arg_types =
new Class[] { Bitmap.class,
float.class,
float.class };
1386 Method create = PointerIconClass.getMethod(
"create", arg_types);
1387 mCursors.put(mLastCursorID, create.invoke(null, bitmap, hotSpotX, hotSpotY));
1388 }
catch (Exception
e) {
1400 Class PointerIconClass = Class.forName(
"android.view.PointerIcon");
1401 Method setPointerIcon = SDLSurface.class.getMethod(
"setPointerIcon", PointerIconClass);
1402 setPointerIcon.invoke(mSurface, mCursors.get(cursorID));
1403 }
catch (Exception
e) {
1413 int cursor_type = 0;
1454 Class PointerIconClass = Class.forName(
"android.view.PointerIcon");
1455 Class[] arg_types =
new Class[] { Context.class,
int.class };
1456 Method getSystemIcon = PointerIconClass.getMethod(
"getSystemIcon", arg_types);
1457 Method setPointerIcon = SDLSurface.class.getMethod(
"setPointerIcon", PointerIconClass);
1458 setPointerIcon.invoke(mSurface, getSystemIcon.invoke(null,
SDL.
getContext(), cursor_type));
1459 }
catch (Exception
e) {
1469 class SDLMain
implements Runnable {
1477 Log.v(
"SDL",
"Running main function " +
function +
" from library " + library);
1480 Log.v(
"SDL",
"Finished main function");
1496 class SDLSurface
extends SurfaceView implements SurfaceHolder.Callback,
1497 View.OnKeyListener, View.OnTouchListener, SensorEventListener {
1500 protected static SensorManager mSensorManager;
1501 protected static Display mDisplay;
1504 protected static float mWidth, mHeight;
1507 public SDLSurface(Context
context) {
1509 getHolder().addCallback(
this);
1512 setFocusableInTouchMode(
true);
1514 setOnKeyListener(
this);
1515 setOnTouchListener(
this);
1517 mDisplay = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
1518 mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
1520 if (Build.VERSION.SDK_INT >= 12) {
1529 public void handlePause() {
1530 enableSensor(Sensor.TYPE_ACCELEROMETER,
false);
1533 public void handleResume() {
1535 setFocusableInTouchMode(
true);
1537 setOnKeyListener(
this);
1538 setOnTouchListener(
this);
1539 enableSensor(Sensor.TYPE_ACCELEROMETER,
true);
1543 return getHolder().getSurface();
1548 public void surfaceCreated(SurfaceHolder holder) {
1549 Log.v(
"SDL",
"surfaceCreated()");
1550 holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
1555 public void surfaceDestroyed(SurfaceHolder holder) {
1556 Log.v(
"SDL",
"surfaceDestroyed()");
1568 public void surfaceChanged(SurfaceHolder holder,
1570 Log.v(
"SDL",
"surfaceChanged()");
1576 int sdlFormat = 0x15151002;
1578 case PixelFormat.A_8:
1579 Log.v(
"SDL",
"pixel format A_8");
1581 case PixelFormat.LA_88:
1582 Log.v(
"SDL",
"pixel format LA_88");
1584 case PixelFormat.L_8:
1585 Log.v(
"SDL",
"pixel format L_8");
1587 case PixelFormat.RGBA_4444:
1588 Log.v(
"SDL",
"pixel format RGBA_4444");
1589 sdlFormat = 0x15421002;
1591 case PixelFormat.RGBA_5551:
1592 Log.v(
"SDL",
"pixel format RGBA_5551");
1593 sdlFormat = 0x15441002;
1595 case PixelFormat.RGBA_8888:
1596 Log.v(
"SDL",
"pixel format RGBA_8888");
1597 sdlFormat = 0x16462004;
1599 case PixelFormat.RGBX_8888:
1600 Log.v(
"SDL",
"pixel format RGBX_8888");
1601 sdlFormat = 0x16261804;
1603 case PixelFormat.RGB_332:
1604 Log.v(
"SDL",
"pixel format RGB_332");
1605 sdlFormat = 0x14110801;
1607 case PixelFormat.RGB_565:
1608 Log.v(
"SDL",
"pixel format RGB_565");
1609 sdlFormat = 0x15151002;
1611 case PixelFormat.RGB_888:
1612 Log.v(
"SDL",
"pixel format RGB_888");
1614 sdlFormat = 0x16161804;
1617 Log.v(
"SDL",
"pixel format unknown " + format);
1623 int nDeviceWidth =
width;
1624 int nDeviceHeight =
height;
1627 if (Build.VERSION.SDK_INT >= 17) {
1628 android.util.DisplayMetrics realMetrics =
new android.util.DisplayMetrics();
1629 mDisplay.getRealMetrics( realMetrics );
1630 nDeviceWidth = realMetrics.widthPixels;
1631 nDeviceHeight = realMetrics.heightPixels;
1634 catch ( java.lang.Throwable throwable ) {}
1641 Log.v(
"SDL",
"Window size: " + width +
"x" + height);
1642 Log.v(
"SDL",
"Device size: " + nDeviceWidth +
"x" + nDeviceHeight);
1645 boolean skip =
false;
1648 if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
1652 else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT)
1654 if (mWidth > mHeight) {
1657 }
else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE || requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
1658 if (mWidth < mHeight) {
1665 double min = Math.min(mWidth, mHeight);
1666 double max = Math.max(mWidth, mHeight);
1668 if (max / min < 1.20) {
1669 Log.v(
"SDL",
"Don't skip on such aspect-ratio. Could be a square resolution.");
1675 Log.v(
"SDL",
"Skip .. Surface is not ready.");
1691 public boolean onKey(View
v,
int keyCode, KeyEvent
event) {
1701 if (event.getAction() == KeyEvent.ACTION_DOWN) {
1705 }
else if (event.getAction() == KeyEvent.ACTION_UP) {
1712 if ((event.getSource() & InputDevice.SOURCE_KEYBOARD) != 0) {
1713 if (event.getAction() == KeyEvent.ACTION_DOWN) {
1716 SDLInputConnection.nativeCommitText(String.valueOf((
char) event.getUnicodeChar()), 1);
1721 else if (event.getAction() == KeyEvent.ACTION_UP) {
1728 if ((event.getSource() & InputDevice.SOURCE_MOUSE) != 0) {
1731 if ((keyCode == KeyEvent.KEYCODE_BACK) || (keyCode == KeyEvent.KEYCODE_FORWARD)) {
1732 switch (event.getAction()) {
1733 case KeyEvent.ACTION_DOWN:
1734 case KeyEvent.ACTION_UP:
1747 public boolean onTouch(View v, MotionEvent event) {
1749 final int touchDevId =
event.getDeviceId();
1750 final int pointerCount =
event.getPointerCount();
1751 int action =
event.getActionMasked();
1752 int pointerFingerId;
1760 if (Build.VERSION.SDK_INT < 14) {
1764 mouseButton = (Integer) event.getClass().getMethod(
"getButtonState").invoke(event);
1765 }
catch(Exception
e) {
1773 x = motionListener.getEventX(event);
1774 y = motionListener.getEventY(event);
1779 case MotionEvent.ACTION_MOVE:
1780 for (i = 0; i < pointerCount; i++) {
1781 pointerFingerId =
event.getPointerId(i);
1782 x =
event.getX(i) / mWidth;
1783 y =
event.getY(i) / mHeight;
1784 p =
event.getPressure(i);
1794 case MotionEvent.ACTION_UP:
1795 case MotionEvent.ACTION_DOWN:
1798 case MotionEvent.ACTION_POINTER_UP:
1799 case MotionEvent.ACTION_POINTER_DOWN:
1802 i =
event.getActionIndex();
1805 pointerFingerId =
event.getPointerId(i);
1806 x =
event.getX(i) / mWidth;
1807 y =
event.getY(i) / mHeight;
1808 p =
event.getPressure(i);
1817 case MotionEvent.ACTION_CANCEL:
1818 for (i = 0; i < pointerCount; i++) {
1819 pointerFingerId =
event.getPointerId(i);
1820 x =
event.getX(i) / mWidth;
1821 y =
event.getY(i) / mHeight;
1822 p =
event.getPressure(i);
1841 public void enableSensor(
int sensortype,
boolean enabled) {
1844 mSensorManager.registerListener(
this,
1845 mSensorManager.getDefaultSensor(sensortype),
1846 SensorManager.SENSOR_DELAY_GAME, null);
1848 mSensorManager.unregisterListener(
this,
1849 mSensorManager.getDefaultSensor(sensortype));
1854 public void onAccuracyChanged(Sensor sensor,
int accuracy) {
1859 public void onSensorChanged(SensorEvent event) {
1860 if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
1867 switch (mDisplay.getRotation()) {
1868 case Surface.ROTATION_90:
1869 x = -
event.values[1];
1870 y =
event.values[0];
1873 case Surface.ROTATION_270:
1874 x =
event.values[1];
1875 y = -
event.values[0];
1878 case Surface.ROTATION_180:
1879 x = -
event.values[1];
1880 y = -
event.values[0];
1884 x =
event.values[0];
1885 y =
event.values[1];
1896 y / SensorManager.GRAVITY_EARTH,
1897 event.values[2] / SensorManager.GRAVITY_EARTH);
1904 public boolean onCapturedPointerEvent(MotionEvent event)
1906 int action =
event.getActionMasked();
1910 case MotionEvent.ACTION_SCROLL:
1911 x =
event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
1912 y =
event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
1916 case MotionEvent.ACTION_HOVER_MOVE:
1917 case MotionEvent.ACTION_MOVE:
1923 case MotionEvent.ACTION_BUTTON_PRESS:
1924 case MotionEvent.ACTION_BUTTON_RELEASE:
1927 if (action == MotionEvent.ACTION_BUTTON_PRESS) {
1928 action = MotionEvent.ACTION_DOWN;
1930 else if (action == MotionEvent.ACTION_BUTTON_RELEASE) {
1931 action = MotionEvent.ACTION_UP;
1936 int button =
event.getButtonState();
1950 class DummyEdit
extends View implements View.OnKeyListener {
1953 public DummyEdit(Context
context) {
1955 setFocusableInTouchMode(
true);
1957 setOnKeyListener(
this);
1961 public boolean onCheckIsTextEditor() {
1966 public boolean onKey(View
v,
int keyCode, KeyEvent
event) {
1970 if (event.getAction() == KeyEvent.ACTION_DOWN) {
1972 ic.commitText(String.valueOf((
char) event.getUnicodeChar()), 1);
1977 }
else if (event.getAction() == KeyEvent.ACTION_UP) {
1986 public boolean onKeyPreIme (
int keyCode, KeyEvent event) {
1993 if (event.getAction()==KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
1998 return super.onKeyPreIme(keyCode, event);
2002 public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
2003 ic =
new SDLInputConnection(
this,
true);
2005 outAttrs.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
2006 outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI
2007 | EditorInfo.IME_FLAG_NO_FULLSCREEN ;
2013 class SDLInputConnection
extends BaseInputConnection {
2015 public SDLInputConnection(View targetView,
boolean fullEditor) {
2016 super(targetView, fullEditor);
2021 public boolean sendKeyEvent(KeyEvent
event) {
2034 if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
2036 if ((imeHide != null) && imeHide.equals(
"1")) {
2039 SDLActivity activity = (SDLActivity)c;
2040 activity.sendCommand(SDLActivity.COMMAND_TEXTEDIT_HIDE, null);
2047 return super.sendKeyEvent(event);
2051 public boolean commitText(CharSequence
text,
int newCursorPosition) {
2053 for (
int i = 0;
i < text.length();
i++) {
2054 char c = text.charAt(
i);
2055 nativeGenerateScancodeForUnichar(c);
2058 SDLInputConnection.nativeCommitText(text.toString(), newCursorPosition);
2060 return super.commitText(text, newCursorPosition);
2064 public boolean setComposingText(CharSequence text,
int newCursorPosition) {
2066 nativeSetComposingText(text.toString(), newCursorPosition);
2068 return super.setComposingText(text, newCursorPosition);
2071 public static native
void nativeCommitText(String text,
int newCursorPosition);
2073 public native
void nativeGenerateScancodeForUnichar(
char c);
2075 public native
void nativeSetComposingText(String text,
int newCursorPosition);
2078 public boolean deleteSurroundingText(
int beforeLength,
int afterLength) {
2081 if (beforeLength > 0 && afterLength == 0) {
2084 while (beforeLength-- > 0) {
2085 boolean ret_key = sendKeyEvent(
new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL))
2086 && sendKeyEvent(
new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));
2087 ret = ret && ret_key;
2092 return super.deleteSurroundingText(beforeLength, afterLength);
2096 interface SDLClipboardHandler {
2105 class SDLClipboardHandler_API11
implements 2106 SDLClipboardHandler,
2107 android.content.ClipboardManager.OnPrimaryClipChangedListener {
2109 protected android.content.ClipboardManager mClipMgr;
2111 SDLClipboardHandler_API11() {
2112 mClipMgr = (android.content.ClipboardManager)
SDL.
getContext().getSystemService(Context.CLIPBOARD_SERVICE);
2113 mClipMgr.addPrimaryClipChangedListener(
this);
2118 return mClipMgr.hasText();
2124 text = mClipMgr.getText();
2126 return text.toString();
2133 mClipMgr.removePrimaryClipChangedListener(
this);
2134 mClipMgr.setText(
string);
2135 mClipMgr.addPrimaryClipChangedListener(
this);
2139 public void onPrimaryClipChanged() {
2145 class SDLClipboardHandler_Old
implements 2146 SDLClipboardHandler {
2148 protected android.text.ClipboardManager mClipMgrOld;
2150 SDLClipboardHandler_Old() {
2151 mClipMgrOld = (android.text.ClipboardManager)
SDL.
getContext().getSystemService(Context.CLIPBOARD_SERVICE);
2156 return mClipMgrOld.hasText();
2162 text = mClipMgrOld.getText();
2164 return text.toString();
2171 mClipMgrOld.setText(
string);
static boolean isDeXMode()
static boolean isDeviceSDLJoystick(int deviceId)
static native void onNativeKeyboardFocusLost()
static int getCurrentOrientation()
GLsizei GLfixed GLfixed GLfixed GLfixed const GLubyte * bitmap
static boolean mExitCalledFromJava
static SDLGenericMotionListener_API12 mMotionListener
int messageboxShowMessageBox(final int flags, final String title, final String message, final int[] buttonFlags, final int[] buttonIds, final String[] buttonTexts, final int[] colors)
static boolean setActivityTitle(String title)
static native String nativeGetHint(String name)
static native void onNativeSurfaceDestroyed()
static native void onNativeMouse(int button, int action, float x, float y, boolean relative)
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 Uint32 * e
static boolean setRelativeMouseEnabled(boolean enabled)
static void release(HIDDeviceManager manager)
GLint GLint GLint GLint GLint x
GLuint GLsizei const GLchar * message
static void loadLibrary(String libraryName)
static final int SDL_SYSTEM_CURSOR_SIZEWE
static HIDDeviceManager acquire(Context context)
static final int SDL_ORIENTATION_LANDSCAPE
static native void onNativeOrientationChanged(int orientation)
static boolean isTablet()
static int createCustomCursor(int[] colors, int width, int height, int hotSpotX, int hotSpotY)
static final int SDL_SYSTEM_CURSOR_IBEAM
static boolean supportsRelativeMouse()
static final int SDL_SYSTEM_CURSOR_WAIT
static native void onNativeKeyDown(int keycode)
GLfloat GLfloat GLfloat GLfloat h
static native void nativeResume()
static native void onNativeClipboardChanged()
static screen_context_t context
void onSystemUiVisibilityChange(int visibility)
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
static boolean setCustomCursor(int cursorID)
static boolean isScreenKeyboardShown()
static Hashtable< Integer, Object > mCursors
static SDLSurface mSurface
static native int onNativePadUp(int device_id, int keycode)
static native int onNativePadDown(int device_id, int keycode)
static void handleNativeState()
GLsizei GLenum const void GLuint GLsizei GLfloat * metrics
static View getContentView()
void setFrozen(boolean frozen)
static final int SDL_SYSTEM_CURSOR_SIZEALL
GLuint const GLchar * name
static boolean mIsResumedCalled
static NativeState mCurrentNativeState
GLint GLint GLsizei width
static void setContext(Context context)
static void handleNativeExit()
static boolean mFullscreenModeActive
static final int COMMAND_USER
static native void onNativeTouch(int touchDevId, int pointerFingerId, int action, float x, float y, float p)
static int [] inputGetInputDeviceIds(int sources)
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
static final int SDL_SYSTEM_CURSOR_NO
boolean dispatchKeyEvent(KeyEvent event)
static SDL_AudioDeviceID device
static final int SDL_ORIENTATION_PORTRAIT_FLIPPED
static native void nativeQuit()
static InputStream openAPKExpansionInputStream(String fileName)
static final int SDL_SYSTEM_CURSOR_HAND
static boolean mBrokenLibraries
static boolean getManifestEnvironmentVariables()
static void setWindowStyle(boolean fullscreen)
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 ** d
static boolean sendMessage(int command, int param)
static void clipboardSetText(String string)
static final int SDL_ORIENTATION_LANDSCAPE_FLIPPED
static native void onNativeDropFile(String filename)
void handleMessage(Message msg)
void superOnBackPressed()
static boolean isAndroidTV()
static String clipboardGetText()
static boolean mSeparateMouseAndTouch
GLubyte GLubyte GLubyte GLubyte w
GLsizei const GLfloat * value
static void manualBackButton()
static native int nativeSetupJNI()
GLint GLint GLint GLint GLint GLint y
void onWindowFocusChanged(boolean hasFocus)
static int mCurrentOrientation
void onCreate(Bundle savedInstanceState)
static boolean setSystemCursor(int cursorID)
static final int SDL_SYSTEM_CURSOR_SIZENESW
static native void nativeLowMemory()
void setOrientationBis(int w, int h, boolean resizable, String hint)
boolean onUnhandledMessage(int command, Object param)
static final int SDL_SYSTEM_CURSOR_SIZENWSE
static boolean isTextInputEvent(KeyEvent event)
static native void onNativeResize(int surfaceWidth, int surfaceHeight, int deviceWidth, int deviceHeight, int format, float rate)
GLenum GLenum GLsizei const GLuint GLboolean enabled
String getMainSharedObject()
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
static Method expansionFileMethod
final int [] messageboxSelection
static Object expansionFile
static native void onNativeSurfaceChanged()
static final int SDL_ORIENTATION_UNKNOWN
static native void nativePause()
static char text[MAX_TEXT_LENGTH]
static DisplayMetrics getDisplayDPI()
GLint GLint GLsizei GLsizei height
static final int SDL_SYSTEM_CURSOR_ARROW
static final int SDL_SYSTEM_CURSOR_SIZENS
static boolean clipboardHasText()
static Context getContext()
EGLSurface EGLNativeWindowType * window
static HIDDeviceManager mHIDDeviceManager
static boolean showTextInput(int x, int y, int w, int h)
static native void nativeSetenv(String name, String value)
Dialog onCreateDialog(int ignore, Bundle args)
static Surface getNativeSurface()
static final int SDL_SYSTEM_CURSOR_CROSSHAIR
GLenum GLenum GLenum GLenum mapping
static SDLActivity mSingleton
static final int SDL_SYSTEM_CURSOR_WAITARROW
static SDLClipboardHandler mClipboardHandler
static NativeState mNextNativeState
static native int nativeRunMain(String library, String function, Object arguments)
static final int SDL_ORIENTATION_PORTRAIT
static struct @63 buttons[NUM_DRUMS]
static final int SDL_SYSTEM_CURSOR_NONE
static native void onNativeAccel(float x, float y, float z)
static boolean mScreenKeyboardShown
final Runnable rehideSystemUi
static boolean isChromebook()
static SDL_Color textColor
static Context getContext()
static SDLGenericMotionListener_API12 getMotionListener()
static native void onNativeKeyUp(int keycode)
static void setOrientation(int w, int h, boolean resizable, String hint)