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:
+ *
+ *
+ * - Manages a surface, which is a special piece of memory that can be
+ * composited into the Android view system.
+ *
- Manages an EGL display, which enables OpenGL to render into a surface.
+ *
- Accepts a user-provided Renderer object that does the actual rendering.
+ *
- Renders on a dedicated thread to decouple rendering performance from the
+ * UI thread.
+ *
- Supports both on-demand and continuous rendering.
+ *
- Optionally wraps, traces, and/or error-checks the renderer's OpenGL calls.
+ *
+ *
+ * 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:
+ *
+ * - {@link #setDebugFlags(int)}
+ *
- {@link #setEGLConfigChooser(boolean)}
+ *
- {@link #setEGLConfigChooser(EGLConfigChooser)}
+ *
- {@link #setEGLConfigChooser(int, int, int, int, int, int)}
+ *
- {@link #setGLWrapper(GLWrapper)}
+ *
+ *
+ *
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:
+ *
+ * - {@link #setEGLConfigChooser(boolean)}
+ *
- {@link #setEGLConfigChooser(EGLConfigChooser)}
+ *
- {@link #setEGLConfigChooser(int, int, int, int, int, int)}
+ *
+ *
+ * The following GLSurfaceView methods can only be called after
+ * setRenderer is called:
+ *
+ * - {@link #getRenderMode()}
+ *
- {@link #onPause()}
+ *
- {@link #onResume()}
+ *
- {@link #queueEvent(Runnable)}
+ *
- {@link #requestRender()}
+ *
- {@link #setRenderMode(int)}
+ *
+ *
+ * @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/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/Settings.java b/project/javaSDL2/Settings.java
new file mode 100644
index 000000000..5fa4a6994
--- /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(); // TODO: Disabled in SDL2
+ 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