From e7fa0c35d5c6b757250466eb6b045470b2fe4fde Mon Sep 17 00:00:00 2001 From: Gerhard Stein Date: Fri, 11 Oct 2013 09:11:24 +0200 Subject: [PATCH] Extra java for SDL2 added, maybe later we can merge it back to one java source later --- changeAppSettings.sh | 17 +- project/javaSDL2/Accelerometer.java | 129 ++ project/javaSDL2/Advertisement.java | 50 + project/javaSDL2/Audio.java | 307 ++++ project/javaSDL2/DataDownloader.java | 758 ++++++++++ project/javaSDL2/GLSurfaceView_SDL.java | 1276 +++++++++++++++++ project/javaSDL2/Globals.java | 125 ++ project/javaSDL2/Keycodes.java | 592 ++++++++ project/javaSDL2/MainActivity.java | 1211 ++++++++++++++++ project/javaSDL2/Settings.java | 782 ++++++++++ project/javaSDL2/SettingsMenu.java | 257 ++++ project/javaSDL2/SettingsMenuKeyboard.java | 843 +++++++++++ project/javaSDL2/SettingsMenuKeyboard.java~ | 843 +++++++++++ project/javaSDL2/SettingsMenuMisc.java | 755 ++++++++++ project/javaSDL2/SettingsMenuMouse.java | 771 ++++++++++ project/javaSDL2/Video.java | 845 +++++++++++ project/javaSDL2/admob/Advertisement.java | 75 + project/javaSDL2/translations/generate.sh | 31 + project/javaSDL2/translations/translate.py | 24 + .../translations/unsupported/readme.txt | 3 + .../unsupported/values-de/strings.xml | 137 ++ .../unsupported/values-fi/strings.xml | 137 ++ .../translations/values-fr/strings.xml | 176 +++ .../translations/values-ru/strings.xml | 149 ++ .../translations/values-uk/strings.xml | 148 ++ .../javaSDL2/translations/values/strings.xml | 181 +++ 26 files changed, 10616 insertions(+), 6 deletions(-) create mode 100644 project/javaSDL2/Accelerometer.java create mode 100644 project/javaSDL2/Advertisement.java create mode 100644 project/javaSDL2/Audio.java create mode 100644 project/javaSDL2/DataDownloader.java create mode 100644 project/javaSDL2/GLSurfaceView_SDL.java create mode 100644 project/javaSDL2/Globals.java create mode 100644 project/javaSDL2/Keycodes.java create mode 100644 project/javaSDL2/MainActivity.java create mode 100644 project/javaSDL2/Settings.java create mode 100644 project/javaSDL2/SettingsMenu.java create mode 100644 project/javaSDL2/SettingsMenuKeyboard.java create mode 100644 project/javaSDL2/SettingsMenuKeyboard.java~ create mode 100644 project/javaSDL2/SettingsMenuMisc.java create mode 100644 project/javaSDL2/SettingsMenuMouse.java create mode 100644 project/javaSDL2/Video.java create mode 100644 project/javaSDL2/admob/Advertisement.java create mode 100755 project/javaSDL2/translations/generate.sh create mode 100755 project/javaSDL2/translations/translate.py create mode 100644 project/javaSDL2/translations/unsupported/readme.txt create mode 100644 project/javaSDL2/translations/unsupported/values-de/strings.xml create mode 100644 project/javaSDL2/translations/unsupported/values-fi/strings.xml create mode 100644 project/javaSDL2/translations/values-fr/strings.xml create mode 100644 project/javaSDL2/translations/values-ru/strings.xml create mode 100644 project/javaSDL2/translations/values-uk/strings.xml create mode 100644 project/javaSDL2/translations/values/strings.xml diff --git a/changeAppSettings.sh b/changeAppSettings.sh index 7cae70600..29b350a16 100755 --- a/changeAppSettings.sh +++ b/changeAppSettings.sh @@ -3,6 +3,7 @@ CHANGE_APP_SETTINGS_VERSION=19 AUTO= CHANGED= +JAVA_SRC_PATH=project/java if [ "X$1" = "X-a" ]; then AUTO=a @@ -34,6 +35,10 @@ if [ -n "$var" ] ; then fi fi +if [ "$LibSdlVersion" = "2.0" ]; then + JAVA_SRC_PATH=project/javaSDL2 +fi + if [ -z "$AppName" -o -z "$AUTO" ]; then echo echo -n "Specify application name (e.x. My Application) ($AppName): " @@ -520,7 +525,7 @@ fi MenuOptionsAvailable= for FF in Menu MenuMisc MenuMouse MenuKeyboard ; do - MenuOptionsAvailable1=`grep 'extends Menu' project/java/Settings$FF.java | sed "s/.* class \(.*\) extends .*/Settings$FF.\1/" | tr '\n' ' '` + MenuOptionsAvailable1=`grep 'extends Menu' $JAVA_SRC_PATH/Settings$FF.java | sed "s/.* class \(.*\) extends .*/Settings$FF.\1/" | tr '\n' ' '` MenuOptionsAvailable="$MenuOptionsAvailable $MenuOptionsAvailable1" done if [ -z "$AUTO" ]; then @@ -1239,10 +1244,10 @@ fi rm -rf project/src mkdir -p project/src -cd project/java +cd $JAVA_SRC_PATH for F in *.java; do echo Patching $F - echo '// DO NOT EDIT THIS FILE - it is automatically generated, ALL YOUR CHANGES WILL BE OVERWRITTEN, edit the file under project/java dir' > ../src/$F + echo '// DO NOT EDIT THIS FILE - it is automatically generated, ALL YOUR CHANGES WILL BE OVERWRITTEN, edit the file under $JAVA_SRC_PATH dir' > ../src/$F cat $F | sed "s/package .*;/package $AppFullName;/" >> ../src/$F # | sed 's@$@ // THIS FILE IS AUTO-GENERATED@' >> done cd ../.. @@ -1258,9 +1263,9 @@ if [ "$AdmobPublisherId" = "n" -o -z "$AdmobPublisherId" ] ; then $SEDI "/==ADMOB==/ d" project/AndroidManifest.xml AdmobPublisherId="" else - F=project/java/admob/Advertisement.java + F=$JAVA_SRC_PATH/admob/Advertisement.java echo Patching $F - echo '// DO NOT EDIT THIS FILE - it is automatically generated, edit file under project/java dir' > project/src/Advertisement.java + echo '// DO NOT EDIT THIS FILE - it is automatically generated, edit file under $JAVA_SRC_PATH dir' > project/src/Advertisement.java cat $F | sed "s/package .*;/package $AppFullName;/" >> project/src/Advertisement.java fi @@ -1356,7 +1361,7 @@ cat project/jni/SettingsTemplate.mk | \ echo Patching strings.xml rm -rf project/res/values* -cd project/java/translations +cd $JAVA_SRC_PATH/translations for F in */strings.xml; do mkdir -p ../../res/`dirname $F` cat $F | \ diff --git a/project/javaSDL2/Accelerometer.java b/project/javaSDL2/Accelerometer.java new file mode 100644 index 000000000..978020850 --- /dev/null +++ b/project/javaSDL2/Accelerometer.java @@ -0,0 +1,129 @@ +/* +Simple DirectMedia Layer +Java source code (C) 2009-2012 Sergii Pylypenko + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +package net.sourceforge.clonekeenplus; + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.view.MotionEvent; +import android.view.KeyEvent; +import android.view.Window; +import android.view.WindowManager; +import android.os.Vibrator; +import android.hardware.SensorManager; +import android.hardware.SensorEventListener; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.util.Log; +import android.widget.TextView; + + +class AccelerometerReader implements SensorEventListener +{ + + private SensorManager _manager = null; + public boolean openedBySDL = false; + public static final GyroscopeListener gyro = new GyroscopeListener(); + + public AccelerometerReader(Activity context) + { + _manager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); + } + + public synchronized void stop() + { + if( _manager != null ) + { + Log.i("SDL", "libSDL: stopping accelerometer/gyroscope"); + _manager.unregisterListener(this); + _manager.unregisterListener(gyro); + } + } + + public synchronized void start() + { + if( (Globals.UseAccelerometerAsArrowKeys || Globals.AppUsesAccelerometer) && + _manager != null && _manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null ) + { + Log.i("SDL", "libSDL: starting accelerometer"); + _manager.registerListener(this, _manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_GAME); + } + if( Globals.AppUsesGyroscope && _manager != null && _manager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) != null ) + { + Log.i("SDL", "libSDL: starting gyroscope"); + _manager.registerListener(gyro, _manager.getDefaultSensor(Sensor.TYPE_GYROSCOPE), SensorManager.SENSOR_DELAY_GAME); + } + } + + public void onSensorChanged(SensorEvent event) + { + if( Globals.HorizontalOrientation ) + nativeAccelerometer(event.values[1], -event.values[0], event.values[2]); + else + nativeAccelerometer(event.values[0], event.values[1], event.values[2]); // TODO: not tested! + } + public void onAccuracyChanged(Sensor s, int a) + { + } + + static class GyroscopeListener implements SensorEventListener + { + public float x1, x2, xc, y1, y2, yc, z1, z2, zc; + public GyroscopeListener() + { + } + public void onSensorChanged(SensorEvent event) + { + // TODO: vertical orientation + //if( Globals.HorizontalOrientation ) + if( event.values[0] < x1 || event.values[0] > x2 || + event.values[1] < y1 || event.values[1] > y2 || + event.values[2] < z1 || event.values[2] > z2 ) + nativeGyroscope(event.values[0] - xc, event.values[1] - yc, event.values[2] - zc); + } + public void onAccuracyChanged(Sensor s, int a) + { + } + public boolean available(Activity context) + { + SensorManager manager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); + return ( manager != null && manager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) != null ); + } + public void registerListener(Activity context, SensorEventListener l) + { + SensorManager manager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); + if ( manager == null && manager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) == null ) + return; + manager.registerListener(l, manager.getDefaultSensor(Sensor.TYPE_GYROSCOPE), SensorManager.SENSOR_DELAY_GAME); + } + public void unregisterListener(Activity context,SensorEventListener l) + { + SensorManager manager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); + if ( manager == null ) + return; + manager.unregisterListener(l); + } + } + + private static native void nativeAccelerometer(float accX, float accY, float accZ); + private static native void nativeGyroscope(float X, float Y, float Z); +} diff --git a/project/javaSDL2/Advertisement.java b/project/javaSDL2/Advertisement.java new file mode 100644 index 000000000..43b007fd7 --- /dev/null +++ b/project/javaSDL2/Advertisement.java @@ -0,0 +1,50 @@ +/* +Simple DirectMedia Layer +Java source code (C) 2009-2012 Sergii Pylypenko + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +package net.sourceforge.clonekeenplus; + +import android.app.Activity; +import android.content.Context; +import android.view.MotionEvent; +import android.view.KeyEvent; +import android.view.Window; +import android.view.WindowManager; +import android.widget.TextView; +import android.view.View; + +class Advertisement +{ + MainActivity parent; + + public Advertisement(MainActivity p) + { + parent = p; + } + + public View getView() + { + return null; + } + + public void requestNewAd() + { + } +} diff --git a/project/javaSDL2/Audio.java b/project/javaSDL2/Audio.java new file mode 100644 index 000000000..080cbf97f --- /dev/null +++ b/project/javaSDL2/Audio.java @@ -0,0 +1,307 @@ +/* +Simple DirectMedia Layer +Java source code (C) 2009-2012 Sergii Pylypenko + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +package net.sourceforge.clonekeenplus; + + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.view.MotionEvent; +import android.view.KeyEvent; +import android.view.Window; +import android.view.WindowManager; +import android.media.AudioTrack; +import android.media.AudioManager; +import android.media.AudioFormat; +import android.media.AudioRecord; +import android.media.MediaRecorder.AudioSource; +import java.io.*; +import android.util.Log; +import java.util.concurrent.Semaphore; + + + +class AudioThread +{ + + private MainActivity mParent; + private AudioTrack mAudio; + private byte[] mAudioBuffer; + private int mVirtualBufSize; + + public AudioThread(MainActivity parent) + { + mParent = parent; + mAudio = null; + mAudioBuffer = null; + //nativeAudioInitJavaCallbacks(); + } + + public int fillBuffer() + { + if( mParent.isPaused() ) + { + try{ + Thread.sleep(500); + } catch (InterruptedException e) {} + } + else + { + //if( Globals.AudioBufferConfig == 0 ) // Gives too much spam to logcat, makes things worse + // mAudio.flush(); + + mAudio.write( mAudioBuffer, 0, mVirtualBufSize ); + } + + return 1; + } + + public int initAudio(int rate, int channels, int encoding, int bufSize) + { + if( mAudio == null ) + { + channels = ( channels == 1 ) ? AudioFormat.CHANNEL_CONFIGURATION_MONO : + AudioFormat.CHANNEL_CONFIGURATION_STEREO; + encoding = ( encoding == 1 ) ? AudioFormat.ENCODING_PCM_16BIT : + AudioFormat.ENCODING_PCM_8BIT; + + mVirtualBufSize = bufSize; + + if( AudioTrack.getMinBufferSize( rate, channels, encoding ) > bufSize ) + bufSize = AudioTrack.getMinBufferSize( rate, channels, encoding ); + + if(Globals.AudioBufferConfig != 0) { // application's choice - use minimal buffer + bufSize = (int)((float)bufSize * (((float)(Globals.AudioBufferConfig - 1) * 2.5f) + 1.0f)); + mVirtualBufSize = bufSize; + } + mAudioBuffer = new byte[bufSize]; + + mAudio = new AudioTrack(AudioManager.STREAM_MUSIC, + rate, + channels, + encoding, + bufSize, + AudioTrack.MODE_STREAM ); + mAudio.play(); + } + return mVirtualBufSize; + } + + public byte[] getBuffer() + { + return mAudioBuffer; + } + + public int deinitAudio() + { + if( mAudio != null ) + { + mAudio.stop(); + mAudio.release(); + mAudio = null; + } + mAudioBuffer = null; + return 1; + } + + public int initAudioThread() + { + // Make audio thread priority higher so audio thread won't get underrun + Thread.currentThread().setPriority(Thread.MAX_PRIORITY); + return 1; + } + + public int pauseAudioPlayback() + { + if( mAudio != null ) + { + mAudio.pause(); + } + if( mRecordThread != null ) + { + mRecordThread.pauseRecording(); + } + return 1; + } + + public int resumeAudioPlayback() + { + if( mAudio != null ) + { + mAudio.play(); + } + if( mRecordThread != null ) + { + mRecordThread.resumeRecording(); + } + return 1; + } + + private native int nativeAudioInitJavaCallbacks(); + + // ----- Audio recording ----- + + private RecordingThread mRecordThread = null; + private AudioRecord mRecorder = null; + private int mRecorderBufferSize = 0; + + private byte[] startRecording(int rate, int channels, int encoding, int bufsize) + { + if( mRecordThread == null ) + { + mRecordThread = new RecordingThread(); + mRecordThread.start(); + } + if( !mRecordThread.isStopped() ) + { + Log.i("SDL", "SDL: error: application already opened audio recording device"); + return null; + } + + mRecordThread.init(bufsize); + + int channelConfig = ( channels == 1 ) ? AudioFormat.CHANNEL_IN_MONO : + AudioFormat.CHANNEL_IN_STEREO; + int encodingConfig = ( encoding == 1 ) ? AudioFormat.ENCODING_PCM_16BIT : + AudioFormat.ENCODING_PCM_8BIT; + + int minBufDevice = AudioRecord.getMinBufferSize(rate, channelConfig, encodingConfig); + int minBufferSize = Math.max(bufsize * 8, minBufDevice + (bufsize - (minBufDevice % bufsize))); + Log.i("SDL", "SDL: app opened recording device, rate " + rate + " channels " + channels + " sample size " + (encoding+1) + " bufsize " + bufsize + " internal bufsize " + minBufferSize); + if( mRecorder == null || mRecorder.getSampleRate() != rate || + mRecorder.getChannelCount() != channels || + mRecorder.getAudioFormat() != encodingConfig || + mRecorderBufferSize != minBufferSize ) + { + if( mRecorder != null ) + mRecorder.release(); + mRecorder = null; + try { + mRecorder = new AudioRecord(AudioSource.DEFAULT, rate, channelConfig, encodingConfig, minBufferSize); + mRecorderBufferSize = minBufferSize; + } catch (IllegalArgumentException e) { + Log.i("SDL", "SDL: error: failed to open recording device!"); + return null; + } + } + else + { + Log.i("SDL", "SDL: reusing old recording device"); + } + mRecordThread.startRecording(); + return mRecordThread.mRecordBuffer; + } + + private void stopRecording() + { + if( mRecordThread == null || mRecordThread.isStopped() ) + { + Log.i("SDL", "SDL: error: application already closed audio recording device"); + return; + } + mRecordThread.stopRecording(); + Log.i("SDL", "SDL: app closed recording device"); + } + + private class RecordingThread extends Thread + { + private boolean stopped = true; + byte[] mRecordBuffer; + private Semaphore waitStarted = new Semaphore(0); + private boolean sleep = false; + + RecordingThread() + { + super(); + } + + void init(int bufsize) + { + if( mRecordBuffer == null || mRecordBuffer.length != bufsize ) + mRecordBuffer = new byte[bufsize]; + } + + public void run() + { + while( true ) + { + waitStarted.acquireUninterruptibly(); + waitStarted.drainPermits(); + stopped = false; + sleep = false; + + while( !sleep ) + { + int got = mRecorder.read(mRecordBuffer, 0, mRecordBuffer.length); + if( got != mRecordBuffer.length ) + { + // Audio is stopped here, sleep a bit. + try{ + Thread.sleep(1000); + } catch (InterruptedException e) {} + } + else + { + //Log.i("SDL", "SDL: nativeAudioRecordCallback with len " + mRecordBuffer.length); + nativeAudioRecordCallback(); + //Log.i("SDL", "SDL: nativeAudioRecordCallback returned"); + } + } + + stopped = true; + mRecorder.stop(); + } + } + + public void startRecording() + { + mRecorder.startRecording(); + waitStarted.release(); + } + public void stopRecording() + { + sleep = true; + while( !stopped ) + { + try{ + Thread.sleep(100); + } catch (InterruptedException e) {} + } + } + public void pauseRecording() + { + if( !stopped ) + mRecorder.stop(); + } + public void resumeRecording() + { + if( !stopped ) + mRecorder.startRecording(); + } + public boolean isStopped() + { + return stopped; + } + } + + private native void nativeAudioRecordCallback(); +} diff --git a/project/javaSDL2/DataDownloader.java b/project/javaSDL2/DataDownloader.java new file mode 100644 index 000000000..b5e22d130 --- /dev/null +++ b/project/javaSDL2/DataDownloader.java @@ -0,0 +1,758 @@ +/* +Simple DirectMedia Layer +Java source code (C) 2009-2012 Sergii Pylypenko + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +package net.sourceforge.clonekeenplus; + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.view.MotionEvent; +import android.view.KeyEvent; +import android.view.Window; +import android.view.WindowManager; +import android.os.Environment; + +import android.widget.TextView; +import org.apache.http.client.methods.*; +import org.apache.http.*; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.conn.*; +import org.apache.http.conn.params.*; +import org.apache.http.conn.scheme.*; +import org.apache.http.conn.ssl.*; +import org.apache.http.impl.*; +import org.apache.http.impl.client.*; +import org.apache.http.impl.conn.SingleClientConnManager; +import java.security.cert.*; +import java.security.SecureRandom; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import java.util.zip.*; +import java.io.*; +import android.util.Log; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; + +import android.content.Context; +import android.content.res.Resources; +import java.lang.String; +import android.text.SpannedString; +import android.app.AlertDialog; +import android.content.DialogInterface; + + +class CountingInputStream extends BufferedInputStream +{ + + private long bytesReadMark = 0; + private long bytesRead = 0; + + public CountingInputStream(InputStream in, int size) { + + super(in, size); + } + + public CountingInputStream(InputStream in) { + + super(in); + } + + public long getBytesRead() { + + return bytesRead; + } + + public synchronized int read() throws IOException { + + int read = super.read(); + if (read >= 0) { + bytesRead++; + } + return read; + } + + public synchronized int read(byte[] b, int off, int len) throws IOException { + + int read = super.read(b, off, len); + if (read >= 0) { + bytesRead += read; + } + return read; + } + + public synchronized long skip(long n) throws IOException { + + long skipped = super.skip(n); + if (skipped >= 0) { + bytesRead += skipped; + } + return skipped; + } + + public synchronized void mark(int readlimit) { + + super.mark(readlimit); + bytesReadMark = bytesRead; + } + + public synchronized void reset() throws IOException { + + super.reset(); + bytesRead = bytesReadMark; + } +} + + +class DataDownloader extends Thread +{ + + public static final String DOWNLOAD_FLAG_FILENAME = "libsdl-DownloadFinished-"; + + class StatusWriter + { + private TextView Status; + private MainActivity Parent; + private SpannedString oldText = new SpannedString(""); + + public StatusWriter( TextView _Status, MainActivity _Parent ) + { + Status = _Status; + Parent = _Parent; + } + public void setParent( TextView _Status, MainActivity _Parent ) + { + synchronized(DataDownloader.this) { + Status = _Status; + Parent = _Parent; + setText( oldText.toString() ); + } + } + + public void setText(final String str) + { + class Callback implements Runnable + { + public TextView Status; + public SpannedString text; + public void run() + { + Status.setText(text); + } + } + synchronized(DataDownloader.this) { + Callback cb = new Callback(); + oldText = new SpannedString(str); + cb.text = new SpannedString(str); + cb.Status = Status; + if( Parent != null && Status != null ) + Parent.runOnUiThread(cb); + } + } + + } + public DataDownloader( MainActivity _Parent, TextView _Status ) + { + Parent = _Parent; + Status = new StatusWriter( _Status, _Parent ); + //Status.setText( "Connecting to " + Globals.DataDownloadUrl ); + outFilesDir = Globals.DataDir; + DownloadComplete = false; + this.start(); + } + + public void setStatusField(TextView _Status) + { + synchronized(this) { + Status.setParent( _Status, Parent ); + } + } + + @Override + public void run() + { + Parent.keyListener = new BackKeyListener(Parent); + String [] downloadFiles = Globals.DataDownloadUrl; + int total = 0; + int count = 0; + for( int i = 0; i < downloadFiles.length; i++ ) + { + if( downloadFiles[i].length() > 0 && + ( Globals.OptionalDataDownload.length > i && Globals.OptionalDataDownload[i] ) || + ( Globals.OptionalDataDownload.length <= i && downloadFiles[i].indexOf("!") == 0 ) ) + total += 1; + } + for( int i = 0; i < downloadFiles.length; i++ ) + { + if( downloadFiles[i].length() > 0 && + ( Globals.OptionalDataDownload.length > i && Globals.OptionalDataDownload[i] ) || + ( Globals.OptionalDataDownload.length <= i && downloadFiles[i].indexOf("!") == 0 ) ) + { + if( ! DownloadDataFile(downloadFiles[i], DOWNLOAD_FLAG_FILENAME + String.valueOf(i) + ".flag", count+1, total, i) ) + { + DownloadFailed = true; + return; + } + count += 1; + } + } + DownloadComplete = true; + Parent.keyListener = null; + initParent(); + } + + public boolean DownloadDataFile(final String DataDownloadUrl, final String DownloadFlagFileName, int downloadCount, int downloadTotal, int downloadIndex) + { + DownloadCanBeResumed = false; + Resources res = Parent.getResources(); + + String [] downloadUrls = DataDownloadUrl.split("[|]"); + if( downloadUrls.length < 2 ) + { + Log.i("SDL", "Error: download string invalid: '" + DataDownloadUrl + "', your AndroidAppSettigns.cfg is broken"); + Status.setText( res.getString(R.string.error_dl_from, DataDownloadUrl) ); + return false; + } + + boolean forceOverwrite = false; + String path = getOutFilePath(DownloadFlagFileName); + InputStream checkFile = null; + try { + checkFile = new FileInputStream( path ); + } catch( FileNotFoundException e ) { + } catch( SecurityException e ) { }; + if( checkFile != null ) + { + try { + byte b[] = new byte[ Globals.DataDownloadUrl[downloadIndex].getBytes("UTF-8").length + 1 ]; + int readed = checkFile.read(b); + String compare = ""; + if( readed > 0 ) + compare = new String( b, 0, readed, "UTF-8" ); + boolean matched = false; + //Log.i("SDL", "Read URL: '" + compare + "'"); + for( int i = 1; i < downloadUrls.length; i++ ) + { + //Log.i("SDL", "Comparing: '" + downloadUrls[i] + "'"); + if( compare.compareTo(downloadUrls[i]) == 0 ) + matched = true; + } + //Log.i("SDL", "Matched: " + String.valueOf(matched)); + if( ! matched ) + throw new IOException(); + Status.setText( res.getString(R.string.download_unneeded) ); + return true; + } catch ( IOException e ) { + forceOverwrite = true; + new File(path).delete(); + } + } + checkFile = null; + + // Create output directory (not necessary for phone storage) + Log.i("SDL", "Downloading data to: '" + outFilesDir + "'"); + try { + File outDir = new File( outFilesDir ); + if( !(outDir.exists() && outDir.isDirectory()) ) + outDir.mkdirs(); + OutputStream out = new FileOutputStream( getOutFilePath(".nomedia") ); + out.flush(); + out.close(); + } + catch( SecurityException e ) {} + catch( FileNotFoundException e ) {} + catch( IOException e ) {}; + + HttpResponse response = null, responseError = null; + HttpGet request; + long totalLen = 0; + CountingInputStream stream; + byte[] buf = new byte[16384]; + boolean DoNotUnzip = false; + boolean FileInAssets = false; + String url = ""; + long partialDownloadLen = 0; + + int downloadUrlIndex = 1; + while( downloadUrlIndex < downloadUrls.length ) + { + Log.i("SDL", "Processing download " + downloadUrls[downloadUrlIndex]); + url = new String(downloadUrls[downloadUrlIndex]); + DoNotUnzip = false; + if(url.indexOf(":") == 0) + { + path = getOutFilePath(url.substring( 1, url.indexOf(":", 1) )); + url = url.substring( url.indexOf(":", 1) + 1 ); + DoNotUnzip = true; + DownloadCanBeResumed = true; + File partialDownload = new File( path ); + if( partialDownload.exists() && !partialDownload.isDirectory() && !forceOverwrite ) + partialDownloadLen = partialDownload.length(); + } + Status.setText( downloadCount + "/" + downloadTotal + ": " + res.getString(R.string.connecting_to, url) ); + if( url.indexOf("http://") == -1 && url.indexOf("https://") == -1 ) // File inside assets + { + InputStream stream1 = null; + try { + stream1 = Parent.getAssets().open(url); + stream1.close(); + } catch( Exception e ) { + try { + stream1 = Parent.getAssets().open(url + "000"); + stream1.close(); + } catch( Exception ee ) { + Log.i("SDL", "Failed to open file in assets: " + url); + downloadUrlIndex++; + continue; + } + } + FileInAssets = true; + Log.i("SDL", "Fetching file from assets: " + url); + break; + } + else + { + Log.i("SDL", "Connecting to: " + url); + request = new HttpGet(url); + request.addHeader("Accept", "*/*"); + if( partialDownloadLen > 0 ) { + request.addHeader("Range", "bytes=" + partialDownloadLen + "-"); + Log.i("SDL", "Trying to resume download at pos " + partialDownloadLen); + } + try { + DefaultHttpClient client = HttpWithDisabledSslCertCheck(); + client.getParams().setBooleanParameter("http.protocol.handle-redirects", true); + response = client.execute(request); + } catch (IOException e) { + Log.i("SDL", "Failed to connect to " + url); + downloadUrlIndex++; + }; + if( response != null ) + { + if( response.getStatusLine().getStatusCode() != 200 && response.getStatusLine().getStatusCode() != 206 ) + { + Log.i("SDL", "Failed to connect to " + url + " with error " + response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase()); + responseError = response; + response = null; + downloadUrlIndex++; + } + else + break; + } + } + } + if( FileInAssets ) + { + int multipartCounter = 0; + InputStream multipart = null; + while( true ) + { + try { + // Make string ".zip000", ".zip001" etc for multipart archives + String url1 = url + String.format("%03d", multipartCounter); + CountingInputStream stream1 = new CountingInputStream(Parent.getAssets().open(url1), 8192); + while( stream1.skip(65536) > 0 ) { }; + totalLen += stream1.getBytesRead(); + stream1.close(); + InputStream s = Parent.getAssets().open(url1); + if( multipart == null ) + multipart = s; + else + multipart = new SequenceInputStream(multipart, s); + Log.i("SDL", "Multipart archive found: " + url1); + } catch( IOException e ) { + break; + } + multipartCounter += 1; + } + if( multipart != null ) + stream = new CountingInputStream(multipart, 8192); + else + { + try { + stream = new CountingInputStream(Parent.getAssets().open(url), 8192); + while( stream.skip(65536) > 0 ) { }; + totalLen += stream.getBytesRead(); + stream.close(); + stream = new CountingInputStream(Parent.getAssets().open(url), 8192); + } catch( IOException e ) { + Log.i("SDL", "Unpacking from assets '" + url + "' - error: " + e.toString()); + Status.setText( res.getString(R.string.error_dl_from, url) ); + return false; + } + } + } + else + { + if( response == null ) + { + Log.i("SDL", "Error connecting to " + url); + Status.setText( res.getString(R.string.failed_connecting_to, url) + (responseError == null ? "" : ": " + responseError.getStatusLine().getStatusCode() + " " + responseError.getStatusLine().getReasonPhrase()) ); + return false; + } + + Status.setText( downloadCount + "/" + downloadTotal + ": " + res.getString(R.string.dl_from, url) ); + totalLen = response.getEntity().getContentLength(); + try { + stream = new CountingInputStream(response.getEntity().getContent(), 8192); + } catch( java.io.IOException e ) { + Status.setText( res.getString(R.string.error_dl_from, url) ); + return false; + } + } + + long updateStatusTime = 0; + + if(DoNotUnzip) + { + Log.i("SDL", "Saving file '" + path + "'"); + OutputStream out = null; + try { + try { + File outDir = new File( path.substring(0, path.lastIndexOf("/") )); + if( !(outDir.exists() && outDir.isDirectory()) ) + outDir.mkdirs(); + } catch( SecurityException e ) { }; + + if( partialDownloadLen > 0 ) + { + try { + Header[] range = response.getHeaders("Content-Range"); + if( range.length > 0 && range[0].getValue().indexOf("bytes") == 0 ) + { + //Log.i("SDL", "Resuming download of file '" + path + "': Content-Range: " + range[0].getValue()); + String[] skippedBytes = range[0].getValue().split("/")[0].split("-")[0].split(" "); + if( skippedBytes.length >= 2 && Long.parseLong(skippedBytes[1]) == partialDownloadLen ) + { + out = new FileOutputStream( path, true ); + Log.i("SDL", "Resuming download of file '" + path + "' at pos " + partialDownloadLen); + } + } + else + Log.i("SDL", "Server does not support partial downloads. " + (range.length == 0 ? "" : range[0].getValue())); + } catch (Exception e) { } + } + if( out == null ) + { + out = new FileOutputStream( path ); + partialDownloadLen = 0; + } + } catch( FileNotFoundException e ) { + Log.i("SDL", "Saving file '" + path + "' - error creating output file: " + e.toString()); + } catch( SecurityException e ) { + Log.i("SDL", "Saving file '" + path + "' - error creating output file: " + e.toString()); + }; + if( out == null ) + { + Status.setText( res.getString(R.string.error_write, path) ); + Log.i("SDL", "Saving file '" + path + "' - error creating output file"); + return false; + } + + try { + int len = stream.read(buf); + while (len >= 0) + { + if(len > 0) + out.write(buf, 0, len); + len = stream.read(buf); + + float percent = 0.0f; + if( totalLen > 0 ) + percent = (stream.getBytesRead() + partialDownloadLen) * 100.0f / (totalLen + partialDownloadLen); + if( System.currentTimeMillis() > updateStatusTime + 1000 ) + { + updateStatusTime = System.currentTimeMillis(); + Status.setText( downloadCount + "/" + downloadTotal + ": " + res.getString(R.string.dl_progress, percent, path) ); + } + } + out.flush(); + out.close(); + out = null; + } catch( java.io.IOException e ) { + Status.setText( res.getString(R.string.error_write, path) + ": " + e.getMessage() ); + Log.i("SDL", "Saving file '" + path + "' - error writing: " + e.toString()); + return false; + } + Log.i("SDL", "Saving file '" + path + "' done"); + } + else + { + Log.i("SDL", "Reading from zip file '" + url + "'"); + ZipInputStream zip = new ZipInputStream(stream); + + while(true) + { + ZipEntry entry = null; + try { + entry = zip.getNextEntry(); + if( entry != null ) + Log.i("SDL", "Reading from zip file '" + url + "' entry '" + entry.getName() + "'"); + } catch( java.io.IOException e ) { + Status.setText( res.getString(R.string.error_dl_from, url) ); + Log.i("SDL", "Error reading from zip file '" + url + "': " + e.toString()); + return false; + } + if( entry == null ) + { + Log.i("SDL", "Reading from zip file '" + url + "' finished"); + break; + } + if( entry.isDirectory() ) + { + Log.i("SDL", "Creating dir '" + getOutFilePath(entry.getName()) + "'"); + try { + File outDir = new File( getOutFilePath(entry.getName()) ); + if( !(outDir.exists() && outDir.isDirectory()) ) + outDir.mkdirs(); + } catch( SecurityException e ) { }; + continue; + } + + OutputStream out = null; + path = getOutFilePath(entry.getName()); + float percent = 0.0f; + + Log.i("SDL", "Saving file '" + path + "'"); + + try { + File outDir = new File( path.substring(0, path.lastIndexOf("/") )); + if( !(outDir.exists() && outDir.isDirectory()) ) + outDir.mkdirs(); + } catch( SecurityException e ) { }; + + try { + CheckedInputStream check = new CheckedInputStream( new FileInputStream(path), new CRC32() ); + while( check.read(buf, 0, buf.length) >= 0 ) {}; + check.close(); + if( check.getChecksum().getValue() != entry.getCrc() ) + { + File ff = new File(path); + ff.delete(); + throw new Exception(); + } + Log.i("SDL", "File '" + path + "' exists and passed CRC check - not overwriting it"); + if( totalLen > 0 ) + percent = stream.getBytesRead() * 100.0f / totalLen; + if( System.currentTimeMillis() > updateStatusTime + 1000 ) + { + updateStatusTime = System.currentTimeMillis(); + Status.setText( downloadCount + "/" + downloadTotal + ": " + res.getString(R.string.dl_progress, percent, path) ); + } + continue; + } catch( Exception e ) { } + + try { + out = new FileOutputStream( path ); + } catch( FileNotFoundException e ) { + Log.i("SDL", "Saving file '" + path + "' - cannot create file: " + e.toString()); + } catch( SecurityException e ) { + Log.i("SDL", "Saving file '" + path + "' - cannot create file: " + e.toString()); + }; + if( out == null ) + { + Status.setText( res.getString(R.string.error_write, path) ); + Log.i("SDL", "Saving file '" + path + "' - cannot create file"); + return false; + } + + if( totalLen > 0 ) + percent = stream.getBytesRead() * 100.0f / totalLen; + if( System.currentTimeMillis() > updateStatusTime + 1000 ) + { + updateStatusTime = System.currentTimeMillis(); + Status.setText( downloadCount + "/" + downloadTotal + ": " + res.getString(R.string.dl_progress, percent, path) ); + } + + try { + int len = zip.read(buf); + while (len >= 0) + { + if(len > 0) + out.write(buf, 0, len); + len = zip.read(buf); + + percent = 0.0f; + if( totalLen > 0 ) + percent = stream.getBytesRead() * 100.0f / totalLen; + if( System.currentTimeMillis() > updateStatusTime + 1000 ) + { + updateStatusTime = System.currentTimeMillis(); + Status.setText( downloadCount + "/" + downloadTotal + ": " + res.getString(R.string.dl_progress, percent, path) ); + } + } + out.flush(); + out.close(); + out = null; + } catch( java.io.IOException e ) { + Status.setText( res.getString(R.string.error_write, path) + ": " + e.getMessage() ); + Log.i("SDL", "Saving file '" + path + "' - error writing or downloading: " + e.toString()); + return false; + } + + try { + long count = 0, ret = 0; + CheckedInputStream check = new CheckedInputStream( new FileInputStream(path), new CRC32() ); + while( ret >= 0 ) + { + count += ret; + ret = check.read(buf, 0, buf.length); + } + check.close(); + if( check.getChecksum().getValue() != entry.getCrc() || count != entry.getSize() ) + { + File ff = new File(path); + ff.delete(); + Log.i("SDL", "Saving file '" + path + "' - CRC check failed, ZIP: " + + String.format("%x", entry.getCrc()) + " actual file: " + String.format("%x", check.getChecksum().getValue()) + + " file size in ZIP: " + entry.getSize() + " actual size " + count ); + throw new Exception(); + } + } catch( Exception e ) { + Status.setText( res.getString(R.string.error_write, path) + ": " + e.getMessage() ); + return false; + } + Log.i("SDL", "Saving file '" + path + "' done"); + } + }; + + OutputStream out = null; + path = getOutFilePath(DownloadFlagFileName); + try { + out = new FileOutputStream( path ); + out.write(downloadUrls[downloadUrlIndex].getBytes("UTF-8")); + out.flush(); + out.close(); + } catch( FileNotFoundException e ) { + } catch( SecurityException e ) { + } catch( java.io.IOException e ) { + Status.setText( res.getString(R.string.error_write, path) + ": " + e.getMessage() ); + return false; + }; + Status.setText( downloadCount + "/" + downloadTotal + ": " + res.getString(R.string.dl_finished) ); + + try { + stream.close(); + } catch( java.io.IOException e ) { + }; + + return true; + }; + + private void initParent() + { + class Callback implements Runnable + { + public MainActivity Parent; + public void run() + { + Parent.initSDL(); + } + } + Callback cb = new Callback(); + synchronized(this) { + cb.Parent = Parent; + if(Parent != null) + Parent.runOnUiThread(cb); + } + } + + private String getOutFilePath(final String filename) + { + return outFilesDir + "/" + filename; + }; + + private static DefaultHttpClient HttpWithDisabledSslCertCheck() + { + return new DefaultHttpClient(); + // This code does not work + /* + HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; + + DefaultHttpClient client = new DefaultHttpClient(); + + SchemeRegistry registry = new SchemeRegistry(); + SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory(); + socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier); + registry.register(new Scheme("https", socketFactory, 443)); + SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry); + DefaultHttpClient http = new DefaultHttpClient(mgr, client.getParams()); + + HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier); + + return http; + */ + } + + + public class BackKeyListener implements MainActivity.KeyEventsListener + { + MainActivity p; + public BackKeyListener(MainActivity _p) + { + p = _p; + } + + public void onKeyEvent(final int keyCode) + { + if( DownloadFailed ) + System.exit(1); + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.cancel_download)); + builder.setMessage(p.getResources().getString(R.string.cancel_download) + (DownloadCanBeResumed ? " " + p.getResources().getString(R.string.cancel_download_resume) : "")); + + builder.setPositiveButton(p.getResources().getString(R.string.yes), new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + System.exit(1); + dialog.dismiss(); + } + }); + builder.setNegativeButton(p.getResources().getString(R.string.no), new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + dialog.dismiss(); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + public StatusWriter Status; + public boolean DownloadComplete = false; + public boolean DownloadFailed = false; + public boolean DownloadCanBeResumed = false; + private MainActivity Parent; + private String outFilesDir = null; +} + diff --git a/project/javaSDL2/GLSurfaceView_SDL.java b/project/javaSDL2/GLSurfaceView_SDL.java new file mode 100644 index 000000000..998bf1c5c --- /dev/null +++ b/project/javaSDL2/GLSurfaceView_SDL.java @@ -0,0 +1,1276 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* This is GLSurfaceView class ripped out of Android 2.1 sources, + fixed with a hammer to work with libSDL port */ + +package net.sourceforge.clonekeenplus; + +import java.io.Writer; +import java.util.ArrayList; +import java.util.concurrent.Semaphore; + +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGL11; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; +import javax.microedition.khronos.egl.EGLSurface; +import javax.microedition.khronos.opengles.GL; +import javax.microedition.khronos.opengles.GL10; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.Log; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.app.KeyguardManager; + +/** + * An implementation of SurfaceView that uses the dedicated surface for + * displaying OpenGL rendering. + *

+ * A GLSurfaceView provides the following features: + *

+ *

+ * + *

Using GLSurfaceView

+ *

+ * Typically you use GLSurfaceView by subclassing it and overriding one or more of the + * View system input event methods. If your application does not need to override event + * methods then GLSurfaceView can be used as-is. For the most part + * GLSurfaceView behavior is customized by calling "set" methods rather than by subclassing. + * For example, unlike a regular View, drawing is delegated to a separate Renderer object which + * is registered with the GLSurfaceView + * using the {@link #setRenderer(Renderer)} call. + *

+ *

Initializing GLSurfaceView

+ * All you have to do to initialize a GLSurfaceView is call {@link #setRenderer(Renderer)}. + * However, if desired, you can modify the default behavior of GLSurfaceView by calling one or + * more of these methods before calling setRenderer: + * + *

+ *

Choosing an EGL Configuration

+ * A given Android device may support multiple possible types of drawing surfaces. + * The available surfaces may differ in how may channels of data are present, as + * well as how many bits are allocated to each channel. Therefore, the first thing + * GLSurfaceView has to do when starting to render is choose what type of surface to use. + *

+ * By default GLSurfaceView chooses an available surface that's closest to a 16-bit R5G6B5 surface + * with a 16-bit depth buffer and no stencil. If you would prefer a different surface (for example, + * if you do not need a depth buffer) you can override the default behavior by calling one of the + * setEGLConfigChooser methods. + *

+ *

Debug Behavior

+ * You can optionally modify the behavior of GLSurfaceView by calling + * one or more of the debugging methods {@link #setDebugFlags(int)}, + * and {@link #setGLWrapper}. These methods may be called before and/or after setRenderer, but + * typically they are called before setRenderer so that they take effect immediately. + *

+ *

Setting a Renderer

+ * Finally, you must call {@link #setRenderer} to register a {@link Renderer}. + * The renderer is + * responsible for doing the actual OpenGL rendering. + *

+ *

Rendering Mode

+ * Once the renderer is set, you can control whether the renderer draws + * continuously or on-demand by calling + * {@link #setRenderMode}. The default is continuous rendering. + *

+ *

Activity Life-cycle

+ * A GLSurfaceView must be notified when the activity is paused and resumed. GLSurfaceView clients + * are required to call {@link #onPause()} when the activity pauses and + * {@link #onResume()} when the activity resumes. These calls allow GLSurfaceView to + * pause and resume the rendering thread, and also allow GLSurfaceView to release and recreate + * the OpenGL display. + *

+ *

Handling events

+ *

+ * To handle an event you will typically subclass GLSurfaceView and override the + * appropriate method, just as you would with any other View. However, when handling + * the event, you may need to communicate with the Renderer object + * that's running in the rendering thread. You can do this using any + * standard Java cross-thread communication mechanism. In addition, + * one relatively easy way to communicate with your renderer is + * to call + * {@link #queueEvent(Runnable)}. For example: + *

+ * class MyGLSurfaceView extends GLSurfaceView {
+ *
+ *     private MyRenderer mMyRenderer;
+ *
+ *     public void start() {
+ *         mMyRenderer = ...;
+ *         setRenderer(mMyRenderer);
+ *     }
+ *
+ *     public boolean onKeyDown(int keyCode, KeyEvent event) {
+ *         if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
+ *             queueEvent(new Runnable() {
+ *                 // This method will be called on the rendering
+ *                 // thread:
+ *                 public void run() {
+ *                     mMyRenderer.handleDpadCenter();
+ *                 }});
+ *             return true;
+ *         }
+ *         return super.onKeyDown(keyCode, event);
+ *     }
+ * }
+ * 
+ * + */ +public class GLSurfaceView_SDL extends SurfaceView implements SurfaceHolder.Callback { + /** + * The renderer only renders + * when the surface is created, or when {@link #requestRender} is called. + * + * @see #getRenderMode() + * @see #setRenderMode(int) + */ + public final static int RENDERMODE_WHEN_DIRTY = 0; + /** + * The renderer is called + * continuously to re-render the scene. + * + * @see #getRenderMode() + * @see #setRenderMode(int) + * @see #requestRender() + */ + public final static int RENDERMODE_CONTINUOUSLY = 1; + + /** + * Check glError() after every GL call and throw an exception if glError indicates + * that an error has occurred. This can be used to help track down which OpenGL ES call + * is causing an error. + * + * @see #getDebugFlags + * @see #setDebugFlags + */ + public final static int DEBUG_CHECK_GL_ERROR = 1; + + /** + * Log GL calls to the system log at "verbose" level with tag "GLSurfaceView". + * + * @see #getDebugFlags + * @see #setDebugFlags + */ + public final static int DEBUG_LOG_GL_CALLS = 2; + + /** + * Standard View constructor. In order to render something, you + * must call {@link #setRenderer} to register a renderer. + */ + public GLSurfaceView_SDL(Context context) { + super(context); + init(); + } + + /** + * Standard View constructor. In order to render something, you + * must call {@link #setRenderer} to register a renderer. + */ + public GLSurfaceView_SDL(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + private void init() { + // Install a SurfaceHolder.Callback so we get notified when the + // underlying surface is created and destroyed + SurfaceHolder holder = getHolder(); + holder.addCallback(this); + holder.setType(SurfaceHolder.SURFACE_TYPE_GPU); + } + + /** + * Set the glWrapper. If the glWrapper is not null, its + * {@link GLWrapper#wrap(GL)} method is called + * whenever a surface is created. A GLWrapper can be used to wrap + * the GL object that's passed to the renderer. Wrapping a GL + * object enables examining and modifying the behavior of the + * GL calls made by the renderer. + *

+ * Wrapping is typically used for debugging purposes. + *

+ * The default value is null. + * @param glWrapper the new GLWrapper + */ + public void setGLWrapper(GLWrapper glWrapper) { + mGLWrapper = glWrapper; + } + + /** + * Set the debug flags to a new value. The value is + * constructed by OR-together zero or more + * of the DEBUG_CHECK_* constants. The debug flags take effect + * whenever a surface is created. The default value is zero. + * @param debugFlags the new debug flags + * @see #DEBUG_CHECK_GL_ERROR + * @see #DEBUG_LOG_GL_CALLS + */ + public void setDebugFlags(int debugFlags) { + mDebugFlags = debugFlags; + } + + /** + * Get the current value of the debug flags. + * @return the current value of the debug flags. + */ + public int getDebugFlags() { + return mDebugFlags; + } + + /** + * Set the renderer associated with this view. Also starts the thread that + * will call the renderer, which in turn causes the rendering to start. + *

This method should be called once and only once in the life-cycle of + * a GLSurfaceView. + *

The following GLSurfaceView methods can only be called before + * setRenderer is called: + *

+ *

+ * The following GLSurfaceView methods can only be called after + * setRenderer is called: + *

+ * + * @param renderer the renderer to use to perform OpenGL drawing. + */ + public void setRenderer(Renderer renderer) { + if (mGLThread != null) { + throw new IllegalStateException( + "setRenderer has already been called for this instance."); + } + if (mEGLConfigChooser == null) { + mEGLConfigChooser = getEglConfigChooser(16, false, false, false); + } + mGLThread = new GLThread(renderer); + mGLThread.start(); + } + + /** + * Install a custom EGLConfigChooser. + *

If this method is + * called, it must be called before {@link #setRenderer(Renderer)} + * is called. + *

+ * If no setEGLConfigChooser method is called, then by default the + * view will choose a config as close to 16-bit RGB as possible, with + * a depth buffer as close to 16 bits as possible. + * @param configChooser + */ + public void setEGLConfigChooser(EGLConfigChooser configChooser) { + if (mGLThread != null) { + throw new IllegalStateException( + "setRenderer has already been called for this instance."); + } + mEGLConfigChooser = configChooser; + } + + /** + * Install a config chooser which will choose a config + * as close to 16-bit RGB as possible, with or without an optional depth + * buffer as close to 16-bits as possible. + *

If this method is + * called, it must be called before {@link #setRenderer(Renderer)} + * is called. + *

+ * If no setEGLConfigChooser method is called, then by default the + * view will choose a config as close to 16-bit RGB as possible, with + * a depth buffer as close to 16 bits as possible. + * + * @param needDepth + */ + public void setEGLConfigChooser(int bpp, boolean needDepth, boolean stencil, boolean gles2) { + setEGLConfigChooser(getEglConfigChooser(bpp, needDepth, stencil, gles2)); + } + + /** + * Install a config chooser which will choose a config + * with at least the specified component sizes, and as close + * to the specified component sizes as possible. + *

If this method is + * called, it must be called before {@link #setRenderer(Renderer)} + * is called. + *

+ * If no setEGLConfigChooser method is called, then by default the + * view will choose a config as close to 16-bit RGB as possible, with + * a depth buffer as close to 16 bits as possible. + * + */ + public void setEGLConfigChooser(int redSize, int greenSize, int blueSize, + int alphaSize, int depthSize, int stencilSize, boolean gles2) { + setEGLConfigChooser(new ComponentSizeChooser(redSize, greenSize, + blueSize, alphaSize, depthSize, stencilSize, gles2)); + } + /** + * Set the rendering mode. When renderMode is + * RENDERMODE_CONTINUOUSLY, the renderer is called + * repeatedly to re-render the scene. When renderMode + * is RENDERMODE_WHEN_DIRTY, the renderer only rendered when the surface + * is created, or when {@link #requestRender} is called. Defaults to RENDERMODE_CONTINUOUSLY. + *

+ * Using RENDERMODE_WHEN_DIRTY can improve battery life and overall system performance + * by allowing the GPU and CPU to idle when the view does not need to be updated. + *

+ * This method can only be called after {@link #setRenderer(Renderer)} + * + * @param renderMode one of the RENDERMODE_X constants + * @see #RENDERMODE_CONTINUOUSLY + * @see #RENDERMODE_WHEN_DIRTY + */ + public void setRenderMode(int renderMode) { + mGLThread.setRenderMode(renderMode); + } + + /** + * Get the current rendering mode. May be called + * from any thread. Must not be called before a renderer has been set. + * @return the current rendering mode. + * @see #RENDERMODE_CONTINUOUSLY + * @see #RENDERMODE_WHEN_DIRTY + */ + public int getRenderMode() { + return mGLThread.getRenderMode(); + } + + /** + * Request that the renderer render a frame. + * This method is typically used when the render mode has been set to + * {@link #RENDERMODE_WHEN_DIRTY}, so that frames are only rendered on demand. + * May be called + * from any thread. Must not be called before a renderer has been set. + */ + public void requestRender() { + mGLThread.requestRender(); + } + + /** + * This method is part of the SurfaceHolder.Callback interface, and is + * not normally called or subclassed by clients of GLSurfaceView. + */ + public void surfaceCreated(SurfaceHolder holder) { + mGLThread.surfaceCreated(); + } + + /** + * This method is part of the SurfaceHolder.Callback interface, and is + * not normally called or subclassed by clients of GLSurfaceView. + */ + public void surfaceDestroyed(SurfaceHolder holder) { + // Surface will be destroyed when we return + mGLThread.surfaceDestroyed(); + } + + /** + * This method is part of the SurfaceHolder.Callback interface, and is + * not normally called or subclassed by clients of GLSurfaceView. + */ + public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { + mGLThread.onWindowResize(w, h); + } + + /** + * Inform the view that the activity is paused. The owner of this view must + * call this method when the activity is paused. Calling this method will + * pause the rendering thread. + * Must not be called before a renderer has been set. + */ + public void onPause() { + mGLThread.onPause(); + } + + /** + * Inform the view that the activity is resumed. The owner of this view must + * call this method when the activity is resumed. Calling this method will + * recreate the OpenGL display and resume the rendering + * thread. + * Must not be called before a renderer has been set. + */ + public void onResume() { + mGLThread.onResume(); + } + + /** + * Queue a runnable to be run on the GL rendering thread. This can be used + * to communicate with the Renderer on the rendering thread. + * Must not be called before a renderer has been set. + * @param r the runnable to be run on the GL rendering thread. + */ + public void queueEvent(Runnable r) { + mGLThread.queueEvent(r); + } + + /** + * This method is used as part of the View class and is not normally + * called or subclassed by clients of GLSurfaceView. + * Must not be called before a renderer has been set. + */ + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mGLThread.requestExitAndWait(); + } + + // ---------------------------------------------------------------------- + + /** + * An interface used to wrap a GL interface. + *

Typically + * used for implementing debugging and tracing on top of the default + * GL interface. You would typically use this by creating your own class + * that implemented all the GL methods by delegating to another GL instance. + * Then you could add your own behavior before or after calling the + * delegate. All the GLWrapper would do was instantiate and return the + * wrapper GL instance: + *

+     * class MyGLWrapper implements GLWrapper {
+     *     GL wrap(GL gl) {
+     *         return new MyGLImplementation(gl);
+     *     }
+     *     static class MyGLImplementation implements GL,GL10,GL11,... {
+     *         ...
+     *     }
+     * }
+     * 
+ * @see #setGLWrapper(GLWrapper) + */ + public interface GLWrapper { + /** + * Wraps a gl interface in another gl interface. + * @param gl a GL interface that is to be wrapped. + * @return either the input argument or another GL object that wraps the input argument. + */ + GL wrap(GL gl); + } + + /** + * A generic renderer interface. + *

+ * The renderer is responsible for making OpenGL calls to render a frame. + *

+ * GLSurfaceView clients typically create their own classes that implement + * this interface, and then call {@link GLSurfaceView#setRenderer} to + * register the renderer with the GLSurfaceView. + *

+ *

Threading

+ * The renderer will be called on a separate thread, so that rendering + * performance is decoupled from the UI thread. Clients typically need to + * communicate with the renderer from the UI thread, because that's where + * input events are received. Clients can communicate using any of the + * standard Java techniques for cross-thread communication, or they can + * use the {@link GLSurfaceView#queueEvent(Runnable)} convenience method. + *

+ *

EGL Context Lost

+ * There are situations where the EGL rendering context will be lost. This + * typically happens when device wakes up after going to sleep. When + * the EGL context is lost, all OpenGL resources (such as textures) that are + * associated with that context will be automatically deleted. In order to + * keep rendering correctly, a renderer must recreate any lost resources + * that it still needs. The {@link #onSurfaceCreated(GL10, EGLConfig)} method + * is a convenient place to do this. + * + * + * @see #setRenderer(Renderer) + */ + public static interface SwapBuffersCallback { + public boolean SwapBuffers(); + } + + public static abstract class Renderer { + /** + * Called when the surface is created or recreated. + *

+ * Called when the rendering thread + * starts and whenever the EGL context is lost. The context will typically + * be lost when the Android device awakes after going to sleep. + *

+ * Since this method is called at the beginning of rendering, as well as + * every time the EGL context is lost, this method is a convenient place to put + * code to create resources that need to be created when the rendering + * starts, and that need to be recreated when the EGL context is lost. + * Textures are an example of a resource that you might want to create + * here. + *

+ * Note that when the EGL context is lost, all OpenGL resources associated + * with that context will be automatically deleted. You do not need to call + * the corresponding "glDelete" methods such as glDeleteTextures to + * manually delete these lost resources. + *

+ * @param gl the GL interface. Use instanceof to + * test if the interface supports GL11 or higher interfaces. + * @param config the EGLConfig of the created surface. Can be used + * to create matching pbuffers. + */ + public abstract void onSurfaceCreated(GL10 gl, EGLConfig config); + + public abstract void onSurfaceDestroyed(); + + /** + * Called when the surface changed size. + *

+ * Called after the surface is created and whenever + * the OpenGL ES surface size changes. + *

+ * Typically you will set your viewport here. If your camera + * is fixed then you could also set your projection matrix here: + *

+         * void onSurfaceChanged(GL10 gl, int width, int height) {
+         *     gl.glViewport(0, 0, width, height);
+         *     // for a fixed camera, set the projection too
+         *     float ratio = (float) width / height;
+         *     gl.glMatrixMode(GL10.GL_PROJECTION);
+         *     gl.glLoadIdentity();
+         *     gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
+         * }
+         * 
+ * @param gl the GL interface. Use instanceof to + * test if the interface supports GL11 or higher interfaces. + * @param width + * @param height + */ + public abstract void onSurfaceChanged(GL10 gl, int width, int height); + + /** + * Called to draw the current frame. + *

+ * This method is responsible for drawing the current frame. + *

+ * The implementation of this method typically looks like this: + *

+         * void onDrawFrame(GL10 gl) {
+         *     gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
+         *     //... other gl calls to render the scene ...
+         * }
+         * 
+ * @param gl the GL interface. Use instanceof to + * test if the interface supports GL11 or higher interfaces. + */ + public abstract void onDrawFrame(GL10 gl); + + public boolean SwapBuffers() { + if( mSwapBuffersCallback != null ) + return mSwapBuffersCallback.SwapBuffers(); + return false; + } + + public void setSwapBuffersCallback( SwapBuffersCallback c ) { + mSwapBuffersCallback = c; + } + + private SwapBuffersCallback mSwapBuffersCallback = null; + } + + /** + * An interface for choosing an EGLConfig configuration from a list of + * potential configurations. + *

+ * This interface must be implemented by clients wishing to call + * {@link GLSurfaceView#setEGLConfigChooser(EGLConfigChooser)} + */ + public interface EGLConfigChooser { + /** + * Choose a configuration from the list. Implementors typically + * implement this method by calling + * {@link EGL10#eglChooseConfig} and iterating through the results. Please consult the + * EGL specification available from The Khronos Group to learn how to call eglChooseConfig. + * @param egl the EGL10 for the current display. + * @param display the current display. + * @return the chosen configuration. + */ + EGLConfig chooseConfig(EGL10 egl, EGLDisplay display); + public boolean isGles2Required(); + } + + private static abstract class BaseConfigChooser + implements EGLConfigChooser { + public BaseConfigChooser(int[] configSpec) { + mConfigSpec = configSpec; + } + public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { + int[] num_config = new int[1]; + egl.eglChooseConfig(display, mConfigSpec, null, 0, num_config); + + int numConfigs = num_config[0]; + + if (numConfigs <= 0) { + throw new IllegalArgumentException( + "No configs match configSpec"); + } + + EGLConfig[] configs = new EGLConfig[numConfigs]; + egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, + num_config); + EGLConfig config = chooseConfig(egl, display, configs); + if (config == null) { + throw new IllegalArgumentException("No config chosen"); + } + return config; + } + + abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, + EGLConfig[] configs); + + protected int[] mConfigSpec; + } + + private static class ComponentSizeChooser extends BaseConfigChooser { + public ComponentSizeChooser(int redSize, int greenSize, int blueSize, + int alphaSize, int depthSize, int stencilSize, boolean isGles2) { + super(new int[] {EGL10.EGL_NONE}); // Get all possible configs + mValue = new int[1]; + mRedSize = redSize; + mGreenSize = greenSize; + mBlueSize = blueSize; + mAlphaSize = alphaSize; + mDepthSize = depthSize; + mStencilSize = stencilSize; + mIsGles2 = isGles2; + } + + @Override + public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, + EGLConfig[] configs) { + EGLConfig closestConfig = null; + int closestDistance = 1000; + String cfglog = ""; + int idx = 0; + int selectidx = -1; + + Log.v("SDL", "Desired GL config: " + "R" + mRedSize + "G" + mGreenSize + "B" + mBlueSize + "A" + mAlphaSize + " depth " + mDepthSize + " stencil " + mStencilSize + " type " + (mIsGles2 ? "GLES2" : "GLES")); + for(EGLConfig config : configs) { + if ( config == null ) + continue; + int r = findConfigAttrib(egl, display, config, + EGL10.EGL_RED_SIZE, 0); + int g = findConfigAttrib(egl, display, config, + EGL10.EGL_GREEN_SIZE, 0); + int b = findConfigAttrib(egl, display, config, + EGL10.EGL_BLUE_SIZE, 0); + int a = findConfigAttrib(egl, display, config, + EGL10.EGL_ALPHA_SIZE, 0); + int d = findConfigAttrib(egl, display, config, + EGL10.EGL_DEPTH_SIZE, 0); + int s = findConfigAttrib(egl, display, config, + EGL10.EGL_STENCIL_SIZE, 0); + int rendertype = findConfigAttrib(egl, display, config, + EGL10.EGL_RENDERABLE_TYPE, 0); + int desiredtype = mIsGles2 ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_ES_BIT; + int nativeRender = findConfigAttrib(egl, display, config, + EGL10.EGL_NATIVE_RENDERABLE, 0); + int caveat = findConfigAttrib(egl, display, config, + EGL10.EGL_CONFIG_CAVEAT, EGL10.EGL_NONE); + int distance = Math.abs(r - mRedSize) + Math.abs(g - mGreenSize) + Math.abs(b - mBlueSize); + int dist1 = distance; + if( mAlphaSize - a > 0 ) + distance += mAlphaSize - a; + else if( mAlphaSize - a < 0 ) + distance += 1; // Small penalty if we don't need alpha channel but it is present + int dist2 = distance; + if( (d > 0) != (mDepthSize > 0) ) + distance += (mDepthSize > 0) ? 5 : 1; // Small penalty if we don't need zbuffer but it is present + int dist3 = distance; + if( (s > 0) != (mStencilSize > 0) ) + distance += (mStencilSize > 0) ? 5 : 1; // Small penalty if we don't need stencil buffer but it is present + int dist4 = distance; + if( (rendertype & desiredtype) == 0 ) + distance += 5; + int dist5 = distance; + if( caveat == EGL10.EGL_SLOW_CONFIG ) + distance += 4; + if( caveat == EGL10.EGL_NON_CONFORMANT_CONFIG ) // dunno what that means, probably R and B channels swapped + distance += 1; + + String cfgcur = "R" + r + "G" + g + "B" + b + "A" + a + " depth " + d + " stencil " + s + + " type " + rendertype + " ("; + if((rendertype & EGL_OPENGL_ES_BIT) != 0) + cfgcur += "GLES"; + if((rendertype & EGL_OPENGL_ES2_BIT) != 0) + cfgcur += " GLES2"; + if((rendertype & EGL_OPENGL_BIT) != 0) + cfgcur += " OPENGL"; + if((rendertype & EGL_OPENVG_BIT) != 0) + cfgcur += " OPENVG"; + cfgcur += ")"; + cfgcur += " caveat " + (caveat == EGL10.EGL_NONE ? "none" : + (caveat == EGL10.EGL_SLOW_CONFIG ? "SLOW" : + caveat == EGL10.EGL_NON_CONFORMANT_CONFIG ? "non-conformant" : + String.valueOf(caveat))); + cfgcur += " nr " + nativeRender; + cfgcur += " pos " + distance + " (" + dist1 + "," + dist2 + "," + dist3 + "," + dist4 + "," + dist5 + ")"; + Log.v("SDL", "GL config " + idx + ": " + cfgcur); + if (distance < closestDistance) { + closestDistance = distance; + closestConfig = config; + cfglog = new String(cfgcur); + selectidx = idx; + } + idx += 1; + } + Log.v("SDL", "GLSurfaceView_SDL::EGLConfigChooser::chooseConfig(): selected " + selectidx + ": " + cfglog ); + return closestConfig; + } + + private int findConfigAttrib(EGL10 egl, EGLDisplay display, + EGLConfig config, int attribute, int defaultValue) { + mValue[0] = -1; + if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { + return mValue[0]; + } + Log.w("SDL", "GLSurfaceView_SDL::EGLConfigChooser::findConfigAttrib(): attribute doesn't exist: " + attribute); + return defaultValue; + } + + public boolean isGles2Required() + { + return mIsGles2; + } + + private int[] mValue; + // Subclasses can adjust these values: + protected int mRedSize; + protected int mGreenSize; + protected int mBlueSize; + protected int mAlphaSize; + protected int mDepthSize; + protected int mStencilSize; + protected boolean mIsGles2 = false; + + public static final int EGL_OPENGL_ES_BIT = 1; + public static final int EGL_OPENVG_BIT = 2; + public static final int EGL_OPENGL_ES2_BIT = 4; + public static final int EGL_OPENGL_BIT = 8; + } + + /** + * This class will choose a supported surface as close to + * RGB565 as possible, with or without a depth buffer. + * + */ + private static class SimpleEGLConfigChooser16 extends ComponentSizeChooser { + public SimpleEGLConfigChooser16(boolean withDepthBuffer, boolean stencil, boolean gles2) { + super(4, 4, 4, 0, withDepthBuffer ? 16 : 0, stencil ? 8 : 0, gles2); + // Adjust target values. This way we'll accept a 4444 or + // 555 buffer if there's no 565 buffer available. + mRedSize = 5; + mGreenSize = 6; + mBlueSize = 5; + } + } + + private static class SimpleEGLConfigChooser24 extends ComponentSizeChooser { + public SimpleEGLConfigChooser24(boolean withDepthBuffer, boolean stencil, boolean gles2) { + super(8, 8, 8, 0, withDepthBuffer ? 16 : 0, stencil ? 8 : 0, gles2); + mRedSize = 8; + mGreenSize = 8; + mBlueSize = 8; + } + } + + private static class SimpleEGLConfigChooser32 extends ComponentSizeChooser { + public SimpleEGLConfigChooser32(boolean withDepthBuffer, boolean stencil, boolean gles2) { + super(8, 8, 8, 8, withDepthBuffer ? 16 : 0, stencil ? 8 : 0, gles2); + mRedSize = 8; + mGreenSize = 8; + mBlueSize = 8; + mAlphaSize = 8; + } + } + private static ComponentSizeChooser getEglConfigChooser(int videoDepthBpp, boolean withDepthBuffer, boolean stencil, boolean gles2) { + if(videoDepthBpp == 16) + return new SimpleEGLConfigChooser16(withDepthBuffer, stencil, gles2); + if(videoDepthBpp == 24) + return new SimpleEGLConfigChooser24(withDepthBuffer, stencil, gles2); + if(videoDepthBpp == 32) + return new SimpleEGLConfigChooser32(withDepthBuffer, stencil, gles2); + return null; + }; + + /** + * An EGL helper class. + */ + + private class EglHelper { + public EglHelper() { + + } + + /** + * Initialize EGL for a given configuration spec. + * @param configSpec + */ + public void start(){ + + Log.v("SDL", "GLSurfaceView_SDL::EglHelper::start(): creating GL context"); + /* + * Get an EGL instance + */ + mEgl = (EGL10) EGLContext.getEGL(); + + /* + * Get to the default display. + */ + mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + + /* + * We can now initialize EGL for that display + */ + int[] version = new int[2]; + mEgl.eglInitialize(mEglDisplay, version); + mEglConfig = mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay); + if( mEglConfig == null ) + Log.e("SDL", "GLSurfaceView_SDL::EglHelper::start(): mEglConfig is NULL"); + + /* + * Create an OpenGL ES context. This must be done only once, an + * OpenGL context is a somewhat heavy object. + */ + final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; + final int[] gles2_attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; + + mEglContext = mEgl.eglCreateContext(mEglDisplay, mEglConfig, + EGL10.EGL_NO_CONTEXT, mEGLConfigChooser.isGles2Required() ? gles2_attrib_list : null ); + + if( mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT ) + Log.e("SDL", "GLSurfaceView_SDL::EglHelper::start(): mEglContext is EGL_NO_CONTEXT, error: " + mEgl.eglGetError()); + + mEglSurface = null; + } + + /* + * React to the creation of a new surface by creating and returning an + * OpenGL interface that renders to that surface. + */ + public GL createSurface(SurfaceHolder holder) { + Log.v("SDL", "GLSurfaceView_SDL::EglHelper::createSurface(): creating GL context"); + /* + * The window size has changed, so we need to create a new + * surface. + */ + if (mEglSurface != null) { + + /* + * Unbind and destroy the old EGL surface, if + * there is one. + */ + mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, + EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); + mEgl.eglDestroySurface(mEglDisplay, mEglSurface); + } + + /* + * Create an EGL surface we can render into. + */ + /* + // This does not have any effect on Galaxy Note + int [] attribList = new int[4]; + attribList[0] = mEgl.EGL_RENDER_BUFFER; + attribList[1] = mEgl.EGL_SINGLE_BUFFER; + attribList[2] = mEgl.EGL_NONE; + attribList[3] = mEgl.EGL_NONE; + */ + mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, + mEglConfig, holder, null); + + /* + * Before we can issue GL commands, we need to make sure + * the context is current and bound to a surface. + */ + mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, + mEglContext); + + + GL gl = mEglContext.getGL(); + if (mGLWrapper != null) { + gl = mGLWrapper.wrap(gl); + } + + return gl; + } + + /** + * Display the current render surface. + * @return false if the context has been lost. + */ + public boolean swap() { + mEgl.eglSwapBuffers(mEglDisplay, mEglSurface); + + /* + * Always check for EGL_CONTEXT_LOST, which means the context + * and all associated data were lost (For instance because + * the device went to sleep). We need to sleep until we + * get a new surface. + */ + return mEgl.eglGetError() != EGL11.EGL_CONTEXT_LOST; + } + + public void finish() { + Log.v("SDL", "GLSurfaceView_SDL::EglHelper::finish(): destroying GL context"); + if (mEglSurface != null) { + mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, + EGL10.EGL_NO_SURFACE, + EGL10.EGL_NO_CONTEXT); + mEgl.eglDestroySurface(mEglDisplay, mEglSurface); + mEglSurface = null; + } + if (mEglContext != null) { + mEgl.eglDestroyContext(mEglDisplay, mEglContext); + mEglContext = null; + } + if (mEglDisplay != null) { + mEgl.eglTerminate(mEglDisplay); + mEglDisplay = null; + } + } + + EGL10 mEgl; + EGLDisplay mEglDisplay; + EGLSurface mEglSurface; + EGLConfig mEglConfig; + EGLContext mEglContext; + } + + /** + * A generic GL Thread. Takes care of initializing EGL and GL. Delegates + * to a Renderer instance to do the actual drawing. Can be configured to + * render continuously or on request. + * + */ + class GLThread extends Thread implements SwapBuffersCallback { + GLThread(Renderer renderer) { + super(); + mDone = false; + mWidth = 0; + mHeight = 0; + mRequestRender = true; + mRenderMode = RENDERMODE_CONTINUOUSLY; + mRenderer = renderer; + mRenderer.setSwapBuffersCallback(this); + setName("GLThread"); + } + + @Override + public void run() { + /* + * When the android framework launches a second instance of + * an activity, the new instance's onCreate() method may be + * called before the first instance returns from onDestroy(). + * + * This semaphore ensures that only one instance at a time + * accesses EGL. + */ + try { + sEglSemaphore.acquire(); + } catch (InterruptedException e) { + return; + } + + mEglHelper = new EglHelper(); + // mEglHelper.start(); + mNeedStart = true; + mSizeChanged = true; + SwapBuffers(); + + mRenderer.onDrawFrame(mGL); + + mEglHelper.finish(); + + /* + synchronized (sGLThreadManager) { + stopEglLocked(); + } + sGLThreadManager.threadExiting(this); + */ + + sEglSemaphore.release(); + } + + public boolean SwapBuffers() { + + boolean tellRendererSurfaceCreated = false; + boolean tellRendererSurfaceChanged = false; + + /* + * This is our main activity thread's loop, we go until + * asked to quit. + */ + + /* + * Update the asynchronous state (window size) + */ + while(true) { // Loop until we're re-created GL context and successfully called swap() + + int w, h; + boolean changed = false; + synchronized (this) { + /* + Runnable r; + while ((r = getEvent()) != null) { + r.run(); + } + */ + if (mPaused) { + mRenderer.onSurfaceDestroyed(); + mEglHelper.finish(); + mNeedStart = true; + if( Globals.NonBlockingSwapBuffers ) + return false; + } + while (needToWait()) { + //Log.v("SDL", "GLSurfaceView_SDL::run(): paused"); + try { + wait(500); + } catch(Exception e) { } + } + if (mDone) { + return false; + } + // changed = mSizeChanged; + w = mWidth; + h = mHeight; + mSizeChanged = false; + mRequestRender = false; + } + if (mNeedStart) { + mEglHelper.start(); + tellRendererSurfaceCreated = true; + changed = true; + mNeedStart = false; + } + if (changed) { + mGL = (GL10) mEglHelper.createSurface(getHolder()); + tellRendererSurfaceChanged = true; + } + if (tellRendererSurfaceCreated) { + mRenderer.onSurfaceCreated(mGL, mEglHelper.mEglConfig); + tellRendererSurfaceCreated = false; + } + if (tellRendererSurfaceChanged) { + mRenderer.onSurfaceChanged(mGL, w, h); + tellRendererSurfaceChanged = false; + } + /* + * Once we're done with GL, we need to call swapBuffers() + * to instruct the system to display the rendered frame + */ + if( mEglHelper.swap() ) + return true; + // We've lost GL context - recreate it + mRenderer.onSurfaceDestroyed(); + mEglHelper.finish(); + mNeedStart = true; + if( Globals.NonBlockingSwapBuffers ) + return false; + } + } + + private boolean needToWait() { + if (((KeyguardManager)getContext().getSystemService(Context.KEYGUARD_SERVICE)).inKeyguardRestrictedInputMode()) { + return true; // We're in lockscreen - sleep until user unlocks the device + } + + if (mDone) { + return false; + } + + if (mPaused || (! mHasSurface)) { + return true; + } + + if ((mWidth > 0) && (mHeight > 0) && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY))) { + return false; + } + + return true; + } + + public void setRenderMode(int renderMode) { + if ( !((RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= RENDERMODE_CONTINUOUSLY)) ) { + throw new IllegalArgumentException("renderMode"); + } + synchronized(this) { + mRenderMode = renderMode; + if (renderMode == RENDERMODE_CONTINUOUSLY) { + notify(); + } + } + } + + public int getRenderMode() { + synchronized(this) { + return mRenderMode; + } + } + + public void requestRender() { + synchronized(this) { + mRequestRender = true; + notify(); + } + } + + public void surfaceCreated() { + synchronized(this) { + mHasSurface = true; + notify(); + } + } + + public void surfaceDestroyed() { + synchronized(this) { + mHasSurface = false; + notify(); + } + } + + public void onPause() { + Log.v("SDL", "GLSurfaceView_SDL::onPause()"); + synchronized (this) { + mPaused = true; + } + } + + public void onResume() { + Log.v("SDL", "GLSurfaceView_SDL::onResume()"); + synchronized (this) { + mPaused = false; + notify(); + } + } + + public void onWindowResize(int w, int h) { + synchronized (this) { + mWidth = w; + mHeight = h; + mSizeChanged = true; + notify(); + } + } + + public void requestExitAndWait() { + // don't call this from GLThread thread or it is a guaranteed + // deadlock! + synchronized(this) { + mDone = true; + notify(); + } + try { + join(); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + + /** + * Queue an "event" to be run on the GL rendering thread. + * @param r the runnable to be run on the GL rendering thread. + */ + public void queueEvent(Runnable r) { + synchronized(this) { + mEventQueue.add(r); + } + } + + private Runnable getEvent() { + synchronized(this) { + if (mEventQueue.size() > 0) { + return mEventQueue.remove(0); + } + + } + return null; + } + + private boolean mDone; + private boolean mPaused; + private boolean mHasSurface; + private int mWidth; + private int mHeight; + private int mRenderMode; + private boolean mRequestRender; + private Renderer mRenderer; + private ArrayList mEventQueue = new ArrayList(); + private EglHelper mEglHelper; + private GL10 mGL = null; + private boolean mNeedStart = false; + } + + static class LogWriter extends Writer { + + @Override public void close() { + flushBuilder(); + } + + @Override public void flush() { + flushBuilder(); + } + + @Override public void write(char[] buf, int offset, int count) { + for(int i = 0; i < count; i++) { + char c = buf[offset + i]; + if ( c == '\n') { + flushBuilder(); + } + else { + mBuilder.append(c); + } + } + } + + private void flushBuilder() { + if (mBuilder.length() > 0) { + Log.v("GLSurfaceView", mBuilder.toString()); + mBuilder.delete(0, mBuilder.length()); + } + } + + private StringBuilder mBuilder = new StringBuilder(); + } + + private static final Semaphore sEglSemaphore = new Semaphore(1); + private boolean mSizeChanged = true; + + private GLThread mGLThread; + private EGLConfigChooser mEGLConfigChooser; + private GLWrapper mGLWrapper; + private int mDebugFlags; +} diff --git a/project/javaSDL2/Globals.java b/project/javaSDL2/Globals.java new file mode 100644 index 000000000..5e2959a3c --- /dev/null +++ b/project/javaSDL2/Globals.java @@ -0,0 +1,125 @@ +/* +Simple DirectMedia Layer +Java source code (C) 2009-2012 Sergii Pylypenko + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +package net.sourceforge.clonekeenplus; + +import android.app.Activity; +import android.content.Context; +import java.util.Vector; +import android.view.KeyEvent; + +class Globals +{ + // These config options are modified by ChangeAppsettings.sh script - see the detailed descriptions there + public static String ApplicationName = "CommanderGenius"; + public static String AppLibraries[] = { "sdl-1.2", }; + public static String AppMainLibraries[] = { "application", "sdl_main" }; + public static final boolean Using_SDL_1_3 = false; + public static String[] DataDownloadUrl = { "Data files are 2 Mb|https://sourceforge.net/projects/libsdl-android/files/CommanderGenius/commandergenius-data.zip/download", "High-quality GFX and music - 40 Mb|https://sourceforge.net/projects/libsdl-android/files/CommanderGenius/commandergenius-hqp.zip/download" }; + public static int VideoDepthBpp = 16; + public static boolean SwVideoMode = false; + public static boolean NeedDepthBuffer = false; + public static boolean NeedStencilBuffer = false; + public static boolean NeedGles2 = false; + public static boolean CompatibilityHacksVideo = false; + public static boolean CompatibilityHacksStaticInit = false; + public static boolean CompatibilityHacksTextInputEmulatesHwKeyboard = false; + public static boolean HorizontalOrientation = true; + public static boolean KeepAspectRatioDefaultSetting = false; + public static boolean InhibitSuspend = false; + public static String ReadmeText = "^You may press \"Home\" now - the data will be downloaded in background".replace("^","\n"); + public static String CommandLine = ""; + public static boolean AppUsesMouse = false; + public static boolean AppNeedsTwoButtonMouse = false; + public static boolean ForceRelativeMouseMode = false; // If both on-screen keyboard and mouse are needed, this will only set the default setting, user may override it later + public static boolean ShowMouseCursor = false; + public static boolean AppNeedsArrowKeys = true; + public static boolean AppNeedsTextInput = true; + public static boolean AppUsesJoystick = false; + public static boolean AppUsesSecondJoystick = false; + public static boolean AppUsesAccelerometer = false; + public static boolean AppUsesGyroscope = false; + public static boolean AppUsesMultitouch = false; + public static boolean NonBlockingSwapBuffers = false; + public static boolean ResetSdlConfigForThisVersion = false; + public static String DeleteFilesOnUpgrade = ""; + public static int AppTouchscreenKeyboardKeysAmount = 4; + public static int AppTouchscreenKeyboardKeysAmountAutoFire = 1; + public static String[] AppTouchscreenKeyboardKeysNames = "Fire Shoot Switch_weapon Jump Run Hide/Seek".split(" "); + public static int StartupMenuButtonTimeout = 3000; + public static int AppMinimumRAM = 0; + public static SettingsMenu.Menu HiddenMenuOptions [] = {}; // If you see error here - update HiddenMenuOptions in your AndroidAppSettings.cfg: change OptionalDownloadConfig to SettingsMenuMisc.OptionalDownloadConfig etc. + public static SettingsMenu.Menu FirstStartMenuOptions [] = { new SettingsMenuMisc.ShowReadme(), (AppUsesMouse && ! ForceRelativeMouseMode ? new SettingsMenuMouse.DisplaySizeConfig() : new SettingsMenu.DummyMenu()), new SettingsMenuMisc.OptionalDownloadConfig(), new SettingsMenuMisc.GyroscopeCalibration() }; + public static String AdmobPublisherId = ""; + public static String AdmobTestDeviceId = ""; + public static String AdmobBannerSize = ""; + + // Phone-specific config, modified by user in "Change phone config" startup dialog, TODO: move this to settings + public static boolean DownloadToSdcard = true; + public static boolean PhoneHasTrackball = false; + public static boolean PhoneHasArrowKeys = false; + public static boolean UseAccelerometerAsArrowKeys = false; + public static boolean UseTouchscreenKeyboard = true; + public static int TouchscreenKeyboardSize = 1; + public static final int TOUCHSCREEN_KEYBOARD_CUSTOM = 4; + public static int TouchscreenKeyboardDrawSize = 1; + public static int TouchscreenKeyboardTheme = 2; + public static int TouchscreenKeyboardTransparency = 2; + public static int AccelerometerSensitivity = 2; + public static int AccelerometerCenterPos = 2; + public static int TrackballDampening = 0; + public static int AudioBufferConfig = 0; + public static boolean OptionalDataDownload[] = null; + public static int LeftClickMethod = Mouse.LEFT_CLICK_NORMAL; + public static int LeftClickKey = KeyEvent.KEYCODE_DPAD_CENTER; + public static int LeftClickTimeout = 3; + public static int RightClickTimeout = 4; + public static int RightClickMethod = AppNeedsTwoButtonMouse ? Mouse.RIGHT_CLICK_WITH_MULTITOUCH : Mouse.RIGHT_CLICK_NONE; + public static int RightClickKey = KeyEvent.KEYCODE_MENU; + public static boolean MoveMouseWithJoystick = false; + public static int MoveMouseWithJoystickSpeed = 0; + public static int MoveMouseWithJoystickAccel = 0; + public static boolean ClickMouseWithDpad = false; + public static boolean RelativeMouseMovement = ForceRelativeMouseMode; // Laptop touchpad mode + public static int RelativeMouseMovementSpeed = 2; + public static int RelativeMouseMovementAccel = 0; + public static int ShowScreenUnderFinger = Mouse.ZOOM_NONE; + public static boolean KeepAspectRatio = KeepAspectRatioDefaultSetting; + public static int ClickScreenPressure = 0; + public static int ClickScreenTouchspotSize = 0; + public static int RemapHwKeycode[] = new int[SDL_Keys.JAVA_KEYCODE_LAST]; + public static int RemapScreenKbKeycode[] = new int[6]; + public static int ScreenKbControlsLayout[][] = AppUsesSecondJoystick ? // Values for 800x480 resolution + new int[][] { { 0, 303, 177, 480 }, { 0, 0, 48, 48 }, { 400, 392, 488, 480 }, { 312, 392, 400, 480 }, { 400, 304, 488, 392 }, { 312, 304, 400, 392 }, { 400, 216, 488, 304 }, { 312, 216, 400, 304 }, { 623, 303, 800, 480 } } : + new int[][] { { 0, 303, 177, 480 }, { 0, 0, 48, 48 }, { 712, 392, 800, 480 }, { 624, 392, 712, 480 }, { 712, 304, 800, 392 }, { 624, 304, 712, 392 }, { 712, 216, 800, 304 }, { 624, 216, 712, 304 } }; + public static boolean ScreenKbControlsShown[] = new boolean[ScreenKbControlsLayout.length]; /* Also joystick and text input button added */ + public static int RemapMultitouchGestureKeycode[] = new int[4]; + public static boolean MultitouchGesturesUsed[] = new boolean[4]; + public static int MultitouchGestureSensitivity = 1; + public static int TouchscreenCalibration[] = new int[4]; + public static String DataDir = new String(""); + public static boolean VideoLinearFilter = true; + public static boolean MultiThreadedVideo = false; + public static boolean BrokenLibCMessageShown = false; + // Gyroscope calibration + public static float gyro_x1, gyro_x2, gyro_xc, gyro_y1, gyro_y2, gyro_yc, gyro_z1, gyro_z2, gyro_zc; + public static boolean OuyaEmulation = false; // For debugging +} diff --git a/project/javaSDL2/Keycodes.java b/project/javaSDL2/Keycodes.java new file mode 100644 index 000000000..15aa6b6e9 --- /dev/null +++ b/project/javaSDL2/Keycodes.java @@ -0,0 +1,592 @@ +/* +Simple DirectMedia Layer +Java source code (C) 2009-2012 Sergii Pylypenko + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +package net.sourceforge.clonekeenplus; + +import java.lang.String; +import java.util.ArrayList; +import java.util.Arrays; +import java.lang.reflect.Field; + + +// Autogenerated by hand with a command: +// grep 'SDLK_' SDL_keysym.h | sed 's/SDLK_\([a-zA-Z0-9_]\+\).*[=] \([0-9]\+\).*/public static final int SDLK_\1 = \2;/' >> Keycodes.java +class SDL_1_2_Keycodes +{ + public static final int SDLK_UNKNOWN = 0; + public static final int SDLK_BACKSPACE = 8; + public static final int SDLK_TAB = 9; + public static final int SDLK_CLEAR = 12; + public static final int SDLK_RETURN = 13; + public static final int SDLK_PAUSE = 19; + public static final int SDLK_ESCAPE = 27; + public static final int SDLK_SPACE = 32; + public static final int SDLK_EXCLAIM = 33; + public static final int SDLK_QUOTEDBL = 34; + public static final int SDLK_HASH = 35; + public static final int SDLK_DOLLAR = 36; + public static final int SDLK_AMPERSAND = 38; + public static final int SDLK_QUOTE = 39; + public static final int SDLK_LEFTPAREN = 40; + public static final int SDLK_RIGHTPAREN = 41; + public static final int SDLK_ASTERISK = 42; + public static final int SDLK_PLUS = 43; + public static final int SDLK_COMMA = 44; + public static final int SDLK_MINUS = 45; + public static final int SDLK_PERIOD = 46; + public static final int SDLK_SLASH = 47; + public static final int SDLK_0 = 48; + public static final int SDLK_1 = 49; + public static final int SDLK_2 = 50; + public static final int SDLK_3 = 51; + public static final int SDLK_4 = 52; + public static final int SDLK_5 = 53; + public static final int SDLK_6 = 54; + public static final int SDLK_7 = 55; + public static final int SDLK_8 = 56; + public static final int SDLK_9 = 57; + public static final int SDLK_COLON = 58; + public static final int SDLK_SEMICOLON = 59; + public static final int SDLK_LESS = 60; + public static final int SDLK_EQUALS = 61; + public static final int SDLK_GREATER = 62; + public static final int SDLK_QUESTION = 63; + public static final int SDLK_AT = 64; + public static final int SDLK_LEFTBRACKET = 91; + public static final int SDLK_BACKSLASH = 92; + public static final int SDLK_RIGHTBRACKET = 93; + public static final int SDLK_CARET = 94; + public static final int SDLK_UNDERSCORE = 95; + public static final int SDLK_BACKQUOTE = 96; + public static final int SDLK_a = 97; + public static final int SDLK_b = 98; + public static final int SDLK_c = 99; + public static final int SDLK_d = 100; + public static final int SDLK_e = 101; + public static final int SDLK_f = 102; + public static final int SDLK_g = 103; + public static final int SDLK_h = 104; + public static final int SDLK_i = 105; + public static final int SDLK_j = 106; + public static final int SDLK_k = 107; + public static final int SDLK_l = 108; + public static final int SDLK_m = 109; + public static final int SDLK_n = 110; + public static final int SDLK_o = 111; + public static final int SDLK_p = 112; + public static final int SDLK_q = 113; + public static final int SDLK_r = 114; + public static final int SDLK_s = 115; + public static final int SDLK_t = 116; + public static final int SDLK_u = 117; + public static final int SDLK_v = 118; + public static final int SDLK_w = 119; + public static final int SDLK_x = 120; + public static final int SDLK_y = 121; + public static final int SDLK_z = 122; + public static final int SDLK_DELETE = 127; + public static final int SDLK_WORLD_0 = 160; + public static final int SDLK_WORLD_1 = 161; + public static final int SDLK_WORLD_2 = 162; + public static final int SDLK_WORLD_3 = 163; + public static final int SDLK_WORLD_4 = 164; + public static final int SDLK_WORLD_5 = 165; + public static final int SDLK_WORLD_6 = 166; + public static final int SDLK_WORLD_7 = 167; + public static final int SDLK_WORLD_8 = 168; + public static final int SDLK_WORLD_9 = 169; + public static final int SDLK_WORLD_10 = 170; + public static final int SDLK_WORLD_11 = 171; + public static final int SDLK_WORLD_12 = 172; + public static final int SDLK_WORLD_13 = 173; + public static final int SDLK_WORLD_14 = 174; + public static final int SDLK_WORLD_15 = 175; + public static final int SDLK_WORLD_16 = 176; + public static final int SDLK_WORLD_17 = 177; + public static final int SDLK_WORLD_18 = 178; + public static final int SDLK_WORLD_19 = 179; + public static final int SDLK_WORLD_20 = 180; + public static final int SDLK_WORLD_21 = 181; + public static final int SDLK_WORLD_22 = 182; + public static final int SDLK_WORLD_23 = 183; + public static final int SDLK_WORLD_24 = 184; + public static final int SDLK_WORLD_25 = 185; + public static final int SDLK_WORLD_26 = 186; + public static final int SDLK_WORLD_27 = 187; + public static final int SDLK_WORLD_28 = 188; + public static final int SDLK_WORLD_29 = 189; + public static final int SDLK_WORLD_30 = 190; + public static final int SDLK_WORLD_31 = 191; + public static final int SDLK_WORLD_32 = 192; + public static final int SDLK_WORLD_33 = 193; + public static final int SDLK_WORLD_34 = 194; + public static final int SDLK_WORLD_35 = 195; + public static final int SDLK_WORLD_36 = 196; + public static final int SDLK_WORLD_37 = 197; + public static final int SDLK_WORLD_38 = 198; + public static final int SDLK_WORLD_39 = 199; + public static final int SDLK_WORLD_40 = 200; + public static final int SDLK_WORLD_41 = 201; + public static final int SDLK_WORLD_42 = 202; + public static final int SDLK_WORLD_43 = 203; + public static final int SDLK_WORLD_44 = 204; + public static final int SDLK_WORLD_45 = 205; + public static final int SDLK_WORLD_46 = 206; + public static final int SDLK_WORLD_47 = 207; + public static final int SDLK_WORLD_48 = 208; + public static final int SDLK_WORLD_49 = 209; + public static final int SDLK_WORLD_50 = 210; + public static final int SDLK_WORLD_51 = 211; + public static final int SDLK_WORLD_52 = 212; + public static final int SDLK_WORLD_53 = 213; + public static final int SDLK_WORLD_54 = 214; + public static final int SDLK_WORLD_55 = 215; + public static final int SDLK_WORLD_56 = 216; + public static final int SDLK_WORLD_57 = 217; + public static final int SDLK_WORLD_58 = 218; + public static final int SDLK_WORLD_59 = 219; + public static final int SDLK_WORLD_60 = 220; + public static final int SDLK_WORLD_61 = 221; + public static final int SDLK_WORLD_62 = 222; + public static final int SDLK_WORLD_63 = 223; + public static final int SDLK_WORLD_64 = 224; + public static final int SDLK_WORLD_65 = 225; + public static final int SDLK_WORLD_66 = 226; + public static final int SDLK_WORLD_67 = 227; + public static final int SDLK_WORLD_68 = 228; + public static final int SDLK_WORLD_69 = 229; + public static final int SDLK_WORLD_70 = 230; + public static final int SDLK_WORLD_71 = 231; + public static final int SDLK_WORLD_72 = 232; + public static final int SDLK_WORLD_73 = 233; + public static final int SDLK_WORLD_74 = 234; + public static final int SDLK_WORLD_75 = 235; + public static final int SDLK_WORLD_76 = 236; + public static final int SDLK_WORLD_77 = 237; + public static final int SDLK_WORLD_78 = 238; + public static final int SDLK_WORLD_79 = 239; + public static final int SDLK_WORLD_80 = 240; + public static final int SDLK_WORLD_81 = 241; + public static final int SDLK_WORLD_82 = 242; + public static final int SDLK_WORLD_83 = 243; + public static final int SDLK_WORLD_84 = 244; + public static final int SDLK_WORLD_85 = 245; + public static final int SDLK_WORLD_86 = 246; + public static final int SDLK_WORLD_87 = 247; + public static final int SDLK_WORLD_88 = 248; + public static final int SDLK_WORLD_89 = 249; + public static final int SDLK_WORLD_90 = 250; + public static final int SDLK_WORLD_91 = 251; + public static final int SDLK_WORLD_92 = 252; + public static final int SDLK_WORLD_93 = 253; + public static final int SDLK_WORLD_94 = 254; + public static final int SDLK_WORLD_95 = 255; + public static final int SDLK_KP0 = 256; + public static final int SDLK_KP1 = 257; + public static final int SDLK_KP2 = 258; + public static final int SDLK_KP3 = 259; + public static final int SDLK_KP4 = 260; + public static final int SDLK_KP5 = 261; + public static final int SDLK_KP6 = 262; + public static final int SDLK_KP7 = 263; + public static final int SDLK_KP8 = 264; + public static final int SDLK_KP9 = 265; + public static final int SDLK_KP_PERIOD = 266; + public static final int SDLK_KP_DIVIDE = 267; + public static final int SDLK_KP_MULTIPLY = 268; + public static final int SDLK_KP_MINUS = 269; + public static final int SDLK_KP_PLUS = 270; + public static final int SDLK_KP_ENTER = 271; + public static final int SDLK_KP_EQUALS = 272; + public static final int SDLK_UP = 273; + public static final int SDLK_DOWN = 274; + public static final int SDLK_RIGHT = 275; + public static final int SDLK_LEFT = 276; + public static final int SDLK_INSERT = 277; + public static final int SDLK_HOME = 278; + public static final int SDLK_END = 279; + public static final int SDLK_PAGEUP = 280; + public static final int SDLK_PAGEDOWN = 281; + public static final int SDLK_F1 = 282; + public static final int SDLK_F2 = 283; + public static final int SDLK_F3 = 284; + public static final int SDLK_F4 = 285; + public static final int SDLK_F5 = 286; + public static final int SDLK_F6 = 287; + public static final int SDLK_F7 = 288; + public static final int SDLK_F8 = 289; + public static final int SDLK_F9 = 290; + public static final int SDLK_F10 = 291; + public static final int SDLK_F11 = 292; + public static final int SDLK_F12 = 293; + public static final int SDLK_F13 = 294; + public static final int SDLK_F14 = 295; + public static final int SDLK_F15 = 296; + public static final int SDLK_NUMLOCK = 300; + public static final int SDLK_CAPSLOCK = 301; + public static final int SDLK_SCROLLOCK = 302; + public static final int SDLK_RSHIFT = 303; + public static final int SDLK_LSHIFT = 304; + public static final int SDLK_RCTRL = 305; + public static final int SDLK_LCTRL = 306; + public static final int SDLK_RALT = 307; + public static final int SDLK_LALT = 308; + public static final int SDLK_RMETA = 309; + public static final int SDLK_LMETA = 310; + public static final int SDLK_LSUPER = 311; + public static final int SDLK_RSUPER = 312; + public static final int SDLK_MODE = 313; + public static final int SDLK_COMPOSE = 314; + public static final int SDLK_HELP = 315; + public static final int SDLK_PRINT = 316; + public static final int SDLK_SYSREQ = 317; + public static final int SDLK_BREAK = 318; + public static final int SDLK_MENU = 319; + public static final int SDLK_POWER = 320; + public static final int SDLK_EURO = 321; + public static final int SDLK_UNDO = 322; + + public static final int SDLK_NO_REMAP = 512; +} + +// Autogenerated by hand with a command: +// grep 'SDL_SCANCODE_' SDL_scancode.h | sed 's/SDL_SCANCODE_\([a-zA-Z0-9_]\+\).*[=] \([0-9]\+\).*/public static final int SDLK_\1 = \2;/' >> Keycodes.java +class SDL_1_3_Keycodes +{ + public static final int SDLK_UNKNOWN = 0; + public static final int SDLK_A = 4; + public static final int SDLK_B = 5; + public static final int SDLK_C = 6; + public static final int SDLK_D = 7; + public static final int SDLK_E = 8; + public static final int SDLK_F = 9; + public static final int SDLK_G = 10; + public static final int SDLK_H = 11; + public static final int SDLK_I = 12; + public static final int SDLK_J = 13; + public static final int SDLK_K = 14; + public static final int SDLK_L = 15; + public static final int SDLK_M = 16; + public static final int SDLK_N = 17; + public static final int SDLK_O = 18; + public static final int SDLK_P = 19; + public static final int SDLK_Q = 20; + public static final int SDLK_R = 21; + public static final int SDLK_S = 22; + public static final int SDLK_T = 23; + public static final int SDLK_U = 24; + public static final int SDLK_V = 25; + public static final int SDLK_W = 26; + public static final int SDLK_X = 27; + public static final int SDLK_Y = 28; + public static final int SDLK_Z = 29; + public static final int SDLK_1 = 30; + public static final int SDLK_2 = 31; + public static final int SDLK_3 = 32; + public static final int SDLK_4 = 33; + public static final int SDLK_5 = 34; + public static final int SDLK_6 = 35; + public static final int SDLK_7 = 36; + public static final int SDLK_8 = 37; + public static final int SDLK_9 = 38; + public static final int SDLK_0 = 39; + public static final int SDLK_RETURN = 40; + public static final int SDLK_ESCAPE = 41; + public static final int SDLK_BACKSPACE = 42; + public static final int SDLK_TAB = 43; + public static final int SDLK_SPACE = 44; + public static final int SDLK_MINUS = 45; + public static final int SDLK_EQUALS = 46; + public static final int SDLK_LEFTBRACKET = 47; + public static final int SDLK_RIGHTBRACKET = 48; + public static final int SDLK_BACKSLASH = 49; + public static final int SDLK_NONUSHASH = 50; + public static final int SDLK_SEMICOLON = 51; + public static final int SDLK_APOSTROPHE = 52; + public static final int SDLK_GRAVE = 53; + public static final int SDLK_COMMA = 54; + public static final int SDLK_PERIOD = 55; + public static final int SDLK_SLASH = 56; + public static final int SDLK_CAPSLOCK = 57; + public static final int SDLK_F1 = 58; + public static final int SDLK_F2 = 59; + public static final int SDLK_F3 = 60; + public static final int SDLK_F4 = 61; + public static final int SDLK_F5 = 62; + public static final int SDLK_F6 = 63; + public static final int SDLK_F7 = 64; + public static final int SDLK_F8 = 65; + public static final int SDLK_F9 = 66; + public static final int SDLK_F10 = 67; + public static final int SDLK_F11 = 68; + public static final int SDLK_F12 = 69; + public static final int SDLK_PRINTSCREEN = 70; + public static final int SDLK_SCROLLLOCK = 71; + public static final int SDLK_PAUSE = 72; + public static final int SDLK_INSERT = 73; + public static final int SDLK_HOME = 74; + public static final int SDLK_PAGEUP = 75; + public static final int SDLK_DELETE = 76; + public static final int SDLK_END = 77; + public static final int SDLK_PAGEDOWN = 78; + public static final int SDLK_RIGHT = 79; + public static final int SDLK_LEFT = 80; + public static final int SDLK_DOWN = 81; + public static final int SDLK_UP = 82; + public static final int SDLK_NUMLOCKCLEAR = 83; + public static final int SDLK_KP_DIVIDE = 84; + public static final int SDLK_KP_MULTIPLY = 85; + public static final int SDLK_KP_MINUS = 86; + public static final int SDLK_KP_PLUS = 87; + public static final int SDLK_KP_ENTER = 88; + public static final int SDLK_KP_1 = 89; + public static final int SDLK_KP_2 = 90; + public static final int SDLK_KP_3 = 91; + public static final int SDLK_KP_4 = 92; + public static final int SDLK_KP_5 = 93; + public static final int SDLK_KP_6 = 94; + public static final int SDLK_KP_7 = 95; + public static final int SDLK_KP_8 = 96; + public static final int SDLK_KP_9 = 97; + public static final int SDLK_KP_0 = 98; + public static final int SDLK_KP_PERIOD = 99; + public static final int SDLK_NONUSBACKSLASH = 100; + public static final int SDLK_APPLICATION = 101; + public static final int SDLK_POWER = 102; + public static final int SDLK_KP_EQUALS = 103; + public static final int SDLK_F13 = 104; + public static final int SDLK_F14 = 105; + public static final int SDLK_F15 = 106; + public static final int SDLK_F16 = 107; + public static final int SDLK_F17 = 108; + public static final int SDLK_F18 = 109; + public static final int SDLK_F19 = 110; + public static final int SDLK_F20 = 111; + public static final int SDLK_F21 = 112; + public static final int SDLK_F22 = 113; + public static final int SDLK_F23 = 114; + public static final int SDLK_F24 = 115; + public static final int SDLK_EXECUTE = 116; + public static final int SDLK_HELP = 117; + public static final int SDLK_MENU = 118; + public static final int SDLK_SELECT = 119; + public static final int SDLK_STOP = 120; + public static final int SDLK_AGAIN = 121; + public static final int SDLK_UNDO = 122; + public static final int SDLK_CUT = 123; + public static final int SDLK_COPY = 124; + public static final int SDLK_PASTE = 125; + public static final int SDLK_FIND = 126; + public static final int SDLK_MUTE = 127; + public static final int SDLK_VOLUMEUP = 128; + public static final int SDLK_VOLUMEDOWN = 129; + public static final int SDLK_KP_COMMA = 133; + public static final int SDLK_KP_EQUALSAS400 = 134; + public static final int SDLK_INTERNATIONAL1 = 135; + public static final int SDLK_INTERNATIONAL2 = 136; + public static final int SDLK_INTERNATIONAL3 = 137; + public static final int SDLK_INTERNATIONAL4 = 138; + public static final int SDLK_INTERNATIONAL5 = 139; + public static final int SDLK_INTERNATIONAL6 = 140; + public static final int SDLK_INTERNATIONAL7 = 141; + public static final int SDLK_INTERNATIONAL8 = 142; + public static final int SDLK_INTERNATIONAL9 = 143; + public static final int SDLK_LANG1 = 144; + public static final int SDLK_LANG2 = 145; + public static final int SDLK_LANG3 = 146; + public static final int SDLK_LANG4 = 147; + public static final int SDLK_LANG5 = 148; + public static final int SDLK_LANG6 = 149; + public static final int SDLK_LANG7 = 150; + public static final int SDLK_LANG8 = 151; + public static final int SDLK_LANG9 = 152; + public static final int SDLK_ALTERASE = 153; + public static final int SDLK_SYSREQ = 154; + public static final int SDLK_CANCEL = 155; + public static final int SDLK_CLEAR = 156; + public static final int SDLK_PRIOR = 157; + public static final int SDLK_RETURN2 = 158; + public static final int SDLK_SEPARATOR = 159; + public static final int SDLK_OUT = 160; + public static final int SDLK_OPER = 161; + public static final int SDLK_CLEARAGAIN = 162; + public static final int SDLK_CRSEL = 163; + public static final int SDLK_EXSEL = 164; + public static final int SDLK_KP_00 = 176; + public static final int SDLK_KP_000 = 177; + public static final int SDLK_THOUSANDSSEPARATOR = 178; + public static final int SDLK_DECIMALSEPARATOR = 179; + public static final int SDLK_CURRENCYUNIT = 180; + public static final int SDLK_CURRENCYSUBUNIT = 181; + public static final int SDLK_KP_LEFTPAREN = 182; + public static final int SDLK_KP_RIGHTPAREN = 183; + public static final int SDLK_KP_LEFTBRACE = 184; + public static final int SDLK_KP_RIGHTBRACE = 185; + public static final int SDLK_KP_TAB = 186; + public static final int SDLK_KP_BACKSPACE = 187; + public static final int SDLK_KP_A = 188; + public static final int SDLK_KP_B = 189; + public static final int SDLK_KP_C = 190; + public static final int SDLK_KP_D = 191; + public static final int SDLK_KP_E = 192; + public static final int SDLK_KP_F = 193; + public static final int SDLK_KP_XOR = 194; + public static final int SDLK_KP_POWER = 195; + public static final int SDLK_KP_PERCENT = 196; + public static final int SDLK_KP_LESS = 197; + public static final int SDLK_KP_GREATER = 198; + public static final int SDLK_KP_AMPERSAND = 199; + public static final int SDLK_KP_DBLAMPERSAND = 200; + public static final int SDLK_KP_VERTICALBAR = 201; + public static final int SDLK_KP_DBLVERTICALBAR = 202; + public static final int SDLK_KP_COLON = 203; + public static final int SDLK_KP_HASH = 204; + public static final int SDLK_KP_SPACE = 205; + public static final int SDLK_KP_AT = 206; + public static final int SDLK_KP_EXCLAM = 207; + public static final int SDLK_KP_MEMSTORE = 208; + public static final int SDLK_KP_MEMRECALL = 209; + public static final int SDLK_KP_MEMCLEAR = 210; + public static final int SDLK_KP_MEMADD = 211; + public static final int SDLK_KP_MEMSUBTRACT = 212; + public static final int SDLK_KP_MEMMULTIPLY = 213; + public static final int SDLK_KP_MEMDIVIDE = 214; + public static final int SDLK_KP_PLUSMINUS = 215; + public static final int SDLK_KP_CLEAR = 216; + public static final int SDLK_KP_CLEARENTRY = 217; + public static final int SDLK_KP_BINARY = 218; + public static final int SDLK_KP_OCTAL = 219; + public static final int SDLK_KP_DECIMAL = 220; + public static final int SDLK_KP_HEXADECIMAL = 221; + public static final int SDLK_LCTRL = 224; + public static final int SDLK_LSHIFT = 225; + public static final int SDLK_LALT = 226; + public static final int SDLK_LGUI = 227; + public static final int SDLK_RCTRL = 228; + public static final int SDLK_RSHIFT = 229; + public static final int SDLK_RALT = 230; + public static final int SDLK_RGUI = 231; + public static final int SDLK_MODE = 257; + public static final int SDLK_AUDIONEXT = 258; + public static final int SDLK_AUDIOPREV = 259; + public static final int SDLK_AUDIOSTOP = 260; + public static final int SDLK_AUDIOPLAY = 261; + public static final int SDLK_AUDIOMUTE = 262; + public static final int SDLK_MEDIASELECT = 263; + public static final int SDLK_WWW = 264; + public static final int SDLK_MAIL = 265; + public static final int SDLK_CALCULATOR = 266; + public static final int SDLK_COMPUTER = 267; + public static final int SDLK_AC_SEARCH = 268; + public static final int SDLK_AC_HOME = 269; + public static final int SDLK_AC_BACK = 270; + public static final int SDLK_AC_FORWARD = 271; + public static final int SDLK_AC_STOP = 272; + public static final int SDLK_AC_REFRESH = 273; + public static final int SDLK_AC_BOOKMARKS = 274; + public static final int SDLK_BRIGHTNESSDOWN = 275; + public static final int SDLK_BRIGHTNESSUP = 276; + public static final int SDLK_DISPLAYSWITCH = 277; + public static final int SDLK_KBDILLUMTOGGLE = 278; + public static final int SDLK_KBDILLUMDOWN = 279; + public static final int SDLK_KBDILLUMUP = 280; + public static final int SDLK_EJECT = 281; + public static final int SDLK_SLEEP = 282; + + public static final int SDLK_NO_REMAP = 512; +} + +class SDL_Keys +{ + public static String [] names = null; + public static Integer [] values = null; + + public static String [] namesSorted = null; + public static Integer [] namesSortedIdx = null; + public static Integer [] namesSortedBackIdx = null; + + static final int JAVA_KEYCODE_LAST = 255; // Android 2.3 added several new gaming keys, Android 3.1 added even more - keep in sync with javakeycodes.h + + static String getName(int v) + { + for( int f = 0; f < values.length; f++ ) + { + if( values[f] == v ) + return names[f]; + } + return names[0]; + } + + static + { + ArrayList Names = new ArrayList (); + ArrayList Values = new ArrayList (); + Field [] fields = SDL_1_2_Keycodes.class.getDeclaredFields(); + if( Globals.Using_SDL_1_3 ) + { + fields = SDL_1_3_Keycodes.class.getDeclaredFields(); + } + + try { + for(Field f: fields) + { + Values.add(f.getInt(null)); + Names.add(f.getName().substring(5).toUpperCase()); + } + } catch(IllegalAccessException e) {}; + + // Sort by value + for( int i = 0; i < Values.size(); i++ ) + { + for( int j = i; j < Values.size(); j++ ) + { + if( Values.get(i) > Values.get(j) ) + { + int x = Values.get(i); + Values.set(i, Values.get(j)); + Values.set(j, x); + String s = Names.get(i); + Names.set(i, Names.get(j)); + Names.set(j, s); + } + } + } + + names = Names.toArray(new String[0]); + values = Values.toArray(new Integer[0]); + namesSorted = Names.toArray(new String[0]); + namesSortedIdx = new Integer[values.length]; + namesSortedBackIdx = new Integer[values.length]; + Arrays.sort(namesSorted); + for( int i = 0; i < namesSorted.length; i++ ) + { + for( int j = 0; j < namesSorted.length; j++ ) + { + if( namesSorted[i].equals( names[j] ) ) + { + namesSortedIdx[i] = j; + namesSortedBackIdx[j] = i; + break; + } + } + } + } +} diff --git a/project/javaSDL2/MainActivity.java b/project/javaSDL2/MainActivity.java new file mode 100644 index 000000000..baca83d3d --- /dev/null +++ b/project/javaSDL2/MainActivity.java @@ -0,0 +1,1211 @@ +/* +Simple DirectMedia Layer +Java source code (C) 2009-2012 Sergii Pylypenko + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +package net.sourceforge.clonekeenplus; + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.view.MotionEvent; +import android.view.KeyEvent; +import android.view.Window; +import android.view.WindowManager; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import android.widget.EditText; +import android.text.Editable; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.FrameLayout; +import android.graphics.drawable.Drawable; +import android.graphics.Color; +import android.content.res.Configuration; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Intent; +import android.view.View.OnKeyListener; +import android.view.MenuItem; +import android.view.Menu; +import android.view.Gravity; +import android.text.method.TextKeyListener; +import java.util.LinkedList; +import java.io.SequenceInputStream; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.FileOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.util.zip.*; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.Set; +import android.text.SpannedString; +import java.io.BufferedReader; +import java.io.BufferedInputStream; +import java.io.InputStreamReader; +import android.view.inputmethod.InputMethodManager; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.Handler; +import android.os.Message; +import android.os.SystemClock; +import java.util.concurrent.Semaphore; +import android.content.pm.ActivityInfo; +import android.view.Display; +import android.text.InputType; +import android.util.Log; + +public class MainActivity extends Activity +{ + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + setRequestedOrientation(Globals.HorizontalOrientation ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + + instance = this; + // fullscreen mode + requestWindowFeature(Window.FEATURE_NO_TITLE); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + if(Globals.InhibitSuspend) + getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, + WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + + Log.i("SDL", "libSDL: Creating startup screen"); + _layout = new LinearLayout(this); + _layout.setOrientation(LinearLayout.VERTICAL); + _layout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + _layout2 = new LinearLayout(this); + _layout2.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + + final Semaphore loadedLibraries = new Semaphore(0); + + if( Globals.StartupMenuButtonTimeout > 0 ) + { + _btn = new Button(this); + _btn.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + _btn.setText(getResources().getString(R.string.device_change_cfg)); + class onClickListener implements View.OnClickListener + { + public MainActivity p; + onClickListener( MainActivity _p ) { p = _p; } + public void onClick(View v) + { + setUpStatusLabel(); + Log.i("SDL", "libSDL: User clicked change phone config button"); + loadedLibraries.acquireUninterruptibly(); + SettingsMenu.showConfig(p, false); + } + }; + _btn.setOnClickListener(new onClickListener(this)); + + _layout2.addView(_btn); + } + + _layout.addView(_layout2); + + ImageView img = new ImageView(this); + + img.setScaleType(ImageView.ScaleType.FIT_CENTER /* FIT_XY */ ); + try + { + img.setImageDrawable(Drawable.createFromStream(getAssets().open("logo.png"), "logo.png")); + } + catch(Exception e) + { + img.setImageResource(R.drawable.publisherlogo); + } + img.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + _layout.addView(img); + + _videoLayout = new FrameLayout(this); + _videoLayout.addView(_layout); + + _ad = new Advertisement(this); + if( _ad.getView() != null ) + { + _videoLayout.addView(_ad.getView()); + _ad.getView().setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM | Gravity.RIGHT)); + } + + setContentView(_videoLayout); + + class Callback implements Runnable + { + MainActivity p; + Callback( MainActivity _p ) { p = _p; } + public void run() + { + try { + Thread.sleep(200); + } catch( InterruptedException e ) {}; + + if(p.mAudioThread == null) + { + Log.i("SDL", "libSDL: Loading libraries"); + p.LoadLibraries(); + p.mAudioThread = new AudioThread(p); + Log.i("SDL", "libSDL: Loading settings"); + final Semaphore loaded = new Semaphore(0); + class Callback2 implements Runnable + { + public MainActivity Parent; + public void run() + { + Settings.Load(Parent); + loaded.release(); + loadedLibraries.release(); + } + } + Callback2 cb = new Callback2(); + cb.Parent = p; + p.runOnUiThread(cb); + loaded.acquireUninterruptibly(); + if(!Globals.CompatibilityHacksStaticInit) + p.LoadApplicationLibrary(p); + } + + if( !Settings.settingsChanged ) + { + if( Globals.StartupMenuButtonTimeout > 0 ) + { + Log.i("SDL", "libSDL: " + String.valueOf(Globals.StartupMenuButtonTimeout) + "-msec timeout in startup screen"); + try { + Thread.sleep(Globals.StartupMenuButtonTimeout); + } catch( InterruptedException e ) {}; + } + if( Settings.settingsChanged ) + return; + Log.i("SDL", "libSDL: Timeout reached in startup screen, process with downloader"); + p.startDownloader(); + } + } + }; + (new Thread(new Callback(this))).start(); + } + + public void setUpStatusLabel() + { + MainActivity Parent = this; // Too lazy to rename + if( Parent._btn != null ) + { + Parent._layout2.removeView(Parent._btn); + Parent._btn = null; + } + if( Parent._tv == null ) + { + Parent._tv = new TextView(Parent); + Parent._tv.setMaxLines(2); // To show some long texts on smaller devices + Parent._tv.setMinLines(2); // Otherwise the background picture is getting resized at random, which does not look good + Parent._tv.setText(R.string.init); + Parent._layout2.addView(Parent._tv); + } + } + + public void startDownloader() + { + Log.i("SDL", "libSDL: Starting data downloader"); + class Callback implements Runnable + { + public MainActivity Parent; + public void run() + { + setUpStatusLabel(); + Log.i("SDL", "libSDL: Starting downloader"); + if( Parent.downloader == null ) + Parent.downloader = new DataDownloader(Parent, Parent._tv); + } + } + Callback cb = new Callback(); + cb.Parent = this; + this.runOnUiThread(cb); + } + + public void initSDL() + { + (new Thread(new Runnable() + { + public void run() + { + //int tries = 30; + while( isCurrentOrientationHorizontal() != Globals.HorizontalOrientation ) + { + Log.i("SDL", "libSDL: Waiting for screen orientation to change - the device is probably in the lockscreen mode"); + try { + Thread.sleep(500); + } catch( Exception e ) {} + /* + tries--; + if( tries <= 0 ) + { + Log.i("SDL", "libSDL: Giving up waiting for screen orientation change"); + break; + } + */ + if( _isPaused ) + { + Log.i("SDL", "libSDL: Application paused, cancelling SDL initialization until it will be brought to foreground"); + return; + } + } + runOnUiThread(new Runnable() + { + public void run() + { + initSDLInternal(); + } + }); + } + })).start(); + } + + private void initSDLInternal() + { + if(sdlInited) + return; + Log.i("SDL", "libSDL: Initializing video and SDL application"); + + sdlInited = true; + _videoLayout.removeView(_layout); + if( _ad.getView() != null ) + _videoLayout.removeView(_ad.getView()); + _layout = null; + _layout2 = null; + _btn = null; + _tv = null; + _inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + _videoLayout = new FrameLayout(this); + SetLayerType.get().setLayerType(_videoLayout); + setContentView(_videoLayout); + mGLView = new DemoGLSurfaceView(this); + SetLayerType.get().setLayerType(mGLView); + _videoLayout.addView(mGLView); + mGLView.setFocusableInTouchMode(true); + mGLView.setFocusable(true); + mGLView.requestFocus(); + if( _ad.getView() != null ) + { + _videoLayout.addView(_ad.getView()); + _ad.getView().setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.TOP | Gravity.RIGHT)); + } + // Receive keyboard events + DimSystemStatusBar.get().dim(_videoLayout); + DimSystemStatusBar.get().dim(mGLView); + } + + @Override + protected void onPause() { + if( downloader != null ) + { + synchronized( downloader ) + { + downloader.setStatusField(null); + } + } + _isPaused = true; + if( mGLView != null ) + mGLView.onPause(); + //if( _ad.getView() != null ) + // _ad.getView().onPause(); + super.onPause(); + } + + @Override + protected void onResume() { + super.onResume(); + if( mGLView != null ) + { + mGLView.onResume(); + DimSystemStatusBar.get().dim(_videoLayout); + DimSystemStatusBar.get().dim(mGLView); + } + else + if( downloader != null ) + { + synchronized( downloader ) + { + downloader.setStatusField(_tv); + if( downloader.DownloadComplete ) + { + initSDL(); + } + } + } + //if( _ad.getView() != null ) + // _ad.getView().onResume(); + _isPaused = false; + } + + @Override + public void onWindowFocusChanged (boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + Log.i("SDL", "libSDL: onWindowFocusChanged: " + hasFocus + " - sending onPause/onResume"); + if (hasFocus == false) + onPause(); + else + onResume(); + /* + if (hasFocus == false) { + synchronized(textInput) { + // Send 'SDLK_PAUSE' (to enter pause mode) to native code: + DemoRenderer.nativeTextInput( 19, 19 ); + } + } + */ + } + + public boolean isPaused() + { + return _isPaused; + } + + @Override + protected void onDestroy() + { + if( downloader != null ) + { + synchronized( downloader ) + { + downloader.setStatusField(null); + } + } + if( mGLView != null ) + mGLView.exitApp(); + super.onDestroy(); + try{ + Thread.sleep(2000); // The event is sent asynchronously, allow app to save it's state, and call exit() itself. + } catch (InterruptedException e) {} + System.exit(0); + } + + public void showScreenKeyboardWithoutTextInputField() + { + _inputManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); + _inputManager.showSoftInput(mGLView, InputMethodManager.SHOW_FORCED); + getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); + } + + public void showScreenKeyboard(final String oldText, boolean sendBackspace) + { + if(Globals.CompatibilityHacksTextInputEmulatesHwKeyboard) + { + showScreenKeyboardWithoutTextInputField(); + return; + } + if(_screenKeyboard != null) + return; + class simpleKeyListener implements OnKeyListener + { + MainActivity _parent; + boolean sendBackspace; + simpleKeyListener(MainActivity parent, boolean sendBackspace) { _parent = parent; this.sendBackspace = sendBackspace; }; + public boolean onKey(View v, int keyCode, KeyEvent event) + { + if ((event.getAction() == KeyEvent.ACTION_UP) && ( + keyCode == KeyEvent.KEYCODE_ENTER || + keyCode == KeyEvent.KEYCODE_BACK || + keyCode == KeyEvent.KEYCODE_MENU || + keyCode == KeyEvent.KEYCODE_BUTTON_A || + keyCode == KeyEvent.KEYCODE_BUTTON_B || + keyCode == KeyEvent.KEYCODE_BUTTON_X || + keyCode == KeyEvent.KEYCODE_BUTTON_Y || + keyCode == KeyEvent.KEYCODE_BUTTON_1 || + keyCode == KeyEvent.KEYCODE_BUTTON_2 || + keyCode == KeyEvent.KEYCODE_BUTTON_3 || + keyCode == KeyEvent.KEYCODE_BUTTON_4 )) + { + _parent.hideScreenKeyboard(); + return true; + } + if (keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_CLEAR) + { + if (sendBackspace && event.getAction() == KeyEvent.ACTION_UP) + { + synchronized(textInput) { + DemoRenderer.nativeTextInput( 8, 0 ); // Send backspace to native code + } + } + // EditText deletes two characters at a time, here's a hacky fix + if (event.getAction() == KeyEvent.ACTION_DOWN && (event.getFlags() | KeyEvent.FLAG_SOFT_KEYBOARD) != 0) + { + EditText t = (EditText) v; + int start = t.getSelectionStart(); //get cursor starting position + int end = t.getSelectionEnd(); //get cursor ending position + if ( start < 0 ) + return true; + if ( end < 0 || end == start ) + { + start --; + if ( start < 0 ) + return true; + end = start + 1; + } + t.setText(t.getText().toString().substring(0, start) + t.getText().toString().substring(end)); + t.setSelection(start); + return true; + } + } + //Log.i("SDL", "Key " + keyCode + " flags " + event.getFlags() + " action " + event.getAction()); + return false; + } + }; + _screenKeyboard = new EditText(this); + // This code does not work + /* + _screenKeyboard.setMaxLines(100); + ViewGroup.LayoutParams layout = _screenKeyboard.getLayoutParams(); + if( layout != null ) + { + layout.width = ViewGroup.LayoutParams.FILL_PARENT; + layout.height = ViewGroup.LayoutParams.FILL_PARENT; + _screenKeyboard.setLayoutParams(layout); + } + _screenKeyboard.setGravity(android.view.Gravity.BOTTOM | android.view.Gravity.LEFT); + */ + String hint = _screenKeyboardHintMessage; + _screenKeyboard.setHint(hint != null ? hint : getString(R.string.text_edit_click_here)); + _screenKeyboard.setText(oldText); + _screenKeyboard.setSelection(_screenKeyboard.getText().length()); + _screenKeyboard.setOnKeyListener(new simpleKeyListener(this, sendBackspace)); + _screenKeyboard.setBackgroundColor(Color.BLACK); // Full opaque - do not show semi-transparent edit box, it's confusing + _screenKeyboard.setTextColor(Color.WHITE); // Just to be sure about gamma + if( isRunningOnOUYA() ) + _screenKeyboard.setPadding(100, 100, 100, 100); // Bad bad HDMI TVs all have cropped borders + _videoLayout.addView(_screenKeyboard); + //_screenKeyboard.setKeyListener(new TextKeyListener(TextKeyListener.Capitalize.NONE, false)); + _screenKeyboard.setInputType(InputType.TYPE_CLASS_TEXT); + _screenKeyboard.setFocusableInTouchMode(true); + _screenKeyboard.setFocusable(true); + _screenKeyboard.requestFocus(); + _inputManager.showSoftInput(_screenKeyboard, InputMethodManager.SHOW_IMPLICIT); + getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); + // Hack to try to force on-screen keyboard + final EditText keyboard = _screenKeyboard; + keyboard.postDelayed( new Runnable() + { + public void run() + { + keyboard.requestFocus(); + //_inputManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); + _inputManager.showSoftInput(keyboard, InputMethodManager.SHOW_FORCED); + // Hack from Stackoverflow, to force text input on Ouya + keyboard.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN , 0, 0, 0)); + keyboard.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_UP , 0, 0, 0)); + keyboard.postDelayed( new Runnable() + { + public void run() + { + keyboard.setSelection(keyboard.getText().length()); + } + }, 100 ); + } + }, 500 ); + }; + + public void hideScreenKeyboard() + { + if(_screenKeyboard == null) + return; + + synchronized(textInput) + { + String text = _screenKeyboard.getText().toString(); + for(int i = 0; i < text.length(); i++) + { + DemoRenderer.nativeTextInput( (int)text.charAt(i), (int)text.codePointAt(i) ); + } + } + DemoRenderer.nativeTextInputFinished(); + _inputManager.hideSoftInputFromWindow(_screenKeyboard.getWindowToken(), 0); + _videoLayout.removeView(_screenKeyboard); + _screenKeyboard = null; + mGLView.setFocusableInTouchMode(true); + mGLView.setFocusable(true); + mGLView.requestFocus(); + }; + + public boolean isScreenKeyboardShown() + { + return _screenKeyboard != null; + }; + + public void setScreenKeyboardHintMessage(String s) + { + _screenKeyboardHintMessage = s; + //Log.i("SDL", "setScreenKeyboardHintMessage: " + (_screenKeyboardHintMessage != null ? _screenKeyboardHintMessage : getString(R.string.text_edit_click_here))); + runOnUiThread(new Runnable() + { + public void run() + { + if( _screenKeyboard != null ) + { + String hint = _screenKeyboardHintMessage; + _screenKeyboard.setHint(hint != null ? hint : getString(R.string.text_edit_click_here)); + } + } + } ); + } + + final static int ADVERTISEMENT_POSITION_RIGHT = -1; + final static int ADVERTISEMENT_POSITION_BOTTOM = -1; + final static int ADVERTISEMENT_POSITION_CENTER = -2; + + public void setAdvertisementPosition(int x, int y) + { + + if( _ad.getView() != null ) + { + final FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + layout.gravity = 0; + layout.leftMargin = 0; + layout.topMargin = 0; + if( x == ADVERTISEMENT_POSITION_RIGHT ) + layout.gravity |= Gravity.RIGHT; + else if ( x == ADVERTISEMENT_POSITION_CENTER ) + layout.gravity |= Gravity.CENTER_HORIZONTAL; + else + { + layout.gravity |= Gravity.LEFT; + layout.leftMargin = x; + } + if( y == ADVERTISEMENT_POSITION_BOTTOM ) + layout.gravity |= Gravity.BOTTOM; + else if ( x == ADVERTISEMENT_POSITION_CENTER ) + layout.gravity |= Gravity.CENTER_VERTICAL; + else + { + layout.gravity |= Gravity.TOP; + layout.topMargin = y; + } + class Callback implements Runnable + { + public void run() + { + _ad.getView().setLayoutParams(layout); + } + }; + runOnUiThread(new Callback()); + } + } + public void setAdvertisementVisible(final int visible) + { + if( _ad.getView() != null ) + { + class Callback implements Runnable + { + public void run() + { + if( visible == 0 ) + _ad.getView().setVisibility(View.GONE); + else + _ad.getView().setVisibility(View.VISIBLE); + } + } + runOnUiThread(new Callback()); + } + } + + public void getAdvertisementParams(int params[]) + { + for( int i = 0; i < 5; i++ ) + params[i] = 0; + if( _ad.getView() != null ) + { + params[0] = (_ad.getView().getVisibility() == View.VISIBLE) ? 1 : 0; + FrameLayout.LayoutParams layout = (FrameLayout.LayoutParams) _ad.getView().getLayoutParams(); + params[1] = layout.leftMargin; + params[2] = layout.topMargin; + params[3] = _ad.getView().getMeasuredWidth(); + params[4] = _ad.getView().getMeasuredHeight(); + } + } + public void requestNewAdvertisement() + { + if( _ad.getView() != null ) + { + class Callback implements Runnable + { + public void run() + { + _ad.requestNewAd(); + } + } + runOnUiThread(new Callback()); + } + } + + @Override + public boolean onKeyDown(int keyCode, final KeyEvent event) + { + if(_screenKeyboard != null) + _screenKeyboard.onKeyDown(keyCode, event); + else + if( mGLView != null ) + { + if( mGLView.nativeKey( keyCode, 1 ) == 0 ) + return super.onKeyDown(keyCode, event); + } + /* + else + if( keyCode == KeyEvent.KEYCODE_BACK && downloader != null ) + { + if( downloader.DownloadFailed ) + System.exit(1); + if( !downloader.DownloadComplete ) + onStop(); + } + */ + else + if( keyListener != null ) + { + keyListener.onKeyEvent(keyCode); + } + return true; + } + + @Override + public boolean onKeyUp(int keyCode, final KeyEvent event) + { + if(_screenKeyboard != null) + _screenKeyboard.onKeyUp(keyCode, event); + else + if( mGLView != null ) + { + if( mGLView.nativeKey( keyCode, 0 ) == 0 ) + return super.onKeyUp(keyCode, event); + if( keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU ) + { + DimSystemStatusBar.get().dim(_videoLayout); + DimSystemStatusBar.get().dim(mGLView); + } + } + return true; + } + + @Override + public boolean dispatchTouchEvent(final MotionEvent ev) + { + //Log.i("SDL", "dispatchTouchEvent: " + ev.getAction() + " coords " + ev.getX() + ":" + ev.getY() ); + if(_screenKeyboard != null) + _screenKeyboard.dispatchTouchEvent(ev); + else + if( _ad.getView() != null && // User clicked the advertisement, ignore when user moved finger from game screen to advertisement or touches screen with several fingers + ((ev.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN || + (ev.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP) && + _ad.getView().getLeft() <= (int)ev.getX() && + _ad.getView().getRight() > (int)ev.getX() && + _ad.getView().getTop() <= (int)ev.getY() && + _ad.getView().getBottom() > (int)ev.getY() ) + return super.dispatchTouchEvent(ev); + else + if(mGLView != null) + mGLView.onTouchEvent(ev); + else + if( _btn != null ) + return _btn.dispatchTouchEvent(ev); + else + if( touchListener != null ) + touchListener.onTouchEvent(ev); + return true; + } + + @Override + public boolean dispatchGenericMotionEvent (MotionEvent ev) + { + //Log.i("SDL", "dispatchGenericMotionEvent: " + ev.getAction() + " coords " + ev.getX() + ":" + ev.getY() ); + // This code fails to run for Android 1.6, so there will be no generic motion event for Andorid screen keyboard + /* + if(_screenKeyboard != null) + _screenKeyboard.dispatchGenericMotionEvent(ev); + else + */ + if(mGLView != null) + mGLView.onGenericMotionEvent(ev); + return true; + } + + @Override + public void onConfigurationChanged(Configuration newConfig) + { + super.onConfigurationChanged(newConfig); + // Do nothing here + } + + public void setText(final String t) + { + class Callback implements Runnable + { + MainActivity Parent; + public SpannedString text; + public void run() + { + Parent.setUpStatusLabel(); + if(Parent._tv != null) + Parent._tv.setText(text); + } + } + Callback cb = new Callback(); + cb.text = new SpannedString(t); + cb.Parent = this; + this.runOnUiThread(cb); + } + + public void showTaskbarNotification() + { + showTaskbarNotification("SDL application paused", "SDL application", "Application is paused, click to activate"); + } + + // Stolen from SDL port by Mamaich + public void showTaskbarNotification(String text0, String text1, String text2) + { + NotificationManager NotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + Intent intent = new Intent(this, MainActivity.class); + PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK); + Notification n = new Notification(R.drawable.icon, text0, System.currentTimeMillis()); + n.setLatestEventInfo(this, text1, text2, pendingIntent); + NotificationManager.notify(NOTIFY_ID, n); + } + + public void hideTaskbarNotification() + { + NotificationManager NotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + NotificationManager.cancel(NOTIFY_ID); + } + + public void LoadLibraries() + { + try + { + if(Globals.NeedGles2) + System.loadLibrary("GLESv2"); + Log.i("SDL", "libSDL: loaded GLESv2 lib"); + } + catch ( UnsatisfiedLinkError e ) + { + Log.i("SDL", "libSDL: Cannot load GLESv2 lib"); + } + + // Load all libraries + try + { + for(String l : Globals.AppLibraries) + { + try + { + String libname = System.mapLibraryName(l); + File libpath = new File(getFilesDir().getAbsolutePath() + "/../lib/" + libname); + Log.i("SDL", "libSDL: loading lib " + libpath.getAbsolutePath()); + System.load(libpath.getPath()); + } + catch( UnsatisfiedLinkError e ) + { + Log.i("SDL", "libSDL: error loading lib " + l + ": " + e.toString()); + try + { + String libname = System.mapLibraryName(l); + File libpath = new File(getFilesDir().getAbsolutePath() + "/" + libname); + Log.i("SDL", "libSDL: loading lib " + libpath.getAbsolutePath()); + System.load(libpath.getPath()); + } + catch( UnsatisfiedLinkError ee ) + { + Log.i("SDL", "libSDL: error loading lib " + l + ": " + ee.toString()); + System.loadLibrary(l); + } + } + } + } + catch ( UnsatisfiedLinkError e ) + { + try { + Log.i("SDL", "libSDL: Extracting APP2SD-ed libs"); + + InputStream in = null; + try + { + for( int i = 0; ; i++ ) + { + InputStream in2 = getAssets().open("bindata" + String.valueOf(i)); + if( in == null ) + in = in2; + else + in = new SequenceInputStream( in, in2 ); + } + } + catch( IOException ee ) { } + + if( in == null ) + throw new RuntimeException("libSDL: Extracting APP2SD-ed libs failed, the .apk file packaged incorrectly"); + + ZipInputStream zip = new ZipInputStream(in); + + File libDir = getFilesDir(); + try { + libDir.mkdirs(); + } catch( SecurityException ee ) { }; + + byte[] buf = new byte[16384]; + while(true) + { + ZipEntry entry = null; + entry = zip.getNextEntry(); + /* + if( entry != null ) + Log.i("SDL", "Extracting lib " + entry.getName()); + */ + if( entry == null ) + { + Log.i("SDL", "Extracting libs finished"); + break; + } + if( entry.isDirectory() ) + { + File outDir = new File( libDir.getAbsolutePath() + "/" + entry.getName() ); + if( !(outDir.exists() && outDir.isDirectory()) ) + outDir.mkdirs(); + continue; + } + + OutputStream out = null; + String path = libDir.getAbsolutePath() + "/" + entry.getName(); + try { + File outDir = new File( path.substring(0, path.lastIndexOf("/") )); + if( !(outDir.exists() && outDir.isDirectory()) ) + outDir.mkdirs(); + } catch( SecurityException eeeee ) { }; + + Log.i("SDL", "Saving to file '" + path + "'"); + + out = new FileOutputStream( path ); + int len = zip.read(buf); + while (len >= 0) + { + if(len > 0) + out.write(buf, 0, len); + len = zip.read(buf); + } + + out.flush(); + out.close(); + } + + for(String l : Globals.AppLibraries) + { + String libname = System.mapLibraryName(l); + File libpath = new File(libDir, libname); + Log.i("SDL", "libSDL: loading lib " + libpath.getPath()); + System.load(libpath.getPath()); + libpath.delete(); + } + } + catch ( Exception ee ) + { + Log.i("SDL", "libSDL: Error: " + ee.toString()); + } + } + + // ----- VCMI hack ----- + String [] binaryZipNames = { "binaries-" + android.os.Build.CPU_ABI + ".zip", "binaries.zip" }; + for(String binaryZip: binaryZipNames) + { + try { + Log.i("SDL", "libSDL: Trying to extract binaries from assets " + binaryZip); + + InputStream in = null; + try + { + for( int i = 0; ; i++ ) + { + InputStream in2 = getAssets().open(binaryZip + String.format("%02d", i)); + if( in == null ) + in = in2; + else + in = new SequenceInputStream( in, in2 ); + } + } + catch( IOException ee ) + { + try + { + if( in == null ) + in = getAssets().open(binaryZip); + } + catch( IOException eee ) {} + } + + if( in == null ) + throw new RuntimeException("libSDL: Extracting binaries failed, the .apk file packaged incorrectly"); + + ZipInputStream zip = new ZipInputStream(in); + + File libDir = getFilesDir(); + try { + libDir.mkdirs(); + } catch( SecurityException ee ) { }; + + byte[] buf = new byte[16384]; + while(true) + { + ZipEntry entry = null; + entry = zip.getNextEntry(); + /* + if( entry != null ) + Log.i("SDL", "Extracting lib " + entry.getName()); + */ + if( entry == null ) + { + Log.i("SDL", "Extracting binaries finished"); + break; + } + if( entry.isDirectory() ) + { + File outDir = new File( libDir.getAbsolutePath() + "/" + entry.getName() ); + if( !(outDir.exists() && outDir.isDirectory()) ) + outDir.mkdirs(); + continue; + } + + OutputStream out = null; + String path = libDir.getAbsolutePath() + "/" + entry.getName(); + try { + File outDir = new File( path.substring(0, path.lastIndexOf("/") )); + if( !(outDir.exists() && outDir.isDirectory()) ) + outDir.mkdirs(); + } catch( SecurityException eeeeeee ) { }; + + try { + CheckedInputStream check = new CheckedInputStream( new FileInputStream(path), new CRC32() ); + while( check.read(buf, 0, buf.length) > 0 ) {}; + check.close(); + if( check.getChecksum().getValue() != entry.getCrc() ) + { + File ff = new File(path); + ff.delete(); + throw new Exception(); + } + Log.i("SDL", "File '" + path + "' exists and passed CRC check - not overwriting it"); + continue; + } catch( Exception eeeeee ) { } + + Log.i("SDL", "Saving to file '" + path + "'"); + + out = new FileOutputStream( path ); + int len = zip.read(buf); + while (len >= 0) + { + if(len > 0) + out.write(buf, 0, len); + len = zip.read(buf); + } + + out.flush(); + out.close(); + Settings.nativeChmod(path, 0755); + //String chmod[] = { "/system/bin/chmod", "0755", path }; + //Runtime.getRuntime().exec(chmod).waitFor(); + } + } + catch ( Exception eee ) + { + //Log.i("SDL", "libSDL: Error: " + eee.toString()); + } + } + // ----- VCMI hack ----- + }; + + public static void LoadApplicationLibrary(final Context context) + { + Settings.nativeChdir(Globals.DataDir); + for(String l : Globals.AppMainLibraries) + { + try + { + String libname = System.mapLibraryName(l); + File libpath = new File(context.getFilesDir().getAbsolutePath() + "/../lib/" + libname); + Log.i("SDL", "libSDL: loading lib " + libpath.getAbsolutePath()); + System.load(libpath.getPath()); + } + catch( UnsatisfiedLinkError e ) + { + Log.i("SDL", "libSDL: error loading lib " + l + ": " + e.toString()); + try + { + String libname = System.mapLibraryName(l); + File libpath = new File(context.getFilesDir().getAbsolutePath() + "/" + libname); + Log.i("SDL", "libSDL: loading lib " + libpath.getAbsolutePath()); + System.load(libpath.getPath()); + } + catch( UnsatisfiedLinkError ee ) + { + Log.i("SDL", "libSDL: error loading lib " + l + ": " + ee.toString()); + System.loadLibrary(l); + } + } + } + } + + public int getApplicationVersion() + { + try { + PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0); + return packageInfo.versionCode; + } catch (PackageManager.NameNotFoundException e) { + Log.i("SDL", "libSDL: Cannot get the version of our own package: " + e); + } + return 0; + } + + public boolean isRunningOnOUYA() + { + try { + PackageInfo packageInfo = getPackageManager().getPackageInfo("tv.ouya", 0); + return true; + } catch (PackageManager.NameNotFoundException e) { + } + return Globals.OuyaEmulation; + } + + public boolean isCurrentOrientationHorizontal() + { + Display getOrient = getWindowManager().getDefaultDisplay(); + return getOrient.getWidth() >= getOrient.getHeight(); + } + + public FrameLayout getVideoLayout() { return _videoLayout; } + + static int NOTIFY_ID = 12367098; // Random ID + + private static DemoGLSurfaceView mGLView = null; + private static AudioThread mAudioThread = null; + private static DataDownloader downloader = null; + + private TextView _tv = null; + private Button _btn = null; + private LinearLayout _layout = null; + private LinearLayout _layout2 = null; + private Advertisement _ad = null; + + private FrameLayout _videoLayout = null; + private EditText _screenKeyboard = null; + private String _screenKeyboardHintMessage = null; + private boolean sdlInited = false; + + public interface TouchEventsListener + { + public void onTouchEvent(final MotionEvent ev); + } + + public interface KeyEventsListener + { + public void onKeyEvent(final int keyCode); + } + + public TouchEventsListener touchListener = null; + public KeyEventsListener keyListener = null; + boolean _isPaused = false; + private InputMethodManager _inputManager = null; + + public LinkedList textInput = new LinkedList (); + public static MainActivity instance = null; +} + +// *** HONEYCOMB / ICS FIX FOR FULLSCREEN MODE, by lmak *** +abstract class DimSystemStatusBar +{ + public static DimSystemStatusBar get() + { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) + return DimSystemStatusBarHoneycomb.Holder.sInstance; + else + return DimSystemStatusBarDummy.Holder.sInstance; + } + public abstract void dim(final View view); + + private static class DimSystemStatusBarHoneycomb extends DimSystemStatusBar + { + private static class Holder + { + private static final DimSystemStatusBarHoneycomb sInstance = new DimSystemStatusBarHoneycomb(); + } + public void dim(final View view) + { + /* + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + // ICS has the same constant redefined with a different name. + hiddenStatusCode = android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE; + } + */ + view.setSystemUiVisibility(android.view.View.STATUS_BAR_HIDDEN); + } + } + private static class DimSystemStatusBarDummy extends DimSystemStatusBar + { + private static class Holder + { + private static final DimSystemStatusBarDummy sInstance = new DimSystemStatusBarDummy(); + } + public void dim(final View view) + { + } + } +} + +abstract class SetLayerType +{ + public static SetLayerType get() + { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) + return SetLayerTypeHoneycomb.Holder.sInstance; + else + return SetLayerTypeDummy.Holder.sInstance; + } + public abstract void setLayerType(final View view); + + private static class SetLayerTypeHoneycomb extends SetLayerType + { + private static class Holder + { + private static final SetLayerTypeHoneycomb sInstance = new SetLayerTypeHoneycomb(); + } + public void setLayerType(final View view) + { + view.setLayerType(android.view.View.LAYER_TYPE_NONE, null); + //view.setLayerType(android.view.View.LAYER_TYPE_HARDWARE, null); + } + } + private static class SetLayerTypeDummy extends SetLayerType + { + private static class Holder + { + private static final SetLayerTypeDummy sInstance = new SetLayerTypeDummy(); + } + public void setLayerType(final View view) + { + } + } +} diff --git a/project/javaSDL2/Settings.java b/project/javaSDL2/Settings.java new file mode 100644 index 000000000..5a7720876 --- /dev/null +++ b/project/javaSDL2/Settings.java @@ -0,0 +1,782 @@ +/* +Simple DirectMedia Layer +Java source code (C) 2009-2012 Sergii Pylypenko + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +package net.sourceforge.clonekeenplus; + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.view.MotionEvent; +import android.view.KeyEvent; +import android.view.Window; +import android.view.WindowManager; +import android.widget.TextView; +import android.util.Log; +import java.io.*; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.os.Environment; +import android.os.StatFs; +import java.util.Locale; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.zip.GZIPInputStream; +import java.util.Collections; +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import java.lang.String; +import android.graphics.Matrix; +import android.graphics.RectF; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.FrameLayout; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.BitmapFactory; +import android.graphics.Bitmap; +import android.widget.TextView; +import android.widget.EditText; +import android.widget.ScrollView; +import android.widget.Button; +import android.view.View; +import android.widget.LinearLayout; +import android.text.Editable; +import android.text.SpannedString; +import android.content.Intent; +import android.app.PendingIntent; +import android.app.AlarmManager; +import android.util.DisplayMetrics; +import android.net.Uri; +import java.util.concurrent.Semaphore; +import java.util.Arrays; +import android.graphics.Color; +import android.hardware.SensorEventListener; +import android.hardware.SensorEvent; +import android.hardware.Sensor; +import android.widget.Toast; + + +// TODO: too much code here, split into multiple files, possibly auto-generated menus? +class Settings +{ + static String SettingsFileName = "libsdl-settings.cfg"; + + static boolean settingsLoaded = false; + static boolean settingsChanged = false; + static final int SETTINGS_FILE_VERSION = 5; + + static void Save(final MainActivity p) + { + try { + ObjectOutputStream out = new ObjectOutputStream(p.openFileOutput( SettingsFileName, p.MODE_WORLD_READABLE )); + out.writeInt(SETTINGS_FILE_VERSION); + out.writeBoolean(Globals.DownloadToSdcard); + out.writeBoolean(Globals.PhoneHasArrowKeys); + out.writeBoolean(Globals.PhoneHasTrackball); + out.writeBoolean(Globals.UseAccelerometerAsArrowKeys); + out.writeBoolean(Globals.UseTouchscreenKeyboard); + out.writeInt(Globals.TouchscreenKeyboardSize); + out.writeInt(Globals.AccelerometerSensitivity); + out.writeInt(Globals.AccelerometerCenterPos); + out.writeInt(Globals.TrackballDampening); + out.writeInt(Globals.AudioBufferConfig); + out.writeInt(Globals.TouchscreenKeyboardTheme); + out.writeInt(Globals.RightClickMethod); + out.writeInt(Globals.ShowScreenUnderFinger); + out.writeInt(Globals.LeftClickMethod); + out.writeBoolean(Globals.MoveMouseWithJoystick); + out.writeBoolean(Globals.ClickMouseWithDpad); + out.writeInt(Globals.ClickScreenPressure); + out.writeInt(Globals.ClickScreenTouchspotSize); + out.writeBoolean(Globals.KeepAspectRatio); + out.writeInt(Globals.MoveMouseWithJoystickSpeed); + out.writeInt(Globals.MoveMouseWithJoystickAccel); + out.writeInt(SDL_Keys.JAVA_KEYCODE_LAST); + for( int i = 0; i < SDL_Keys.JAVA_KEYCODE_LAST; i++ ) + { + out.writeInt(Globals.RemapHwKeycode[i]); + } + out.writeInt(Globals.RemapScreenKbKeycode.length); + for( int i = 0; i < Globals.RemapScreenKbKeycode.length; i++ ) + { + out.writeInt(Globals.RemapScreenKbKeycode[i]); + } + out.writeInt(Globals.ScreenKbControlsShown.length); + for( int i = 0; i < Globals.ScreenKbControlsShown.length; i++ ) + { + out.writeBoolean(Globals.ScreenKbControlsShown[i]); + } + out.writeInt(Globals.TouchscreenKeyboardTransparency); + out.writeInt(Globals.RemapMultitouchGestureKeycode.length); + for( int i = 0; i < Globals.RemapMultitouchGestureKeycode.length; i++ ) + { + out.writeInt(Globals.RemapMultitouchGestureKeycode[i]); + out.writeBoolean(Globals.MultitouchGesturesUsed[i]); + } + out.writeInt(Globals.MultitouchGestureSensitivity); + for( int i = 0; i < Globals.TouchscreenCalibration.length; i++ ) + out.writeInt(Globals.TouchscreenCalibration[i]); + out.writeInt(Globals.DataDir.length()); + for( int i = 0; i < Globals.DataDir.length(); i++ ) + out.writeChar(Globals.DataDir.charAt(i)); + out.writeInt(Globals.CommandLine.length()); + for( int i = 0; i < Globals.CommandLine.length(); i++ ) + out.writeChar(Globals.CommandLine.charAt(i)); + out.writeInt(Globals.ScreenKbControlsLayout.length); + for( int i = 0; i < Globals.ScreenKbControlsLayout.length; i++ ) + for( int ii = 0; ii < 4; ii++ ) + out.writeInt(Globals.ScreenKbControlsLayout[i][ii]); + out.writeInt(Globals.LeftClickKey); + out.writeInt(Globals.RightClickKey); + out.writeBoolean(Globals.VideoLinearFilter); + out.writeInt(Globals.LeftClickTimeout); + out.writeInt(Globals.RightClickTimeout); + out.writeBoolean(Globals.RelativeMouseMovement); + out.writeInt(Globals.RelativeMouseMovementSpeed); + out.writeInt(Globals.RelativeMouseMovementAccel); + out.writeBoolean(Globals.MultiThreadedVideo); + + out.writeInt(Globals.OptionalDataDownload.length); + for(int i = 0; i < Globals.OptionalDataDownload.length; i++) + out.writeBoolean(Globals.OptionalDataDownload[i]); + out.writeBoolean(Globals.BrokenLibCMessageShown); + out.writeInt(Globals.TouchscreenKeyboardDrawSize); + out.writeInt(p.getApplicationVersion()); + out.writeFloat(Globals.gyro_x1); + out.writeFloat(Globals.gyro_x2); + out.writeFloat(Globals.gyro_xc); + out.writeFloat(Globals.gyro_y1); + out.writeFloat(Globals.gyro_y2); + out.writeFloat(Globals.gyro_yc); + out.writeFloat(Globals.gyro_z1); + out.writeFloat(Globals.gyro_z2); + out.writeFloat(Globals.gyro_zc); + + out.writeBoolean(Globals.OuyaEmulation); + + out.close(); + settingsLoaded = true; + + } catch( FileNotFoundException e ) { + } catch( SecurityException e ) { + } catch ( IOException e ) {}; + } + + static void Load( final MainActivity p ) + { + if(settingsLoaded) // Prevent starting twice + { + return; + } + Log.i("SDL", "libSDL: Settings.Load(): enter"); + nativeInitKeymap(); + if( p.isRunningOnOUYA() ) + nativeSetKeymapKey(KeyEvent.KEYCODE_MENU, nativeGetKeymapKey(KeyEvent.KEYCODE_BACK)); // Ouya does not have Back key, only Menu, so remap Back keycode to Menu + for( int i = 0; i < SDL_Keys.JAVA_KEYCODE_LAST; i++ ) + { + int sdlKey = nativeGetKeymapKey(i); + int idx = 0; + for(int ii = 0; ii < SDL_Keys.values.length; ii++) + if(SDL_Keys.values[ii] == sdlKey) + idx = ii; + Globals.RemapHwKeycode[i] = idx; + } + for( int i = 0; i < Globals.RemapScreenKbKeycode.length; i++ ) + { + int sdlKey = nativeGetKeymapKeyScreenKb(i); + int idx = 0; + for(int ii = 0; ii < SDL_Keys.values.length; ii++) + if(SDL_Keys.values[ii] == sdlKey) + idx = ii; + Globals.RemapScreenKbKeycode[i] = idx; + } + Globals.ScreenKbControlsShown[0] = (Globals.AppNeedsArrowKeys || Globals.AppUsesJoystick); + Globals.ScreenKbControlsShown[1] = Globals.AppNeedsTextInput; + for( int i = 2; i < Globals.ScreenKbControlsShown.length; i++ ) + Globals.ScreenKbControlsShown[i] = ( i - 2 < Globals.AppTouchscreenKeyboardKeysAmount ); + if( Globals.AppUsesSecondJoystick ) + Globals.ScreenKbControlsShown[8] = true; + for( int i = 0; i < Globals.RemapMultitouchGestureKeycode.length; i++ ) + { + int sdlKey = nativeGetKeymapKeyMultitouchGesture(i); + int idx = 0; + for(int ii = 0; ii < SDL_Keys.values.length; ii++) + if(SDL_Keys.values[ii] == sdlKey) + idx = ii; + Globals.RemapMultitouchGestureKeycode[i] = idx; + } + for( int i = 0; i < Globals.MultitouchGesturesUsed.length; i++ ) + Globals.MultitouchGesturesUsed[i] = true; + // Adjust coordinates of on-screen buttons from 800x480 + int displayX = 800; + int displayY = 480; + try { + DisplayMetrics dm = new DisplayMetrics(); + p.getWindowManager().getDefaultDisplay().getMetrics(dm); + displayX = dm.widthPixels; + displayY = dm.heightPixels; + } catch (Exception eeeee) {} + for( int i = 0; i < Globals.ScreenKbControlsLayout.length; i++ ) + { + Globals.ScreenKbControlsLayout[i][0] *= (float)displayX / 800.0f; + Globals.ScreenKbControlsLayout[i][2] *= (float)displayX / 800.0f; + Globals.ScreenKbControlsLayout[i][1] *= (float)displayY / 480.0f; + Globals.ScreenKbControlsLayout[i][3] *= (float)displayY / 480.0f; + // Make them square + int wh = Math.min( Globals.ScreenKbControlsLayout[i][2] - Globals.ScreenKbControlsLayout[i][0], Globals.ScreenKbControlsLayout[i][3] - Globals.ScreenKbControlsLayout[i][1] ); + Globals.ScreenKbControlsLayout[i][2] = Globals.ScreenKbControlsLayout[i][0] + wh; + Globals.ScreenKbControlsLayout[i][3] = Globals.ScreenKbControlsLayout[i][1] + wh; + } + + Log.i("SDL", "android.os.Build.MODEL: " + android.os.Build.MODEL); + if( (android.os.Build.MODEL.equals("GT-N7000") || android.os.Build.MODEL.equals("SGH-I717")) + && android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.GINGERBREAD_MR1 ) + { + // Samsung Galaxy Note generates a keypress when you hover a stylus over the screen, and that messes up OpenTTD dialogs + // ICS update sends events in a proper way + Globals.RemapHwKeycode[112] = SDL_1_2_Keycodes.SDLK_UNKNOWN; + } + + try { + ObjectInputStream settingsFile = new ObjectInputStream(new FileInputStream( p.getFilesDir().getAbsolutePath() + "/" + SettingsFileName )); + if( settingsFile.readInt() != SETTINGS_FILE_VERSION ) + throw new IOException(); + Globals.DownloadToSdcard = settingsFile.readBoolean(); + Globals.PhoneHasArrowKeys = settingsFile.readBoolean(); + Globals.PhoneHasTrackball = settingsFile.readBoolean(); + Globals.UseAccelerometerAsArrowKeys = settingsFile.readBoolean(); + Globals.UseTouchscreenKeyboard = settingsFile.readBoolean(); + Globals.TouchscreenKeyboardSize = settingsFile.readInt(); + Globals.AccelerometerSensitivity = settingsFile.readInt(); + Globals.AccelerometerCenterPos = settingsFile.readInt(); + Globals.TrackballDampening = settingsFile.readInt(); + Globals.AudioBufferConfig = settingsFile.readInt(); + Globals.TouchscreenKeyboardTheme = settingsFile.readInt(); + Globals.RightClickMethod = settingsFile.readInt(); + Globals.ShowScreenUnderFinger = settingsFile.readInt(); + Globals.LeftClickMethod = settingsFile.readInt(); + Globals.MoveMouseWithJoystick = settingsFile.readBoolean(); + Globals.ClickMouseWithDpad = settingsFile.readBoolean(); + Globals.ClickScreenPressure = settingsFile.readInt(); + Globals.ClickScreenTouchspotSize = settingsFile.readInt(); + Globals.KeepAspectRatio = settingsFile.readBoolean(); + Globals.MoveMouseWithJoystickSpeed = settingsFile.readInt(); + Globals.MoveMouseWithJoystickAccel = settingsFile.readInt(); + int readKeys = settingsFile.readInt(); + for( int i = 0; i < readKeys; i++ ) + { + Globals.RemapHwKeycode[i] = settingsFile.readInt(); + } + if( settingsFile.readInt() != Globals.RemapScreenKbKeycode.length ) + throw new IOException(); + for( int i = 0; i < Globals.RemapScreenKbKeycode.length; i++ ) + { + Globals.RemapScreenKbKeycode[i] = settingsFile.readInt(); + } + if( settingsFile.readInt() != Globals.ScreenKbControlsShown.length ) + throw new IOException(); + for( int i = 0; i < Globals.ScreenKbControlsShown.length; i++ ) + { + Globals.ScreenKbControlsShown[i] = settingsFile.readBoolean(); + } + Globals.TouchscreenKeyboardTransparency = settingsFile.readInt(); + if( settingsFile.readInt() != Globals.RemapMultitouchGestureKeycode.length ) + throw new IOException(); + for( int i = 0; i < Globals.RemapMultitouchGestureKeycode.length; i++ ) + { + Globals.RemapMultitouchGestureKeycode[i] = settingsFile.readInt(); + Globals.MultitouchGesturesUsed[i] = settingsFile.readBoolean(); + } + Globals.MultitouchGestureSensitivity = settingsFile.readInt(); + for( int i = 0; i < Globals.TouchscreenCalibration.length; i++ ) + Globals.TouchscreenCalibration[i] = settingsFile.readInt(); + StringBuilder b = new StringBuilder(); + int len = settingsFile.readInt(); + for( int i = 0; i < len; i++ ) + b.append( settingsFile.readChar() ); + Globals.DataDir = b.toString(); + + b = new StringBuilder(); + len = settingsFile.readInt(); + for( int i = 0; i < len; i++ ) + b.append( settingsFile.readChar() ); + Globals.CommandLine = b.toString(); + + if( settingsFile.readInt() != Globals.ScreenKbControlsLayout.length ) + throw new IOException(); + for( int i = 0; i < Globals.ScreenKbControlsLayout.length; i++ ) + for( int ii = 0; ii < 4; ii++ ) + Globals.ScreenKbControlsLayout[i][ii] = settingsFile.readInt(); + Globals.LeftClickKey = settingsFile.readInt(); + Globals.RightClickKey = settingsFile.readInt(); + Globals.VideoLinearFilter = settingsFile.readBoolean(); + Globals.LeftClickTimeout = settingsFile.readInt(); + Globals.RightClickTimeout = settingsFile.readInt(); + Globals.RelativeMouseMovement = settingsFile.readBoolean(); + Globals.RelativeMouseMovementSpeed = settingsFile.readInt(); + Globals.RelativeMouseMovementAccel = settingsFile.readInt(); + Globals.MultiThreadedVideo = settingsFile.readBoolean(); + + Globals.OptionalDataDownload = new boolean[settingsFile.readInt()]; + for(int i = 0; i < Globals.OptionalDataDownload.length; i++) + Globals.OptionalDataDownload[i] = settingsFile.readBoolean(); + Globals.BrokenLibCMessageShown = settingsFile.readBoolean(); + Globals.TouchscreenKeyboardDrawSize = settingsFile.readInt(); + int cfgVersion = settingsFile.readInt(); + Globals.gyro_x1 = settingsFile.readFloat(); + Globals.gyro_x2 = settingsFile.readFloat(); + Globals.gyro_xc = settingsFile.readFloat(); + Globals.gyro_y1 = settingsFile.readFloat(); + Globals.gyro_y2 = settingsFile.readFloat(); + Globals.gyro_yc = settingsFile.readFloat(); + Globals.gyro_z1 = settingsFile.readFloat(); + Globals.gyro_z2 = settingsFile.readFloat(); + Globals.gyro_zc = settingsFile.readFloat(); + + Globals.OuyaEmulation = settingsFile.readBoolean(); + + settingsLoaded = true; + + Log.i("SDL", "libSDL: Settings.Load(): loaded settings successfully"); + settingsFile.close(); + + Log.i("SDL", "libSDL: old cfg version " + cfgVersion + ", our version " + p.getApplicationVersion()); + if( cfgVersion != p.getApplicationVersion() ) + { + DeleteFilesOnUpgrade(p); + if( Globals.ResetSdlConfigForThisVersion ) + { + Log.i("SDL", "libSDL: old cfg version " + cfgVersion + ", our version " + p.getApplicationVersion() + " and we need to clean up config file"); + // Delete settings file, and restart the application + DeleteSdlConfigOnUpgradeAndRestart(p); + } + Save(p); + } + + return; + + } catch( FileNotFoundException e ) { + } catch( SecurityException e ) { + } catch ( IOException e ) { + DeleteFilesOnUpgrade(p); + if( Globals.ResetSdlConfigForThisVersion ) + { + Log.i("SDL", "libSDL: old cfg version unknown or too old, our version " + p.getApplicationVersion() + " and we need to clean up config file"); + DeleteSdlConfigOnUpgradeAndRestart(p); + } + }; + + if( Globals.DataDir.length() == 0 ) + { + if( !Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ) + { + Log.i("SDL", "libSDL: SD card or external storage is not mounted (state " + Environment.getExternalStorageState() + "), switching to the internal storage."); + Globals.DownloadToSdcard = false; + } + Globals.DataDir = Globals.DownloadToSdcard ? + SdcardAppPath.getPath(p) : + p.getFilesDir().getAbsolutePath(); + if( Globals.DownloadToSdcard ) + { + // Check if data already installed into deprecated location at /sdcard/app-data/ + String[] fileList = new File(SdcardAppPath.deprecatedPath(p)).list(); + if( fileList != null ) + for( String s: fileList ) + if( s.toUpperCase().startsWith(DataDownloader.DOWNLOAD_FLAG_FILENAME.toUpperCase()) ) + Globals.DataDir = SdcardAppPath.deprecatedPath(p); + } + } + + Log.i("SDL", "libSDL: Settings.Load(): loading settings failed, running config dialog"); + p.setUpStatusLabel(); + if( checkRamSize(p) ) + SettingsMenu.showConfig(p, true); + } + + // =============================================================================================== + + public static boolean deleteRecursively(File dir) + { + if (dir.isDirectory()) { + String[] children = dir.list(); + for (int i=0; i Globals.TouchscreenCalibration[0] ) + nativeSetTouchscreenCalibration(Globals.TouchscreenCalibration[0], Globals.TouchscreenCalibration[1], + Globals.TouchscreenCalibration[2], Globals.TouchscreenCalibration[3]); + + String lang = new String(Locale.getDefault().getLanguage()); + if( Locale.getDefault().getCountry().length() > 0 ) + lang = lang + "_" + Locale.getDefault().getCountry(); + Log.i("SDL", "libSDL: setting envvar LANGUAGE to '" + lang + "'"); + nativeSetEnv( "LANG", lang ); + nativeSetEnv( "LANGUAGE", lang ); + // TODO: get current user name and set envvar USER, the API is not availalbe on Android 1.6 so I don't bother with this + nativeSetEnv( "APPDIR", p.getFilesDir().getAbsolutePath() ); + nativeSetEnv( "SECURE_STORAGE_DIR", p.getFilesDir().getAbsolutePath() ); + nativeSetEnv( "DATADIR", Globals.DataDir ); + nativeSetEnv( "UNSECURE_STORAGE_DIR", Globals.DataDir ); + nativeSetEnv( "HOME", Globals.DataDir ); + nativeSetEnv( "ANDROID_VERSION", String.valueOf(android.os.Build.VERSION.SDK_INT) ); + Log.d("SDL", "libSDL: Is running on OUYA: " + p.isRunningOnOUYA()); + if( p.isRunningOnOUYA() ) + nativeSetEnv( "OUYA", "1" ); + try { + DisplayMetrics dm = new DisplayMetrics(); + p.getWindowManager().getDefaultDisplay().getMetrics(dm); + float xx = dm.widthPixels/dm.xdpi; + float yy = dm.heightPixels/dm.ydpi; + float x = Math.max(xx, yy); + float y = Math.min(xx, yy); + float displayInches = (float)Math.sqrt( x*x + y*y ); + nativeSetEnv( "DISPLAY_SIZE", String.valueOf(displayInches) ); + nativeSetEnv( "DISPLAY_SIZE_MM", String.valueOf((int)(displayInches*25.4f)) ); + nativeSetEnv( "DISPLAY_WIDTH", String.valueOf(x) ); + nativeSetEnv( "DISPLAY_HEIGHT", String.valueOf(y) ); + nativeSetEnv( "DISPLAY_WIDTH_MM", String.valueOf((int)(x*25.4f)) ); + nativeSetEnv( "DISPLAY_HEIGHT_MM", String.valueOf((int)(y*25.4f)) ); + nativeSetEnv( "DISPLAY_RESOLUTION_WIDTH", String.valueOf(Math.max(dm.widthPixels, dm.heightPixels)) ); + nativeSetEnv( "DISPLAY_RESOLUTION_HEIGHT", String.valueOf(Math.min(dm.widthPixels, dm.heightPixels)) ); + } catch (Exception eeeee) {} + } + + static byte [] loadRaw(Activity p, int res) + { + byte [] buf = new byte[65536 * 2]; + byte [] a = new byte[65536 * 4 * 10]; // We need 2363516 bytes for the Sun theme + int written = 0; + try{ + InputStream is = new GZIPInputStream(p.getResources().openRawResource(res)); + int readed = 0; + while( (readed = is.read(buf)) >= 0 ) + { + if( written + readed > a.length ) + { + byte [] b = new byte [written + readed]; + System.arraycopy(a, 0, b, 0, written); + a = b; + } + System.arraycopy(buf, 0, a, written, readed); + written += readed; + } + } catch(Exception e) {}; + byte [] b = new byte [written]; + System.arraycopy(a, 0, b, 0, written); + return b; + } + + static void SetupTouchscreenKeyboardGraphics(Activity p) + { + if( Globals.UseTouchscreenKeyboard ) + { + if(Globals.TouchscreenKeyboardTheme < 0) + Globals.TouchscreenKeyboardTheme = 0; + if(Globals.TouchscreenKeyboardTheme > 3) + Globals.TouchscreenKeyboardTheme = 3; + + if( Globals.TouchscreenKeyboardTheme == 0 ) + { + nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.ultimatedroid)); + } + if( Globals.TouchscreenKeyboardTheme == 1 ) + { + nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.simpletheme)); + } + if( Globals.TouchscreenKeyboardTheme == 2 ) + { + nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.sun)); + } + if( Globals.TouchscreenKeyboardTheme == 3 ) + { + nativeSetupScreenKeyboardButtons(loadRaw(p, R.raw.keen)); + } + } + } + + abstract static class SdcardAppPath + { + private static SdcardAppPath get() + { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.FROYO) + return Froyo.Holder.sInstance; + else + return Dummy.Holder.sInstance; + } + public abstract String path(final Context p); + public static String deprecatedPath(final Context p) + { + return Environment.getExternalStorageDirectory().getAbsolutePath() + "/app-data/" + p.getPackageName(); + } + public static String getPath(final Context p) + { + try { + return get().path(p); + } catch(Exception e) { } + return Dummy.Holder.sInstance.path(p); + } + + private static class Froyo extends SdcardAppPath + { + private static class Holder + { + private static final Froyo sInstance = new Froyo(); + } + public String path(final Context p) + { + return p.getExternalFilesDir(null).getAbsolutePath(); + } + } + private static class Dummy extends SdcardAppPath + { + private static class Holder + { + private static final Dummy sInstance = new Dummy(); + } + public String path(final Context p) + { + return Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + p.getPackageName() + "/files"; + } + } + } + + static boolean checkRamSize(final MainActivity p) + { + try { + BufferedReader reader = new BufferedReader(new FileReader("/proc/meminfo")); + String line = null; + while( ( line = reader.readLine() ) != null ) + { + if( line.indexOf("MemTotal:") == 0 ) + { + String[] fields = line.split("[ \t]+"); + Long size = Long.parseLong(fields[1]); + Log.i("SDL", "Device RAM size: " + size / 1024 + " Mb, required minimum RAM: " + Globals.AppMinimumRAM + " Mb" ); + if( size / 1024 < Globals.AppMinimumRAM ) + { + settingsChanged = true; + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(R.string.not_enough_ram); + builder.setMessage(p.getResources().getString( R.string.not_enough_ram_size, Globals.AppMinimumRAM, (int)(size / 1024)) ); + builder.setPositiveButton(p.getResources().getString(R.string.ok), new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + p.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + p.getPackageName()))); + System.exit(0); + } + }); + builder.setNegativeButton(p.getResources().getString(R.string.ignore), new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + SettingsMenu.showConfig(p, true); + return; + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + p.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + p.getPackageName()))); + System.exit(0); + } + }); + final AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + return false; + } + } + } + } catch ( Exception e ) { + Log.i("SDL", "Error: cannot parse /proc/meminfo: " + e.toString()); + } + return true; + } + + private static native void nativeSetTrackballUsed(); + private static native void nativeSetTrackballDampening(int value); + private static native void nativeSetAccelerometerSettings(int sensitivity, int centerPos); + private static native void nativeSetMouseUsed(int RightClickMethod, int ShowScreenUnderFinger, int LeftClickMethod, + int MoveMouseWithJoystick, int ClickMouseWithDpad, int MaxForce, int MaxRadius, + int MoveMouseWithJoystickSpeed, int MoveMouseWithJoystickAccel, + int leftClickKeycode, int rightClickKeycode, + int leftClickTimeout, int rightClickTimeout, + int relativeMovement, int relativeMovementSpeed, + int relativeMovementAccel, int showMouseCursor); + private static native void nativeSetJoystickUsed(int firstJoystickUsed, int secondJoystickUsed); + private static native void nativeSetAccelerometerUsed(); + private static native void nativeSetMultitouchUsed(); + private static native void nativeSetTouchscreenKeyboardUsed(); + private static native void nativeSetVideoLinearFilter(); + private static native void nativeSetVideoDepth(int bpp, int gles2); + private static native void nativeSetCompatibilityHacks(); + private static native void nativeSetVideoMultithreaded(); + private static native void nativeSetVideoForceSoftwareMode(); + private static native void nativeSetupScreenKeyboard(int size, int drawsize, int theme, int nbuttonsAutoFire, int transparency); + private static native void nativeSetupScreenKeyboardButtons(byte[] img); + private static native void nativeInitKeymap(); + private static native int nativeGetKeymapKey(int key); + private static native void nativeSetKeymapKey(int javakey, int key); + private static native int nativeGetKeymapKeyScreenKb(int keynum); + private static native void nativeSetKeymapKeyScreenKb(int keynum, int key); + private static native void nativeSetScreenKbKeyUsed(int keynum, int used); + private static native void nativeSetScreenKbKeyLayout(int keynum, int x1, int y1, int x2, int y2); + private static native int nativeGetKeymapKeyMultitouchGesture(int keynum); + private static native void nativeSetKeymapKeyMultitouchGesture(int keynum, int key); + private static native void nativeSetMultitouchGestureSensitivity(int sensitivity); + private static native void nativeSetTouchscreenCalibration(int x1, int y1, int x2, int y2); + public static native void nativeSetEnv(final String name, final String value); + public static native int nativeChmod(final String name, int mode); + public static native void nativeChdir(final String dir); +} + diff --git a/project/javaSDL2/SettingsMenu.java b/project/javaSDL2/SettingsMenu.java new file mode 100644 index 000000000..544eb0977 --- /dev/null +++ b/project/javaSDL2/SettingsMenu.java @@ -0,0 +1,257 @@ +/* +Simple DirectMedia Layer +Java source code (C) 2009-2012 Sergii Pylypenko + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +package net.sourceforge.clonekeenplus; + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.view.MotionEvent; +import android.view.KeyEvent; +import android.view.Window; +import android.view.WindowManager; +import android.widget.TextView; +import android.util.Log; +import java.io.*; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.os.Environment; +import android.os.StatFs; +import java.util.Locale; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.zip.GZIPInputStream; +import java.util.Collections; +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import java.lang.String; +import android.graphics.Matrix; +import android.graphics.RectF; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.FrameLayout; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.BitmapFactory; +import android.graphics.Bitmap; +import android.widget.TextView; +import android.widget.EditText; +import android.widget.ScrollView; +import android.widget.Button; +import android.view.View; +import android.widget.LinearLayout; +import android.text.Editable; +import android.text.SpannedString; +import android.content.Intent; +import android.app.PendingIntent; +import android.app.AlarmManager; +import android.util.DisplayMetrics; +import android.net.Uri; +import java.util.concurrent.Semaphore; +import java.util.Arrays; +import android.graphics.Color; +import android.hardware.SensorEventListener; +import android.hardware.SensorEvent; +import android.hardware.Sensor; +import android.widget.Toast; + + +class SettingsMenu +{ + public static abstract class Menu + { + // Should be overridden by children + abstract void run(final MainActivity p); + abstract String title(final MainActivity p); + boolean enabled() + { + return true; + } + // Should not be overridden + boolean enabledOrHidden() + { + for( Menu m: Globals.HiddenMenuOptions ) + { + if( m.getClass().getName().equals( this.getClass().getName() ) ) + return false; + } + return enabled(); + } + void showMenuOptionsList(final MainActivity p, final Menu[] list) + { + menuStack.add(this); + ArrayList items = new ArrayList (); + for( Menu m: list ) + { + if(m.enabledOrHidden()) + items.add(m.title(p)); + } + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(title(p)); + builder.setItems(items.toArray(new CharSequence[0]), new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + dialog.dismiss(); + int selected = 0; + + for( Menu m: list ) + { + if(m.enabledOrHidden()) + { + if( selected == item ) + { + m.run(p); + return; + } + selected ++; + } + } + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBackOuterMenu(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + static ArrayList

menuStack = new ArrayList (); + + public static void showConfig(final MainActivity p, final boolean firstStart) + { + Settings.settingsChanged = true; + if( Globals.OptionalDataDownload == null ) + { + String downloads[] = Globals.DataDownloadUrl; + Globals.OptionalDataDownload = new boolean[downloads.length]; + boolean oldFormat = true; + for( int i = 0; i < downloads.length; i++ ) + { + if( downloads[i].indexOf("!") == 0 ) + { + Globals.OptionalDataDownload[i] = true; + oldFormat = false; + } + } + if( oldFormat ) + Globals.OptionalDataDownload[0] = true; + } + + if(!firstStart) + new MainMenu().run(p); + else + { + if( Globals.StartupMenuButtonTimeout > 0 ) // If we did not disable startup menu altogether + { + for( Menu m: Globals.FirstStartMenuOptions ) + { + boolean hidden = false; + for( Menu m1: Globals.HiddenMenuOptions ) + { + if( m1.getClass().getName().equals( m.getClass().getName() ) ) + hidden = true; + } + if( ! hidden ) + menuStack.add(0, m); + } + } + goBack(p); + } + } + + static void goBack(final MainActivity p) + { + if(menuStack.isEmpty()) + { + Settings.Save(p); + p.startDownloader(); + } + else + { + Menu c = menuStack.remove(menuStack.size() - 1); + c.run(p); + } + } + + static void goBackOuterMenu(final MainActivity p) + { + if(!menuStack.isEmpty()) + menuStack.remove(menuStack.size() - 1); + goBack(p); + } + + static class OkButton extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.ok); + } + void run (final MainActivity p) + { + goBackOuterMenu(p); + } + } + + static class DummyMenu extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.ok); + } + void run (final MainActivity p) + { + goBack(p); + } + } + + static class MainMenu extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.device_config); + } + void run (final MainActivity p) + { + Menu options[] = + { + new SettingsMenuMisc.DownloadConfig(), + new SettingsMenuMisc.OptionalDownloadConfig(false), + new SettingsMenuKeyboard.KeyboardConfigMainMenu(), + new SettingsMenuMouse.MouseConfigMainMenu(), + new SettingsMenuMisc.GyroscopeCalibration(), + new SettingsMenuMisc.AudioConfig(), + new SettingsMenuKeyboard.RemapHwKeysConfig(), + new SettingsMenuKeyboard.ScreenGesturesConfig(), + new SettingsMenuMisc.VideoSettingsConfig(), + new SettingsMenuMisc.ResetToDefaultsConfig(), + new OkButton(), + }; + showMenuOptionsList(p, options); + } + } +} diff --git a/project/javaSDL2/SettingsMenuKeyboard.java b/project/javaSDL2/SettingsMenuKeyboard.java new file mode 100644 index 000000000..d0d67148e --- /dev/null +++ b/project/javaSDL2/SettingsMenuKeyboard.java @@ -0,0 +1,843 @@ +/* +Simple DirectMedia Layer +Java source code (C) 2009-2012 Sergii Pylypenko + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +package net.sourceforge.clonekeenplus; + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.view.MotionEvent; +import android.view.KeyEvent; +import android.view.Window; +import android.view.WindowManager; +import android.widget.TextView; +import android.util.Log; +import java.io.*; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.os.Environment; +import android.os.StatFs; +import java.util.Locale; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.zip.GZIPInputStream; +import java.util.Collections; +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import java.lang.String; +import android.graphics.Matrix; +import android.graphics.RectF; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.FrameLayout; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.BitmapFactory; +import android.graphics.Bitmap; +import android.widget.TextView; +import android.widget.EditText; +import android.widget.ScrollView; +import android.widget.Button; +import android.view.View; +import android.widget.LinearLayout; +import android.text.Editable; +import android.text.SpannedString; +import android.content.Intent; +import android.app.PendingIntent; +import android.app.AlarmManager; +import android.util.DisplayMetrics; +import android.net.Uri; +import java.util.concurrent.Semaphore; +import java.util.Arrays; +import android.graphics.Color; +import android.hardware.SensorEventListener; +import android.hardware.SensorEvent; +import android.hardware.Sensor; +import android.widget.Toast; + + +class SettingsMenuKeyboard extends SettingsMenu +{ + static class KeyboardConfigMainMenu extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.controls_screenkb); + } + boolean enabled() + { + return Globals.UseTouchscreenKeyboard; + } + void run (final MainActivity p) + { + Menu options[] = + { + new ScreenKeyboardThemeConfig(), + new ScreenKeyboardSizeConfig(), + new ScreenKeyboardDrawSizeConfig(), + new ScreenKeyboardTransparencyConfig(), + new RemapScreenKbConfig(), + new CustomizeScreenKbLayout(), + new OkButton(), + }; + showMenuOptionsList(p, options); + } + } + + static class ScreenKeyboardSizeConfig extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.controls_screenkb_size); + } + void run (final MainActivity p) + { + final CharSequence[] items = { p.getResources().getString(R.string.controls_screenkb_large), + p.getResources().getString(R.string.controls_screenkb_medium), + p.getResources().getString(R.string.controls_screenkb_small), + p.getResources().getString(R.string.controls_screenkb_tiny), + p.getResources().getString(R.string.controls_screenkb_custom) }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.controls_screenkb_size)); + builder.setSingleChoiceItems(items, Globals.TouchscreenKeyboardSize, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.TouchscreenKeyboardSize = item; + dialog.dismiss(); + if( Globals.TouchscreenKeyboardSize == Globals.TOUCHSCREEN_KEYBOARD_CUSTOM ) + new CustomizeScreenKbLayout().run(p); + else + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + static class ScreenKeyboardDrawSizeConfig extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.controls_screenkb_drawsize); + } + void run (final MainActivity p) + { + final CharSequence[] items = { p.getResources().getString(R.string.controls_screenkb_large), + p.getResources().getString(R.string.controls_screenkb_medium), + p.getResources().getString(R.string.controls_screenkb_small), + p.getResources().getString(R.string.controls_screenkb_tiny) }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.controls_screenkb_drawsize)); + builder.setSingleChoiceItems(items, Globals.TouchscreenKeyboardDrawSize, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.TouchscreenKeyboardDrawSize = item; + + dialog.dismiss(); + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + static class ScreenKeyboardThemeConfig extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.controls_screenkb_theme); + } + void run (final MainActivity p) + { + final CharSequence[] items = { + p.getResources().getString(R.string.controls_screenkb_by, "Ultimate Droid", "Sean Stieber"), + p.getResources().getString(R.string.controls_screenkb_by, "Simple Theme", "Beholder"), + p.getResources().getString(R.string.controls_screenkb_by, "Sun", "Sirea"), + p.getResources().getString(R.string.controls_screenkb_by, "Keen", "Gerstrong") + }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.controls_screenkb_theme)); + builder.setSingleChoiceItems(items, Globals.TouchscreenKeyboardTheme, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.TouchscreenKeyboardTheme = item; + + dialog.dismiss(); + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + static class ScreenKeyboardTransparencyConfig extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.controls_screenkb_transparency); + } + void run (final MainActivity p) + { + final CharSequence[] items = { p.getResources().getString(R.string.controls_screenkb_trans_0), + p.getResources().getString(R.string.controls_screenkb_trans_1), + p.getResources().getString(R.string.controls_screenkb_trans_2), + p.getResources().getString(R.string.controls_screenkb_trans_3), + p.getResources().getString(R.string.controls_screenkb_trans_4) }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.controls_screenkb_transparency)); + builder.setSingleChoiceItems(items, Globals.TouchscreenKeyboardTransparency, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.TouchscreenKeyboardTransparency = item; + + dialog.dismiss(); + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + static class RemapHwKeysConfig extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.remap_hwkeys); + } + void run (final MainActivity p) + { + p.setText(p.getResources().getString(R.string.remap_hwkeys_press)); + p.keyListener = new KeyRemapTool(p); + } + + public static class KeyRemapTool implements MainActivity.KeyEventsListener + { + MainActivity p; + public KeyRemapTool(MainActivity _p) + { + p = _p; + } + + public void onKeyEvent(final int keyCode) + { + p.keyListener = null; + int keyIndex = keyCode; + if( keyIndex < 0 ) + keyIndex = 0; + if( keyIndex > SDL_Keys.JAVA_KEYCODE_LAST ) + keyIndex = 0; + + final int KeyIndexFinal = keyIndex; + CharSequence[] items = { + SDL_Keys.names[Globals.RemapScreenKbKeycode[0]], + SDL_Keys.names[Globals.RemapScreenKbKeycode[1]], + SDL_Keys.names[Globals.RemapScreenKbKeycode[2]], + SDL_Keys.names[Globals.RemapScreenKbKeycode[3]], + SDL_Keys.names[Globals.RemapScreenKbKeycode[4]], + SDL_Keys.names[Globals.RemapScreenKbKeycode[5]], + p.getResources().getString(R.string.remap_hwkeys_select_more_keys), + }; + + for( int i = 0; i < Math.min(6, Globals.AppTouchscreenKeyboardKeysNames.length); i++ ) + items[i] = Globals.AppTouchscreenKeyboardKeysNames[i].replace("_", " "); + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(R.string.remap_hwkeys_select_simple); + builder.setItems(items, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + dialog.dismiss(); + if( item >= 6 ) + ShowAllKeys(KeyIndexFinal); + else + { + Globals.RemapHwKeycode[KeyIndexFinal] = Globals.RemapScreenKbKeycode[item]; + goBack(p); + } + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + public void ShowAllKeys(final int KeyIndex) + { + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(R.string.remap_hwkeys_select); + builder.setSingleChoiceItems(SDL_Keys.namesSorted, SDL_Keys.namesSortedBackIdx[Globals.RemapHwKeycode[KeyIndex]], new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.RemapHwKeycode[KeyIndex] = SDL_Keys.namesSortedIdx[item]; + + dialog.dismiss(); + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + } + + static class RemapScreenKbConfig extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.remap_screenkb); + } + //boolean enabled() { return true; }; + void run (final MainActivity p) + { + CharSequence[] items = { + p.getResources().getString(R.string.remap_screenkb_joystick), + p.getResources().getString(R.string.remap_screenkb_button_text), + p.getResources().getString(R.string.remap_screenkb_button) + " 1", + p.getResources().getString(R.string.remap_screenkb_button) + " 2", + p.getResources().getString(R.string.remap_screenkb_button) + " 3", + p.getResources().getString(R.string.remap_screenkb_button) + " 4", + p.getResources().getString(R.string.remap_screenkb_button) + " 5", + p.getResources().getString(R.string.remap_screenkb_button) + " 6", + }; + + boolean defaults[] = Arrays.copyOf(Globals.ScreenKbControlsShown, Globals.ScreenKbControlsShown.length); + if( Globals.AppUsesSecondJoystick ) + { + items = Arrays.copyOf(items, items.length + 1); + items[items.length - 1] = p.getResources().getString(R.string.remap_screenkb_joystick) + " 2"; + defaults = Arrays.copyOf(defaults, defaults.length + 1); + defaults[defaults.length - 1] = true; + } + + for( int i = 0; i < Math.min(6, Globals.AppTouchscreenKeyboardKeysNames.length); i++ ) + items[i+2] = items[i+2] + " - " + Globals.AppTouchscreenKeyboardKeysNames[i].replace("_", " "); + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.remap_screenkb)); + builder.setMultiChoiceItems(items, defaults, new DialogInterface.OnMultiChoiceClickListener() + { + public void onClick(DialogInterface dialog, int item, boolean isChecked) + { + Globals.ScreenKbControlsShown[item] = isChecked; + } + }); + builder.setPositiveButton(p.getResources().getString(R.string.ok), new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + dialog.dismiss(); + showRemapScreenKbConfig2(p, 0); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + + static void showRemapScreenKbConfig2(final MainActivity p, final int currentButton) + { + CharSequence[] items = { + p.getResources().getString(R.string.remap_screenkb_button) + " 1", + p.getResources().getString(R.string.remap_screenkb_button) + " 2", + p.getResources().getString(R.string.remap_screenkb_button) + " 3", + p.getResources().getString(R.string.remap_screenkb_button) + " 4", + p.getResources().getString(R.string.remap_screenkb_button) + " 5", + p.getResources().getString(R.string.remap_screenkb_button) + " 6", + }; + + for( int i = 0; i < Math.min(6, Globals.AppTouchscreenKeyboardKeysNames.length); i++ ) + items[i] = items[i] + " - " + Globals.AppTouchscreenKeyboardKeysNames[i].replace("_", " "); + + if( currentButton >= Globals.RemapScreenKbKeycode.length ) + { + goBack(p); + return; + } + if( ! Globals.ScreenKbControlsShown[currentButton + 2] ) + { + showRemapScreenKbConfig2(p, currentButton + 1); + return; + } + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(items[currentButton]); + builder.setSingleChoiceItems(SDL_Keys.namesSorted, SDL_Keys.namesSortedBackIdx[Globals.RemapScreenKbKeycode[currentButton]], new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.RemapScreenKbKeycode[currentButton] = SDL_Keys.namesSortedIdx[item]; + + dialog.dismiss(); + showRemapScreenKbConfig2(p, currentButton + 1); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + static class ScreenGesturesConfig extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.remap_screenkb_button_gestures); + } + //boolean enabled() { return true; }; + void run (final MainActivity p) + { + CharSequence[] items = { + p.getResources().getString(R.string.remap_screenkb_button_zoomin), + p.getResources().getString(R.string.remap_screenkb_button_zoomout), + p.getResources().getString(R.string.remap_screenkb_button_rotateleft), + p.getResources().getString(R.string.remap_screenkb_button_rotateright), + }; + + boolean defaults[] = { + Globals.MultitouchGesturesUsed[0], + Globals.MultitouchGesturesUsed[1], + Globals.MultitouchGesturesUsed[2], + Globals.MultitouchGesturesUsed[3], + }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.remap_screenkb_button_gestures)); + builder.setMultiChoiceItems(items, defaults, new DialogInterface.OnMultiChoiceClickListener() + { + public void onClick(DialogInterface dialog, int item, boolean isChecked) + { + Globals.MultitouchGesturesUsed[item] = isChecked; + } + }); + builder.setPositiveButton(p.getResources().getString(R.string.ok), new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + dialog.dismiss(); + showScreenGesturesConfig2(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + + static void showScreenGesturesConfig2(final MainActivity p) + { + final CharSequence[] items = { + p.getResources().getString(R.string.accel_slow), + p.getResources().getString(R.string.accel_medium), + p.getResources().getString(R.string.accel_fast), + p.getResources().getString(R.string.accel_veryfast) + }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(R.string.remap_screenkb_button_gestures_sensitivity); + builder.setSingleChoiceItems(items, Globals.MultitouchGestureSensitivity, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.MultitouchGestureSensitivity = item; + + dialog.dismiss(); + showScreenGesturesConfig3(p, 0); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + + static void showScreenGesturesConfig3(final MainActivity p, final int currentButton) + { + CharSequence[] items = { + p.getResources().getString(R.string.remap_screenkb_button_zoomin), + p.getResources().getString(R.string.remap_screenkb_button_zoomout), + p.getResources().getString(R.string.remap_screenkb_button_rotateleft), + p.getResources().getString(R.string.remap_screenkb_button_rotateright), + }; + + if( currentButton >= Globals.RemapMultitouchGestureKeycode.length ) + { + goBack(p); + return; + } + if( ! Globals.MultitouchGesturesUsed[currentButton] ) + { + showScreenGesturesConfig3(p, currentButton + 1); + return; + } + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(items[currentButton]); + builder.setSingleChoiceItems(SDL_Keys.namesSorted, SDL_Keys.namesSortedBackIdx[Globals.RemapMultitouchGestureKeycode[currentButton]], new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.RemapMultitouchGestureKeycode[currentButton] = SDL_Keys.namesSortedIdx[item]; + + dialog.dismiss(); + showScreenGesturesConfig3(p, currentButton + 1); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + static class CustomizeScreenKbLayout extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.screenkb_custom_layout); + } + //boolean enabled() { return true; }; + void run (final MainActivity p) + { + p.setText(p.getResources().getString(R.string.screenkb_custom_layout_help)); + CustomizeScreenKbLayoutTool tool = new CustomizeScreenKbLayoutTool(p); + p.touchListener = tool; + p.keyListener = tool; + Globals.TouchscreenKeyboardSize = Globals.TOUCHSCREEN_KEYBOARD_CUSTOM; + } + + static class CustomizeScreenKbLayoutTool implements MainActivity.TouchEventsListener, MainActivity.KeyEventsListener + { + MainActivity p; + FrameLayout layout = null; + ImageView imgs[] = new ImageView[Globals.ScreenKbControlsLayout.length]; + Bitmap bmps[] = new Bitmap[Globals.ScreenKbControlsLayout.length]; + ImageView boundary = null; + Bitmap boundaryBmp = null; + int currentButton = 0; + int buttons[] = { + R.drawable.dpad, + R.drawable.keyboard, + R.drawable.b1, + R.drawable.b2, + R.drawable.b3, + R.drawable.b4, + R.drawable.b5, + R.drawable.b6, + R.drawable.dpad + }; + int oldX = 0, oldY = 0; + boolean resizing = false; + + public CustomizeScreenKbLayoutTool(MainActivity _p) + { + p = _p; + layout = new FrameLayout(p); + p.getVideoLayout().addView(layout); + boundary = new ImageView(p); + boundary.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + boundary.setScaleType(ImageView.ScaleType.MATRIX); + boundaryBmp = BitmapFactory.decodeResource( p.getResources(), R.drawable.rectangle ); + boundary.setImageBitmap(boundaryBmp); + layout.addView(boundary); + currentButton = -1; + if( Globals.TouchscreenKeyboardTheme == 2 ) + { + buttons = new int[] { + R.drawable.sun_dpad, + R.drawable.sun_keyboard, + R.drawable.sun_b1, + R.drawable.sun_b2, + R.drawable.sun_b3, + R.drawable.sun_b4, + R.drawable.sun_b5, + R.drawable.sun_b6, + R.drawable.sun_dpad + }; + } + + int displayX = 800; + int displayY = 480; + try { + DisplayMetrics dm = new DisplayMetrics(); + p.getWindowManager().getDefaultDisplay().getMetrics(dm); + displayX = dm.widthPixels; + displayY = dm.heightPixels; + } catch (Exception eeeee) {} + + for( int i = 0; i < Globals.ScreenKbControlsLayout.length; i++ ) + { + if( ! Globals.ScreenKbControlsShown[i] ) + continue; + if( currentButton == -1 ) + currentButton = i; + //Log.i("SDL", "Screen kb button " + i + " coords " + Globals.ScreenKbControlsLayout[i][0] + ":" + Globals.ScreenKbControlsLayout[i][1] + ":" + Globals.ScreenKbControlsLayout[i][2] + ":" + Globals.ScreenKbControlsLayout[i][3] ); + // Check if the button is off screen edge or shrunk to zero + if( Globals.ScreenKbControlsLayout[i][0] > Globals.ScreenKbControlsLayout[i][2] - displayY/12 ) + Globals.ScreenKbControlsLayout[i][0] = Globals.ScreenKbControlsLayout[i][2] - displayY/12; + if( Globals.ScreenKbControlsLayout[i][1] > Globals.ScreenKbControlsLayout[i][3] - displayY/12 ) + Globals.ScreenKbControlsLayout[i][1] = Globals.ScreenKbControlsLayout[i][3] - displayY/12; + if( Globals.ScreenKbControlsLayout[i][0] < Globals.ScreenKbControlsLayout[i][2] - displayY*2/3 ) + Globals.ScreenKbControlsLayout[i][0] = Globals.ScreenKbControlsLayout[i][2] - displayY*2/3; + if( Globals.ScreenKbControlsLayout[i][1] < Globals.ScreenKbControlsLayout[i][3] - displayY*2/3 ) + Globals.ScreenKbControlsLayout[i][1] = Globals.ScreenKbControlsLayout[i][3] - displayY*2/3; + if( Globals.ScreenKbControlsLayout[i][0] < 0 ) + { + Globals.ScreenKbControlsLayout[i][2] += -Globals.ScreenKbControlsLayout[i][0]; + Globals.ScreenKbControlsLayout[i][0] = 0; + } + if( Globals.ScreenKbControlsLayout[i][2] > displayX ) + { + Globals.ScreenKbControlsLayout[i][0] -= Globals.ScreenKbControlsLayout[i][2] - displayX; + Globals.ScreenKbControlsLayout[i][2] = displayX; + } + if( Globals.ScreenKbControlsLayout[i][1] < 0 ) + { + Globals.ScreenKbControlsLayout[i][3] += -Globals.ScreenKbControlsLayout[i][1]; + Globals.ScreenKbControlsLayout[i][1] = 0; + } + if( Globals.ScreenKbControlsLayout[i][3] > displayY ) + { + Globals.ScreenKbControlsLayout[i][1] -= Globals.ScreenKbControlsLayout[i][3] - displayY; + Globals.ScreenKbControlsLayout[i][3] = displayY; + } + //Log.i("SDL", "After bounds check coords " + Globals.ScreenKbControlsLayout[i][0] + ":" + Globals.ScreenKbControlsLayout[i][1] + ":" + Globals.ScreenKbControlsLayout[i][2] + ":" + Globals.ScreenKbControlsLayout[i][3] ); + + imgs[i] = new ImageView(p); + imgs[i].setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + imgs[i].setScaleType(ImageView.ScaleType.MATRIX); + bmps[i] = BitmapFactory.decodeResource( p.getResources(), buttons[i] ); + imgs[i].setImageBitmap(bmps[i]); + imgs[i].setAlpha(128); + layout.addView(imgs[i]); + Matrix m = new Matrix(); + RectF src = new RectF(0, 0, bmps[i].getWidth(), bmps[i].getHeight()); + RectF dst = new RectF(Globals.ScreenKbControlsLayout[i][0], Globals.ScreenKbControlsLayout[i][1], + Globals.ScreenKbControlsLayout[i][2], Globals.ScreenKbControlsLayout[i][3]); + m.setRectToRect(src, dst, Matrix.ScaleToFit.FILL); + imgs[i].setImageMatrix(m); + } + boundary.bringToFront(); + if( currentButton == -1 ) + onKeyEvent( KeyEvent.KEYCODE_BACK ); // All buttons disabled - do not show anything + else + setupButton(currentButton); + } + + void setupButton(int i) + { + Matrix m = new Matrix(); + RectF src = new RectF(0, 0, bmps[i].getWidth(), bmps[i].getHeight()); + RectF dst = new RectF(Globals.ScreenKbControlsLayout[i][0], Globals.ScreenKbControlsLayout[i][1], + Globals.ScreenKbControlsLayout[i][2], Globals.ScreenKbControlsLayout[i][3]); + m.setRectToRect(src, dst, Matrix.ScaleToFit.FILL); + imgs[i].setImageMatrix(m); + m = new Matrix(); + src = new RectF(0, 0, boundaryBmp.getWidth(), boundaryBmp.getHeight()); + m.setRectToRect(src, dst, Matrix.ScaleToFit.FILL); + boundary.setImageMatrix(m); + String buttonText = ""; + if( i >= 2 && i <= 7 ) + buttonText = p.getResources().getString(R.string.remap_screenkb_button) + (i - 2); + if( i >= 2 && i - 2 < Globals.AppTouchscreenKeyboardKeysNames.length ) + buttonText = Globals.AppTouchscreenKeyboardKeysNames[i - 2].replace("_", " "); + if( i == 0 ) + buttonText = "Joystick"; + if( i == 1 ) + buttonText = "Text input"; + if( i == 8 ) + buttonText = "Joystick 2"; + p.setText(p.getResources().getString(R.string.screenkb_custom_layout_help) + "\n" + buttonText); + } + + public void onTouchEvent(final MotionEvent ev) + { + if( ev.getAction() == MotionEvent.ACTION_DOWN ) + { + oldX = (int)ev.getX(); + oldY = (int)ev.getY(); + resizing = true; + for( int i = 0; i < Globals.ScreenKbControlsLayout.length; i++ ) + { + if( ! Globals.ScreenKbControlsShown[i] ) + continue; + if( Globals.ScreenKbControlsLayout[i][0] <= oldX && + Globals.ScreenKbControlsLayout[i][2] >= oldX && + Globals.ScreenKbControlsLayout[i][1] <= oldY && + Globals.ScreenKbControlsLayout[i][3] >= oldY ) + { + currentButton = i; + setupButton(currentButton); + resizing = false; + break; + } + } + } + if( ev.getAction() == MotionEvent.ACTION_MOVE ) + { + int dx = (int)ev.getX() - oldX; + int dy = (int)ev.getY() - oldY; + if( resizing ) + { + // Resize slowly, with 1/3 of movement speed + dx /= 6; + dy /= 6; + if( Globals.ScreenKbControlsLayout[currentButton][0] <= Globals.ScreenKbControlsLayout[currentButton][2] + dx*2 ) + { + Globals.ScreenKbControlsLayout[currentButton][0] -= dx; + Globals.ScreenKbControlsLayout[currentButton][2] += dx; + } + if( Globals.ScreenKbControlsLayout[currentButton][1] <= Globals.ScreenKbControlsLayout[currentButton][3] + dy*2 ) + { + Globals.ScreenKbControlsLayout[currentButton][1] += dy; + Globals.ScreenKbControlsLayout[currentButton][3] -= dy; + } + dx *= 6; + dy *= 6; + } + else + { + Globals.ScreenKbControlsLayout[currentButton][0] += dx; + Globals.ScreenKbControlsLayout[currentButton][2] += dx; + Globals.ScreenKbControlsLayout[currentButton][1] += dy; + Globals.ScreenKbControlsLayout[currentButton][3] += dy; + } + oldX += dx; + oldY += dy; + Matrix m = new Matrix(); + RectF src = new RectF(0, 0, bmps[currentButton].getWidth(), bmps[currentButton].getHeight()); + RectF dst = new RectF(Globals.ScreenKbControlsLayout[currentButton][0], Globals.ScreenKbControlsLayout[currentButton][1], + Globals.ScreenKbControlsLayout[currentButton][2], Globals.ScreenKbControlsLayout[currentButton][3]); + m.setRectToRect(src, dst, Matrix.ScaleToFit.FILL); + imgs[currentButton].setImageMatrix(m); + m = new Matrix(); + src = new RectF(0, 0, boundaryBmp.getWidth(), boundaryBmp.getHeight()); + m.setRectToRect(src, dst, Matrix.ScaleToFit.FILL); + boundary.setImageMatrix(m); + } + } + + public void onKeyEvent(final int keyCode) + { + if( keyCode == KeyEvent.KEYCODE_BACK ) + { + p.getVideoLayout().removeView(layout); + layout = null; + p.touchListener = null; + p.keyListener = null; + goBack(p); + } + } + } + } +} + diff --git a/project/javaSDL2/SettingsMenuKeyboard.java~ b/project/javaSDL2/SettingsMenuKeyboard.java~ new file mode 100644 index 000000000..b28e7829a --- /dev/null +++ b/project/javaSDL2/SettingsMenuKeyboard.java~ @@ -0,0 +1,843 @@ +/* +Simple DirectMedia Layer +Java source code (C) 2009-2012 Sergii Pylypenko + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +package net.sourceforge.clonekeenplus; + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.view.MotionEvent; +import android.view.KeyEvent; +import android.view.Window; +import android.view.WindowManager; +import android.widget.TextView; +import android.util.Log; +import java.io.*; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.os.Environment; +import android.os.StatFs; +import java.util.Locale; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.zip.GZIPInputStream; +import java.util.Collections; +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import java.lang.String; +import android.graphics.Matrix; +import android.graphics.RectF; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.FrameLayout; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.BitmapFactory; +import android.graphics.Bitmap; +import android.widget.TextView; +import android.widget.EditText; +import android.widget.ScrollView; +import android.widget.Button; +import android.view.View; +import android.widget.LinearLayout; +import android.text.Editable; +import android.text.SpannedString; +import android.content.Intent; +import android.app.PendingIntent; +import android.app.AlarmManager; +import android.util.DisplayMetrics; +import android.net.Uri; +import java.util.concurrent.Semaphore; +import java.util.Arrays; +import android.graphics.Color; +import android.hardware.SensorEventListener; +import android.hardware.SensorEvent; +import android.hardware.Sensor; +import android.widget.Toast; + + +class SettingsMenuKeyboard extends SettingsMenu +{ + static class KeyboardConfigMainMenu extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.controls_screenkb); + } + boolean enabled() + { + return Globals.UseTouchscreenKeyboard; + } + void run (final MainActivity p) + { + Menu options[] = + { + new ScreenKeyboardThemeConfig(), + new ScreenKeyboardSizeConfig(), + new ScreenKeyboardDrawSizeConfig(), + new ScreenKeyboardTransparencyConfig(), + new RemapScreenKbConfig(), + new CustomizeScreenKbLayout(), + new OkButton(), + }; + showMenuOptionsList(p, options); + } + } + + static class ScreenKeyboardSizeConfig extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.controls_screenkb_size); + } + void run (final MainActivity p) + { + final CharSequence[] items = { p.getResources().getString(R.string.controls_screenkb_large), + p.getResources().getString(R.string.controls_screenkb_medium), + p.getResources().getString(R.string.controls_screenkb_small), + p.getResources().getString(R.string.controls_screenkb_tiny), + p.getResources().getString(R.string.controls_screenkb_custom) }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.controls_screenkb_size)); + builder.setSingleChoiceItems(items, Globals.TouchscreenKeyboardSize, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.TouchscreenKeyboardSize = item; + dialog.dismiss(); + if( Globals.TouchscreenKeyboardSize == Globals.TOUCHSCREEN_KEYBOARD_CUSTOM ) + new CustomizeScreenKbLayout().run(p); + else + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + static class ScreenKeyboardDrawSizeConfig extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.controls_screenkb_drawsize); + } + void run (final MainActivity p) + { + final CharSequence[] items = { p.getResources().getString(R.string.controls_screenkb_large), + p.getResources().getString(R.string.controls_screenkb_medium), + p.getResources().getString(R.string.controls_screenkb_small), + p.getResources().getString(R.string.controls_screenkb_tiny) }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.controls_screenkb_drawsize)); + builder.setSingleChoiceItems(items, Globals.TouchscreenKeyboardDrawSize, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.TouchscreenKeyboardDrawSize = item; + + dialog.dismiss(); + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + static class ScreenKeyboardThemeConfig extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.controls_screenkb_theme); + } + void run (final MainActivity p) + { + final CharSequence[] items = { + p.getResources().getString(R.string.controls_screenkb_by, "Ultimate Droid", "Sean Stieber"), + p.getResources().getString(R.string.controls_screenkb_by, "Simple Theme", "Beholder"), + p.getResources().getString(R.string.controls_screenkb_by, "Sun", "Sirea") + p.getResources().getString(R.string.controls_screenkb_by, "Keen", "Gerstrong") + }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.controls_screenkb_theme)); + builder.setSingleChoiceItems(items, Globals.TouchscreenKeyboardTheme, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.TouchscreenKeyboardTheme = item; + + dialog.dismiss(); + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + static class ScreenKeyboardTransparencyConfig extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.controls_screenkb_transparency); + } + void run (final MainActivity p) + { + final CharSequence[] items = { p.getResources().getString(R.string.controls_screenkb_trans_0), + p.getResources().getString(R.string.controls_screenkb_trans_1), + p.getResources().getString(R.string.controls_screenkb_trans_2), + p.getResources().getString(R.string.controls_screenkb_trans_3), + p.getResources().getString(R.string.controls_screenkb_trans_4) }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.controls_screenkb_transparency)); + builder.setSingleChoiceItems(items, Globals.TouchscreenKeyboardTransparency, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.TouchscreenKeyboardTransparency = item; + + dialog.dismiss(); + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + static class RemapHwKeysConfig extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.remap_hwkeys); + } + void run (final MainActivity p) + { + p.setText(p.getResources().getString(R.string.remap_hwkeys_press)); + p.keyListener = new KeyRemapTool(p); + } + + public static class KeyRemapTool implements MainActivity.KeyEventsListener + { + MainActivity p; + public KeyRemapTool(MainActivity _p) + { + p = _p; + } + + public void onKeyEvent(final int keyCode) + { + p.keyListener = null; + int keyIndex = keyCode; + if( keyIndex < 0 ) + keyIndex = 0; + if( keyIndex > SDL_Keys.JAVA_KEYCODE_LAST ) + keyIndex = 0; + + final int KeyIndexFinal = keyIndex; + CharSequence[] items = { + SDL_Keys.names[Globals.RemapScreenKbKeycode[0]], + SDL_Keys.names[Globals.RemapScreenKbKeycode[1]], + SDL_Keys.names[Globals.RemapScreenKbKeycode[2]], + SDL_Keys.names[Globals.RemapScreenKbKeycode[3]], + SDL_Keys.names[Globals.RemapScreenKbKeycode[4]], + SDL_Keys.names[Globals.RemapScreenKbKeycode[5]], + p.getResources().getString(R.string.remap_hwkeys_select_more_keys), + }; + + for( int i = 0; i < Math.min(6, Globals.AppTouchscreenKeyboardKeysNames.length); i++ ) + items[i] = Globals.AppTouchscreenKeyboardKeysNames[i].replace("_", " "); + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(R.string.remap_hwkeys_select_simple); + builder.setItems(items, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + dialog.dismiss(); + if( item >= 6 ) + ShowAllKeys(KeyIndexFinal); + else + { + Globals.RemapHwKeycode[KeyIndexFinal] = Globals.RemapScreenKbKeycode[item]; + goBack(p); + } + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + public void ShowAllKeys(final int KeyIndex) + { + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(R.string.remap_hwkeys_select); + builder.setSingleChoiceItems(SDL_Keys.namesSorted, SDL_Keys.namesSortedBackIdx[Globals.RemapHwKeycode[KeyIndex]], new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.RemapHwKeycode[KeyIndex] = SDL_Keys.namesSortedIdx[item]; + + dialog.dismiss(); + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + } + + static class RemapScreenKbConfig extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.remap_screenkb); + } + //boolean enabled() { return true; }; + void run (final MainActivity p) + { + CharSequence[] items = { + p.getResources().getString(R.string.remap_screenkb_joystick), + p.getResources().getString(R.string.remap_screenkb_button_text), + p.getResources().getString(R.string.remap_screenkb_button) + " 1", + p.getResources().getString(R.string.remap_screenkb_button) + " 2", + p.getResources().getString(R.string.remap_screenkb_button) + " 3", + p.getResources().getString(R.string.remap_screenkb_button) + " 4", + p.getResources().getString(R.string.remap_screenkb_button) + " 5", + p.getResources().getString(R.string.remap_screenkb_button) + " 6", + }; + + boolean defaults[] = Arrays.copyOf(Globals.ScreenKbControlsShown, Globals.ScreenKbControlsShown.length); + if( Globals.AppUsesSecondJoystick ) + { + items = Arrays.copyOf(items, items.length + 1); + items[items.length - 1] = p.getResources().getString(R.string.remap_screenkb_joystick) + " 2"; + defaults = Arrays.copyOf(defaults, defaults.length + 1); + defaults[defaults.length - 1] = true; + } + + for( int i = 0; i < Math.min(6, Globals.AppTouchscreenKeyboardKeysNames.length); i++ ) + items[i+2] = items[i+2] + " - " + Globals.AppTouchscreenKeyboardKeysNames[i].replace("_", " "); + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.remap_screenkb)); + builder.setMultiChoiceItems(items, defaults, new DialogInterface.OnMultiChoiceClickListener() + { + public void onClick(DialogInterface dialog, int item, boolean isChecked) + { + Globals.ScreenKbControlsShown[item] = isChecked; + } + }); + builder.setPositiveButton(p.getResources().getString(R.string.ok), new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + dialog.dismiss(); + showRemapScreenKbConfig2(p, 0); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + + static void showRemapScreenKbConfig2(final MainActivity p, final int currentButton) + { + CharSequence[] items = { + p.getResources().getString(R.string.remap_screenkb_button) + " 1", + p.getResources().getString(R.string.remap_screenkb_button) + " 2", + p.getResources().getString(R.string.remap_screenkb_button) + " 3", + p.getResources().getString(R.string.remap_screenkb_button) + " 4", + p.getResources().getString(R.string.remap_screenkb_button) + " 5", + p.getResources().getString(R.string.remap_screenkb_button) + " 6", + }; + + for( int i = 0; i < Math.min(6, Globals.AppTouchscreenKeyboardKeysNames.length); i++ ) + items[i] = items[i] + " - " + Globals.AppTouchscreenKeyboardKeysNames[i].replace("_", " "); + + if( currentButton >= Globals.RemapScreenKbKeycode.length ) + { + goBack(p); + return; + } + if( ! Globals.ScreenKbControlsShown[currentButton + 2] ) + { + showRemapScreenKbConfig2(p, currentButton + 1); + return; + } + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(items[currentButton]); + builder.setSingleChoiceItems(SDL_Keys.namesSorted, SDL_Keys.namesSortedBackIdx[Globals.RemapScreenKbKeycode[currentButton]], new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.RemapScreenKbKeycode[currentButton] = SDL_Keys.namesSortedIdx[item]; + + dialog.dismiss(); + showRemapScreenKbConfig2(p, currentButton + 1); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + static class ScreenGesturesConfig extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.remap_screenkb_button_gestures); + } + //boolean enabled() { return true; }; + void run (final MainActivity p) + { + CharSequence[] items = { + p.getResources().getString(R.string.remap_screenkb_button_zoomin), + p.getResources().getString(R.string.remap_screenkb_button_zoomout), + p.getResources().getString(R.string.remap_screenkb_button_rotateleft), + p.getResources().getString(R.string.remap_screenkb_button_rotateright), + }; + + boolean defaults[] = { + Globals.MultitouchGesturesUsed[0], + Globals.MultitouchGesturesUsed[1], + Globals.MultitouchGesturesUsed[2], + Globals.MultitouchGesturesUsed[3], + }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.remap_screenkb_button_gestures)); + builder.setMultiChoiceItems(items, defaults, new DialogInterface.OnMultiChoiceClickListener() + { + public void onClick(DialogInterface dialog, int item, boolean isChecked) + { + Globals.MultitouchGesturesUsed[item] = isChecked; + } + }); + builder.setPositiveButton(p.getResources().getString(R.string.ok), new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + dialog.dismiss(); + showScreenGesturesConfig2(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + + static void showScreenGesturesConfig2(final MainActivity p) + { + final CharSequence[] items = { + p.getResources().getString(R.string.accel_slow), + p.getResources().getString(R.string.accel_medium), + p.getResources().getString(R.string.accel_fast), + p.getResources().getString(R.string.accel_veryfast) + }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(R.string.remap_screenkb_button_gestures_sensitivity); + builder.setSingleChoiceItems(items, Globals.MultitouchGestureSensitivity, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.MultitouchGestureSensitivity = item; + + dialog.dismiss(); + showScreenGesturesConfig3(p, 0); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + + static void showScreenGesturesConfig3(final MainActivity p, final int currentButton) + { + CharSequence[] items = { + p.getResources().getString(R.string.remap_screenkb_button_zoomin), + p.getResources().getString(R.string.remap_screenkb_button_zoomout), + p.getResources().getString(R.string.remap_screenkb_button_rotateleft), + p.getResources().getString(R.string.remap_screenkb_button_rotateright), + }; + + if( currentButton >= Globals.RemapMultitouchGestureKeycode.length ) + { + goBack(p); + return; + } + if( ! Globals.MultitouchGesturesUsed[currentButton] ) + { + showScreenGesturesConfig3(p, currentButton + 1); + return; + } + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(items[currentButton]); + builder.setSingleChoiceItems(SDL_Keys.namesSorted, SDL_Keys.namesSortedBackIdx[Globals.RemapMultitouchGestureKeycode[currentButton]], new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.RemapMultitouchGestureKeycode[currentButton] = SDL_Keys.namesSortedIdx[item]; + + dialog.dismiss(); + showScreenGesturesConfig3(p, currentButton + 1); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + static class CustomizeScreenKbLayout extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.screenkb_custom_layout); + } + //boolean enabled() { return true; }; + void run (final MainActivity p) + { + p.setText(p.getResources().getString(R.string.screenkb_custom_layout_help)); + CustomizeScreenKbLayoutTool tool = new CustomizeScreenKbLayoutTool(p); + p.touchListener = tool; + p.keyListener = tool; + Globals.TouchscreenKeyboardSize = Globals.TOUCHSCREEN_KEYBOARD_CUSTOM; + } + + static class CustomizeScreenKbLayoutTool implements MainActivity.TouchEventsListener, MainActivity.KeyEventsListener + { + MainActivity p; + FrameLayout layout = null; + ImageView imgs[] = new ImageView[Globals.ScreenKbControlsLayout.length]; + Bitmap bmps[] = new Bitmap[Globals.ScreenKbControlsLayout.length]; + ImageView boundary = null; + Bitmap boundaryBmp = null; + int currentButton = 0; + int buttons[] = { + R.drawable.dpad, + R.drawable.keyboard, + R.drawable.b1, + R.drawable.b2, + R.drawable.b3, + R.drawable.b4, + R.drawable.b5, + R.drawable.b6, + R.drawable.dpad + }; + int oldX = 0, oldY = 0; + boolean resizing = false; + + public CustomizeScreenKbLayoutTool(MainActivity _p) + { + p = _p; + layout = new FrameLayout(p); + p.getVideoLayout().addView(layout); + boundary = new ImageView(p); + boundary.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + boundary.setScaleType(ImageView.ScaleType.MATRIX); + boundaryBmp = BitmapFactory.decodeResource( p.getResources(), R.drawable.rectangle ); + boundary.setImageBitmap(boundaryBmp); + layout.addView(boundary); + currentButton = -1; + if( Globals.TouchscreenKeyboardTheme == 2 ) + { + buttons = new int[] { + R.drawable.sun_dpad, + R.drawable.sun_keyboard, + R.drawable.sun_b1, + R.drawable.sun_b2, + R.drawable.sun_b3, + R.drawable.sun_b4, + R.drawable.sun_b5, + R.drawable.sun_b6, + R.drawable.sun_dpad + }; + } + + int displayX = 800; + int displayY = 480; + try { + DisplayMetrics dm = new DisplayMetrics(); + p.getWindowManager().getDefaultDisplay().getMetrics(dm); + displayX = dm.widthPixels; + displayY = dm.heightPixels; + } catch (Exception eeeee) {} + + for( int i = 0; i < Globals.ScreenKbControlsLayout.length; i++ ) + { + if( ! Globals.ScreenKbControlsShown[i] ) + continue; + if( currentButton == -1 ) + currentButton = i; + //Log.i("SDL", "Screen kb button " + i + " coords " + Globals.ScreenKbControlsLayout[i][0] + ":" + Globals.ScreenKbControlsLayout[i][1] + ":" + Globals.ScreenKbControlsLayout[i][2] + ":" + Globals.ScreenKbControlsLayout[i][3] ); + // Check if the button is off screen edge or shrunk to zero + if( Globals.ScreenKbControlsLayout[i][0] > Globals.ScreenKbControlsLayout[i][2] - displayY/12 ) + Globals.ScreenKbControlsLayout[i][0] = Globals.ScreenKbControlsLayout[i][2] - displayY/12; + if( Globals.ScreenKbControlsLayout[i][1] > Globals.ScreenKbControlsLayout[i][3] - displayY/12 ) + Globals.ScreenKbControlsLayout[i][1] = Globals.ScreenKbControlsLayout[i][3] - displayY/12; + if( Globals.ScreenKbControlsLayout[i][0] < Globals.ScreenKbControlsLayout[i][2] - displayY*2/3 ) + Globals.ScreenKbControlsLayout[i][0] = Globals.ScreenKbControlsLayout[i][2] - displayY*2/3; + if( Globals.ScreenKbControlsLayout[i][1] < Globals.ScreenKbControlsLayout[i][3] - displayY*2/3 ) + Globals.ScreenKbControlsLayout[i][1] = Globals.ScreenKbControlsLayout[i][3] - displayY*2/3; + if( Globals.ScreenKbControlsLayout[i][0] < 0 ) + { + Globals.ScreenKbControlsLayout[i][2] += -Globals.ScreenKbControlsLayout[i][0]; + Globals.ScreenKbControlsLayout[i][0] = 0; + } + if( Globals.ScreenKbControlsLayout[i][2] > displayX ) + { + Globals.ScreenKbControlsLayout[i][0] -= Globals.ScreenKbControlsLayout[i][2] - displayX; + Globals.ScreenKbControlsLayout[i][2] = displayX; + } + if( Globals.ScreenKbControlsLayout[i][1] < 0 ) + { + Globals.ScreenKbControlsLayout[i][3] += -Globals.ScreenKbControlsLayout[i][1]; + Globals.ScreenKbControlsLayout[i][1] = 0; + } + if( Globals.ScreenKbControlsLayout[i][3] > displayY ) + { + Globals.ScreenKbControlsLayout[i][1] -= Globals.ScreenKbControlsLayout[i][3] - displayY; + Globals.ScreenKbControlsLayout[i][3] = displayY; + } + //Log.i("SDL", "After bounds check coords " + Globals.ScreenKbControlsLayout[i][0] + ":" + Globals.ScreenKbControlsLayout[i][1] + ":" + Globals.ScreenKbControlsLayout[i][2] + ":" + Globals.ScreenKbControlsLayout[i][3] ); + + imgs[i] = new ImageView(p); + imgs[i].setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + imgs[i].setScaleType(ImageView.ScaleType.MATRIX); + bmps[i] = BitmapFactory.decodeResource( p.getResources(), buttons[i] ); + imgs[i].setImageBitmap(bmps[i]); + imgs[i].setAlpha(128); + layout.addView(imgs[i]); + Matrix m = new Matrix(); + RectF src = new RectF(0, 0, bmps[i].getWidth(), bmps[i].getHeight()); + RectF dst = new RectF(Globals.ScreenKbControlsLayout[i][0], Globals.ScreenKbControlsLayout[i][1], + Globals.ScreenKbControlsLayout[i][2], Globals.ScreenKbControlsLayout[i][3]); + m.setRectToRect(src, dst, Matrix.ScaleToFit.FILL); + imgs[i].setImageMatrix(m); + } + boundary.bringToFront(); + if( currentButton == -1 ) + onKeyEvent( KeyEvent.KEYCODE_BACK ); // All buttons disabled - do not show anything + else + setupButton(currentButton); + } + + void setupButton(int i) + { + Matrix m = new Matrix(); + RectF src = new RectF(0, 0, bmps[i].getWidth(), bmps[i].getHeight()); + RectF dst = new RectF(Globals.ScreenKbControlsLayout[i][0], Globals.ScreenKbControlsLayout[i][1], + Globals.ScreenKbControlsLayout[i][2], Globals.ScreenKbControlsLayout[i][3]); + m.setRectToRect(src, dst, Matrix.ScaleToFit.FILL); + imgs[i].setImageMatrix(m); + m = new Matrix(); + src = new RectF(0, 0, boundaryBmp.getWidth(), boundaryBmp.getHeight()); + m.setRectToRect(src, dst, Matrix.ScaleToFit.FILL); + boundary.setImageMatrix(m); + String buttonText = ""; + if( i >= 2 && i <= 7 ) + buttonText = p.getResources().getString(R.string.remap_screenkb_button) + (i - 2); + if( i >= 2 && i - 2 < Globals.AppTouchscreenKeyboardKeysNames.length ) + buttonText = Globals.AppTouchscreenKeyboardKeysNames[i - 2].replace("_", " "); + if( i == 0 ) + buttonText = "Joystick"; + if( i == 1 ) + buttonText = "Text input"; + if( i == 8 ) + buttonText = "Joystick 2"; + p.setText(p.getResources().getString(R.string.screenkb_custom_layout_help) + "\n" + buttonText); + } + + public void onTouchEvent(final MotionEvent ev) + { + if( ev.getAction() == MotionEvent.ACTION_DOWN ) + { + oldX = (int)ev.getX(); + oldY = (int)ev.getY(); + resizing = true; + for( int i = 0; i < Globals.ScreenKbControlsLayout.length; i++ ) + { + if( ! Globals.ScreenKbControlsShown[i] ) + continue; + if( Globals.ScreenKbControlsLayout[i][0] <= oldX && + Globals.ScreenKbControlsLayout[i][2] >= oldX && + Globals.ScreenKbControlsLayout[i][1] <= oldY && + Globals.ScreenKbControlsLayout[i][3] >= oldY ) + { + currentButton = i; + setupButton(currentButton); + resizing = false; + break; + } + } + } + if( ev.getAction() == MotionEvent.ACTION_MOVE ) + { + int dx = (int)ev.getX() - oldX; + int dy = (int)ev.getY() - oldY; + if( resizing ) + { + // Resize slowly, with 1/3 of movement speed + dx /= 6; + dy /= 6; + if( Globals.ScreenKbControlsLayout[currentButton][0] <= Globals.ScreenKbControlsLayout[currentButton][2] + dx*2 ) + { + Globals.ScreenKbControlsLayout[currentButton][0] -= dx; + Globals.ScreenKbControlsLayout[currentButton][2] += dx; + } + if( Globals.ScreenKbControlsLayout[currentButton][1] <= Globals.ScreenKbControlsLayout[currentButton][3] + dy*2 ) + { + Globals.ScreenKbControlsLayout[currentButton][1] += dy; + Globals.ScreenKbControlsLayout[currentButton][3] -= dy; + } + dx *= 6; + dy *= 6; + } + else + { + Globals.ScreenKbControlsLayout[currentButton][0] += dx; + Globals.ScreenKbControlsLayout[currentButton][2] += dx; + Globals.ScreenKbControlsLayout[currentButton][1] += dy; + Globals.ScreenKbControlsLayout[currentButton][3] += dy; + } + oldX += dx; + oldY += dy; + Matrix m = new Matrix(); + RectF src = new RectF(0, 0, bmps[currentButton].getWidth(), bmps[currentButton].getHeight()); + RectF dst = new RectF(Globals.ScreenKbControlsLayout[currentButton][0], Globals.ScreenKbControlsLayout[currentButton][1], + Globals.ScreenKbControlsLayout[currentButton][2], Globals.ScreenKbControlsLayout[currentButton][3]); + m.setRectToRect(src, dst, Matrix.ScaleToFit.FILL); + imgs[currentButton].setImageMatrix(m); + m = new Matrix(); + src = new RectF(0, 0, boundaryBmp.getWidth(), boundaryBmp.getHeight()); + m.setRectToRect(src, dst, Matrix.ScaleToFit.FILL); + boundary.setImageMatrix(m); + } + } + + public void onKeyEvent(final int keyCode) + { + if( keyCode == KeyEvent.KEYCODE_BACK ) + { + p.getVideoLayout().removeView(layout); + layout = null; + p.touchListener = null; + p.keyListener = null; + goBack(p); + } + } + } + } +} + diff --git a/project/javaSDL2/SettingsMenuMisc.java b/project/javaSDL2/SettingsMenuMisc.java new file mode 100644 index 000000000..2e9e30fd2 --- /dev/null +++ b/project/javaSDL2/SettingsMenuMisc.java @@ -0,0 +1,755 @@ +/* +Simple DirectMedia Layer +Java source code (C) 2009-2012 Sergii Pylypenko + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +package net.sourceforge.clonekeenplus; + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.view.MotionEvent; +import android.view.KeyEvent; +import android.view.Window; +import android.view.WindowManager; +import android.widget.TextView; +import android.util.Log; +import java.io.*; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.os.Environment; +import android.os.StatFs; +import java.util.Locale; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.zip.GZIPInputStream; +import java.util.Collections; +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import java.lang.String; +import android.graphics.Matrix; +import android.graphics.RectF; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.FrameLayout; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.BitmapFactory; +import android.graphics.Bitmap; +import android.widget.TextView; +import android.widget.EditText; +import android.widget.ScrollView; +import android.widget.Button; +import android.widget.Scroller; +import android.view.View; +import android.view.Gravity; +import android.widget.LinearLayout; +import android.text.Editable; +import android.text.SpannedString; +import android.content.Intent; +import android.app.PendingIntent; +import android.app.AlarmManager; +import android.util.DisplayMetrics; +import android.net.Uri; +import java.util.concurrent.Semaphore; +import java.util.Arrays; +import android.graphics.Color; +import android.hardware.SensorEventListener; +import android.hardware.SensorEvent; +import android.hardware.Sensor; +import android.widget.Toast; + + +class SettingsMenuMisc extends SettingsMenu +{ + static class DownloadConfig extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.storage_question); + } + void run (final MainActivity p) + { + long freeSdcard = 0; + long freePhone = 0; + try + { + StatFs sdcard = new StatFs(Environment.getExternalStorageDirectory().getPath()); + StatFs phone = new StatFs(Environment.getDataDirectory().getPath()); + freeSdcard = (long)sdcard.getAvailableBlocks() * sdcard.getBlockSize() / 1024 / 1024; + freePhone = (long)phone.getAvailableBlocks() * phone.getBlockSize() / 1024 / 1024; + } + catch(Exception e) {} + + final CharSequence[] items = { p.getResources().getString(R.string.storage_phone, freePhone), + p.getResources().getString(R.string.storage_sd, freeSdcard), + p.getResources().getString(R.string.storage_custom) }; + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.storage_question)); + builder.setSingleChoiceItems(items, Globals.DownloadToSdcard ? 1 : 0, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + dialog.dismiss(); + + if( item == 2 ) + showCustomDownloadDirConfig(p); + else + { + Globals.DownloadToSdcard = (item != 0); + Globals.DataDir = Globals.DownloadToSdcard ? + Settings.SdcardAppPath.getPath(p) : + p.getFilesDir().getAbsolutePath(); + goBack(p); + } + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + static void showCustomDownloadDirConfig(final MainActivity p) + { + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.storage_custom)); + + final EditText edit = new EditText(p); + edit.setFocusableInTouchMode(true); + edit.setFocusable(true); + edit.setText(Globals.DataDir); + builder.setView(edit); + + builder.setPositiveButton(p.getResources().getString(R.string.ok), new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.DataDir = edit.getText().toString(); + dialog.dismiss(); + showCommandLineConfig(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + static void showCommandLineConfig(final MainActivity p) + { + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.storage_commandline)); + + final EditText edit = new EditText(p); + edit.setFocusableInTouchMode(true); + edit.setFocusable(true); + edit.setText(Globals.CommandLine); + builder.setView(edit); + + builder.setPositiveButton(p.getResources().getString(R.string.ok), new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.CommandLine = edit.getText().toString(); + dialog.dismiss(); + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + static class OptionalDownloadConfig extends Menu + { + boolean firstStart = false; + OptionalDownloadConfig() + { + firstStart = true; + } + OptionalDownloadConfig(boolean firstStart) + { + this.firstStart = firstStart; + } + String title(final MainActivity p) + { + return p.getResources().getString(R.string.downloads); + } + void run (final MainActivity p) + { + String [] downloadFiles = Globals.DataDownloadUrl; + final boolean [] mandatory = new boolean[downloadFiles.length]; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.downloads)); + + CharSequence[] items = new CharSequence[downloadFiles.length]; + for(int i = 0; i < downloadFiles.length; i++ ) + { + items[i] = new String(downloadFiles[i].split("[|]")[0]); + if( items[i].toString().indexOf("!") == 0 ) + items[i] = items[i].toString().substring(1); + if( items[i].toString().indexOf("!") == 0 ) + { + items[i] = items[i].toString().substring(1); + mandatory[i] = true; + } + } + + if( Globals.OptionalDataDownload == null || Globals.OptionalDataDownload.length != items.length ) + { + Globals.OptionalDataDownload = new boolean[downloadFiles.length]; + boolean oldFormat = true; + for( int i = 0; i < downloadFiles.length; i++ ) + { + if( downloadFiles[i].indexOf("!") == 0 ) + { + Globals.OptionalDataDownload[i] = true; + oldFormat = false; + } + } + if( oldFormat ) + { + Globals.OptionalDataDownload[0] = true; + mandatory[0] = true; + } + } + + builder.setMultiChoiceItems(items, Globals.OptionalDataDownload, new DialogInterface.OnMultiChoiceClickListener() + { + public void onClick(DialogInterface dialog, int item, boolean isChecked) + { + Globals.OptionalDataDownload[item] = isChecked; + if( mandatory[item] && !isChecked ) + { + Globals.OptionalDataDownload[item] = true; + ((AlertDialog)dialog).getListView().setItemChecked(item, true); + } + } + }); + builder.setPositiveButton(p.getResources().getString(R.string.ok), new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + dialog.dismiss(); + goBack(p); + } + }); + if( firstStart ) + { + builder.setNegativeButton(p.getResources().getString(R.string.show_more_options), new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + dialog.dismiss(); + menuStack.clear(); + new MainMenu().run(p); + } + }); + } + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + static class AudioConfig extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.audiobuf_question); + } + void run (final MainActivity p) + { + final CharSequence[] items = { p.getResources().getString(R.string.audiobuf_verysmall), + p.getResources().getString(R.string.audiobuf_small), + p.getResources().getString(R.string.audiobuf_medium), + p.getResources().getString(R.string.audiobuf_large) }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(R.string.audiobuf_question); + builder.setSingleChoiceItems(items, Globals.AudioBufferConfig, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.AudioBufferConfig = item; + dialog.dismiss(); + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + static class VideoSettingsConfig extends Menu + { + static int debugMenuShowCount = 0; + String title(final MainActivity p) + { + return p.getResources().getString(R.string.video); + } + //boolean enabled() { return true; }; + void run (final MainActivity p) + { + debugMenuShowCount++; + CharSequence[] items = { + p.getResources().getString(R.string.pointandclick_keepaspectratio), + p.getResources().getString(R.string.video_smooth) + }; + boolean defaults[] = { + Globals.KeepAspectRatio, + Globals.VideoLinearFilter + }; + + if(Globals.SwVideoMode && !Globals.CompatibilityHacksVideo) + { + CharSequence[] items2 = { + p.getResources().getString(R.string.pointandclick_keepaspectratio), + p.getResources().getString(R.string.video_smooth), + p.getResources().getString(R.string.video_separatethread), + }; + boolean defaults2[] = { + Globals.KeepAspectRatio, + Globals.VideoLinearFilter, + Globals.MultiThreadedVideo + }; + items = items2; + defaults = defaults2; + } + + if(Globals.Using_SDL_1_3) + { + CharSequence[] items2 = { + p.getResources().getString(R.string.pointandclick_keepaspectratio), + }; + boolean defaults2[] = { + Globals.KeepAspectRatio, + }; + items = items2; + defaults = defaults2; + } + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.video)); + builder.setMultiChoiceItems(items, defaults, new DialogInterface.OnMultiChoiceClickListener() + { + public void onClick(DialogInterface dialog, int item, boolean isChecked) + { + if( item == 0 ) + Globals.KeepAspectRatio = isChecked; + if( item == 1 ) + Globals.VideoLinearFilter = isChecked; + if( item == 2 ) + Globals.MultiThreadedVideo = isChecked; + } + }); + builder.setPositiveButton(p.getResources().getString(R.string.ok), new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + dialog.dismiss(); + if( debugMenuShowCount > 5 || Globals.OuyaEmulation ) + showDebugMenu(p); + else + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + + void showDebugMenu (final MainActivity p) + { + CharSequence[] items = { + "OUYA emulation" + }; + boolean defaults[] = { + Globals.OuyaEmulation, + }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle("Debug settings"); + builder.setMultiChoiceItems(items, defaults, new DialogInterface.OnMultiChoiceClickListener() + { + public void onClick(DialogInterface dialog, int item, boolean isChecked) + { + if( item == 0 ) + Globals.OuyaEmulation = isChecked; + } + }); + builder.setPositiveButton(p.getResources().getString(R.string.ok), new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + dialog.dismiss(); + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + static class ShowReadme extends Menu + { + String title(final MainActivity p) + { + return "Readme"; + } + boolean enabled() + { + return true; + } + void run (final MainActivity p) + { + String readmes[] = Globals.ReadmeText.split("\\^"); + String lang = new String(Locale.getDefault().getLanguage()) + ":"; + if( p.isRunningOnOUYA() ) + lang = "ouya:"; + String readme = readmes[0]; + String buttonName = "", buttonUrl = ""; + for( String r: readmes ) + { + if( r.startsWith(lang) ) + readme = r.substring(lang.length()); + if( r.startsWith("button:") ) + { + buttonName = r.substring("button:".length()); + if( buttonName.indexOf(":") != -1 ) + { + buttonUrl = buttonName.substring(buttonName.indexOf(":") + 1); + buttonName = buttonName.substring(0, buttonName.indexOf(":")); + } + } + } + readme = readme.trim(); + if( readme.length() <= 2 ) + { + goBack(p); + return; + } + TextView text = new TextView(p); + text.setMaxLines(100); + //text.setScroller(new Scroller(p)); + //text.setVerticalScrollBarEnabled(true); + text.setText(readme); + text.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + text.setPadding(0, 5, 0, 20); + text.setTextSize(20.0f); + text.setGravity(Gravity.CENTER); + AlertDialog.Builder builder = new AlertDialog.Builder(p); + ScrollView scroll = new ScrollView(p); + scroll.addView(text, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + Button ok = new Button(p); + final AlertDialog alertDismiss[] = new AlertDialog[1]; + ok.setOnClickListener(new View.OnClickListener() + { + public void onClick(View v) + { + alertDismiss[0].cancel(); + } + }); + ok.setText(R.string.ok); + LinearLayout layout = new LinearLayout(p); + layout.setOrientation(LinearLayout.VERTICAL); + layout.addView(scroll); + //layout.addView(text); + layout.addView(ok); + if( buttonName.length() > 0 ) + { + Button cancel = new Button(p); + cancel.setText(buttonName); + final String url = buttonUrl; + cancel.setOnClickListener(new View.OnClickListener() + { + public void onClick(View v) + { + if( url.length() > 0 ) + { + Intent i = new Intent(Intent.ACTION_VIEW); + i.setData(Uri.parse(url)); + p.startActivity(i); + } + alertDismiss[0].cancel(); + System.exit(0); + } + }); + layout.addView(cancel); + } + builder.setView(layout); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alertDismiss[0] = alert; + alert.setOwnerActivity(p); + alert.show(); + } + } + + static class GyroscopeCalibration extends Menu implements SensorEventListener + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.calibrate_gyroscope); + } + boolean enabled() + { + return Globals.AppUsesGyroscope; + } + void run (final MainActivity p) + { + if( !Globals.AppUsesGyroscope || !AccelerometerReader.gyro.available(p) ) + { + if( Globals.AppUsesGyroscope ) + { + Toast toast = Toast.makeText(p, p.getResources().getString(R.string.calibrate_gyroscope_not_supported), Toast.LENGTH_LONG); + toast.show(); + } + goBack(p); + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.calibrate_gyroscope)); + builder.setMessage(p.getResources().getString(R.string.calibrate_gyroscope_text)); + builder.setPositiveButton(p.getResources().getString(R.string.ok), new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + dialog.dismiss(); + startCalibration(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + + ImageView img; + Bitmap bmp; + int numEvents; + MainActivity p; + + void startCalibration(final MainActivity _p) + { + p = _p; + img = new ImageView(p); + img.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + img.setScaleType(ImageView.ScaleType.MATRIX); + bmp = BitmapFactory.decodeResource( p.getResources(), R.drawable.calibrate ); + img.setImageBitmap(bmp); + Matrix m = new Matrix(); + RectF src = new RectF(0, 0, bmp.getWidth(), bmp.getHeight()); + RectF dst = new RectF( p.getVideoLayout().getWidth()/2 - 50, p.getVideoLayout().getHeight()/2 - 50, + p.getVideoLayout().getWidth()/2 + 50, p.getVideoLayout().getHeight()/2 + 50); + m.setRectToRect(src, dst, Matrix.ScaleToFit.FILL); + img.setImageMatrix(m); + p.getVideoLayout().addView(img); + numEvents = 0; + AccelerometerReader.gyro.x1 = 100; + AccelerometerReader.gyro.x2 = -100; + AccelerometerReader.gyro.xc = 0; + AccelerometerReader.gyro.y1 = 100; + AccelerometerReader.gyro.y2 = -100; + AccelerometerReader.gyro.yc = 0; + AccelerometerReader.gyro.z1 = 100; + AccelerometerReader.gyro.z2 = -100; + AccelerometerReader.gyro.zc = 0; + AccelerometerReader.gyro.registerListener(p, this); + (new Thread(new Runnable() + { + public void run() + { + for(int count = 1; count < 10; count++) + { + p.setText("" + count + "0% ..."); + try { + Thread.sleep(500); + } catch( Exception e ) {} + } + finishCalibration(p); + } + } + )).start(); + } + + public void onSensorChanged(SensorEvent event) + { + gyroscopeEvent(event.values[0], event.values[1], event.values[2]); + } + public void onAccuracyChanged(Sensor s, int a) + { + } + void gyroscopeEvent(float x, float y, float z) + { + numEvents++; + AccelerometerReader.gyro.xc += x; + AccelerometerReader.gyro.yc += y; + AccelerometerReader.gyro.zc += z; + AccelerometerReader.gyro.x1 = Math.min(AccelerometerReader.gyro.x1, x * 1.1f); // Small safety bound coefficient + AccelerometerReader.gyro.x2 = Math.max(AccelerometerReader.gyro.x2, x * 1.1f); + AccelerometerReader.gyro.y1 = Math.min(AccelerometerReader.gyro.y1, y * 1.1f); + AccelerometerReader.gyro.y2 = Math.max(AccelerometerReader.gyro.y2, y * 1.1f); + AccelerometerReader.gyro.z1 = Math.min(AccelerometerReader.gyro.z1, z * 1.1f); + AccelerometerReader.gyro.z2 = Math.max(AccelerometerReader.gyro.z2, z * 1.1f); + final Matrix m = new Matrix(); + RectF src = new RectF(0, 0, bmp.getWidth(), bmp.getHeight()); + RectF dst = new RectF( x * 5000 + p.getVideoLayout().getWidth()/2 - 50, y * 5000 + p.getVideoLayout().getHeight()/2 - 50, + x * 5000 + p.getVideoLayout().getWidth()/2 + 50, y * 5000 + p.getVideoLayout().getHeight()/2 + 50); + m.setRectToRect(src, dst, Matrix.ScaleToFit.FILL); + p.runOnUiThread(new Runnable() + { + public void run() + { + img.setImageMatrix(m); + } + }); + } + void finishCalibration(final MainActivity p) + { + AccelerometerReader.gyro.unregisterListener(p, this); + try { + Thread.sleep(200); // Just in case we have pending events + } catch( Exception e ) {} + if( numEvents > 5 ) + { + AccelerometerReader.gyro.xc /= (float)numEvents; + AccelerometerReader.gyro.yc /= (float)numEvents; + AccelerometerReader.gyro.zc /= (float)numEvents; + } + p.runOnUiThread(new Runnable() + { + public void run() + { + p.getVideoLayout().removeView(img); + goBack(p); + } + }); + } + } + + static class ResetToDefaultsConfig extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.reset_config); + } + boolean enabled() + { + return true; + } + void run (final MainActivity p) + { + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.reset_config_ask)); + builder.setMessage(p.getResources().getString(R.string.reset_config_ask)); + + builder.setPositiveButton(p.getResources().getString(R.string.ok), new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Settings.DeleteSdlConfigOnUpgradeAndRestart(p); // Never returns + dialog.dismiss(); + goBack(p); + } + }); + builder.setNegativeButton(p.getResources().getString(R.string.cancel), new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + dialog.dismiss(); + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } +} + diff --git a/project/javaSDL2/SettingsMenuMouse.java b/project/javaSDL2/SettingsMenuMouse.java new file mode 100644 index 000000000..c4495874d --- /dev/null +++ b/project/javaSDL2/SettingsMenuMouse.java @@ -0,0 +1,771 @@ +/* +Simple DirectMedia Layer +Java source code (C) 2009-2012 Sergii Pylypenko + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +package net.sourceforge.clonekeenplus; + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.view.MotionEvent; +import android.view.KeyEvent; +import android.view.Window; +import android.view.WindowManager; +import android.widget.TextView; +import android.util.Log; +import java.io.*; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.os.Environment; +import android.os.StatFs; +import java.util.Locale; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.zip.GZIPInputStream; +import java.util.Collections; +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import java.lang.String; +import android.graphics.Matrix; +import android.graphics.RectF; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.FrameLayout; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.BitmapFactory; +import android.graphics.Bitmap; +import android.widget.TextView; +import android.widget.EditText; +import android.widget.ScrollView; +import android.widget.Button; +import android.view.View; +import android.widget.LinearLayout; +import android.text.Editable; +import android.text.SpannedString; +import android.content.Intent; +import android.app.PendingIntent; +import android.app.AlarmManager; +import android.util.DisplayMetrics; +import android.net.Uri; +import java.util.concurrent.Semaphore; +import java.util.Arrays; +import android.graphics.Color; +import android.hardware.SensorEventListener; +import android.hardware.SensorEvent; +import android.hardware.Sensor; +import android.widget.Toast; + + +class SettingsMenuMouse extends SettingsMenu +{ + static class MouseConfigMainMenu extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.mouse_emulation); + } + boolean enabled() + { + return Globals.AppUsesMouse; + } + void run (final MainActivity p) + { + Menu options[] = + { + new DisplaySizeConfig(false), + new LeftClickConfig(), + new RightClickConfig(), + new AdditionalMouseConfig(), + new JoystickMouseConfig(), + new TouchPressureMeasurementTool(), + new CalibrateTouchscreenMenu(), + new OkButton(), + }; + showMenuOptionsList(p, options); + } + } + + static class DisplaySizeConfig extends Menu + { + boolean firstStart = false; + DisplaySizeConfig() + { + this.firstStart = true; + } + DisplaySizeConfig(boolean firstStart) + { + this.firstStart = firstStart; + } + String title(final MainActivity p) + { + return p.getResources().getString(R.string.display_size_mouse); + } + void run (final MainActivity p) + { + CharSequence[] items = { + p.getResources().getString(R.string.display_size_tiny_touchpad), + p.getResources().getString(R.string.display_size_tiny), + p.getResources().getString(R.string.display_size_small), + p.getResources().getString(R.string.display_size_small_touchpad), + p.getResources().getString(R.string.display_size_large), + }; + int _size_tiny_touchpad = 0; + int _size_tiny = 1; + int _size_small = 2; + int _size_small_touchpad = 3; + int _size_large = 4; + int _more_options = 5; + + if( ! Globals.SwVideoMode ) + { + CharSequence[] items2 = { + p.getResources().getString(R.string.display_size_small_touchpad), + p.getResources().getString(R.string.display_size_large), + }; + items = items2; + _size_small_touchpad = 0; + _size_large = 1; + _size_tiny_touchpad = _size_tiny = _size_small = 1000; + + } + if( firstStart ) + { + CharSequence[] items2 = { + p.getResources().getString(R.string.display_size_tiny_touchpad), + p.getResources().getString(R.string.display_size_tiny), + p.getResources().getString(R.string.display_size_small), + p.getResources().getString(R.string.display_size_small_touchpad), + p.getResources().getString(R.string.display_size_large), + p.getResources().getString(R.string.show_more_options), + }; + items = items2; + if( ! Globals.SwVideoMode ) + { + CharSequence[] items3 = { + p.getResources().getString(R.string.display_size_small_touchpad), + p.getResources().getString(R.string.display_size_large), + p.getResources().getString(R.string.show_more_options), + }; + items = items3; + _more_options = 3; + } + } + // Java is so damn worse than C++11 + final int size_tiny_touchpad = _size_tiny_touchpad; + final int size_tiny = _size_tiny; + final int size_small = _size_small; + final int size_small_touchpad = _size_small_touchpad; + final int size_large = _size_large; + final int more_options = _more_options; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(R.string.display_size); + class ClickListener implements DialogInterface.OnClickListener + { + public void onClick(DialogInterface dialog, int item) + { + dialog.dismiss(); + if( item == size_large ) + { + Globals.LeftClickMethod = Mouse.LEFT_CLICK_NORMAL; + Globals.RelativeMouseMovement = false; + Globals.ShowScreenUnderFinger = Mouse.ZOOM_NONE; + } + if( item == size_small ) + { + Globals.LeftClickMethod = Mouse.LEFT_CLICK_NEAR_CURSOR; + Globals.RelativeMouseMovement = false; + Globals.ShowScreenUnderFinger = Mouse.ZOOM_MAGNIFIER; + } + if( item == size_small_touchpad ) + { + Globals.LeftClickMethod = Mouse.LEFT_CLICK_WITH_TAP_OR_TIMEOUT; + Globals.RelativeMouseMovement = true; + Globals.ShowScreenUnderFinger = Mouse.ZOOM_NONE; + } + if( item == size_tiny ) + { + Globals.LeftClickMethod = Mouse.LEFT_CLICK_NEAR_CURSOR; + Globals.RelativeMouseMovement = false; + Globals.ShowScreenUnderFinger = Mouse.ZOOM_SCREEN_TRANSFORM; + } + if( item == size_tiny_touchpad ) + { + Globals.LeftClickMethod = Mouse.LEFT_CLICK_WITH_TAP_OR_TIMEOUT; + Globals.RelativeMouseMovement = true; + Globals.ShowScreenUnderFinger = Mouse.ZOOM_FULLSCREEN_MAGNIFIER; + } + if( item == more_options ) + { + menuStack.clear(); + new MainMenu().run(p); + return; + } + goBack(p); + } + } + builder.setItems(items, new ClickListener()); + /* + else + builder.setSingleChoiceItems(items, + Globals.ShowScreenUnderFinger == Mouse.ZOOM_NONE ? + ( Globals.RelativeMouseMovement ? Globals.SwVideoMode ? 2 : 1 : 0 ) : + ( Globals.ShowScreenUnderFinger == Mouse.ZOOM_MAGNIFIER && Globals.SwVideoMode ) ? 1 : + Globals.ShowScreenUnderFinger + 1, + new ClickListener()); + */ + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + static class LeftClickConfig extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.leftclick_question); + } + void run (final MainActivity p) + { + final CharSequence[] items = { p.getResources().getString(R.string.leftclick_normal), + p.getResources().getString(R.string.leftclick_near_cursor), + p.getResources().getString(R.string.leftclick_multitouch), + p.getResources().getString(R.string.leftclick_pressure), + p.getResources().getString(R.string.rightclick_key), + p.getResources().getString(R.string.leftclick_timeout), + p.getResources().getString(R.string.leftclick_tap), + p.getResources().getString(R.string.leftclick_tap_or_timeout) }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(R.string.leftclick_question); + builder.setSingleChoiceItems(items, Globals.LeftClickMethod, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + dialog.dismiss(); + Globals.LeftClickMethod = item; + if( item == Mouse.LEFT_CLICK_WITH_KEY ) + p.keyListener = new KeyRemapToolMouseClick(p, true); + else if( item == Mouse.LEFT_CLICK_WITH_TIMEOUT || item == Mouse.LEFT_CLICK_WITH_TAP_OR_TIMEOUT ) + showLeftClickTimeoutConfig(p); + else + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + static void showLeftClickTimeoutConfig(final MainActivity p) { + final CharSequence[] items = { p.getResources().getString(R.string.leftclick_timeout_time_0), + p.getResources().getString(R.string.leftclick_timeout_time_1), + p.getResources().getString(R.string.leftclick_timeout_time_2), + p.getResources().getString(R.string.leftclick_timeout_time_3), + p.getResources().getString(R.string.leftclick_timeout_time_4) }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(R.string.leftclick_timeout_time); + builder.setSingleChoiceItems(items, Globals.LeftClickTimeout, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.LeftClickTimeout = item; + dialog.dismiss(); + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + static class RightClickConfig extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.rightclick_question); + } + boolean enabled() + { + return Globals.AppNeedsTwoButtonMouse; + } + void run (final MainActivity p) + { + final CharSequence[] items = { p.getResources().getString(R.string.rightclick_none), + p.getResources().getString(R.string.rightclick_multitouch), + p.getResources().getString(R.string.rightclick_pressure), + p.getResources().getString(R.string.rightclick_key), + p.getResources().getString(R.string.leftclick_timeout) }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(R.string.rightclick_question); + builder.setSingleChoiceItems(items, Globals.RightClickMethod, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.RightClickMethod = item; + dialog.dismiss(); + if( item == Mouse.RIGHT_CLICK_WITH_KEY ) + p.keyListener = new KeyRemapToolMouseClick(p, false); + else if( item == Mouse.RIGHT_CLICK_WITH_TIMEOUT ) + showRightClickTimeoutConfig(p); + else + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + + static void showRightClickTimeoutConfig(final MainActivity p) { + final CharSequence[] items = { p.getResources().getString(R.string.leftclick_timeout_time_0), + p.getResources().getString(R.string.leftclick_timeout_time_1), + p.getResources().getString(R.string.leftclick_timeout_time_2), + p.getResources().getString(R.string.leftclick_timeout_time_3), + p.getResources().getString(R.string.leftclick_timeout_time_4) }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(R.string.leftclick_timeout_time); + builder.setSingleChoiceItems(items, Globals.RightClickTimeout, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.RightClickTimeout = item; + dialog.dismiss(); + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + public static class KeyRemapToolMouseClick implements MainActivity.KeyEventsListener + { + MainActivity p; + boolean leftClick; + public KeyRemapToolMouseClick(MainActivity _p, boolean leftClick) + { + p = _p; + p.setText(p.getResources().getString(R.string.remap_hwkeys_press)); + this.leftClick = leftClick; + } + + public void onKeyEvent(final int keyCode) + { + p.keyListener = null; + int keyIndex = keyCode; + if( keyIndex < 0 ) + keyIndex = 0; + if( keyIndex > SDL_Keys.JAVA_KEYCODE_LAST ) + keyIndex = 0; + + if( leftClick ) + Globals.LeftClickKey = keyIndex; + else + Globals.RightClickKey = keyIndex; + + goBack(p); + } + } + + static class AdditionalMouseConfig extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.pointandclick_question); + } + void run (final MainActivity p) + { + CharSequence[] items = { + p.getResources().getString(R.string.pointandclick_joystickmouse), + p.getResources().getString(R.string.click_with_dpadcenter), + p.getResources().getString(R.string.pointandclick_relative) + }; + + boolean defaults[] = { + Globals.MoveMouseWithJoystick, + Globals.ClickMouseWithDpad, + Globals.RelativeMouseMovement + }; + + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.pointandclick_question)); + builder.setMultiChoiceItems(items, defaults, new DialogInterface.OnMultiChoiceClickListener() + { + public void onClick(DialogInterface dialog, int item, boolean isChecked) + { + if( item == 0 ) + Globals.MoveMouseWithJoystick = isChecked; + if( item == 1 ) + Globals.ClickMouseWithDpad = isChecked; + if( item == 2 ) + Globals.RelativeMouseMovement = isChecked; + } + }); + builder.setPositiveButton(p.getResources().getString(R.string.ok), new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + dialog.dismiss(); + if( Globals.RelativeMouseMovement ) + showRelativeMouseMovementConfig(p); + else + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + + static void showRelativeMouseMovementConfig(final MainActivity p) + { + final CharSequence[] items = { p.getResources().getString(R.string.accel_veryslow), + p.getResources().getString(R.string.accel_slow), + p.getResources().getString(R.string.accel_medium), + p.getResources().getString(R.string.accel_fast), + p.getResources().getString(R.string.accel_veryfast) }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(R.string.pointandclick_relative_speed); + builder.setSingleChoiceItems(items, Globals.RelativeMouseMovementSpeed, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.RelativeMouseMovementSpeed = item; + + dialog.dismiss(); + showRelativeMouseMovementConfig1(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + + static void showRelativeMouseMovementConfig1(final MainActivity p) + { + final CharSequence[] items = { p.getResources().getString(R.string.none), + p.getResources().getString(R.string.accel_slow), + p.getResources().getString(R.string.accel_medium), + p.getResources().getString(R.string.accel_fast) }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(R.string.pointandclick_relative_accel); + builder.setSingleChoiceItems(items, Globals.RelativeMouseMovementAccel, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.RelativeMouseMovementAccel = item; + + dialog.dismiss(); + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + static class JoystickMouseConfig extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.pointandclick_joystickmousespeed); + } + boolean enabled() + { + return Globals.MoveMouseWithJoystick; + }; + void run (final MainActivity p) + { + final CharSequence[] items = { p.getResources().getString(R.string.accel_slow), + p.getResources().getString(R.string.accel_medium), + p.getResources().getString(R.string.accel_fast) }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(R.string.pointandclick_joystickmousespeed); + builder.setSingleChoiceItems(items, Globals.MoveMouseWithJoystickSpeed, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.MoveMouseWithJoystickSpeed = item; + + dialog.dismiss(); + showJoystickMouseAccelConfig(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + + static void showJoystickMouseAccelConfig(final MainActivity p) + { + final CharSequence[] items = { p.getResources().getString(R.string.none), + p.getResources().getString(R.string.accel_slow), + p.getResources().getString(R.string.accel_medium), + p.getResources().getString(R.string.accel_fast) }; + + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(R.string.pointandclick_joystickmouseaccel); + builder.setSingleChoiceItems(items, Globals.MoveMouseWithJoystickAccel, new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + Globals.MoveMouseWithJoystickAccel = item; + + dialog.dismiss(); + goBack(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + } + + static class TouchPressureMeasurementTool extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.measurepressure); + } + boolean enabled() + { + return Globals.RightClickMethod == Mouse.RIGHT_CLICK_WITH_PRESSURE || + Globals.LeftClickMethod == Mouse.LEFT_CLICK_WITH_PRESSURE; + }; + void run (final MainActivity p) + { + p.setText(p.getResources().getString(R.string.measurepressure_touchplease)); + p.touchListener = new TouchMeasurementTool(p); + } + + public static class TouchMeasurementTool implements MainActivity.TouchEventsListener + { + MainActivity p; + ArrayList force = new ArrayList(); + ArrayList radius = new ArrayList(); + static final int maxEventAmount = 100; + + public TouchMeasurementTool(MainActivity _p) + { + p = _p; + } + + public void onTouchEvent(final MotionEvent ev) + { + force.add(new Integer((int)(ev.getPressure() * 1000.0))); + radius.add(new Integer((int)(ev.getSize() * 1000.0))); + p.setText(p.getResources().getString(R.string.measurepressure_response, force.get(force.size()-1), radius.get(radius.size()-1))); + try { + Thread.sleep(10L); + } catch (InterruptedException e) { } + + if( force.size() >= maxEventAmount ) + { + p.touchListener = null; + Globals.ClickScreenPressure = getAverageForce(); + Globals.ClickScreenTouchspotSize = getAverageRadius(); + Log.i("SDL", "SDL: measured average force " + Globals.ClickScreenPressure + " radius " + Globals.ClickScreenTouchspotSize); + goBack(p); + } + } + + int getAverageForce() + { + int avg = 0; + for(Integer f: force) + { + avg += f; + } + return avg / force.size(); + } + int getAverageRadius() + { + int avg = 0; + for(Integer r: radius) + { + avg += r; + } + return avg / radius.size(); + } + } + } + + static class CalibrateTouchscreenMenu extends Menu + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.calibrate_touchscreen); + } + //boolean enabled() { return true; }; + void run (final MainActivity p) + { + p.setText(p.getResources().getString(R.string.calibrate_touchscreen_touch)); + Globals.TouchscreenCalibration[0] = 0; + Globals.TouchscreenCalibration[1] = 0; + Globals.TouchscreenCalibration[2] = 0; + Globals.TouchscreenCalibration[3] = 0; + ScreenEdgesCalibrationTool tool = new ScreenEdgesCalibrationTool(p); + p.touchListener = tool; + p.keyListener = tool; + } + + static class ScreenEdgesCalibrationTool implements MainActivity.TouchEventsListener, MainActivity.KeyEventsListener + { + MainActivity p; + ImageView img; + Bitmap bmp; + + public ScreenEdgesCalibrationTool(MainActivity _p) + { + p = _p; + img = new ImageView(p); + img.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + img.setScaleType(ImageView.ScaleType.MATRIX); + bmp = BitmapFactory.decodeResource( p.getResources(), R.drawable.calibrate ); + img.setImageBitmap(bmp); + Matrix m = new Matrix(); + RectF src = new RectF(0, 0, bmp.getWidth(), bmp.getHeight()); + RectF dst = new RectF(Globals.TouchscreenCalibration[0], Globals.TouchscreenCalibration[1], + Globals.TouchscreenCalibration[2], Globals.TouchscreenCalibration[3]); + m.setRectToRect(src, dst, Matrix.ScaleToFit.FILL); + img.setImageMatrix(m); + p.getVideoLayout().addView(img); + } + + public void onTouchEvent(final MotionEvent ev) + { + if( Globals.TouchscreenCalibration[0] == Globals.TouchscreenCalibration[1] && + Globals.TouchscreenCalibration[1] == Globals.TouchscreenCalibration[2] && + Globals.TouchscreenCalibration[2] == Globals.TouchscreenCalibration[3] ) + { + Globals.TouchscreenCalibration[0] = (int)ev.getX(); + Globals.TouchscreenCalibration[1] = (int)ev.getY(); + Globals.TouchscreenCalibration[2] = (int)ev.getX(); + Globals.TouchscreenCalibration[3] = (int)ev.getY(); + } + if( ev.getX() < Globals.TouchscreenCalibration[0] ) + Globals.TouchscreenCalibration[0] = (int)ev.getX(); + if( ev.getY() < Globals.TouchscreenCalibration[1] ) + Globals.TouchscreenCalibration[1] = (int)ev.getY(); + if( ev.getX() > Globals.TouchscreenCalibration[2] ) + Globals.TouchscreenCalibration[2] = (int)ev.getX(); + if( ev.getY() > Globals.TouchscreenCalibration[3] ) + Globals.TouchscreenCalibration[3] = (int)ev.getY(); + Matrix m = new Matrix(); + RectF src = new RectF(0, 0, bmp.getWidth(), bmp.getHeight()); + RectF dst = new RectF(Globals.TouchscreenCalibration[0], Globals.TouchscreenCalibration[1], + Globals.TouchscreenCalibration[2], Globals.TouchscreenCalibration[3]); + m.setRectToRect(src, dst, Matrix.ScaleToFit.FILL); + img.setImageMatrix(m); + } + + public void onKeyEvent(final int keyCode) + { + p.touchListener = null; + p.keyListener = null; + p.getVideoLayout().removeView(img); + goBack(p); + } + } + } +} + diff --git a/project/javaSDL2/Video.java b/project/javaSDL2/Video.java new file mode 100644 index 000000000..8fcf0eb4c --- /dev/null +++ b/project/javaSDL2/Video.java @@ -0,0 +1,845 @@ +/* +Simple DirectMedia Layer +Java source code (C) 2009-2012 Sergii Pylypenko + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +package net.sourceforge.clonekeenplus; + +import javax.microedition.khronos.opengles.GL10; +import javax.microedition.khronos.opengles.GL11; +import javax.microedition.khronos.opengles.GL11Ext; + +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGL11; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; +import javax.microedition.khronos.egl.EGLSurface; + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.view.MotionEvent; +import android.view.KeyEvent; +import android.view.InputDevice; +import android.view.Window; +import android.view.WindowManager; +import android.os.Environment; +import java.io.File; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.content.res.Resources; +import android.content.res.AssetManager; +import android.widget.Toast; +import android.util.Log; + +import android.widget.TextView; +import java.lang.Thread; +import java.util.concurrent.locks.ReentrantLock; +import android.os.Build; +import java.lang.reflect.Method; +import java.util.LinkedList; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + + +class Mouse +{ + public static final int LEFT_CLICK_NORMAL = 0; + public static final int LEFT_CLICK_NEAR_CURSOR = 1; + public static final int LEFT_CLICK_WITH_MULTITOUCH = 2; + public static final int LEFT_CLICK_WITH_PRESSURE = 3; + public static final int LEFT_CLICK_WITH_KEY = 4; + public static final int LEFT_CLICK_WITH_TIMEOUT = 5; + public static final int LEFT_CLICK_WITH_TAP = 6; + public static final int LEFT_CLICK_WITH_TAP_OR_TIMEOUT = 7; + + public static final int RIGHT_CLICK_NONE = 0; + public static final int RIGHT_CLICK_WITH_MULTITOUCH = 1; + public static final int RIGHT_CLICK_WITH_PRESSURE = 2; + public static final int RIGHT_CLICK_WITH_KEY = 3; + public static final int RIGHT_CLICK_WITH_TIMEOUT = 4; + + public static final int SDL_FINGER_DOWN = 0; + public static final int SDL_FINGER_UP = 1; + public static final int SDL_FINGER_MOVE = 2; + public static final int SDL_FINGER_HOVER = 3; + + public static final int ZOOM_NONE = 0; + public static final int ZOOM_MAGNIFIER = 1; + public static final int ZOOM_SCREEN_TRANSFORM = 2; + public static final int ZOOM_FULLSCREEN_MAGNIFIER = 3; +} + +abstract class DifferentTouchInput +{ + public abstract void process(final MotionEvent event); + public abstract void processGenericEvent(final MotionEvent event); + + public static boolean ExternalMouseDetected = false; + + public static DifferentTouchInput getInstance() + { + boolean multiTouchAvailable1 = false; + boolean multiTouchAvailable2 = false; + // Not checking for getX(int), getY(int) etc 'cause I'm lazy + Method methods [] = MotionEvent.class.getDeclaredMethods(); + for(Method m: methods) + { + if( m.getName().equals("getPointerCount") ) + multiTouchAvailable1 = true; + if( m.getName().equals("getPointerId") ) + multiTouchAvailable2 = true; + } + try { + Log.i("SDL", "Device model: " + android.os.Build.MODEL); + if( android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH ) + { + if( DetectCrappyDragonRiseDatexGamepad() ) + return CrappyDragonRiseDatexGamepadInputWhichNeedsItsOwnHandlerBecauseImTooCheapAndStupidToBuyProperGamepad.Holder.sInstance; + return IcsTouchInput.Holder.sInstance; + } + if( android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD ) + return GingerbreadTouchInput.Holder.sInstance; + if (multiTouchAvailable1 && multiTouchAvailable2) + return MultiTouchInput.Holder.sInstance; + else + return SingleTouchInput.Holder.sInstance; + } catch( Exception e ) { + try { + if (multiTouchAvailable1 && multiTouchAvailable2) + return MultiTouchInput.Holder.sInstance; + else + return SingleTouchInput.Holder.sInstance; + } catch( Exception ee ) { + return SingleTouchInput.Holder.sInstance; + } + } + } + private static boolean DetectCrappyDragonRiseDatexGamepad() + { + if( CrappyDragonRiseDatexGamepadInputWhichNeedsItsOwnHandlerBecauseImTooCheapAndStupidToBuyProperGamepad.Holder.sInstance == null ) + return false; + return CrappyDragonRiseDatexGamepadInputWhichNeedsItsOwnHandlerBecauseImTooCheapAndStupidToBuyProperGamepad.Holder.sInstance.detect(); + } + + private static class SingleTouchInput extends DifferentTouchInput + { + private static class Holder + { + private static final SingleTouchInput sInstance = new SingleTouchInput(); + } + @Override + public void processGenericEvent(final MotionEvent event) + { + process(event); + } + public void process(final MotionEvent event) + { + int action = -1; + if( event.getAction() == MotionEvent.ACTION_DOWN ) + action = Mouse.SDL_FINGER_DOWN; + if( event.getAction() == MotionEvent.ACTION_UP ) + action = Mouse.SDL_FINGER_UP; + if( event.getAction() == MotionEvent.ACTION_MOVE ) + action = Mouse.SDL_FINGER_MOVE; + if ( action >= 0 ) + DemoGLSurfaceView.nativeMotionEvent( (int)event.getX(), (int)event.getY(), action, 0, + (int)(event.getPressure() * 1000.0), + (int)(event.getSize() * 1000.0) ); + } + } + private static class MultiTouchInput extends DifferentTouchInput + { + public static final int TOUCH_EVENTS_MAX = 16; // Max multitouch pointers + + private class touchEvent + { + public boolean down = false; + public int x = 0; + public int y = 0; + public int pressure = 0; + public int size = 0; + } + + protected touchEvent touchEvents[]; + + MultiTouchInput() + { + touchEvents = new touchEvent[TOUCH_EVENTS_MAX]; + for( int i = 0; i < TOUCH_EVENTS_MAX; i++ ) + touchEvents[i] = new touchEvent(); + } + + private static class Holder + { + private static final MultiTouchInput sInstance = new MultiTouchInput(); + } + + public void processGenericEvent(final MotionEvent event) + { + process(event); + } + public void process(final MotionEvent event) + { + int action = -1; + + //Log.i("SDL", "Got motion event, type " + (int)(event.getAction()) + " X " + (int)event.getX() + " Y " + (int)event.getY()); + if( (event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP || + (event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_CANCEL ) + { + action = Mouse.SDL_FINGER_UP; + for( int i = 0; i < TOUCH_EVENTS_MAX; i++ ) + { + if( touchEvents[i].down ) + { + touchEvents[i].down = false; + DemoGLSurfaceView.nativeMotionEvent( touchEvents[i].x, touchEvents[i].y, action, i, touchEvents[i].pressure, touchEvents[i].size ); + } + } + } + if( (event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN ) + { + action = Mouse.SDL_FINGER_DOWN; + for( int i = 0; i < event.getPointerCount(); i++ ) + { + int id = event.getPointerId(i); + if( id >= TOUCH_EVENTS_MAX ) + id = TOUCH_EVENTS_MAX - 1; + touchEvents[id].down = true; + touchEvents[id].x = (int)event.getX(i); + touchEvents[id].y = (int)event.getY(i); + touchEvents[id].pressure = (int)(event.getPressure(i) * 1000.0); + touchEvents[id].size = (int)(event.getSize(i) * 1000.0); + DemoGLSurfaceView.nativeMotionEvent( touchEvents[id].x, touchEvents[id].y, action, id, touchEvents[id].pressure, touchEvents[id].size ); + } + } + if( (event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_MOVE || + (event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_DOWN || + (event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP ) + { + /* + String s = "MOVE: ptrs " + event.getPointerCount(); + for( int i = 0 ; i < event.getPointerCount(); i++ ) + { + s += " p" + event.getPointerId(i) + "=" + (int)event.getX(i) + ":" + (int)event.getY(i); + } + Log.i("SDL", s); + */ + int pointerReleased = -1; + if( (event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP ) + pointerReleased = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; + + for( int id = 0; id < TOUCH_EVENTS_MAX; id++ ) + { + int ii; + for( ii = 0; ii < event.getPointerCount(); ii++ ) + { + if( id == event.getPointerId(ii) ) + break; + } + if( ii >= event.getPointerCount() ) + { + // Up event + if( touchEvents[id].down ) + { + action = Mouse.SDL_FINGER_UP; + touchEvents[id].down = false; + DemoGLSurfaceView.nativeMotionEvent( touchEvents[id].x, touchEvents[id].y, action, id, touchEvents[id].pressure, touchEvents[id].size ); + } + } + else + { + if( pointerReleased == id && touchEvents[pointerReleased].down ) + { + action = Mouse.SDL_FINGER_UP; + touchEvents[id].down = false; + } + else if( touchEvents[id].down ) + { + action = Mouse.SDL_FINGER_MOVE; + } + else + { + action = Mouse.SDL_FINGER_DOWN; + touchEvents[id].down = true; + } + touchEvents[id].x = (int)event.getX(ii); + touchEvents[id].y = (int)event.getY(ii); + touchEvents[id].pressure = (int)(event.getPressure(ii) * 1000.0); + touchEvents[id].size = (int)(event.getSize(ii) * 1000.0); + DemoGLSurfaceView.nativeMotionEvent( touchEvents[id].x, touchEvents[id].y, action, id, touchEvents[id].pressure, touchEvents[id].size ); + } + } + } + if( (event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_HOVER_MOVE ) // Support bluetooth/USB mouse - available since Android 3.1 + { + // TODO: it is possible that multiple pointers return that event, but we're handling only pointer #0 + if( touchEvents[0].down ) + action = Mouse.SDL_FINGER_UP; + else + action = Mouse.SDL_FINGER_HOVER; + touchEvents[0].down = false; + touchEvents[0].x = (int)event.getX(); + touchEvents[0].y = (int)event.getY(); + touchEvents[0].pressure = 0; + touchEvents[0].size = 0; + DemoGLSurfaceView.nativeMotionEvent( touchEvents[0].x, touchEvents[0].y, action, 0, touchEvents[0].pressure, touchEvents[0].size ); + } + } + } + private static class GingerbreadTouchInput extends MultiTouchInput + { + private static class Holder + { + private static final GingerbreadTouchInput sInstance = new GingerbreadTouchInput(); + } + + GingerbreadTouchInput() + { + super(); + } + public void process(final MotionEvent event) + { + boolean hwMouseEvent = ( (event.getSource() & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE || + (event.getSource() & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS || + (event.getMetaState() & KeyEvent.FLAG_TRACKING) != 0 ); // Hack to recognize Galaxy Note Gingerbread stylus + if( ExternalMouseDetected != hwMouseEvent ) + { + ExternalMouseDetected = hwMouseEvent; + DemoGLSurfaceView.nativeHardwareMouseDetected(hwMouseEvent ? 1 : 0); + } + super.process(event); + } + public void processGenericEvent(final MotionEvent event) + { + process(event); + } + } + private static class IcsTouchInput extends GingerbreadTouchInput + { + private static class Holder + { + private static final IcsTouchInput sInstance = new IcsTouchInput(); + } + private int buttonState = 0; + public void process(final MotionEvent event) + { + //Log.i("SDL", "Got motion event, type " + (int)(event.getAction()) + " X " + (int)event.getX() + " Y " + (int)event.getY() + " buttons " + buttonState + " source " + event.getSource()); + int buttonStateNew = event.getButtonState(); + if( buttonStateNew != buttonState ) + { + for( int i = 1; i <= MotionEvent.BUTTON_FORWARD; i *= 2 ) + { + if( (buttonStateNew & i) != (buttonState & i) ) + DemoGLSurfaceView.nativeMouseButtonsPressed(i, ((buttonStateNew & i) == 0) ? 0 : 1); + } + buttonState = buttonStateNew; + } + super.process(event); // Push mouse coordinate first + } + public void processGenericEvent(final MotionEvent event) + { + // Joysticks are supported since Honeycomb, but I don't care about it, because very little devices have it + if( (event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK ) + { + DemoGLSurfaceView.nativeGamepadAnalogJoystickInput( + event.getAxisValue(MotionEvent.AXIS_X), event.getAxisValue(MotionEvent.AXIS_Y), + event.getAxisValue(MotionEvent.AXIS_Z), event.getAxisValue(MotionEvent.AXIS_RZ), + event.getAxisValue(MotionEvent.AXIS_RTRIGGER), event.getAxisValue(MotionEvent.AXIS_LTRIGGER) ); + return; + } + // Process mousewheel + if( event.getAction() == MotionEvent.ACTION_SCROLL ) + { + int scrollX = Math.round(event.getAxisValue(MotionEvent.AXIS_HSCROLL)); + int scrollY = Math.round(event.getAxisValue(MotionEvent.AXIS_VSCROLL)); + DemoGLSurfaceView.nativeMouseWheel(scrollX, scrollY); + return; + } + super.processGenericEvent(event); + } + } + private static class CrappyDragonRiseDatexGamepadInputWhichNeedsItsOwnHandlerBecauseImTooCheapAndStupidToBuyProperGamepad extends IcsTouchInput + { + private static class Holder + { + private static final CrappyDragonRiseDatexGamepadInputWhichNeedsItsOwnHandlerBecauseImTooCheapAndStupidToBuyProperGamepad sInstance = new CrappyDragonRiseDatexGamepadInputWhichNeedsItsOwnHandlerBecauseImTooCheapAndStupidToBuyProperGamepad(); + } + float hatX = 0.0f, hatY = 0.0f; + public void processGenericEvent(final MotionEvent event) + { + // Joysticks are supported since Honeycomb, but I don't care about it, because very little devices have it + if( (event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK ) + { + // event.getAxisValue(AXIS_HAT_X) and event.getAxisValue(AXIS_HAT_Y) are joystick arrow keys, they also send keyboard events + DemoGLSurfaceView.nativeGamepadAnalogJoystickInput( + event.getAxisValue(MotionEvent.AXIS_X), event.getAxisValue(MotionEvent.AXIS_Y), + event.getAxisValue(MotionEvent.AXIS_RX), event.getAxisValue(MotionEvent.AXIS_RZ), + 0, 0); + if( event.getAxisValue(MotionEvent.AXIS_HAT_X) != hatX ) + { + hatX = event.getAxisValue(MotionEvent.AXIS_HAT_X); + if( hatX == 0.0f ) + { + DemoGLSurfaceView.nativeKey(KeyEvent.KEYCODE_DPAD_LEFT, 0); + DemoGLSurfaceView.nativeKey(KeyEvent.KEYCODE_DPAD_RIGHT, 0); + } + else + DemoGLSurfaceView.nativeKey(hatX < 0.0f ? KeyEvent.KEYCODE_DPAD_LEFT : KeyEvent.KEYCODE_DPAD_RIGHT, 1); + } + if( event.getAxisValue(MotionEvent.AXIS_HAT_Y) != hatY ) + { + hatY = event.getAxisValue(MotionEvent.AXIS_HAT_Y); + if( hatY == 0.0f ) + { + DemoGLSurfaceView.nativeKey(KeyEvent.KEYCODE_DPAD_UP, 0); + DemoGLSurfaceView.nativeKey(KeyEvent.KEYCODE_DPAD_DOWN, 0); + } + else + DemoGLSurfaceView.nativeKey(hatY < 0.0f ? KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN, 1); + } + return; + } + super.processGenericEvent(event); + } + public boolean detect() + { + int[] devIds = InputDevice.getDeviceIds(); + for( int id : devIds ) + { + InputDevice device = InputDevice.getDevice(id); + if( device == null ) + continue; + System.out.println("libSDL: input device ID " + id + " type " + device.getSources() + " name " + device.getName() ); + if( (device.getSources() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD && + (device.getSources() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK && + device.getName().indexOf("DragonRise Inc") == 0 ) + { + System.out.println("libSDL: Detected crappy DragonRise gamepad, enabling special hack for it. Please press button labeled 'Analog', otherwise it won't work, because it's cheap and crappy"); + return true; + } + } + return false; + } + } +} + + +class DemoRenderer extends GLSurfaceView_SDL.Renderer +{ + public DemoRenderer(MainActivity _context) + { + context = _context; + } + + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + Log.i("SDL", "libSDL: DemoRenderer.onSurfaceCreated(): paused " + mPaused + " mFirstTimeStart " + mFirstTimeStart ); + mGlSurfaceCreated = true; + mGl = gl; + if( ! mPaused && ! mFirstTimeStart ) + nativeGlContextRecreated(); + mFirstTimeStart = false; + } + + public void onSurfaceChanged(GL10 gl, int w, int h) { + Log.i("SDL", "libSDL: DemoRenderer.onSurfaceChanged(): paused " + mPaused + " mFirstTimeStart " + mFirstTimeStart + " w " + w + " h " + h); + if( w < h && Globals.HorizontalOrientation ) + { + // Sometimes when Android awakes from lockscreen, portrait orientation is kept + int x = w; + w = h; + h = x; + } + mWidth = w; + mHeight = h; + mGl = gl; + nativeResize(w, h, Globals.KeepAspectRatio ? 1 : 0); + } + + public void onSurfaceDestroyed() { + Log.i("SDL", "libSDL: DemoRenderer.onSurfaceDestroyed(): paused " + mPaused + " mFirstTimeStart " + mFirstTimeStart ); + mGlSurfaceCreated = false; + mGlContextLost = true; + nativeGlContextLost(); + }; + + public void onDrawFrame(GL10 gl) { + + mGl = gl; + DrawLogo(mGl); + SwapBuffers(); + + nativeInitJavaCallbacks(); + + // Make main thread priority lower so audio thread won't get underrun + // Thread.currentThread().setPriority((Thread.currentThread().getPriority() + Thread.MIN_PRIORITY)/2); + + mGlContextLost = false; + + if(Globals.CompatibilityHacksStaticInit) + MainActivity.LoadApplicationLibrary(context); + + Settings.Apply(context); + accelerometer = new AccelerometerReader(context); + // Tweak video thread priority, if user selected big audio buffer + if(Globals.AudioBufferConfig >= 2) + Thread.currentThread().setPriority( (Thread.NORM_PRIORITY + Thread.MIN_PRIORITY) / 2 ); // Lower than normal + // Calls main() and never returns, hehe - we'll call eglSwapBuffers() from native code + nativeInit( Globals.DataDir, + Globals.CommandLine, + ( (Globals.SwVideoMode && Globals.MultiThreadedVideo) || Globals.CompatibilityHacksVideo ) ? 1 : 0, + android.os.Debug.isDebuggerConnected() ? 1 : 0 ); + System.exit(0); // The main() returns here - I don't bother with deinit stuff, just terminate process + } + + public int swapBuffers() // Called from native code + { + if( ! super.SwapBuffers() && Globals.NonBlockingSwapBuffers ) + { + if(mRatelimitTouchEvents) + { + synchronized(this) + { + this.notify(); + } + } + return 0; + } + + if(mGlContextLost) { + mGlContextLost = false; + Settings.SetupTouchscreenKeyboardGraphics(context); // Reload on-screen buttons graphics + DrawLogo(mGl); + super.SwapBuffers(); + } + + // Unblock event processing thread only after we've finished rendering + if(mRatelimitTouchEvents) + { + synchronized(this) + { + this.notify(); + } + } + if( context.isScreenKeyboardShown() ) + { + try { + Thread.sleep(50); // Give some time to the keyboard input thread + } catch(Exception e) { }; + } + return 1; + } + + public void showScreenKeyboardWithoutTextInputField() // Called from native code + { + class Callback implements Runnable + { + public MainActivity parent; + public void run() + { + parent.showScreenKeyboardWithoutTextInputField(); + } + } + Callback cb = new Callback(); + cb.parent = context; + context.runOnUiThread(cb); + } + + public void showScreenKeyboard(final String oldText, int sendBackspace) // Called from native code + { + class Callback implements Runnable + { + public MainActivity parent; + public String oldText; + public boolean sendBackspace; + public void run() + { + parent.showScreenKeyboard(oldText, sendBackspace); + } + } + Callback cb = new Callback(); + cb.parent = context; + cb.oldText = oldText; + cb.sendBackspace = (sendBackspace != 0); + context.runOnUiThread(cb); + } + + public void hideScreenKeyboard() // Called from native code + { + class Callback implements Runnable + { + public MainActivity parent; + public void run() + { + parent.hideScreenKeyboard(); + } + } + Callback cb = new Callback(); + cb.parent = context; + context.runOnUiThread(cb); + } + + public int isScreenKeyboardShown() // Called from native code + { + return context.isScreenKeyboardShown() ? 1 : 0; + } + + public void setScreenKeyboardHintMessage(String s) + { + context.setScreenKeyboardHintMessage(s); + } + + public void startAccelerometerGyroscope(int started) + { + accelerometer.openedBySDL = (started != 0); + if( accelerometer.openedBySDL && !mPaused ) + accelerometer.start(); + else + accelerometer.stop(); + } + + public void exitApp() + { + nativeDone(); + } + + public void getAdvertisementParams(int params[]) + { + context.getAdvertisementParams(params); + } + public void setAdvertisementVisible(int visible) + { + context.setAdvertisementVisible(visible); + } + public void setAdvertisementPosition(int left, int top) + { + context.setAdvertisementPosition(left, top); + } + public void requestNewAdvertisement() + { + context.requestNewAdvertisement(); + } + + private int PowerOf2(int i) + { + int value = 1; + while (value < i) + value <<= 1; + return value; + } + public void DrawLogo(GL10 gl) + { + /* + // TODO: this not quite works, as it seems + BitmapDrawable bmp = null; + try + { + bmp = new BitmapDrawable(context.getAssets().open("logo.png")); + } + catch(Exception e) + { + bmp = new BitmapDrawable(context.getResources().openRawResource(R.drawable.publisherlogo)); + } + int width = bmp.getBitmap().getWidth(); + int height = bmp.getBitmap().getHeight(); + ByteBuffer byteBuffer = ByteBuffer.allocateDirect(4 * width * height); + //byteBuffer.order(ByteOrder.BIG_ENDIAN); + bmp.getBitmap().copyPixelsToBuffer(byteBuffer); + byteBuffer.position(0); + + gl.glViewport(0, 0, mWidth, mHeight); + gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT); + gl.glColor4x(0x10000, 0x10000, 0x10000, 0x10000); + gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1); + gl.glEnable(GL10.GL_TEXTURE_2D); + int textureName = -1; + int mTextureNameWorkspace[] = new int[1]; + int mCropWorkspace[] = new int[4]; + gl.glGenTextures(1, mTextureNameWorkspace, 0); + textureName = mTextureNameWorkspace[0]; + gl.glBindTexture(GL10.GL_TEXTURE_2D, textureName); + gl.glActiveTexture(textureName); + gl.glClientActiveTexture(textureName); + gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, + PowerOf2(width), PowerOf2(height), 0, + GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, null); + gl.glTexSubImage2D(GL10.GL_TEXTURE_2D, 0, 0, 0, + width, height, + GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, byteBuffer); + mCropWorkspace[0] = 0; // u + mCropWorkspace[1] = height; // v + mCropWorkspace[2] = width; + mCropWorkspace[3] = -height; + ((GL11) gl).glTexParameteriv(GL10.GL_TEXTURE_2D, + GL11Ext.GL_TEXTURE_CROP_RECT_OES, mCropWorkspace, 0); + ((GL11Ext) gl).glDrawTexiOES(0, -mHeight, 0, mWidth, mHeight); + gl.glActiveTexture(0); + gl.glClientActiveTexture(0); + gl.glBindTexture(GL10.GL_TEXTURE_2D, 0); + gl.glDeleteTextures(1, mTextureNameWorkspace, 0); + + gl.glFlush(); + */ + } + + + private native void nativeInitJavaCallbacks(); + private native void nativeInit(String CurrentPath, String CommandLine, int multiThreadedVideo, int isDebuggerConnected); + private native void nativeResize(int w, int h, int keepAspectRatio); + private native void nativeDone(); + private native void nativeGlContextLost(); + public native void nativeGlContextRecreated(); + public native void nativeGlContextLostAsyncEvent(); + public static native void nativeTextInput( int ascii, int unicode ); + public static native void nativeTextInputFinished(); + + private MainActivity context = null; + public AccelerometerReader accelerometer = null; + + private GL10 mGl = null; + private EGL10 mEgl = null; + private EGLDisplay mEglDisplay = null; + private EGLSurface mEglSurface = null; + private EGLContext mEglContext = null; + private boolean mGlContextLost = false; + public boolean mGlSurfaceCreated = false; + public boolean mPaused = false; + private boolean mFirstTimeStart = true; + public int mWidth = 0; + public int mHeight = 0; + + public static final boolean mRatelimitTouchEvents = true; //(Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO); +} + +class DemoGLSurfaceView extends GLSurfaceView_SDL { + public DemoGLSurfaceView(MainActivity context) { + super(context); + mParent = context; + touchInput = DifferentTouchInput.getInstance(); + setEGLConfigChooser(Globals.VideoDepthBpp, Globals.NeedDepthBuffer, Globals.NeedStencilBuffer, Globals.NeedGles2); + mRenderer = new DemoRenderer(context); + setRenderer(mRenderer); + } + + @Override + public boolean onTouchEvent(final MotionEvent event) + { + touchInput.process(event); + if( DemoRenderer.mRatelimitTouchEvents ) + { + limitEventRate(event); + } + return true; + }; + + @Override + public boolean onGenericMotionEvent (final MotionEvent event) + { + touchInput.processGenericEvent(event); + if( DemoRenderer.mRatelimitTouchEvents ) + { + limitEventRate(event); + } + return true; + } + + public void limitEventRate(final MotionEvent event) + { + // Wait a bit, and try to synchronize to app framerate, or event thread will eat all CPU and we'll lose FPS + // With Froyo the rate of touch events seems to be limited by OS, but they are arriving faster then we're redrawing anyway + if((event.getAction() == MotionEvent.ACTION_MOVE || + event.getAction() == MotionEvent.ACTION_HOVER_MOVE)) + { + synchronized(mRenderer) + { + try + { + mRenderer.wait(300L); // And sometimes the app decides not to render at all, so this timeout should not be big. + } catch (InterruptedException e) { } + } + } + } + + public void exitApp() { + mRenderer.exitApp(); + }; + + @Override + public void onPause() { + if(mRenderer.mPaused) + return; + mRenderer.mPaused = true; + mRenderer.nativeGlContextLostAsyncEvent(); + if( mRenderer.accelerometer != null ) // For some reason it crashes here often - are we getting this event before initialization? + mRenderer.accelerometer.stop(); + super.onPause(); + }; + + public boolean isPaused() { + return mRenderer.mPaused; + } + + @Override + public void onResume() { + if(!mRenderer.mPaused) + return; + mRenderer.mPaused = false; + super.onResume(); + Log.i("SDL", "libSDL: DemoGLSurfaceView.onResume(): mRenderer.mGlSurfaceCreated " + mRenderer.mGlSurfaceCreated + " mRenderer.mPaused " + mRenderer.mPaused); + if( mRenderer.mGlSurfaceCreated && ! mRenderer.mPaused || Globals.NonBlockingSwapBuffers ) + mRenderer.nativeGlContextRecreated(); + if( mRenderer.accelerometer != null && mRenderer.accelerometer.openedBySDL ) // For some reason it crashes here often - are we getting this event before initialization? + mRenderer.accelerometer.start(); + }; + + // This seems like redundant code - it handled in MainActivity.java + @Override + public boolean onKeyDown(int keyCode, final KeyEvent event) { + //Log.i("SDL", "Got key down event, id " + keyCode + " meta " + event.getMetaState() + " event " + event.toString()); + if( nativeKey( keyCode, 1 ) == 0 ) + return super.onKeyDown(keyCode, event); + return true; + } + + @Override + public boolean onKeyUp(int keyCode, final KeyEvent event) { + //Log.i("SDL", "Got key up event, id " + keyCode + " meta " + event.getMetaState()); + if( nativeKey( keyCode, 0 ) == 0 ) + return super.onKeyUp(keyCode, event); + return true; + } + + DemoRenderer mRenderer; + MainActivity mParent; + DifferentTouchInput touchInput = null; + + public static native void nativeMotionEvent( int x, int y, int action, int pointerId, int pressure, int radius ); + public static native int nativeKey( int keyCode, int down ); + public static native void nativeTouchpad( int x, int y, int down, int multitouch ); + public static native void initJavaCallbacks(); + public static native void nativeHardwareMouseDetected( int detected ); + public static native void nativeMouseButtonsPressed( int buttonId, int pressedState ); + public static native void nativeMouseWheel( int scrollX, int scrollY ); + public static native void nativeGamepadAnalogJoystickInput( float stick1x, float stick1y, float stick2x, float stick2y, float rtrigger, float ltrigger ); +} + + diff --git a/project/javaSDL2/admob/Advertisement.java b/project/javaSDL2/admob/Advertisement.java new file mode 100644 index 000000000..77d639706 --- /dev/null +++ b/project/javaSDL2/admob/Advertisement.java @@ -0,0 +1,75 @@ +/* +Simple DirectMedia Layer +Java source code (C) 2009-2012 Sergii Pylypenko + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +package net.sourceforge.clonekeenplus; + +import android.app.Activity; +import android.content.Context; +import android.view.MotionEvent; +import android.view.KeyEvent; +import android.view.Window; +import android.view.WindowManager; +import android.widget.TextView; +import android.view.View; + +import com.google.ads.*; // Copy GoogleAdMobAdsSdk.jar to the directory project/libs + +class Advertisement +{ + private AdView ad; + MainActivity parent; + + public Advertisement(MainActivity p) + { + parent = p; + AdSize adSize = AdSize.BANNER; + if( Globals.AdmobBannerSize.equals("BANNER") ) + adSize = AdSize.BANNER; + else if( Globals.AdmobBannerSize.equals("IAB_BANNER") ) + adSize = AdSize.IAB_BANNER; + else if( Globals.AdmobBannerSize.equals("IAB_LEADERBOARD") ) + adSize = AdSize.IAB_LEADERBOARD; + else if( Globals.AdmobBannerSize.equals("IAB_MRECT") ) + adSize = AdSize.IAB_MRECT; + else if( Globals.AdmobBannerSize.equals("IAB_WIDE_SKYSCRAPER") ) + adSize = AdSize.IAB_WIDE_SKYSCRAPER; + else if( Globals.AdmobBannerSize.equals("SMART_BANNER") ) + adSize = AdSize.SMART_BANNER; + ad = new AdView(parent, adSize, Globals.AdmobPublisherId); + AdRequest adRequest = new AdRequest(); + adRequest.addTestDevice(AdRequest.TEST_EMULATOR); // Copy GoogleAdMobAdsSdk.jar to the directory project/libs + adRequest.addTestDevice(Globals.AdmobTestDeviceId); + ad.loadAd(adRequest); + } + + public View getView() + { + return ad; + } + + public void requestNewAd() + { + AdRequest adRequest = new AdRequest(); + adRequest.addTestDevice(AdRequest.TEST_EMULATOR); // Copy GoogleAdMobAdsSdk.jar to the directory project/libs + adRequest.addTestDevice(Globals.AdmobTestDeviceId); + ad.loadAd(adRequest); + } +} diff --git a/project/javaSDL2/translations/generate.sh b/project/javaSDL2/translations/generate.sh new file mode 100755 index 000000000..f2f8911f7 --- /dev/null +++ b/project/javaSDL2/translations/generate.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +grep '\([^<]*\).*/\1/'` + if [ "$var" = "app_name" ]; then + continue + fi + PRINTEN=true + echo + for dir in values-*; do + lang=`echo $dir | sed 's/[^-]*-\(..\).*/\1/'` + trans=`grep "" $dir/strings.xml` + transtext=`echo $trans | sed 's/\([^<]*\).*/\1/'` + if [ -z "$transtext" ] ; then + #transtext=`./translate.py en $lang "$text"` + #echo "$transtext" | grep 'Suspected Terms of Service Abuse' > /dev/null && transtext="$text" + transtext="$text" + grep -v "^[<]/resources[>]\$" $dir/strings.xml > $dir/strings.1.xml + echo "$transtext" >> $dir/strings.1.xml + echo "" >> $dir/strings.1.xml + mv -f $dir/strings.1.xml $dir/strings.xml + if $PRINTEN ; then + echo en: $var: $text + PRINTEN=false + fi + echo $lang: $var: $transtext + fi + done +done diff --git a/project/javaSDL2/translations/translate.py b/project/javaSDL2/translations/translate.py new file mode 100755 index 000000000..9160397da --- /dev/null +++ b/project/javaSDL2/translations/translate.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python +from urllib2 import urlopen +from urllib import urlencode +import sys + +# The google translate API can be found here: +# http://code.google.com/apis/ajaxlanguage/documentation/#Examples + +lang1=sys.argv[1] +lang2=sys.argv[2] +langpair='%s|%s'%(lang1,lang2) +text=' '.join(sys.argv[3:]) +base_url='http://ajax.googleapis.com/ajax/services/language/translate?' +params=urlencode( (('v',1.0), +('q',text), +('langpair',langpair),) ) +url=base_url+params +content=urlopen(url).read() +start_idx=content.find('"translatedText":"')+18 +translation=content[start_idx:] +end_idx=translation.find('"}, "') +translation=translation[:end_idx] +print translation + diff --git a/project/javaSDL2/translations/unsupported/readme.txt b/project/javaSDL2/translations/unsupported/readme.txt new file mode 100644 index 000000000..4cba99b02 --- /dev/null +++ b/project/javaSDL2/translations/unsupported/readme.txt @@ -0,0 +1,3 @@ +I''ve tired of using Google Translate to create random gibberish in the languages I don't know, +so from now on the only supported languages are English, Russian, Ukrainian, and French with some community support, +If you wish to maintain a translation - contact me, but I will want a continuous support, not just one-time translation. \ No newline at end of file diff --git a/project/javaSDL2/translations/unsupported/values-de/strings.xml b/project/javaSDL2/translations/unsupported/values-de/strings.xml new file mode 100644 index 000000000..d963f6da5 --- /dev/null +++ b/project/javaSDL2/translations/unsupported/values-de/strings.xml @@ -0,0 +1,137 @@ + + + Initialisiere + Bitte warte, während die Dateien heruntergeladen werden. + + Gerätekonfiguration + Gerätekonfiguration bearbeiten + + Download nicht nötig + Verbinde mit %s + Verbindung mit %s fehlgeschlagen + Fehler beim Verbinden mit %s + Lade Daten von %s + Fehler beim Download von %s + Fehler beim schreiben auf %s + Zu %1$.0f%% abgeschlossen: Datei %2$s + Abgeschlossen + + Interner Speicher: %d MiB frei + SD Karte: %d MiB frei + Wohin sollen die Dateien gespeichert werden + + Pfeiltasten / Joystick / dpad + Trackball + Accelerometer + Welche Arten von Navigationstasten hat das Gerät? + + Keine Dämpfung + Schnell + Mittel + Langsam + Dämpfung des Trackball + + Schnell + Mittel + Langsam + Empfindlichkeit des Accelerometers + + Klein (für schnelle Geräte) + Mittel + Groß (Wenn Ton "hängt") + Größe des Audiopuffers +Optional Downloads +OK +Touchscreen nur +Zusätzliche Kontrollen zu verwenden +On-Screen-Tastatur +Beschleunigungsmesser +On-Screen-Tastatur Größe +Große +Medium +Kleine +Winzig +On-Screen-Tastatur Thema +%1$s von %2$s +Schwimmend +Feste, wenn die Anwendung startet +Fixiert auf Tisch Schreibtisch Orientierung +Beschleunigungsmesser Mittelstellung +Sehr kleine (schnelle Geräte, weniger Verzögerung) +Rechter Mausklick ausgelöst durch +Menütaste +Touch-Screen mit dem zweiten Finger +Touchscreen mit Kraft +Erweiterte Funktionen +Halten 4:3-Bildschirm Seitenverhältnis +Show-Bildschirm unter dem Finger in einem separaten Fenster +Bitte schieben Sie den Finger über den Bildschirm für zwei Sekunden +Deaktivieren der rechten Maustaste +Linke Maustaste +Normal +Tippen Sie auf nahe Mauszeiger +Touch-Screen mit dem zweiten Finger +Touchscreen mit Kraft +Trackball klicken Select-Taste +Bewegen Sie die Maus mit Joystick oder Trackball +Pressure %1$03d Radius %2$03d +Linker Mausklick mit Trackball / Joystick Zentrum +Bewegen Sie die Maus mit Joystick-Geschwindigkeit +Bewegen Sie die Maus mit Joystick-Beschleunigung +Keine +On-Screen-Tastatur Transparenz +Nicht sichtbar +Fast unsichtbar +Transparente +Semi-transparent +Non-transparent +Maus-Emulation +Kalibrieren Touchscreen Druck +Remap physischen Tasten +Drücken Sie eine beliebige Taste außer HOME und POWER, können Sie Lautstärke-Tasten +Wählen Sie SDL Schlüsselcode +Remap On-Screen-Steuerung +On-Screen-Joystick +On-Screen-Taste +On-Screen-Texteingabe-Taste +Zoom in Zwei-Finger-Geste +Verkleinern Zwei-Finger-Geste +Nach links drehen Zwei-Finger-Geste +Nach rechts drehen Zwei-Finger-Geste +Zwei-Finger-Gesten +Sehr schnell +Zwei-Finger-Gesten Bildschirm Empfindlichkeit +Geben Sie direkt +Geben Kommandozeilenparameter +Kalibrieren Touchscreen +Touch allen vier Rändern des Bildschirms, drücken Sie Menü, wenn Sie fertig +Passen Sie auf dem Bildschirm Tastatur-Layout +Slide-Bildschirm hinzufügen Taste, drücken Sie Menü zum letzten Knopf rückgängig machen +Physikalische Schlüssel +On-Screen-Lupe +Video-Einstellungen +Glatte Video +Sehr langsam +Halten Sie an der gleichen Stelle +Tippen Sie auf +Tippen Sie auf oder halten +Holding-Timeout +0,3 Sek. +0,5 Sek. +0,7 Sek. +1 Sek. +1,5 Sek. +Relative Bewegung der Maus (Laptop-Modus) +Relative Maus Bewegungsgeschwindigkeit +Relative Bewegung der Maus Beschleunigung +Downloads +Separaten Thread für Video, FPS bei einigen Geräten zu erhöhen +Tippen Sie auf der Eingabe beginnen, drücken Sie Zurück, wenn Sie fertig +Konfigurieren der Maus je nach Display-Größe +Wählen Sie Ihre Display-Größe +Groß (Tablette) +Klein (Telefon) +Uberklein (Xperia Mini) +Weitere Optionen +Größe der Schaltfläche Bilder + diff --git a/project/javaSDL2/translations/unsupported/values-fi/strings.xml b/project/javaSDL2/translations/unsupported/values-fi/strings.xml new file mode 100644 index 000000000..20b979950 --- /dev/null +++ b/project/javaSDL2/translations/unsupported/values-fi/strings.xml @@ -0,0 +1,137 @@ + + + Käynnistetään + Odota kun tietoja ladataan + + Laiteasetukset + Muuta laiteasetuksia + + Ei tarvitse ladata + Yhdistetään %s + Yhdistäminen epäonnistui %s + Virhe yhdistettäessä %s + Ladataan kohteesta %s + Virhe ladattaessa kohteesta %s + Virhe kirjoittaessa %s + %1$.0f%% valmis: tiedosto %2$s + Valmis + + Sisäinen muisti - %d Mt vapaana + SD kortti - %d Mt vapaana + Minne sovelluksen data ladataan + + Nuolinapit / joystick / dpad + Pallohiiri + Kiihtyvyysanturi + Millaiset navigointinapit laittessasi on? + + Ei vaimennusta + Nopea + Kohtalainen + Hidas + Pallohiiren vaimennus + + Nopea + Kohtalainen + Hidas + Kiihtyvyysanturin herkkyys + + Pieni (nopeat laitteet) + Keskisuuri + Suuri (jos ääni pätkii) + Äänipuskurin koko +Vapaaehtoinen lataukset +OK +Kosketusnäyttö vain +Muita ohjausobjekteja käyttää +Näyttönäppäimistöllä +Kiihtyvyysmittari +Näyttönäppäimistöllä koko +Suuri +Medium +Pienet +Tiny +Näyttönäppäimistöllä teema +%1$s %2$s +Kelluva +Kiinteät kun sovellus käynnistyy +Korjattu taulukko työpöytä suuntautumiseen +Kiihtyvyysmittari keskiasentoon +Hyvin pieni (nopea laitteita, vähemmän lag) +Napsauta hiiren kakkospainikkeella alkunsa +Valikkonäppäin +Kosketusnäyttö on toinen sormi +Kosketusnäyttö voimalla +Lisäominaisuudet +Pidä 04:03 kuvasuhde +Näytä näytön alle sormi erillisessä ikkunassa +Ole hyvä ja liu\u0026#39;uttamalla sormea näytöllä kaksi sekuntia +Poista oikealla hiiren klikkauksella +Vasen hiiren nappi +Normaali +Touch lähellä hiiren kursori +Kosketusnäyttö on toinen sormi +Kosketusnäyttö voimalla +Trackball Valitse / Select-näppäintä +Siirrä hiiren ohjaimella tai trackball +Paine %1$03d säde %2$03d +Vasen hiiren klikkaus trackball-ohjaimella keskusta +Siirrä hiiri ohjainta nopeasti +Siirrä hiiri ohjainta kiihtyvyys +Ei +Näyttönäppäimistöllä avoimuutta +Näkymätön +Lähes näkymätön +Läpinäkyvä +Semi-avoimet +Ei-läpinäkyvä +Hiiren emulointi +Kalibroi kosketusnäyttö paine +Remap fyysiset näppäimet +Paina mitä tahansa näppäintä paitsi koti-ja POWER, voit käyttää äänenvoimakkuusnäppäimiä +Valitse SDL näppäinkoodien +Remap näytön valvonnan +Näytöllä ohjainta +Ruutunäyttöpainike +Näytön tekstin tulopainiketta +Suurenna kahden sormen elettä +Pienennä kahden sormen elettä +Kierrä vasemmalle kahden sormen elettä +Kierrä oikealle kahden sormen elettä +Kahden sormen eleitä +Erittäin nopea +Kahden sormen näytön eleet herkkyys +Määritä hakemisto +Määritä komentoriviparametrit +Kalibroi kosketusnäyttö +Touch kaikki neljä reunaa näytön, paina Valikko, kun olet valmis +Mukauta-ruudun näppäimistö +Työnnä näytön lisätä painikkeen, paina Menu kumota viimeksi painike +Fyysinen avain +Näytöllä suurennuslasi +Videon asetukset +Tasainen video +Erittäin hidas +Pidä samalla paikalla +Hana +Napauta tai pidä +Holding aikakatkaisu +0,3 sekuntia +0,5 sekuntia +0,7 sekuntia +1 sek +1,5 sek +Suhteellinen hiiren liikkeet (kannettavan tietokoneen tilassa) +Suhteellinen hiiren liikkeen nopeus +Suhteellinen hiiren liikkeen kiihtyvyys +Downloads +Erillisessä säikeessä video, kasvaa FPS joissakin laitteissa +Napauta aloittaa kirjoittamisen, paina Takaisin, kun olet valmis +Määritä hiiren riippuen näytön koosta +Valitse näytön koko +Suuri (tabletti) +Pieni (puhelin) +Tiny (Xperia Mini) +Näytä enemmän vaihtoehtoja +Koko painike kuvia + diff --git a/project/javaSDL2/translations/values-fr/strings.xml b/project/javaSDL2/translations/values-fr/strings.xml new file mode 100644 index 000000000..abc5c397c --- /dev/null +++ b/project/javaSDL2/translations/values-fr/strings.xml @@ -0,0 +1,176 @@ + + + Démarrage + Veuillez patienter pendant que les données sont téléchargées + + Configuration de l\'appareil + Changer la configuration + + Téléchargement non nécessaire + Connexion à %s + Echec de la connexion à %s + Erreur durant la connexion à %s + Téléchargement à partir de %s + Erreur lors du téléchargement à partir de %s + Erreur d\'écriture dans %s + %1$.0f%% fait : fichier %2$s + Fini + + Stockage interne - %d Mo de libre + Carte SD - %d Mo de libre + Choisir le répertoire + Choisir les paramètres de la ligne de commande + Où télécharger les données + Téléchargements + Téléchargements + OK + + Flèches / joystick / dpad + Trackball + Accéléromètre + Ecran tactile seul + Quel type de touches votre appareil a-t-il? + + Contrôles supplémentaires + Clavier à l\'écran + Accéléromètre + + Taille du clavier à l\'écran + Taille des images des boutons + Grande + Moyenne + Petite + Minuscule + Thème du clavier à l\'écran + %1$s par %2$s + Transparence du clavier + Invisible + Presque invisible + Transparent + Semi-transparent + Non-transparent + + Sans limite + Rapide + Moyenne + Lente + Limitation du trackball + + Très rapide + Rapide + Moyenne + Lente + Très lente + Sensibilité de l\'accéléromètre + + Flottante + Déterminée au démarrage de l\'application + Orientaton de la table + Position du centre de l\'accéléromètre + + + + + + +Emulation de la souris +Clic droit de la souris +Touche Menu +Touche Physique +Ecran tactile avec le deuxième doigt +Ecran tactile avec force +Désactiver le clic droit de la souris + +Clic gauche de la souris +Normal +Curseur de la souris près Touch +Ecran tactile avec le deuxième doigt +Ecran tactile avec force +Trackball clic / Joystick au centre +Tenir au même endroit +Appuyez sur +Appuyez sur, ou maintenez +timeout Holding +0,3 s +0,5 sec +0,7 sec +1 sec +1,5 sec +Cliquez gauche de la souris avec le Trackball / centre du joystick + +Fonctionnalités avancées +Gardez le format 4:3 écran +Afficher l\'écran sous le doigt dans une fenêtre séparée +Loupe à l\'écran +Déplacez la souris avec un trackball ou le joystick +Déplacez la souris avec la vitesse du joystick +Déplacez la souris avec l\'accélération du joystick +Mouvement relatif de la souris (mode portable) +Vitesse relative de la souris +Accélération relative de la souris + +Aucun + +Calibrer la pression de l\'écran tactile +Glisser les doigts sur l\'écran pendant deux secondes +Pression %1$03d rayon %2$03d + +Très petite (appareils rapides, plus de réactivité) +Petite (appareils rapides) +Moyenne +Grande (appareils anciens, si le son est saccadé) +Taille du tampon audio + +Reconfigurer les touches physiques +Appuyez sur n\'importe quelle touche sauf HOME et POWER, vous pouvez utiliser les touches de volume +Sélectionnez le keycode SDL + +Reconfigurer les contrôles via l\'écran +Joystick à l\'écran +Bouton à l\'écran +Saisie de texte à l\'écran +Gestes avec deux doigts +Sensibilité des gestes +Geste de +Zoom avec deux doigts +Geste de -Zoom avec deux doigts +Geste de rotation à gauche avec deux doigts +Geste de rotation à droite avec deux doigts + +Personnalisation de la présentation du clavier à l\'écran + +Calibrer l\'écran tactile +Touchez les bords de l\'écran, appuyez sur Retour/BACK lorsque vous avez terminé + +Paramètres vidéo +Fluidité de la vidéo +Thread séparé pour la vidéo : permet paroifs d\'augmenter FPS + +Appuyez pour commencer à taper, appuyez sur Retour/BACK lorsque vous avez terminé + +Mode d\'émulation de la souris +Sélectionnez votre taille d\'affichage +Large (tablet) +Petit (téléphone) +Petit, mode touchpad +Très petit +Très petit, mode touchpad + +Afficher plus d\'options + +Hardware mouse detected, disabling mouse emulation +Not enough RAM +This app needs %1$d Mb RAM, your device has %2$d Mb +Ignore +Calibrate gyroscope +Put your phone on a flat surface +Reset config to defaults +Cancel +Your device does not have gyroscope +Reset all options to default values? +Cancel data downloading? +You can resume it later, the data will not be downloaded twice. +Yes +No +Press BACK when done. Resize buttons by sliding on empty space. +Custom + diff --git a/project/javaSDL2/translations/values-ru/strings.xml b/project/javaSDL2/translations/values-ru/strings.xml new file mode 100644 index 000000000..4c615c60c --- /dev/null +++ b/project/javaSDL2/translations/values-ru/strings.xml @@ -0,0 +1,149 @@ + + +Инициализация +Пожалуйста, подождите, пока данные загружаются +Конфигурация устройства +Изменение конфигурации устройства +Нет необходимости скачивать +Подключение к %s +Ошибка подключения к %s +Ошибка подключения к %s +Загрузка данных с %s +Ошибка при загрузке данных с %s +Ошибка записи в %s +%1$.0f%% готово: файл %2$s +Завершенный +Внутреннее хранение - %d Мб +SD карта - %d Мб +Куда сохранять данные приложения +Дополнительные загрузки +Продолжить +Стрелки / джойстик / Dpad +Трекбол +Акселерометр +Только сенсорный экран +Какие на телефоне клавиши навигации? +Дополнительные элементы управления +Экранная клавиатура +Акселерометр +Размер экранной клавиатуры +Большой +Средний +Маленький +Крошечный +Тема клавиатуры +%1$s от %2$s +Нет +Быстрое +Среднее +Медленное +Замедление трекбола +Быстрая +Средний +Медленно +Чувствительность акселерометра +Правая кнопка мыши +Клавиша меню +Касание экрана вторым пальцем +Нажатие на экран с силой +Расширенные функции +Сохранять соотношение сторон 4:3 на экране +Экранная лупа +Пожалуйста, проведите пальцем по экрану в течение двух секунд +Давление %1$03d радиус %2$03d +Очень мало (быстрые устройства) +Малый +Средний +Большой (для старых устройств, если звук прерывается) +Размер буфера аудио +Плавающее +Фиксировано при запуске приложения +Фиксировано на горизонт +Центральное положение акселерометра +Правая кнопка мыши отключена +Левая кнопка мыши +Нормальный +Касание возле курсора мыши +Касание двумя пальцами +Нажатие с силой +Нажатие на трекбол / центр джойстика +Перемещение мыши при помощи джойстика или трекбола +Левый клик мыши при помощи трекбола / центра джойстика +Перемещение мыши джойстиком - скорость +Перемещение мыши джойстиком - ускорение +Нет +Прозрачность клавиатуры +Невидимый +Почти невидимый +Прозрачный +Полупрозрачные +Непрозрачные +Эмуляции мыши +Калибровка сенсорного давления +Переназначение физических клавиш +Нажмите любую клавишу, кроме HOME и POWER, вы можете использовать клавиши регулировки громкости +Выберите код кнопки SDL +Переназначение экранных кнопок +Экранный джойстик +Экранные кнопки +Экранная кнопка ввода текста +Увеличить двумя пальцами +Уменьшить двумя пальцами +Повернуть налево двумя пальцами +Повернуть вправо двумя пальцами +Жест двумя пальцами по экрану +Очень быстро +Чувствительность жеста двумя пальцами по экрану +Укажите каталог +Укажите параметры командной строки +Калибровка сенсорного экрана +Дотроньтесь до всех краев экрана, потом нажмите Назад/BACK +Настройка расположения кнопок +Нажмите клавишу Назад/BACK для завершения. Проведите по пустому месту, чтобы изменить размер кнопки +Физическая кнопка +Наэкранная лупа +Настройки видео +Линейное сглаживание видео +Очень медленно +Нажатие с задержкой +Быстрое нажатие +Быстрое нажатие либо с задержкой +Время нажатия +0,3 сек +0,5 сек +0,7 сек +1 сек +1,5 сек +Относительное движение мыши (режим ноутбука) +Скорость движения мыши +Ускорение движения мыши +Загрузки +Отдельный поток для видео, увеличит FPS на некоторых устройствах +Нажмите, чтобы ввести текст, нажмите Назад, когда закончите +Настройка размера дисплея +Размер дисплея +Большой (таблетка) +Маленький (телефон) +Крохотный +Показать больше параметров +Размер изображения кнопок +Маленький, режим тачпада +Крохотный, режим тачпада +Обнаружена внешняя мышь, эмуляция мыши выключена + +Недостаточно оперативной памяти +Для запуска приложения нужно %1$d Мб оперативной памяти, на этом устройстве есть %2$d Мб +Игнорировать + +Калибровать гироскоп +Положите устройство на ровную поверхность +Сбросить все настройки +Отменить +Гироскоп отсутствует +Сбросить все настройки в значения по умолчанию? +Остановить загрузку? +Загрузка может быть продолжена позднее. +Да +Нет +Пользовательские настройки + diff --git a/project/javaSDL2/translations/values-uk/strings.xml b/project/javaSDL2/translations/values-uk/strings.xml new file mode 100644 index 000000000..746d6aac2 --- /dev/null +++ b/project/javaSDL2/translations/values-uk/strings.xml @@ -0,0 +1,148 @@ + + +Ініціалізація +Будь-ласка, зачекайте, поки завантажуться дані +Конфігурація пристрою +Зміна конфігурації пристрою +Немає необхідності викачувати +Підключенння до %s +Помилка підключення до %s +помилка підключення до %s +Завантаження даних з %s +Помилка при завантаженні даних з %s +Помилка запису в %s +%1$.0f%% готово: файл %2$s +Завершений +Внутрішнє зберігання - %d Мб +SD карта - %d Мб +Куди зберігати дані програми +Додаткові завантаження +ОК +Стрілки / джойстік / Dpad +Трекбол +Акселерометр +Тільки сенсорний екран +Які на телефоні кнопки навігації? +Додаткові элементи керування +Наекранні кнопки +Акселерометр +Розмір наекранних кнопок +Великий +Середній +Малий +Дрібний +Тема кнопок +%1$s від %2$s +Немає +Швидке +Середнє +Повільне +Сповільнення трекболу +Швидко +середньо +повільно +Чутливість акселерометру +Права кнопка миші +Кнопка меню +Торкання екрана другим пальцем +Натиск на екран силою +Розширені функції +Зберігати співвідношення сторін 4:3 на екрані +Наекранна лупа +Будь-ласка, проведіть пальцем по екрану на протязі двох секунд +Тиск %1$03d радіус %2$03d +Дуже мало (швидкі пристрої) +Малий +Середній +Великий (для старих пристроїв, якщо звук переривається) +Розмір буферу аудіо +Плаваюче +Фiксоване під час запуску програми +Фiксоване до горизонту +Центральне положення акселерометра +Вiдключена +Ліва кнопка миші +Нормальна +Дотик біля курсору миші +Натиск на екран другим пальцем +>Натиск на екран з силою +Натиск на трекбол / центр джойстику +Переміщення миші за допомогою джойстика або трекбола +Лівий клік миші за допомогою трекбола / центра джойстика +Переміщення миші джойстиком - швидкiсть +Переміщення миші джойстиком - прискорення +Немає +Прозорість клавіатури +Невидимий +Майже невидимий +Прозорий +Напівпрозорі +Непрозорі +Емуляція миші +Калібрування сенсорного натискання +Перепризначення фізичних кнопок +Натисніть будь-яку клавішу, крім HOME і POWER, ви можете використовувати клавіші регулювання гучності +Виберіть код кнопки SDL +Перепризначення наекранних кнопок +Наекранний джойстік +Наекранні кнопки +Наекранна кнопка вводу тексту +Збільшити двома пальцями +Зменшити двома пальцями +Повернути наліво двома пальцями +Повернути праворуч двома пальцями +Жест двома пальцями по екрану +Дуже швидко +Чутливість жесту двома пальцями по екрану +Вкажіть каталог +Вкажіть параметри командного рядка +Калібрування сенсорного екрану +Доторкнiться до всіх країв екрану, потiм натисніть Назад/BACK +Налаштування положення кнопок +Натисніть Назад/BACK для завершення. Проведiть по екрану, щоб змінити розмір кнопки +Фізична кнопка +Наекранна лупа +Налаштування відео +Лінійне сглажування відео +Дуже повільно +Натискання з затримкою +Швидке натискання +Швидке натискання або з затримкою +Час натискання +0,3 сек +0,5 сек +0,7 секунд +1 сек +1,5 сек +Відносний рух миші (режим ноутбука) +Швидкість руху миші +Прискорення руху миші +Завантаження +Окремий потік для відео, збільшить FPS на деяких пристроях +Натисніть, щоб ввести текст, натисніть Назад, коли закiнчете +Налаштування розміру дисплея +Виберіть розмір дисплея +Великий (таблетка) +Маленький +Крихiтний +Показати більше параметрів +Розмір зображення кнопок +Маленький, режим тачпаду +Крихiтний, режим тачпаду +Виявлена зовнiшня миша, емуляція миші вимкнена + +Недостатньо пам’яті +Потрібно %1$d Mb пам’яті, доступно лише %2$d Mb +Ігнорувати +Калібрувати гіроскоп +Покладіть телефон на рівну поверхню +Скинути всі налаштування +Відмінити +Гіроскоп відсутній +Скинути всі налаштування у значення за замовчуванням? +Припинити завантаження? +Завантаження може бути відновлено пізніше. +Так +Ні +Налаштування користувача + diff --git a/project/javaSDL2/translations/values/strings.xml b/project/javaSDL2/translations/values/strings.xml new file mode 100644 index 000000000..e6ffc801c --- /dev/null +++ b/project/javaSDL2/translations/values/strings.xml @@ -0,0 +1,181 @@ + + + Commander Genius + + + Initializing + Please wait while data is being downloaded + + Device configuration + Change device configuration + + No need to download + Connecting to %s + Failed connecting to %s + Error connecting to %s + Downloading data from %s + Error downloading data from %s + Error writing to %s + %1$.0f%% done: file %2$s + Finished + + Internal storage - %d MB free + SD card storage - %d MB free + Specify directory + Specify command line parameters + Data installation location + Downloads + Downloads + OK + Cancel + + Arrows / joystick / dpad + Trackball + Accelerometer + Touchscreen only + What kind of navigation keys does your device have? + + Additional controls + On-screen keyboard + Accelerometer + + On-screen keyboard size + Size of button images + Large + Medium + Small + Tiny + Custom + On-screen keyboard theme + %1$s by %2$s + On-screen keyboard transparency + Invisible + Almost invisible + Transparent + Semi-transparent + Non-transparent + + No dampening + Fast + Medium + Slow + Trackball dampening + + Very fast + Fast + Medium + Slow + Very slow + Accelerometer sensitivity + + Floating + Fixed when application starts + Fixed to table desk orientation + Accelerometer center position + + Mouse emulation + Right mouse click + Menu key + Physical key + Touch screen with second finger + Touch screen with force + Disable right mouse click + + Left mouse click + Normal + Touch near mouse cursor + Touch screen with second finger + Touch screen with force + Trackball click / joystick center + Hold at the same spot + Tap + Tap or hold + Holding timeout + 0.3 sec + 0.5 sec + 0.7 sec + 1 sec + 1.5 sec + Left mouse click with trackball / joystick center + + Advanced features + Keep 4:3 screen aspect ratio + Show screen under finger in separate window + On-screen magnifying glass + Move mouse with joystick or trackball + Move mouse with joystick speed + Move mouse with joystick acceleration + Relative mouse movement (laptop mode) + Relative mouse movement speed + Relative mouse movement acceleration + + None + + Calibrate touchscreen pressure + Please slide finger across the screen for two seconds + Pressure %1$03d radius %2$03d + + Very small (fast devices, less lag) + Small + Medium + Large (older devices, if sound is choppy) + Size of audio buffer + + Remap physical keys + Press any key except HOME and POWER, you may use volume keys + Select SDL keycode + Select action + Show all keycodes + + Remap on-screen controls + Joystick + Button + Text input button + Two-finger screen gestures + Two-finger screen gestures sensitivity + Zoom in two-finger gesture + Zoom out two-finger gesture + Rotate left two-finger gesture + Rotate right two-finger gesture + + Customize on-screen keyboard layout + Press BACK when done. Resize buttons by sliding on empty space. + + Calibrate touchscreen + Touch all edges of the screen, press BACK when done + + Video settings + Linear video filtering + Separate thread for video, will increase FPS on some devices + + Tap to start typing, press Back when done + + Mouse emulation mode + Display size for mouse emulation + Large (tablets) + Small, magnifying glass + Small, touchpad mode + Tiny + Tiny, touchpad mode + + Show more options + + Hardware mouse detected, disabling mouse emulation + + Not enough RAM + This app needs %1$d Mb RAM, your device has %2$d Mb + Ignore + + Calibrate gyroscope + Put your device on a flat surface + Your device does not have gyroscope + + Reset config to defaults + Reset all options to default values? + + Cancel data downloading? + You can resume it later, the data will not be downloaded twice. + Yes + No + +