From 0ea01bface51acef15a83fd8b5ca2d150d1331f6 Mon Sep 17 00:00:00 2001 From: pelya Date: Sat, 2 Feb 2013 21:50:14 +0200 Subject: [PATCH] Dialog to calibrate gyroscope --- changeAppSettings.sh | 6 +- project/java/Accelerometer.java | 36 +++- project/java/Globals.java | 4 +- project/java/Settings.java | 165 ++++++++++++++++++ project/java/translations/values/strings.xml | 3 + .../openarena/AndroidAppSettings.cfg | 2 +- project/project.properties | 2 +- readme.txt | 4 +- 8 files changed, 208 insertions(+), 14 deletions(-) diff --git a/changeAppSettings.sh b/changeAppSettings.sh index 9613863ad..e20904d5f 100755 --- a/changeAppSettings.sh +++ b/changeAppSettings.sh @@ -435,7 +435,7 @@ if [ -n "$var" ] ; then fi fi -FirstStartMenuOptionsDefault='(AppUsesMouse \&\& \! ForceRelativeMouseMode ? new Settings.DisplaySizeConfig(true) : new Settings.DummyMenu()), new Settings.OptionalDownloadConfig(true)' +FirstStartMenuOptionsDefault='(AppUsesMouse \&\& \! ForceRelativeMouseMode ? new Settings.DisplaySizeConfig(true) : new Settings.DummyMenu()), new Settings.OptionalDownloadConfig(true), new Settings.GyroscopeCalibration()' if [ -z "$AUTO" ]; then echo echo "Menu items to show at startup - this is Java code snippet, leave empty for default" @@ -929,8 +929,8 @@ mkdir -p project/src cd project/java for F in *.java; do echo Patching $F - echo '// DO NOT EDIT THIS FILE - it is automatically generated, edit file under project/java dir' > ../src/$F - cat $F | sed "s/package .*;/package $AppFullName;/" >> ../src/$F + echo '// DO NOT EDIT THIS FILE - it is automatically generated, ALL YOUR CHANGES WILL BE OVERWRITTEN, edit the file under project/java dir' > ../src/$F + cat $F | sed "s/package .*;/package $AppFullName;/" >> ../src/$F # | sed 's@$@ // THIS FILE IS AUTO-GENERATED@' >> done cd ../.. diff --git a/project/java/Accelerometer.java b/project/java/Accelerometer.java index 005a71f8f..0e054aecf 100644 --- a/project/java/Accelerometer.java +++ b/project/java/Accelerometer.java @@ -42,7 +42,7 @@ class AccelerometerReader implements SensorEventListener private SensorManager _manager = null; public boolean openedBySDL = false; - private final GyroscopeListener gyro = new GyroscopeListener(); + public static final GyroscopeListener gyro = new GyroscopeListener(); public AccelerometerReader(Activity context) { @@ -61,12 +61,13 @@ class AccelerometerReader implements SensorEventListener public synchronized void start() { - if( (Globals.UseAccelerometerAsArrowKeys || Globals.AppUsesAccelerometer) && _manager != null ) + if( (Globals.UseAccelerometerAsArrowKeys || Globals.AppUsesAccelerometer) && + _manager != null && _manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null ) { System.out.println("libSDL: starting accelerometer"); _manager.registerListener(this, _manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_GAME); } - if( Globals.AppUsesGyroscope && _manager != null ) + if( Globals.AppUsesGyroscope && _manager != null && _manager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) != null ) { System.out.println("libSDL: starting gyroscope"); _manager.registerListener(gyro, _manager.getDefaultSensor(Sensor.TYPE_GYROSCOPE), SensorManager.SENSOR_DELAY_GAME); @@ -84,8 +85,9 @@ class AccelerometerReader implements SensorEventListener { } - class GyroscopeListener implements SensorEventListener + static class GyroscopeListener implements SensorEventListener { + public float x1, x2, xc, y1, y2, yc, z1, z2, zc; public GyroscopeListener() { } @@ -93,11 +95,33 @@ class AccelerometerReader implements SensorEventListener { // TODO: vertical orientation //if( Globals.HorizontalOrientation ) - nativeGyroscope(event.values[0], event.values[1], event.values[2]); + 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 synchronized void onAccuracyChanged(Sensor s, int a) + 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); diff --git a/project/java/Globals.java b/project/java/Globals.java index ae5600cb7..0f455ff2b 100644 --- a/project/java/Globals.java +++ b/project/java/Globals.java @@ -64,7 +64,7 @@ class Globals public static int StartupMenuButtonTimeout = 3000; public static int AppMinimumRAM = 0; public static Settings.Menu HiddenMenuOptions [] = {}; - public static Settings.Menu FirstStartMenuOptions [] = { (AppUsesMouse && ! ForceRelativeMouseMode ? new Settings.DisplaySizeConfig(true) : new Settings.DummyMenu()), new Settings.OptionalDownloadConfig(true) }; + public static Settings.Menu FirstStartMenuOptions [] = { (AppUsesMouse && ! ForceRelativeMouseMode ? new Settings.DisplaySizeConfig(true) : new Settings.DummyMenu()), new Settings.OptionalDownloadConfig(true), new Settings.GyroscopeCalibration() }; public static String AdmobPublisherId = ""; public static String AdmobTestDeviceId = ""; public static String AdmobBannerSize = ""; @@ -113,4 +113,6 @@ class Globals public static boolean VideoLinearFilter = true; public static boolean MultiThreadedVideo = false; public static boolean BrokenLibCMessageShown = false; + // Gyroscope calibration + public static float gyro_x1, gyro_x2, gyro_xc, gyro_y1, gyro_y2, gyro_yc, gyro_z1, gyro_z2, gyro_zc; } diff --git a/project/java/Settings.java b/project/java/Settings.java index 11e30a543..1680881a4 100644 --- a/project/java/Settings.java +++ b/project/java/Settings.java @@ -67,6 +67,9 @@ import android.util.DisplayMetrics; import android.net.Uri; import java.util.concurrent.Semaphore; import android.graphics.Color; +import android.hardware.SensorEventListener; +import android.hardware.SensorEvent; +import android.hardware.Sensor; // TODO: too much code here, split into multiple files, possibly auto-generated menus? class Settings @@ -154,6 +157,15 @@ class Settings 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.close(); settingsLoaded = true; @@ -300,6 +312,15 @@ class Settings 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(); settingsLoaded = true; @@ -531,6 +552,7 @@ class Settings new MouseConfigMainMenu(), new ArrowKeysConfig(), new AccelerometerConfig(), + new GyroscopeCalibration(), new AudioConfig(), new RemapHwKeysConfig(), new ScreenGesturesConfig(), @@ -2486,6 +2508,149 @@ class Settings } } + static class GyroscopeCalibration extends Menu implements SensorEventListener + { + String title(final MainActivity p) + { + return p.getResources().getString(R.string.calibrate_gyroscope); + } + boolean enabled() + { + return Globals.AppUsesGyroscope; + } + void run (final MainActivity p) + { + if( !Globals.AppUsesGyroscope || !AccelerometerReader.gyro.available(p) ) + { + goBack(p); + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(p); + builder.setTitle(p.getResources().getString(R.string.calibrate_gyroscope)); + builder.setMessage(p.getResources().getString(R.string.calibrate_gyroscope_text)); + builder.setPositiveButton(p.getResources().getString(R.string.ok), new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int item) + { + dialog.dismiss(); + startCalibration(p); + } + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() + { + public void onCancel(DialogInterface dialog) + { + goBack(p); + } + }); + AlertDialog alert = builder.create(); + alert.setOwnerActivity(p); + alert.show(); + } + + ImageView img; + Bitmap bmp; + int numEvents; + MainActivity p; + + void startCalibration(final MainActivity _p) + { + p = _p; + img = new ImageView(p); + img.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + img.setScaleType(ImageView.ScaleType.MATRIX); + bmp = BitmapFactory.decodeResource( p.getResources(), R.drawable.calibrate ); + img.setImageBitmap(bmp); + Matrix m = new Matrix(); + RectF src = new RectF(0, 0, bmp.getWidth(), bmp.getHeight()); + RectF dst = new RectF( p.getVideoLayout().getWidth()/2 - 50, p.getVideoLayout().getHeight()/2 - 50, + p.getVideoLayout().getWidth()/2 + 50, p.getVideoLayout().getHeight()/2 + 50); + m.setRectToRect(src, dst, Matrix.ScaleToFit.FILL); + img.setImageMatrix(m); + p.getVideoLayout().addView(img); + numEvents = 0; + AccelerometerReader.gyro.x1 = 0; + AccelerometerReader.gyro.x2 = 0; + AccelerometerReader.gyro.xc = 0; + AccelerometerReader.gyro.y1 = 0; + AccelerometerReader.gyro.y2 = 0; + AccelerometerReader.gyro.yc = 0; + AccelerometerReader.gyro.z1 = 0; + AccelerometerReader.gyro.z2 = 0; + AccelerometerReader.gyro.zc = 0; + AccelerometerReader.gyro.registerListener(p, this); + (new Thread(new Runnable() + { + public void run() + { + for(int count = 1; count < 10; count++) + { + p.setText("" + count + "0% ..."); + try { + Thread.sleep(500); + } catch( Exception e ) {} + } + finishCalibration(p); + } + } + )).start(); + } + + public void onSensorChanged(SensorEvent event) + { + gyroscopeEvent(event.values[0], event.values[1], event.values[2]); + } + public void onAccuracyChanged(Sensor s, int a) + { + } + void gyroscopeEvent(float x, float y, float z) + { + numEvents++; + AccelerometerReader.gyro.xc += x; + AccelerometerReader.gyro.yc += y; + AccelerometerReader.gyro.zc += z; + AccelerometerReader.gyro.x1 = Math.min(AccelerometerReader.gyro.x1, x); + AccelerometerReader.gyro.x2 = Math.max(AccelerometerReader.gyro.x2, x); + AccelerometerReader.gyro.y1 = Math.min(AccelerometerReader.gyro.y1, y); + AccelerometerReader.gyro.y2 = Math.max(AccelerometerReader.gyro.y2, y); + AccelerometerReader.gyro.z1 = Math.min(AccelerometerReader.gyro.z1, z); + AccelerometerReader.gyro.z2 = Math.max(AccelerometerReader.gyro.z2, z); + final Matrix m = new Matrix(); + RectF src = new RectF(0, 0, bmp.getWidth(), bmp.getHeight()); + RectF dst = new RectF( x * 5000 + p.getVideoLayout().getWidth()/2 - 50, y * 5000 + p.getVideoLayout().getHeight()/2 - 50, + x * 5000 + p.getVideoLayout().getWidth()/2 + 50, y * 5000 + p.getVideoLayout().getHeight()/2 + 50); + m.setRectToRect(src, dst, Matrix.ScaleToFit.FILL); + p.runOnUiThread(new Runnable() + { + public void run() + { + img.setImageMatrix(m); + } + }); + } + void finishCalibration(final MainActivity p) + { + AccelerometerReader.gyro.unregisterListener(p, this); + try { + Thread.sleep(200); // Just in case we have pending events + } catch( Exception e ) {} + if( numEvents > 0 ) + { + AccelerometerReader.gyro.xc /= (float)numEvents; + AccelerometerReader.gyro.yc /= (float)numEvents; + AccelerometerReader.gyro.zc /= (float)numEvents; + } + p.runOnUiThread(new Runnable() + { + public void run() + { + p.getVideoLayout().removeView(img); + goBack(p); + } + }); + } + } + // =============================================================================================== public static boolean deleteRecursively(File dir) diff --git a/project/java/translations/values/strings.xml b/project/java/translations/values/strings.xml index 1fc80518a..9d06e3506 100644 --- a/project/java/translations/values/strings.xml +++ b/project/java/translations/values/strings.xml @@ -165,4 +165,7 @@ This app needs %1$d Mb RAM, your device has %2$d Mb Ignore + Calibrate gyroscope + Put your phone on a flat surface + diff --git a/project/jni/application/openarena/AndroidAppSettings.cfg b/project/jni/application/openarena/AndroidAppSettings.cfg index 2ea88666d..a12dfef0c 100644 --- a/project/jni/application/openarena/AndroidAppSettings.cfg +++ b/project/jni/application/openarena/AndroidAppSettings.cfg @@ -41,7 +41,7 @@ MultiABI=y AppMinimumRAM=300 AppVersionCode=08819 AppVersionName="0.8.8.19" -ResetSdlConfigForThisVersion=y +ResetSdlConfigForThisVersion=n DeleteFilesOnUpgrade="libsdl-DownloadFinished-10.flag" CompiledLibraries="sdl_mixer sdl_image freetype curl vorbis ogg" CustomBuildScript=y diff --git a/project/project.properties b/project/project.properties index 0840b4a05..a3ee5ab64 100644 --- a/project/project.properties +++ b/project/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-15 +target=android-17 diff --git a/readme.txt b/readme.txt index 7bb85dbcd..1c77799f2 100644 --- a/readme.txt +++ b/readme.txt @@ -10,10 +10,10 @@ Also this port is developed very slowly, although the same is true for an offici Installation ============ -This project should be compiled with Android 3.1 SDK (API level 15) and NDK r8, r7c, r6 or r5c, +This project should be compiled with Android 4.2 SDK (API level 17) and NDK r8, r7c, r6 or r5c, google for them and install them as described in their docs. You'll need to install Java Ant too. -The application will run on Android OS 1.6 and above, don't mind the 3.1 dependency. +The application will run on Android OS 1.6 and above, but will use features from Android 4.2 if available. Also it's compatible with NDK r4b and all versions of CrystaX NDK starting from r4b. CrystaX NDK adds support for wide chars, and required if you want to use Boost libraries. http://www.crystax.net/android/ndk.php