From 41e044ae012c6b33ea6c9c88860be787b4b5d09e Mon Sep 17 00:00:00 2001 From: Miso Kim Date: Wed, 23 Aug 2017 12:09:38 +0900 Subject: Modification for Android build (NDK r14b, build-tools 21.1.2 and gradle 2.2.1) (#2585) --- android-project/app/build.gradle | 8 +- android-project/app/src/main/AndroidManifest.xml | 2 +- android-project/app/src/main/assets/mame.ini | 201 +++++++++++++++++++++ android-project/app/src/main/assets/ui.ini | 60 ++++++ .../src/main/java/org/libsdl/app/SDLActivity.java | 198 +++++++++++++++----- .../app/src/main/java/org/mamedev/mame/MAME.java | 77 +++++++- android-project/settings.gradle | 2 + 7 files changed, 500 insertions(+), 48 deletions(-) create mode 100644 android-project/app/src/main/assets/mame.ini create mode 100644 android-project/app/src/main/assets/ui.ini (limited to 'android-project') diff --git a/android-project/app/build.gradle b/android-project/app/build.gradle index 4ee2ec059e7..35377908b88 100644 --- a/android-project/app/build.gradle +++ b/android-project/app/build.gradle @@ -1,13 +1,13 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 18 - buildToolsVersion "23.0.3" + compileSdkVersion 21 + buildToolsVersion "21.1.2" defaultConfig { applicationId "org.mamedev.mame" - minSdkVersion 18 - targetSdkVersion 18 + minSdkVersion 21 + targetSdkVersion 21 ndk { moduleName 'main' diff --git a/android-project/app/src/main/AndroidManifest.xml b/android-project/app/src/main/AndroidManifest.xml index 087d63f2763..7b235a4b2fd 100644 --- a/android-project/app/src/main/AndroidManifest.xml +++ b/android-project/app/src/main/AndroidManifest.xml @@ -33,7 +33,7 @@ android:hardwareAccelerated="true" > diff --git a/android-project/app/src/main/assets/mame.ini b/android-project/app/src/main/assets/mame.ini new file mode 100644 index 00000000000..73064edeece --- /dev/null +++ b/android-project/app/src/main/assets/mame.ini @@ -0,0 +1,201 @@ +# +# CORE CONFIGURATION OPTIONS +# +readconfig 1 +writeconfig 0 + +# +# CORE SEARCH PATH OPTIONS +# +homepath . +rompath roms;/sdcard/Download;/sdcard/mame/roms +hashpath hash +samplepath samples +artpath artwork +ctrlrpath ctrlr +inipath . +fontpath . +cheatpath cheat +crosshairpath crosshair +pluginspath plugins +languagepath language +swpath software + +# +# CORE OUTPUT DIRECTORY OPTIONS +# +cfg_directory cfg +nvram_directory nvram +input_directory inp +state_directory sta +snapshot_directory snap +diff_directory diff +comment_directory comments + +# +# CORE STATE/PLAYBACK OPTIONS +# +state +autosave 1 +playback +record +record_timecode 0 +exit_after_playback 0 +mngwrite +aviwrite +wavwrite +snapname %g/%i +snapsize auto +snapview internal +snapbilinear 1 +statename %g +burnin 0 + +# +# CORE PERFORMANCE OPTIONS +# +autoframeskip 1 +frameskip 8 +seconds_to_run 0 +throttle 1 +sleep 0 +speed 1.0 +refreshspeed 30 + +# +# CORE RENDER OPTIONS +# +keepaspect 1 +unevenstretch 1 +unevenstretchx 0 +unevenstretchy 0 +autostretchxy 0 +intoverscan 0 +intscalex 0 +intscaley 0 + +# +# CORE ROTATION OPTIONS +# +rotate 1 +ror 0 +rol 0 +autoror 0 +autorol 0 +flipx 0 +flipy 0 + +# +# CORE ARTWORK OPTIONS +# +artwork_crop 0 +use_backdrops 1 +use_overlays 1 +use_bezels 1 +use_cpanels 1 +use_marquees 1 + +# +# CORE SCREEN OPTIONS +# +brightness 1.0 +contrast 1.0 +gamma 1.0 +pause_brightness 0.65 +effect none + +# +# CORE VECTOR OPTIONS +# +beam_width_min 1.0 +beam_width_max 1.0 +beam_intensity_weight 0 +flicker 0 + +# +# CORE SOUND OPTIONS +# +samplerate 48000 +samples 1 +volume 0 + +# +# CORE INPUT OPTIONS +# +coin_lockout 1 +ctrlr +mouse 0 +joystick 1 +lightgun 0 +multikeyboard 0 +multimouse 0 +steadykey 0 +ui_active 1 +offscreen_reload 0 +joystick_map auto +joystick_deadzone 0.3 +joystick_saturation 0.85 +natural 0 +joystick_contradictory 0 +coin_impulse 0 + +# +# CORE INPUT AUTOMATIC ENABLE OPTIONS +# +paddle_device keyboard +adstick_device keyboard +pedal_device keyboard +dial_device keyboard +trackball_device keyboard +lightgun_device keyboard +positional_device keyboard +mouse_device mouse + +# +# CORE DEBUGGING OPTIONS +# +verbose 0 +log 0 +oslog 0 +debug 0 +update_in_pause 0 +debugscript + +# +# CORE COMM OPTIONS +# +comm_localhost 0.0.0.0 +comm_localport 15112 +comm_remotehost 127.0.0.1 +comm_remoteport 15112 + +# +# CORE MISC OPTIONS +# +drc 1 +drc_use_c 0 +drc_log_uml 0 +drc_log_native 0 +bios +cheat 0 +skip_gameinfo 1 +uifont default +ui cabinet +ramsize +confirm_quit 0 +ui_mouse 1 +autoboot_command +autoboot_delay 0 +autoboot_script +console 0 +plugins 1 +plugin +noplugin +language English + +# +# HTTP SERVER OPTIONS +# +http 0 +http_port 8080 +http_root web diff --git a/android-project/app/src/main/assets/ui.ini b/android-project/app/src/main/assets/ui.ini new file mode 100644 index 00000000000..55f09f7897a --- /dev/null +++ b/android-project/app/src/main/assets/ui.ini @@ -0,0 +1,60 @@ +# +# UI SEARCH PATH OPTIONS +# +historypath history;dats;. +extrainipath folders +cabinets_directory cabinets;cabdevs +cpanels_directory cpanel +pcbs_directory pcb +flyers_directory flyers +titles_directory titles +ends_directory ends +marquees_directory marquees +artwork_preview_directory "artwork preview;artpreview" +bosses_directory bosses +logos_directory logo +scores_directory scores +versus_directory versus +gameover_directory gameover +howto_directory howto +select_directory select +icons_directory icons +covers_directory covers +ui_path ui + +# +# UI MISC OPTIONS +# +remember_last 1 +enlarge_snaps 1 +forced4x3 1 +use_background 1 +skip_biosmenu 1 +skip_partsmenu 1 +last_used_filter Available +last_used_machine narc +info_audit_enabled 0 +hide_romless 1 + +# +# UI OPTIONS +# +infos_text_size 1 +font_rows 30 +hide_main_panel 0 +ui_border_color ffffffff +ui_bg_color ef101030 +ui_clone_color ff808080 +ui_dipsw_color ffffff00 +ui_gfxviewer_color ef101030 +ui_mousedown_bg_color b0606000 +ui_mousedown_color ffffff80 +ui_mouseover_bg_color 70404000 +ui_mouseover_color ffffff80 +ui_selected_bg_color ef808000 +ui_selected_color ffffff00 +ui_slider_color ffffffff +ui_subitem_color ffffffff +ui_text_bg_color ef000000 +ui_text_color ffffffff +ui_unavail_color ff404040 diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java index 0a2e5d87e31..39db993d18a 100644 --- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java +++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java @@ -17,7 +17,7 @@ import android.view.inputmethod.BaseInputConnection; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; -import android.widget.AbsoluteLayout; +import android.widget.RelativeLayout; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; @@ -29,6 +29,9 @@ import android.graphics.drawable.Drawable; import android.media.*; import android.hardware.*; import android.content.pm.ActivityInfo; +import java.io.*; +import android.content.res.AssetManager; +import android.content.res.Configuration; /** SDL Activity @@ -59,6 +62,7 @@ public class SDLActivity extends Activity { // Audio protected static AudioTrack mAudioTrack; + protected static AudioRecord mAudioRecord; /** * This method is called by SDL before loading the native shared libraries. @@ -106,13 +110,14 @@ public class SDLActivity extends Activity { mJoystickHandler = null; mSDLThread = null; mAudioTrack = null; + mAudioRecord = null; mExitCalledFromJava = false; mBrokenLibraries = false; mIsPaused = false; mIsSurfaceReady = false; mHasFocus = true; } - + // Setup @Override protected void onCreate(Bundle savedInstanceState) { @@ -171,7 +176,7 @@ public class SDLActivity extends Activity { mJoystickHandler = new SDLJoystickHandler(); } - mLayout = new AbsoluteLayout(this); + mLayout = new RelativeLayout(this); mLayout.addView(mSurface); setContentView(mLayout); @@ -186,6 +191,15 @@ public class SDLActivity extends Activity { SDLActivity.onNativeDropFile(filename); } } + + View decorView = getWindow().getDecorView(); + // Hide both the navigation bar and the status bar. + // SYSTEM_UI_FLAG_FULLSCREEN is only available on Android 4.1 and higher, but as + // a general rule, you should design your app to hide the status bar whenever you + // hide the navigation bar. + int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN; + decorView.setSystemUiVisibility(uiOptions); } // Events @@ -272,6 +286,11 @@ public class SDLActivity extends Activity { // Reset everything in case the user re opens the app SDLActivity.initialize(); } + + @Override + public void onBackPressed() { + super.onBackPressed(); + } @Override public boolean dispatchKeyEvent(KeyEvent event) { @@ -367,10 +386,13 @@ public class SDLActivity extends Activity { break; case COMMAND_TEXTEDIT_HIDE: if (mTextEdit != null) { - mTextEdit.setVisibility(View.GONE); + // Note: On some devices setting view to GONE creates a flicker in landscape. + // Setting the View's sizes to 0 is similar to GONE but without the flicker. + // The sizes will be set to useful values when the keyboard is shown again. + mTextEdit.setLayoutParams(new RelativeLayout.LayoutParams(0, 0)); - InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(mTextEdit.getWindowToken(), 0); + // InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + // imm.hideSoftInputFromWindow(mTextEdit.getWindowToken(), 0); } break; case COMMAND_SET_KEEP_SCREEN_ON: @@ -504,8 +526,9 @@ public class SDLActivity extends Activity { @Override public void run() { - AbsoluteLayout.LayoutParams params = new AbsoluteLayout.LayoutParams( - w, h + HEIGHT_PADDING, x, y); + RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(w, h + HEIGHT_PADDING); + params.leftMargin = x; + params.topMargin = y; if (mTextEdit == null) { mTextEdit = new DummyEdit(getContext()); @@ -528,7 +551,8 @@ public class SDLActivity extends Activity { */ public static boolean showTextInput(int x, int y, int w, int h) { // Transfer the task to the main thread as a Runnable - return mSingleton.commandHandler.post(new ShowTextInputTask(x, y, w, h)); +// return mSingleton.commandHandler.post(new ShowTextInputTask(x, y, w, h)); + return true; } /** @@ -543,7 +567,7 @@ public class SDLActivity extends Activity { /** * This method is called by SDL using JNI. */ - public static int audioInit(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) { + public static int audioOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) { int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO; int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT; int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1); @@ -622,13 +646,72 @@ public class SDLActivity extends Activity { /** * This method is called by SDL using JNI. */ - public static void audioQuit() { + public static int captureOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) { + int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO; + int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT; + int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1); + + Log.v(TAG, "SDL capture: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer"); + + // Let the user pick a larger buffer if they really want -- but ye + // gods they probably shouldn't, the minimums are horrifyingly high + // latency already + desiredFrames = Math.max(desiredFrames, (AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize); + + if (mAudioRecord == null) { + mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, sampleRate, + channelConfig, audioFormat, desiredFrames * frameSize); + + // see notes about AudioTrack state in audioOpen(), above. Probably also applies here. + if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) { + Log.e(TAG, "Failed during initialization of AudioRecord"); + mAudioRecord.release(); + mAudioRecord = null; + return -1; + } + + mAudioRecord.startRecording(); + } + + Log.v(TAG, "SDL capture: got " + ((mAudioRecord.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioRecord.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioRecord.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer"); + + return 0; + } + + /** This method is called by SDL using JNI. */ + public static int captureReadShortBuffer(short[] buffer, boolean blocking) { + // !!! FIXME: this is available in API Level 23. Until then, we always block. :( + //return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING); + return mAudioRecord.read(buffer, 0, buffer.length); + } + + /** This method is called by SDL using JNI. */ + public static int captureReadByteBuffer(byte[] buffer, boolean blocking) { + // !!! FIXME: this is available in API Level 23. Until then, we always block. :( + //return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING); + return mAudioRecord.read(buffer, 0, buffer.length); + } + + + /** This method is called by SDL using JNI. */ + public static void audioClose() { if (mAudioTrack != null) { mAudioTrack.stop(); + mAudioTrack.release(); mAudioTrack = null; } } + /** This method is called by SDL using JNI. */ + public static void captureClose() { + if (mAudioRecord != null) { + mAudioRecord.stop(); + mAudioRecord.release(); + mAudioRecord = null; + } + } + + // Input /** @@ -662,6 +745,21 @@ public class SDLActivity extends Activity { } } + // Check if a given device is considered a possible SDL joystick + public static boolean isDeviceSDLJoystick(int deviceId) { + InputDevice device = InputDevice.getDevice(deviceId); + // We cannot use InputDevice.isVirtual before API 16, so let's accept + // only nonnegative device ids (VIRTUAL_KEYBOARD equals -1) + if ((device == null) || (deviceId < 0)) { + return false; + } + int sources = device.getSources(); + return (((sources & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK) || + ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) || + ((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) + ); + } + // APK expansion files support /** com.android.vending.expansion.zipfile.ZipResourceFile object or null. */ @@ -976,6 +1074,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, // Keep track of the surface size to normalize touch events protected static float mWidth, mHeight; + static float[] px, py; // Startup public SDLSurface(Context context) { @@ -994,10 +1093,11 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, if(Build.VERSION.SDK_INT >= 12) { setOnGenericMotionListener(new SDLGenericMotionListener_API12()); } - // Some arbitrary defaults to avoid a potential division by zero mWidth = 1.0f; mHeight = 1.0f; + px = new float[10]; + py = new float[10]; } public void handlePause() { @@ -1014,6 +1114,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, } public Surface getNativeSurface() { + Log.v("SDL", "getNativeSurface()"); return getHolder().getSurface(); } @@ -1033,7 +1134,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, SDLActivity.mIsSurfaceReady = false; SDLActivity.onNativeSurfaceDestroyed(); } - + // Called when the surface is resized @Override public void surfaceChanged(SurfaceHolder holder, @@ -1088,8 +1189,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, mWidth = width; mHeight = height; SDLActivity.onNativeResize(width, height, sdlFormat, mDisplay.getRefreshRate()); - Log.v("SDL", "Window size: " + width + "x" + height); - + //Log.v("SDL", "Window size: " + width + "x" + height); boolean skip = false; int requestedOrientation = SDLActivity.mSingleton.getRequestedOrientation(); @@ -1137,13 +1237,13 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, final Thread sdlThread = new Thread(new SDLMain(), "SDLThread"); enableSensor(Sensor.TYPE_ACCELEROMETER, true); - sdlThread.start(); // Set up a listener thread to catch when the native thread ends SDLActivity.mSDLThread = new Thread(new Runnable(){ @Override public void run(){ try { + sdlThread.start(); sdlThread.join(); } catch(Exception e){} @@ -1167,11 +1267,14 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, @Override public boolean onKey(View v, int keyCode, KeyEvent event) { // Dispatch the different events depending on where they come from - // Some SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD - // So, we try to process them as DPAD or GAMEPAD events first, if that fails we try them as KEYBOARD - - if ( (event.getSource() & InputDevice.SOURCE_GAMEPAD) != 0 || - (event.getSource() & InputDevice.SOURCE_DPAD) != 0 ) { + // Some SOURCE_JOYSTICK, SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD + // So, we try to process them as JOYSTICK/DPAD/GAMEPAD events first, if that fails we try them as KEYBOARD + // + // Furthermore, it's possible a game controller has SOURCE_KEYBOARD and + // SOURCE_JOYSTICK, while its key events arrive from the keyboard source + // So, retrieve the device itself and check all of its sources + if (SDLActivity.isDeviceSDLJoystick(event.getDeviceId())) { + // Note that we process events with specific key codes here if (event.getAction() == KeyEvent.ACTION_DOWN) { if (SDLActivity.onNativePadDown(event.getDeviceId(), keyCode) == 0) { return true; @@ -1183,7 +1286,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, } } - if( (event.getSource() & InputDevice.SOURCE_KEYBOARD) != 0) { + if ((event.getSource() & InputDevice.SOURCE_KEYBOARD) != 0) { if (event.getAction() == KeyEvent.ACTION_DOWN) { //Log.v("SDL", "key down: " + keyCode); SDLActivity.onNativeKeyDown(keyCode); @@ -1196,6 +1299,20 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, } } + if ((event.getSource() & InputDevice.SOURCE_MOUSE) != 0) { + // on some devices key events are sent for mouse BUTTON_BACK/FORWARD presses + // they are ignored here because sending them as mouse input to SDL is messy + if ((keyCode == KeyEvent.KEYCODE_BACK) || (keyCode == KeyEvent.KEYCODE_FORWARD)) { + switch (event.getAction()) { + case KeyEvent.ACTION_DOWN: + case KeyEvent.ACTION_UP: + // mark the event as handled or it will be handled by system + // handling KEYCODE_BACK by system will call onBackPressed() + return true; + } + } + } + return false; } @@ -1214,7 +1331,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, // !!! FIXME: dump this SDK check after 2.0.4 ships and require API14. if (event.getSource() == InputDevice.SOURCE_MOUSE && SDLActivity.mSeparateMouseAndTouch) { if (Build.VERSION.SDK_INT < 14) { - mouseButton = 1; // For Android==12 all mouse buttons are the left button + mouseButton = 1; // all mouse buttons are the left button } else { try { mouseButton = (Integer) event.getClass().getMethod("getButtonState").invoke(event); @@ -1236,12 +1353,16 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, // see the documentation of getPressure(i) p = 1.0f; } - SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p); +// SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p); + SDLActivity.onNativeMouse(1, action, event.getX(i) - px[i], event.getY(i) - py[i]); + px[i] = event.getX(i); + py[i] = event.getY(i); } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_DOWN: + //SDLActivity.onNativeKeyDown(KeyEvent.KEYCODE_ENTER); // Primary pointer up/down, the index is always zero i = 0; case MotionEvent.ACTION_POINTER_UP: @@ -1260,7 +1381,8 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, // see the documentation of getPressure(i) p = 1.0f; } - SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p); + SDLActivity.onNativeMouse(1, action, 0, 0); + //SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p); break; case MotionEvent.ACTION_CANCEL: @@ -1274,7 +1396,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, // see the documentation of getPressure(i) p = 1.0f; } - SDLActivity.onNativeTouch(touchDevId, pointerFingerId, MotionEvent.ACTION_UP, x, y, p); + //SDLActivity.onNativeTouch(touchDevId, pointerFingerId, MotionEvent.ACTION_UP, x, y, p); } break; @@ -1328,7 +1450,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, } SDLActivity.onNativeAccel(-x / SensorManager.GRAVITY_EARTH, y / SensorManager.GRAVITY_EARTH, - event.values[2] / SensorManager.GRAVITY_EARTH - 1); + event.values[2] / SensorManager.GRAVITY_EARTH); } } } @@ -1355,7 +1477,7 @@ class DummyEdit extends View implements View.OnKeyListener { public boolean onKey(View v, int keyCode, KeyEvent event) { // This handles the hardware keyboard input - if (event.isPrintingKey()) { + if (event.isPrintingKey() || keyCode == KeyEvent.KEYCODE_SPACE) { if (event.getAction() == KeyEvent.ACTION_DOWN) { ic.commitText(String.valueOf((char) event.getUnicodeChar()), 1); } @@ -1368,8 +1490,7 @@ class DummyEdit extends View implements View.OnKeyListener { } else if (event.getAction() == KeyEvent.ACTION_UP) { SDLActivity.onNativeKeyUp(keyCode); return true; - } - + } return false; } @@ -1418,7 +1539,7 @@ class SDLInputConnection extends BaseInputConnection { */ int keyCode = event.getKeyCode(); if (event.getAction() == KeyEvent.ACTION_DOWN) { - if (event.isPrintingKey()) { + if (event.isPrintingKey() || keyCode == KeyEvent.KEYCODE_SPACE) { commitText(String.valueOf((char) event.getUnicodeChar()), 1); } SDLActivity.onNativeKeyDown(keyCode); @@ -1519,13 +1640,7 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler { if (joystick == null) { joystick = new SDLJoystick(); InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]); - - if ( - (joystickDevice.getSources() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0 - || - (joystickDevice.getSources() & InputDevice.SOURCE_CLASS_BUTTON) != 0 - ) - { + if (SDLActivity.isDeviceSDLJoystick(deviceIds[i])) { joystick.device_id = deviceIds[i]; joystick.name = joystickDevice.getName(); joystick.axes = new ArrayList(); @@ -1534,7 +1649,7 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler { List ranges = joystickDevice.getMotionRanges(); Collections.sort(ranges, new RangeComparator()); for (InputDevice.MotionRange range : ranges ) { - if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0 ) { + if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { if (range.getAxis() == MotionEvent.AXIS_HAT_X || range.getAxis() == MotionEvent.AXIS_HAT_Y) { joystick.hats.add(range); @@ -1588,7 +1703,7 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler { @Override public boolean handleMotionEvent(MotionEvent event) { - if ( (event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) { + if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) { int actionPointerIndex = event.getActionIndex(); int action = event.getActionMasked(); switch(action) { @@ -1627,8 +1742,7 @@ class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener { case InputDevice.SOURCE_JOYSTICK: case InputDevice.SOURCE_GAMEPAD: case InputDevice.SOURCE_DPAD: - SDLActivity.handleJoystickMotionEvent(event); - return true; + return SDLActivity.handleJoystickMotionEvent(event); case InputDevice.SOURCE_MOUSE: action = event.getActionMasked(); diff --git a/android-project/app/src/main/java/org/mamedev/mame/MAME.java b/android-project/app/src/main/java/org/mamedev/mame/MAME.java index d243b59159f..d54ab834a1e 100644 --- a/android-project/app/src/main/java/org/mamedev/mame/MAME.java +++ b/android-project/app/src/main/java/org/mamedev/mame/MAME.java @@ -1,9 +1,84 @@ package org.mamedev.mame; +import java.io.*; +import android.app.*; +import android.os.*; +import android.content.res.AssetManager; +import android.util.Log; import org.libsdl.app.SDLActivity; +import android.view.*; +import android.content.pm.ActivityInfo; +import android.content.res.Configuration; /** SDL Activity */ public class MAME extends SDLActivity { + private static final String TAG = "MAME"; + // Setup + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + copyAssetAll("mame.ini"); + copyAssetAll("ui.ini"); + copyAssetAll("roms"); + } + + public void copyAssetAll(String srcPath) { + AssetManager assetMgr = this.getAssets(); + String assets[] = null; + try { + String destPath = getExternalFilesDir(null) + File.separator + srcPath; + assets = assetMgr.list(srcPath); + if (assets.length == 0) { + copyFile(srcPath, destPath); + } else { + File dir = new File(destPath); + if (!dir.exists()) + dir.mkdir(); + for (String element : assets) { + copyAssetAll(srcPath + File.separator + element); + } + } + } + catch (IOException e) { + e.printStackTrace(); + } + } + public void copyFile(String srcFile, String destFile) { + AssetManager assetMgr = this.getAssets(); + + InputStream is = null; + OutputStream os = null; + try { + is = assetMgr.open(srcFile); + if (new File(destFile).exists() == false) + { + os = new FileOutputStream(destFile); + + byte[] buffer = new byte[1024]; + int read; + while ((read = is.read(buffer)) != -1) { + os.write(buffer, 0, read); + } + is.close(); + os.flush(); + os.close(); + Log.v(TAG, "copy from Asset:" + destFile); + } + } + catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { -} + int keyCode = event.getKeyCode(); + // Ignore certain special keys so they're handled by Android + if (((event.getSource() & InputDevice.SOURCE_CLASS_BUTTON) != 0) && (keyCode == KeyEvent.KEYCODE_BACK)) { + android.os.Process.killProcess(android.os.Process.myPid()); + } + return super.dispatchKeyEvent(event); + } + } diff --git a/android-project/settings.gradle b/android-project/settings.gradle index e7b4def49cb..e66d0475ed0 100644 --- a/android-project/settings.gradle +++ b/android-project/settings.gradle @@ -1 +1,3 @@ +gradle.ext.sdkVersion = 21 + include ':app' -- cgit v1.2.3