diff --git a/README.md b/README.md
index 0fc901d62..588100694 100644
--- a/README.md
+++ b/README.md
@@ -25,8 +25,17 @@ Tools required:
From project root directory:
```
-cd shell\android
-android update project -p .
+cd shell\android\xperia
+
+rm -rf libs
+
+android update project -p . --target "android-9"
+
+ndk-build -j4
+
+cd ..\
+
+android update project -p . --target "android-19"
ant debug
```
diff --git a/shell/android/build.xml b/shell/android/build.xml
index d931a0254..47dc9c9a2 100644
--- a/shell/android/build.xml
+++ b/shell/android/build.xml
@@ -75,6 +75,11 @@
+
+
+
diff --git a/shell/android/jni/Application.mk b/shell/android/jni/Application.mk
index f7255f987..e841bf16a 100644
--- a/shell/android/jni/Application.mk
+++ b/shell/android/jni/Application.mk
@@ -1,3 +1,4 @@
APP_STL := stlport_static
APP_ABI := armeabi-v7a
APP_PLATFORM := android-18
+NDK_TOOLCHAIN_VERSION := 4.8
\ No newline at end of file
diff --git a/shell/android/jni/src/Android.cpp b/shell/android/jni/src/Android.cpp
index 15b8bd04f..292f9432b 100644
--- a/shell/android/jni/src/Android.cpp
+++ b/shell/android/jni/src/Android.cpp
@@ -56,7 +56,7 @@ extern "C"
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_frameskip(JNIEnv *env,jobject obj, jint frames) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_pvrrender(JNIEnv *env,jobject obj, jint render) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_cheatdisk(JNIEnv *env,jobject obj, jstring disk) __attribute__((visibility("default")));
- JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_dreamtime(JNIEnv *env,jobject obj, u32 clock) __attribute__((visibility("default")));
+ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_dreamtime(JNIEnv *env,jobject obj, jlong clock) __attribute__((visibility("default")));
};
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_dynarec(JNIEnv *env,jobject obj, jint dynarec)
@@ -129,9 +129,9 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_cheatdisk(JNIEnv *env
}
-JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_dreamtime(JNIEnv *env,jobject obj, u32 clock)
+JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_dreamtime(JNIEnv *env,jobject obj, jlong clock)
{
- settings.dreamcast.RTC = clock;
+ settings.dreamcast.RTC = (u32)(clock);
}
void egl_stealcntx();
diff --git a/shell/android/src/com/reicast/emulator/GL2JNIActivity.java b/shell/android/src/com/reicast/emulator/GL2JNIActivity.java
index 8b4b35ea3..c3b462502 100644
--- a/shell/android/src/com/reicast/emulator/GL2JNIActivity.java
+++ b/shell/android/src/com/reicast/emulator/GL2JNIActivity.java
@@ -255,8 +255,6 @@ public class GL2JNIActivity extends Activity {
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
- // Log.w("INPUT", event.toString() + " " + event.getSource());
- // Get all the axis for the KeyEvent
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
@@ -272,7 +270,6 @@ public class GL2JNIActivity extends Activity {
return false;
if (!pad.compat[playerNum] && !pad.isActiveMoga[playerNum]) {
- // TODO: Moga should handle this locally
// Joystick
if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
@@ -341,40 +338,6 @@ public class GL2JNIActivity extends Activity {
return true;
}
- // TODO: Controller mapping in options. Trunk has Ouya layout. This is a DS3
- // layout.
- /*
- * map[]= new int[] { OuyaController.BUTTON_Y, key_CONT_B,
- * OuyaController.BUTTON_U, key_CONT_A, OuyaController.BUTTON_O, key_CONT_X,
- * OuyaController.BUTTON_A, key_CONT_Y,
- *
- * OuyaController.BUTTON_DPAD_UP, key_CONT_DPAD_UP,
- * OuyaController.BUTTON_DPAD_DOWN, key_CONT_DPAD_DOWN,
- * OuyaController.BUTTON_DPAD_LEFT, key_CONT_DPAD_LEFT,
- * OuyaController.BUTTON_DPAD_RIGHT, key_CONT_DPAD_RIGHT,
- *
- * OuyaController.BUTTON_MENU, key_CONT_START, OuyaController.BUTTON_L1,
- * key_CONT_START
- *
- * };
- */
-
- /*
- * int map[] = new int[] { OuyaController.BUTTON_Y, key_CONT_B,
- * OuyaController.BUTTON_U, key_CONT_A, OuyaController.BUTTON_O, key_CONT_X,
- * OuyaController.BUTTON_A, key_CONT_Y,
- *
- * OuyaController.BUTTON_DPAD_UP, key_CONT_DPAD_UP,
- * OuyaController.BUTTON_DPAD_DOWN, key_CONT_DPAD_DOWN,
- * OuyaController.BUTTON_DPAD_LEFT, key_CONT_DPAD_LEFT,
- * OuyaController.BUTTON_DPAD_RIGHT, key_CONT_DPAD_RIGHT,
- *
- * OuyaController.BUTTON_MENU, key_CONT_START, OuyaController.BUTTON_L1,
- * key_CONT_START
- *
- * };
- */
-
public boolean handle_key(Integer playerNum, int kc, boolean down) {
if (playerNum == null || playerNum == -1)
return false;
diff --git a/shell/android/src/com/reicast/emulator/GL2JNINative.java b/shell/android/src/com/reicast/emulator/GL2JNINative.java
new file mode 100644
index 000000000..0e8667682
--- /dev/null
+++ b/shell/android/src/com/reicast/emulator/GL2JNINative.java
@@ -0,0 +1,588 @@
+package com.reicast.emulator;
+
+import java.util.Arrays;
+import java.util.HashMap;
+
+import tv.ouya.console.api.OuyaController;
+import android.annotation.TargetApi;
+import android.app.NativeActivity;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup.LayoutParams;
+import android.view.Window;
+import android.widget.LinearLayout;
+import android.widget.PopupWindow;
+import android.widget.Toast;
+
+import com.reicast.emulator.config.Config;
+import com.reicast.emulator.emu.GL2JNIView;
+import com.reicast.emulator.emu.JNIdc;
+import com.reicast.emulator.emu.OnScreenMenu;
+import com.reicast.emulator.emu.OnScreenMenu.FpsPopup;
+import com.reicast.emulator.emu.OnScreenMenu.MainPopup;
+import com.reicast.emulator.emu.OnScreenMenu.VmuPopup;
+import com.reicast.emulator.periph.Gamepad;
+import com.reicast.emulator.periph.MOGAInput;
+import com.reicast.emulator.periph.SipEmulator;
+
+@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
+public class GL2JNINative extends NativeActivity {
+ public GL2JNIView mView;
+ OnScreenMenu menu;
+ public MainPopup popUp;
+ VmuPopup vmuPop;
+ FpsPopup fpsPop;
+ MOGAInput moga = new MOGAInput();
+ private SharedPreferences prefs;
+
+ private Config config;
+ private Gamepad pad = new Gamepad();
+
+ public static byte[] syms;
+
+ static {
+ System.loadLibrary("sexplay");
+ }
+
+ public native void registerNative();
+ public native void registerXperia(int xperia);
+
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+ @Override
+ protected void onCreate(Bundle icicle) {
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ getWindow().takeSurface(null);
+ registerNative();
+
+ prefs = PreferenceManager.getDefaultSharedPreferences(this);
+ config = new Config(GL2JNINative.this);
+ config.getConfigurationPrefs();
+ menu = new OnScreenMenu(GL2JNINative.this, prefs);
+
+ pad.isXperiaPlay = pad.IsXperiaPlay();
+ pad.isOuyaOrTV = pad.IsOuyaOrTV(GL2JNINative.this);
+// isNvidiaShield = Gamepad.IsNvidiaShield();
+
+ String fileName = null;
+
+ // Call parent onCreate()
+ super.onCreate(icicle);
+ OuyaController.init(this);
+ moga.onCreate(this, pad);
+
+ // Populate device descriptor-to-player-map from preferences
+ pad.deviceDescriptor_PlayerNum.put(
+ prefs.getString("device_descriptor_player_1", null), 0);
+ pad.deviceDescriptor_PlayerNum.put(
+ prefs.getString("device_descriptor_player_2", null), 1);
+ pad.deviceDescriptor_PlayerNum.put(
+ prefs.getString("device_descriptor_player_3", null), 2);
+ pad.deviceDescriptor_PlayerNum.put(
+ prefs.getString("device_descriptor_player_4", null), 3);
+ pad.deviceDescriptor_PlayerNum.remove(null);
+
+ boolean controllerTwoConnected = false;
+ boolean controllerThreeConnected = false;
+ boolean controllerFourConnected = false;
+
+ for (HashMap.Entry e : pad.deviceDescriptor_PlayerNum
+ .entrySet()) {
+ String descriptor = e.getKey();
+ Integer playerNum = e.getValue();
+
+ switch (playerNum) {
+ case 1:
+ if (descriptor != null)
+ controllerTwoConnected = true;
+ break;
+ case 2:
+ if (descriptor != null)
+ controllerThreeConnected = true;
+ break;
+ case 3:
+ if (descriptor != null)
+ controllerFourConnected = true;
+ break;
+ }
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
+
+ JNIdc.initControllers(new boolean[] { controllerTwoConnected,
+ controllerThreeConnected, controllerFourConnected });
+ int joys[] = InputDevice.getDeviceIds();
+ for (int joy : joys) {
+ String descriptor = null;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ descriptor = InputDevice.getDevice(joy).getDescriptor();
+ } else {
+ descriptor = InputDevice.getDevice(joy).getName();
+ }
+ Log.d("reidc", "InputDevice ID: " + joy);
+ Log.d("reidc",
+ "InputDevice Name: "
+ + InputDevice.getDevice(joy).getName());
+ if (pad.isXperiaPlay) {
+ if (InputDevice.getDevice(joy).getName()
+ .contains("keypad-game-zeus")) {
+ pad.keypadZeus.add(joy);
+ }
+ if (InputDevice.getDevice(joy).getName()
+ .contains("synaptics_touchpad")) {
+ registerXperia(joy);
+ pad.keypadZeus.add(joy);
+ }
+ }
+ Log.d("reidc", "InputDevice Descriptor: " + descriptor);
+ pad.deviceId_deviceDescriptor.put(joy, descriptor);
+ }
+
+ for (int joy : joys) {
+ Integer playerNum = pad.deviceDescriptor_PlayerNum
+ .get(pad.deviceId_deviceDescriptor.get(joy));
+
+ if (playerNum != null) {
+ String id = pad.portId[playerNum];
+ pad.custom[playerNum] = prefs.getBoolean("modified_key_layout" + id, false);
+ pad.compat[playerNum] = prefs.getBoolean("controller_compat" + id, false);
+ if (InputDevice.getDevice(joy).getName()
+ .contains("keypad-zeus")) {
+ pad.playerNumX.put(joy, playerNum);
+ for (int keys : pad.keypadZeus) {
+ pad.playerNumX.put(keys, playerNum);
+ }
+ if (pad.custom[playerNum]) {
+ setCustomMapping(id, playerNum);
+ } else {
+ pad.map[playerNum] = pad.getXPlayController();
+ }
+ } else {
+ if (!pad.compat[playerNum]) {
+ if (pad.custom[playerNum]) {
+ setCustomMapping(id, playerNum);
+ } else if (InputDevice.getDevice(joy).getName()
+ .equals("Sony PLAYSTATION(R)3 Controller")) {
+ pad.map[playerNum] = pad.getConsoleController();
+ } else if (InputDevice.getDevice(joy).getName()
+ .equals("Microsoft X-Box 360 pad")) {
+ pad.map[playerNum] = pad.getConsoleController();
+ } else if (InputDevice.getDevice(joy).getName()
+ .contains("NVIDIA Corporation NVIDIA Controller")) {
+ pad.map[playerNum] = pad.getConsoleController();
+ } else if (!pad.isActiveMoga[playerNum]) { // Ouya controller
+ pad.map[playerNum] = pad.getOUYAController();
+ }
+ } else{
+ getCompatibilityMap(playerNum, id);
+ }
+ initJoyStickLayout(playerNum);
+ pad.playerNumX.put(joy, playerNum);
+ }
+ } else {
+ runCompatibilityMode(joy);
+ }
+ }
+ }
+
+ // When viewing a resource, pass its URI to the native code for opening
+ Intent intent = getIntent();
+ if (intent.getAction().equals(Intent.ACTION_VIEW))
+ fileName = Uri.decode(intent.getData().toString());
+
+ // Create the actual GLES view
+ mView = new GL2JNIView(getApplication(), config, fileName, false,
+ prefs.getInt("depth_render", 24), 0, false);
+ setContentView(mView);
+
+ String menu_spec;
+ if (pad.isXperiaPlay || pad.isOuyaOrTV) {
+ menu_spec = getApplicationContext().getString(R.string.menu_button);
+ } else {
+ menu_spec = getApplicationContext().getString(R.string.back_button);
+ }
+ Toast.makeText(
+ getApplicationContext(),
+ getApplicationContext()
+ .getString(R.string.bios_menu, menu_spec),
+ Toast.LENGTH_SHORT).show();
+
+ //setup mic
+ boolean micPluggedIn = prefs.getBoolean("mic_plugged_in", false);
+ if(micPluggedIn){
+ SipEmulator sip = new SipEmulator();
+ sip.startRecording();
+ JNIdc.setupMic(sip);
+ }
+
+ popUp = menu.new MainPopup(this);
+ vmuPop = menu.new VmuPopup(this);
+ if(prefs.getBoolean("vmu_floating", false)){
+ //kind of a hack - if the user last had the vmu on screen
+ //inverse it and then "toggle"
+ prefs.edit().putBoolean("vmu_floating", false).commit();
+ //can only display a popup after onCreate
+ mView.post(new Runnable() {
+ public void run() {
+ toggleVmu();
+ }
+ });
+ }
+ JNIdc.setupVmu(menu.getVmu());
+ if (prefs.getBoolean("show_fps", false)) {
+ fpsPop = menu.new FpsPopup(this);
+ mView.setFpsDisplay(fpsPop);
+ mView.post(new Runnable() {
+ public void run() {
+ displayFPS();
+ }
+ });
+ }
+ }
+
+ private void setCustomMapping(String id, int playerNum) {
+ pad.map[playerNum] = pad.setModifiedKeys(id, playerNum, prefs);
+ }
+
+ private void initJoyStickLayout(int playerNum) {
+ pad.globalLS_X[playerNum] = pad.previousLS_X[playerNum] = 0.0f;
+ pad.globalLS_Y[playerNum] = pad.previousLS_Y[playerNum] = 0.0f;
+ }
+
+ private void runCompatibilityMode(int joy) {
+ for (int n = 0; n < 4; n++) {
+ if (pad.compat[n]) {
+ getCompatibilityMap(n, pad.portId[n]);
+ pad.playerNumX.put(joy, n);
+ initJoyStickLayout(n);
+ } else {
+ pad.playerNumX.put(joy, -1);
+ }
+ }
+ }
+
+ private void getCompatibilityMap(int playerNum, String id) {
+ pad.name[playerNum] = prefs.getInt("controller" + id, -1);
+ if (pad.name[playerNum] != -1) {
+ pad.map[playerNum] = pad.setModifiedKeys(id, playerNum, prefs);
+ }
+ }
+
+ public boolean simulatedTouchEvent(int playerNum, float L2, float R2) {
+ GL2JNIView.lt[playerNum] = (int) (L2 * 255);
+ GL2JNIView.rt[playerNum] = (int) (R2 * 255);
+ mView.pushInput();
+ return true;
+ }
+
+ public void displayPopUp(PopupWindow popUp) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ popUp.showAtLocation(mView, Gravity.BOTTOM, 0, 60);
+ } else {
+ popUp.showAtLocation(mView, Gravity.BOTTOM, 0, 0);
+ }
+ popUp.update(LayoutParams.WRAP_CONTENT,
+ LayoutParams.WRAP_CONTENT);
+ }
+
+ public void displayDebug(PopupWindow popUpDebug) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ popUpDebug.showAtLocation(mView, Gravity.BOTTOM, 0, 60);
+ } else {
+ popUpDebug.showAtLocation(mView, Gravity.BOTTOM, 0, 0);
+ }
+ popUpDebug.update(LayoutParams.WRAP_CONTENT,
+ LayoutParams.WRAP_CONTENT);
+ }
+
+ public void displayFPS() {
+ fpsPop.showAtLocation(mView, Gravity.TOP | Gravity.LEFT, 20, 20);
+ fpsPop.update(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ }
+
+ public void toggleVmu() {
+ boolean showFloating = !prefs.getBoolean("vmu_floating", false);
+ if(showFloating){
+ if(popUp.isShowing()){
+ popUp.dismiss();
+ }
+ //remove from popup menu
+ LinearLayout parent = (LinearLayout) popUp.getContentView();
+ parent.removeView(menu.getVmu());
+ //add to floating window
+ vmuPop.showVmu();
+ vmuPop.showAtLocation(mView, Gravity.TOP | Gravity.RIGHT, 4, 4);
+ vmuPop.update(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ }else{
+ vmuPop.dismiss();
+ //remove from floating window
+ LinearLayout parent = (LinearLayout) vmuPop.getContentView();
+ parent.removeView(menu.getVmu());
+ //add back to popup menu
+ popUp.showVmu();
+ }
+ prefs.edit().putBoolean("vmu_floating", showFloating).commit();
+ }
+
+ public void displayConfig(PopupWindow popUpConfig) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ popUpConfig.showAtLocation(mView, Gravity.BOTTOM, 0, 60);
+ } else {
+ popUpConfig.showAtLocation(mView, Gravity.BOTTOM, 0, 0);
+ }
+ popUpConfig.update(LayoutParams.WRAP_CONTENT,
+ LayoutParams.WRAP_CONTENT);
+ }
+
+ @Override
+ public boolean onGenericMotionEvent(MotionEvent event) {
+ // Log.w("INPUT", event.toString() + " " + event.getSource());
+ // Get all the axis for the KeyEvent
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD
+ && event.getSource() != Gamepad.Xperia_Touchpad) {
+
+ Integer playerNum = Arrays.asList(pad.name).indexOf(event.getDeviceId());
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD && playerNum == -1) {
+ playerNum = pad.deviceDescriptor_PlayerNum
+ .get(pad.deviceId_deviceDescriptor.get(event.getDeviceId()));
+ } else {
+ playerNum = -1;
+ }
+ if (playerNum == null || playerNum == -1) {
+ return false;
+ }
+ if (!pad.compat[playerNum] && !pad.isActiveMoga[playerNum]) {
+ // TODO: Moga should handle this locally
+
+ // Joystick
+ if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
+
+ // do other things with joystick
+ float LS_X = event.getAxisValue(OuyaController.AXIS_LS_X);
+ float LS_Y = event.getAxisValue(OuyaController.AXIS_LS_Y);
+ float RS_X = event.getAxisValue(OuyaController.AXIS_RS_X);
+ float RS_Y = event.getAxisValue(OuyaController.AXIS_RS_Y);
+ float L2 = event.getAxisValue(OuyaController.AXIS_L2);
+ float R2 = event.getAxisValue(OuyaController.AXIS_R2);
+
+ pad.previousLS_X[playerNum] = pad.globalLS_X[playerNum];
+ pad.previousLS_Y[playerNum] = pad.globalLS_Y[playerNum];
+ pad.globalLS_X[playerNum] = LS_X;
+ pad.globalLS_Y[playerNum] = LS_Y;
+
+ GL2JNIView.lt[playerNum] = (int) (L2 * 255);
+ GL2JNIView.rt[playerNum] = (int) (R2 * 255);
+
+ GL2JNIView.jx[playerNum] = (int) (LS_X * 126);
+ GL2JNIView.jy[playerNum] = (int) (LS_Y * 126);
+
+ if (prefs.getBoolean("right_buttons", true)) {
+ if (RS_Y > 0.5) {
+ handle_key(playerNum, pad.map[playerNum][0]/* A */, true);
+ pad.wasKeyStick[playerNum] = true;
+ } else if (RS_Y < 0.5) {
+ handle_key(playerNum, pad.map[playerNum][1]/* B */, true);
+ pad.wasKeyStick[playerNum] = true;
+ } else if (pad.wasKeyStick[playerNum]){
+ handle_key(playerNum, pad.map[playerNum][0], false);
+ handle_key(playerNum, pad.map[playerNum][1], false);
+ pad.wasKeyStick[playerNum] = false;
+ }
+ } else {
+ if (RS_Y > 0.5) {
+ GL2JNIView.rt[playerNum] = (int) (RS_Y * 255);
+ } else if (RS_Y < 0.5) {
+ GL2JNIView.lt[playerNum] = (int) (-(RS_Y) * 255);
+ }
+ }
+ }
+ mView.pushInput();
+ }
+ if ((pad.globalLS_X[playerNum] == pad.previousLS_X[playerNum] && pad.globalLS_Y[playerNum] == pad.previousLS_Y[playerNum])
+ || (pad.previousLS_X[playerNum] == 0.0f && pad.previousLS_Y[playerNum] == 0.0f))
+ // Only handle Left Stick on an Xbox 360 controller if there was
+ // some actual motion on the stick,
+ // so otherwise the event can be handled as a DPAD event
+ return false;
+ else
+ return true;
+ }
+ return false;
+
+ }
+
+ boolean handle_key(Integer playerNum, int kc, boolean down) {
+ if (playerNum == null || playerNum == -1)
+ return false;
+ if (kc == pad.getSelectButtonCode()) {
+ return false;
+ }
+ if (pad.isActiveMoga[playerNum]) {
+ return false;
+ }
+
+ boolean rav = false;
+ for (int i = 0; i < pad.map[playerNum].length; i += 2) {
+ if (pad.map[playerNum][i + 0] == kc) {
+ if (down)
+ GL2JNIView.kcode_raw[playerNum] &= ~pad.map[playerNum][i + 1];
+ else
+ GL2JNIView.kcode_raw[playerNum] |= pad.map[playerNum][i + 1];
+ rav = true;
+ break;
+ }
+ }
+ mView.pushInput();
+ return rav;
+ }
+
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
+ return super.onKeyUp(keyCode, event);
+ }
+ return true;
+ }
+
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == pad.getSelectButtonCode()) {
+ return showMenu();
+ }
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1
+ || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH
+ && ViewConfiguration.get(this).hasPermanentMenuKey())) {
+ if (keyCode == KeyEvent.KEYCODE_MENU) {
+ return showMenu();
+ }
+ }
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ if (pad.isXperiaPlay) {
+ return true;
+ } else {
+ return showMenu();
+ }
+ }
+ if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
+ return super.onKeyDown(keyCode, event);
+ }
+ return true;
+ }
+
+ public boolean OnNativeKeyPress(int device, int keyCode, int action, int metaState) {
+ Integer playerNum = pad.playerNumX.get(device);
+ if (playerNum != null && playerNum != -1 && !pad.isActiveMoga[playerNum]) {
+ String id = pad.portId[playerNum];
+ if (action == KeyEvent.ACTION_DOWN) {
+ if (keyCode == prefs.getInt("l_button" + id, KeyEvent.KEYCODE_BUTTON_L1)) {
+ return simulatedTouchEvent(playerNum, 1.0f, 0.0f);
+ } else if (keyCode == prefs.getInt("r_button" + id, KeyEvent.KEYCODE_BUTTON_R1)) {
+ return simulatedTouchEvent(playerNum, 0.0f, 1.0f);
+ } else if (handle_key(playerNum, keyCode, true)) {
+ if (playerNum == 0)
+ JNIdc.hide_osd();
+ return true;
+ }
+ }
+ if (action == KeyEvent.ACTION_UP) {
+ if (keyCode == prefs.getInt("l_button" + id,
+ KeyEvent.KEYCODE_BUTTON_L1)
+ || keyCode == prefs.getInt("r_button" + id,
+ KeyEvent.KEYCODE_BUTTON_R1)) {
+ return simulatedTouchEvent(playerNum, 0.0f, 0.0f);
+ } else {
+ return handle_key(playerNum, keyCode, false);
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean OnNativeMotion(int device, int source, int action, int x, int y, boolean newEvent) {
+ if (newEvent && source == Gamepad.Xperia_Touchpad) {
+ // Source is Xperia Play touchpad
+ Integer playerNum = pad.playerNumX.get(device);
+ if (playerNum != null && playerNum != -1 && !pad.isActiveMoga[playerNum]) {
+ Log.d("reidc", playerNum + " - " + device + ": " + source);
+ if (action == MotionEvent.ACTION_UP) {
+ x = 0;
+ y = 0;
+ }
+ // Sensitive! Zero out the touchpad release
+ if (x > 360 && x < 500) {
+ x = 360;
+ } else if (x > 500 && x < 640) {
+ x = 640;
+ }
+ if (x >= 640) {
+ x = x - 640;
+ }
+ y = 366 - y;
+ // Right stick is an extension of left stick
+ // 360 to 640 is the live gap between sticks
+ // The y-axis is inverted from normal layout
+ // Imagine it as a small MacBook touch mouse
+
+ GL2JNIView.jx[playerNum] = (int) (x * 126);
+ GL2JNIView.jy[playerNum] = (int) (y * 126);
+ mView.pushInput();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean showMenu() {
+ if (popUp != null) {
+ if (!menu.dismissPopUps()) {
+ if (!popUp.isShowing()) {
+ displayPopUp(popUp);
+ } else {
+ popUp.dismiss();
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mView.onPause();
+ moga.onPause();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ moga.onDestroy();
+ }
+
+ @Override
+ protected void onStop() {
+ JNIdc.stop();
+ mView.onStop();
+ super.onStop();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mView.onResume();
+ moga.onResume();
+ }
+}
diff --git a/shell/android/src/com/reicast/emulator/MainActivity.java b/shell/android/src/com/reicast/emulator/MainActivity.java
index d1d8c32b4..5f9bae499 100644
--- a/shell/android/src/com/reicast/emulator/MainActivity.java
+++ b/shell/android/src/com/reicast/emulator/MainActivity.java
@@ -64,21 +64,21 @@ public class MainActivity extends SlidingFragmentActivity implements
mUEHandler = new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable error) {
- if (error != null) {
- StringBuilder output = new StringBuilder();
- output.append("Thread:\n");
- for (StackTraceElement trace : t.getStackTrace()) {
- output.append(trace.toString() + " ");
+ if (error != null) {
+ StringBuilder output = new StringBuilder();
+ output.append("Thread:\n");
+ for (StackTraceElement trace : t.getStackTrace()) {
+ output.append(trace.toString() + "\n");
+ }
+ output.append("\nError:\n");
+ for (StackTraceElement trace : error.getStackTrace()) {
+ output.append(trace.toString() + "\n");
+ }
+ String log = output.toString();
+ mPrefs.edit().putString("prior_error", log).commit();
+ error.printStackTrace();
+ MainActivity.this.finish();
}
- output.append("\n\nError:\n");
- for (StackTraceElement trace : error.getStackTrace()) {
- output.append(trace.toString() + " ");
- }
- String log = output.toString();
- mPrefs.edit().putString("prior_error", log).commit();
- error.printStackTrace();
- MainActivity.this.finish();
- }
}
};
Thread.setDefaultUncaughtExceptionHandler(mUEHandler);
@@ -292,10 +292,8 @@ public class MainActivity extends SlidingFragmentActivity implements
/**
* Display a dialog to notify the user of prior crash
*
- * @param string
+ * @param error
* A generalized summary of the crash cause
- * @param bundle
- * The savedInstanceState passed from onCreate
*/
private void initiateReport(final String error) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
@@ -407,9 +405,13 @@ public class MainActivity extends SlidingFragmentActivity implements
// show it
alertDialog.show();
} else {
- Intent inte = new Intent(Intent.ACTION_VIEW, uri, getBaseContext(),
- GL2JNIActivity.class);
- startActivity(inte);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
+ startActivity(new Intent(Intent.ACTION_VIEW, uri, getBaseContext(),
+ GL2JNINative.class));
+ } else {
+ startActivity(new Intent(Intent.ACTION_VIEW, uri, getBaseContext(),
+ GL2JNIActivity.class));
+ }
}
}
diff --git a/shell/android/src/com/reicast/emulator/emu/GL2JNIView.java b/shell/android/src/com/reicast/emulator/emu/GL2JNIView.java
index eec8544a1..33e7a70d7 100644
--- a/shell/android/src/com/reicast/emulator/emu/GL2JNIView.java
+++ b/shell/android/src/com/reicast/emulator/emu/GL2JNIView.java
@@ -28,6 +28,7 @@ import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener;
import android.view.View;
import com.reicast.emulator.GL2JNIActivity;
+import com.reicast.emulator.GL2JNINative;
import com.reicast.emulator.config.Config;
import com.reicast.emulator.emu.OnScreenMenu.FpsPopup;
import com.reicast.emulator.periph.VJoy;
@@ -169,8 +170,13 @@ public class GL2JNIView extends GLSurfaceView
// This is the game we are going to run
fileName = newFileName;
- if (GL2JNIActivity.syms != null)
- JNIdc.data(1, GL2JNIActivity.syms);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
+ if (GL2JNINative.syms != null)
+ JNIdc.data(1, GL2JNINative.syms);
+ } else {
+ if (GL2JNIActivity.syms != null)
+ JNIdc.data(1, GL2JNIActivity.syms);
+ }
JNIdc.init(fileName);
diff --git a/shell/android/src/com/reicast/emulator/emu/OnScreenMenu.java b/shell/android/src/com/reicast/emulator/emu/OnScreenMenu.java
index a8d056443..50f5be14a 100644
--- a/shell/android/src/com/reicast/emulator/emu/OnScreenMenu.java
+++ b/shell/android/src/com/reicast/emulator/emu/OnScreenMenu.java
@@ -19,6 +19,7 @@ import android.widget.PopupWindow;
import android.widget.TextView;
import com.reicast.emulator.GL2JNIActivity;
+import com.reicast.emulator.GL2JNINative;
import com.reicast.emulator.MainActivity;
import com.reicast.emulator.R;
import com.reicast.emulator.config.Config;
@@ -46,6 +47,9 @@ public class OnScreenMenu {
private boolean boosted = false;
public OnScreenMenu(Activity context, SharedPreferences prefs) {
+ if (context instanceof GL2JNINative) {
+ this.mContext = (GL2JNINative) context;
+ }
if (context instanceof GL2JNIActivity) {
this.mContext = (GL2JNIActivity) context;
}
@@ -59,6 +63,9 @@ public class OnScreenMenu {
vmuLcd = new VmuLcd(mContext);
vmuLcd.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
+ if (mContext instanceof GL2JNINative) {
+ ((GL2JNINative) OnScreenMenu.this.mContext).toggleVmu();
+ }
if (mContext instanceof GL2JNIActivity) {
((GL2JNIActivity) OnScreenMenu.this.mContext).toggleVmu();
}
@@ -67,9 +74,13 @@ public class OnScreenMenu {
}
void displayDebugPopup(final PopupWindow popUp) {
+ if (mContext instanceof GL2JNINative) {
+ ((GL2JNINative) mContext).displayDebug(new DebugPopup(mContext));
+ }
if (mContext instanceof GL2JNIActivity) {
((GL2JNIActivity) mContext).displayDebug(new DebugPopup(mContext));
}
+
}
public class FpsPopup extends PopupWindow {
@@ -95,6 +106,10 @@ public class OnScreenMenu {
private void removePopUp(PopupWindow window) {
window.dismiss();
popups.remove(window);
+ if (mContext instanceof GL2JNINative) {
+ ((GL2JNINative) mContext)
+ .displayPopUp(((GL2JNINative) OnScreenMenu.this.mContext).popUp);
+ }
if (mContext instanceof GL2JNIActivity) {
((GL2JNIActivity) mContext)
.displayPopUp(((GL2JNIActivity) OnScreenMenu.this.mContext).popUp);
@@ -160,6 +175,9 @@ public class OnScreenMenu {
}
void displayConfigPopup(final PopupWindow popUp) {
+ if (mContext instanceof GL2JNINative) {
+ ((GL2JNINative) mContext).displayConfig(new ConfigPopup(mContext));
+ }
if (mContext instanceof GL2JNIActivity) {
((GL2JNIActivity) mContext)
.displayConfig(new ConfigPopup(mContext));
@@ -262,21 +280,29 @@ public class OnScreenMenu {
new OnClickListener() {
public void onClick(View v) {
if (audio) {
+ if (mContext instanceof GL2JNINative) {
+ ((GL2JNINative) mContext).mView
+ .audioDisable(true);
+ }
if (mContext instanceof GL2JNIActivity) {
((GL2JNIActivity) mContext).mView
.audioDisable(true);
}
+ audio = false;
((ImageButton) audiosetting)
.setImageResource(R.drawable.enable_sound);
- audio = false;
} else {
+ if (mContext instanceof GL2JNINative) {
+ ((GL2JNINative) mContext).mView
+ .audioDisable(false);
+ }
if (mContext instanceof GL2JNIActivity) {
((GL2JNIActivity) mContext).mView
.audioDisable(false);
}
+ audio = true;
((ImageButton) audiosetting)
.setImageResource(R.drawable.mute_sound);
- audio = true;
}
}
});
@@ -292,6 +318,10 @@ public class OnScreenMenu {
fastforward = addbut(R.drawable.star, new OnClickListener() {
public void onClick(View v) {
if (boosted) {
+ if (mContext instanceof GL2JNINative) {
+ ((GL2JNINative) mContext).mView
+ .audioDisable(!audio);
+ }
if (mContext instanceof GL2JNIActivity) {
((GL2JNIActivity) mContext).mView
.audioDisable(!audio);
@@ -301,6 +331,9 @@ public class OnScreenMenu {
framelimit.setEnabled(true);
JNIdc.frameskip(frames);
enableState(fdown, fup);
+ if (mContext instanceof GL2JNINative) {
+ ((GL2JNINative) mContext).mView.fastForward(false);
+ }
if (mContext instanceof GL2JNIActivity) {
((GL2JNIActivity) mContext).mView.fastForward(false);
}
@@ -308,6 +341,10 @@ public class OnScreenMenu {
((ImageButton) fastforward)
.setImageResource(R.drawable.star);
} else {
+ if (mContext instanceof GL2JNINative) {
+ ((GL2JNINative) mContext).mView
+ .audioDisable(true);
+ }
if (mContext instanceof GL2JNIActivity) {
((GL2JNIActivity) mContext).mView
.audioDisable(true);
@@ -318,6 +355,9 @@ public class OnScreenMenu {
JNIdc.frameskip(5);
fdown.setEnabled(false);
fup.setEnabled(false);
+ if (mContext instanceof GL2JNINative) {
+ ((GL2JNINative) mContext).mView.fastForward(true);
+ }
if (mContext instanceof GL2JNIActivity) {
((GL2JNIActivity) mContext).mView.fastForward(true);
}
diff --git a/shell/android/src/com/reicast/emulator/periph/Gamepad.java b/shell/android/src/com/reicast/emulator/periph/Gamepad.java
index b63aa5683..ee9ad2ea7 100644
--- a/shell/android/src/com/reicast/emulator/periph/Gamepad.java
+++ b/shell/android/src/com/reicast/emulator/periph/Gamepad.java
@@ -6,7 +6,6 @@ import java.util.List;
import tv.ouya.console.api.OuyaController;
import tv.ouya.console.api.OuyaFacade;
-import android.annotation.TargetApi;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
@@ -103,7 +102,6 @@ public class Gamepad {
};
}
- @TargetApi(Build.VERSION_CODES.GINGERBREAD)
public int[] getMogaController() {
return new int[] {
KeyEvent.KEYCODE_BUTTON_A, key_CONT_A,
diff --git a/shell/android/src/com/reicast/emulator/periph/SipEmulator.java b/shell/android/src/com/reicast/emulator/periph/SipEmulator.java
index 491c6bd8a..f480a9e22 100644
--- a/shell/android/src/com/reicast/emulator/periph/SipEmulator.java
+++ b/shell/android/src/com/reicast/emulator/periph/SipEmulator.java
@@ -98,8 +98,7 @@ public class SipEmulator extends Thread {
while(continueRecording){
byte[] freshData = new byte[ONE_BLIP_SIZE];
// read blocks
- int bytesRead = record.read(freshData, 0, ONE_BLIP_SIZE);
- //Log.d(TAG, "recordThread recorded: "+bytesRead);
+ record.read(freshData, 0, ONE_BLIP_SIZE);
if(!firstGet){
bytesReadBuffer.add(freshData);
}
diff --git a/shell/android/xperia/jni/Android.mk b/shell/android/xperia/jni/Android.mk
new file mode 100644
index 000000000..a3af19b1f
--- /dev/null
+++ b/shell/android/xperia/jni/Android.mk
@@ -0,0 +1,13 @@
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := sexplay
+LOCAL_SRC_FILES := XperiaPlay.c
+LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv1_CM
+LOCAL_STATIC_LIBRARIES := android_native_app_glue
+
+include $(BUILD_SHARED_LIBRARY)
+
+$(call import-module,android/native_app_glue)
\ No newline at end of file
diff --git a/shell/android/xperia/jni/Application.mk b/shell/android/xperia/jni/Application.mk
new file mode 100644
index 000000000..8bb9d5db9
--- /dev/null
+++ b/shell/android/xperia/jni/Application.mk
@@ -0,0 +1,3 @@
+APP_ABI := armeabi-v7a
+APP_PLATFORM := android-9
+NDK_TOOLCHAIN_VERSION := 4.8
\ No newline at end of file
diff --git a/shell/android/xperia/jni/XperiaPlay.c b/shell/android/xperia/jni/XperiaPlay.c
new file mode 100755
index 000000000..89bebc8b0
--- /dev/null
+++ b/shell/android/xperia/jni/XperiaPlay.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2011, Sony Ericsson Mobile Communications AB.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Sony Ericsson Mobile Communications AB nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define EXPORT_XPLAY __attribute__ ((visibility("default")))
+
+static JavaVM *jVM;
+
+typedef unsigned char BOOL;
+#define FALSE 0
+#define TRUE 1
+
+static jobject g_pActivity = 0;
+static jmethodID javaOnNDKTouch = 0;
+static jmethodID javaOnNDKKey = 0;
+
+int target;
+
+/**
+ * Our saved state data.
+ */
+struct TOUCHSTATE
+{
+ int down;
+ int x;
+ int y;
+};
+
+/**
+ * Shared state for our app.
+ */
+struct ENGINE
+{
+ struct android_app* app;
+ int render;
+ int width;
+ int height;
+ int has_focus;
+ //ugly way to track touch states
+ struct TOUCHSTATE touchstate_screen[64];
+ struct TOUCHSTATE touchstate_pad[64];
+};
+
+void attach(){
+
+}
+
+/**
+ * Process the next input event.
+ */
+static
+int32_t
+engine_handle_input( struct android_app* app, AInputEvent* event )
+{
+ JNIEnv *jni;
+ (*jVM)->AttachCurrentThread(jVM, &jni, NULL);
+
+ struct ENGINE* engine = (struct ENGINE*)app->userData;
+ if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY){
+ int device = AInputEvent_getDeviceId(event);
+ int action = AKeyEvent_getAction(event);
+ int keyCode = AKeyEvent_getKeyCode(event);
+ if(jni && g_pActivity){
+ if((*jni)->ExceptionCheck(jni)) {
+ (*jni)->ExceptionDescribe(jni);
+ (*jni)->ExceptionClear(jni);
+ }
+ (*jni)->CallIntMethod(jni, g_pActivity, javaOnNDKKey, device, keyCode, action, AKeyEvent_getMetaState(event));
+ if (!(keyCode == AKEYCODE_MENU || keyCode == AKEYCODE_BACK || keyCode == AKEYCODE_BUTTON_THUMBR || keyCode == AKEYCODE_VOLUME_UP || keyCode == AKEYCODE_VOLUME_DOWN || keyCode == AKEYCODE_BUTTON_SELECT)) {
+ return 1;
+ }
+ }
+ } else if( AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION ) {
+ int device = AInputEvent_getDeviceId( event );
+ int nSourceId = AInputEvent_getSource( event );
+ int nPointerCount = AMotionEvent_getPointerCount( event );
+ int n;
+
+ jboolean newTouch = JNI_TRUE;
+ for( n = 0 ; n < nPointerCount ; ++n )
+ {
+ int nPointerId = AMotionEvent_getPointerId( event, n );
+ int nAction = AMOTION_EVENT_ACTION_MASK & AMotionEvent_getAction( event );
+ int nRawAction = AMotionEvent_getAction( event );
+
+ struct TOUCHSTATE *touchstate = 0;
+ if( nSourceId == AINPUT_SOURCE_TOUCHPAD ) {
+ touchstate = engine->touchstate_pad;
+ } else {
+ touchstate = engine->touchstate_screen;
+ }
+
+ if( nAction == AMOTION_EVENT_ACTION_POINTER_DOWN || nAction == AMOTION_EVENT_ACTION_POINTER_UP )
+ {
+ int nPointerIndex = (AMotionEvent_getAction( event ) & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+ nPointerId = AMotionEvent_getPointerId( event, nPointerIndex );
+ }
+
+ if( nAction == AMOTION_EVENT_ACTION_DOWN || nAction == AMOTION_EVENT_ACTION_POINTER_DOWN )
+ {
+ touchstate[nPointerId].down = 1;
+ }
+ else if( nAction == AMOTION_EVENT_ACTION_UP || nAction == AMOTION_EVENT_ACTION_POINTER_UP || nAction == AMOTION_EVENT_ACTION_CANCEL )
+ {
+ touchstate[nPointerId].down = 0;
+ }
+
+ if (touchstate[nPointerId].down == 1)
+ {
+ touchstate[nPointerId].x = AMotionEvent_getX( event, n );
+ touchstate[nPointerId].y = AMotionEvent_getY( event, n );
+ }
+ if( jni && g_pActivity && device == target ) {
+ (*jni)->CallVoidMethod( jni, g_pActivity, javaOnNDKTouch, device, nSourceId, nRawAction, touchstate[nPointerId].x, touchstate[nPointerId].y, newTouch);
+ }
+ newTouch = JNI_FALSE;
+ }
+ if( device == target ) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Process the next main command.
+ */
+static
+void
+engine_handle_cmd( struct android_app* app, int32_t cmd )
+{
+ struct ENGINE* engine = (struct ENGINE*)app->userData;
+ switch( cmd )
+ {
+ case APP_CMD_SAVE_STATE:
+ // The system has asked us to save our current state. Do so if needed
+ break;
+ case APP_CMD_INIT_WINDOW:
+ // The window is being shown, get it ready.
+ if( engine->app->window != NULL )
+ {
+ engine->has_focus = 1;
+ }
+ break;
+
+ case APP_CMD_GAINED_FOCUS:
+ engine->has_focus = 1;
+ break;
+
+ case APP_CMD_LOST_FOCUS:
+ // When our app loses focus, we stop rendering.
+ engine->render = 0;
+ engine->has_focus = 0;
+ //engine_draw_frame( engine );
+ break;
+ }
+}
+
+static
+bool
+IsXperiaPlay() {
+ char mod[PROP_VALUE_MAX + 1];
+ int lmod = __system_property_get("ro.product.model", mod);
+ return mod == "R800a" || mod == "R800i" || mod == "R800x" || mod == "R800at" || mod == "SO-01D" || mod == "zeus";
+}
+
+/**
+ * This is the main entry point of a native application that is using
+ * android_native_app_glue. It runs in its own thread, with its own
+ * event loop for receiving input events and doing other things (rendering).
+ */
+void
+android_main( struct android_app* state )
+{
+ struct ENGINE engine;
+
+ // Make sure glue isn't stripped.
+ app_dummy();
+
+ memset( &engine, 0, sizeof(engine) );
+ state->userData = &engine;
+ state->onAppCmd = engine_handle_cmd;
+ state->onInputEvent = engine_handle_input;
+ engine.app = state;
+
+ //setup(state);
+ //JNIEnv *env;
+ //(*jVM)->AttachCurrentThread(jVM, &env, NULL);
+
+ if( state->savedState != NULL )
+ {
+ // We are starting with a previous saved state; restore from it.
+ }
+ // our 'main loop'
+ while( 1 )
+ {
+ // Read all pending events.
+ int ident;
+ int events;
+ struct android_poll_source* source;
+ // If not rendering, we will block forever waiting for events.
+ // If rendering, we loop until all events are read, then continue
+ // to draw the next frame.
+ while( (ident = ALooper_pollAll( 250, NULL, &events, (void**)&source) ) >= 0 )
+ {
+ // Process this event.
+ // This will call the function pointer android_app:nInputEvent() which in our case is
+ // engine_handle_input()
+ if( source != NULL )
+ {
+ source->process( state, source );
+ }
+ // Check if we are exiting.
+ if( state->destroyRequested != 0 )
+ {
+ return;
+ }
+ //usleep(20000); //20 miliseconds
+ }
+ }
+}
+
+void EXPORT_XPLAY JNICALL Java_com_reicast_emulator_GL2JNINative_registerNative(JNIEnv *env, jobject clazz)
+{
+ g_pActivity = (jobject)(*env)->NewGlobalRef(env, clazz);
+}
+void EXPORT_XPLAY JNICALL Java_com_reicast_emulator_GL2JNINative_registerXperia(JNIEnv *env, jobject clazz, jint xperia)
+{
+ target = xperia;
+}
+jint EXPORT_XPLAY JNICALL JNI_OnLoad(JavaVM * vm, void * reserved)
+{
+ JNIEnv *env;
+ jVM = vm;
+ if((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK)
+ {
+ return -1;
+ }
+ const char* interface_path = "com/reicast/emulator/GL2JNINative";
+ jclass java_activity_class = (*env)->FindClass( env, interface_path );
+ javaOnNDKTouch = (*env)->GetMethodID( env, java_activity_class, "OnNativeMotion", "(IIIIIZ)Z");
+ javaOnNDKKey = (*env)->GetMethodID( env, java_activity_class, "OnNativeKeyPress", "(IIII)Z");
+ return JNI_VERSION_1_4;
+}