summaryrefslogtreecommitdiffstatshomepage
path: root/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
diff options
context:
space:
mode:
Diffstat (limited to 'android-project/app/src/main/java/org/libsdl/app/SDLActivity.java')
-rw-r--r--android-project/app/src/main/java/org/libsdl/app/SDLActivity.java198
1 files changed, 156 insertions, 42 deletions
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<InputDevice.MotionRange>();
@@ -1534,7 +1649,7 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler {
List<InputDevice.MotionRange> 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();