package system; import geo.GeoObj; import geo.GeoUtils; import gl.GLCamera; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import listeners.eventManagerListeners.LocationEventListener; import listeners.eventManagerListeners.OrientationChangedListener; import listeners.eventManagerListeners.TrackBallEventListener; import util.Log; import android.app.Activity; import android.content.Context; import android.content.res.Configuration; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.location.Location; import android.location.LocationListener; import android.os.Bundle; import android.view.KeyEvent; import android.view.MotionEvent; import commands.Command; /** * this EventManager is attached to the main {@link Thread} and should react on * any kind of event or input * * @author Spobo * */ public class EventManager implements LocationListener, SensorEventListener { private static final String LOG_TAG = "Event Manager"; private static EventManager myInstance; public static boolean isTabletDevice = false; // all the predefined actions: protected List<TrackBallEventListener> onTrackballEventList; protected List<OrientationChangedListener> onOrientationChangedList; protected List<LocationEventListener> onLocationChangedList; public HashMap<Integer, Command> myOnKeyPressedCommandList; public List<LocationEventListener> getOnLocationChangedAction() { return onLocationChangedList; } public List<OrientationChangedListener> getOnOrientationChangedAction() { return onOrientationChangedList; } public List<TrackBallEventListener> getOnTrackballEventAction() { return onTrackballEventList; } private GeoObj zeroPos; private GeoObj currentLocation; private Activity myTargetActivity; public EventManager() { } /** * @param c * @param newInstance * pass a subclass of {@link EventManager} here */ public static final void initInstance(Context c, EventManager newInstance) { isTabletDevice = deviceHasLargeScreenAndOrientationFlipped(c); initInstance(newInstance); } public static EventManager getInstance() { if (myInstance == null) { Log.e(LOG_TAG, "EventManager instance was not initialized!"); initInstance(new EventManager()); } return myInstance; } private static void initInstance(EventManager instance) { myInstance = instance; } public void registerListeners(Activity targetActivity, boolean useAccelAndMagnetoSensors) { myTargetActivity = targetActivity; registerSensorUpdates(targetActivity, useAccelAndMagnetoSensors); registerLocationUpdates(); } protected void registerSensorUpdates(Activity myTargetActivity, boolean useAccelAndMagnetoSensors) { SensorManager sensorManager = (SensorManager) myTargetActivity .getSystemService(Context.SENSOR_SERVICE); if (useAccelAndMagnetoSensors) { /* * To register the EventManger for magnet- and accelerometer-sensor * events, two Sensor-objects have to be obtained and then the * EventManager is set as the Listener for these type of sensor * events. The update rate is set by SENSOR_DELAY_GAME to a high * frequency required to react on fast device movement */ Sensor magnetSensor = sensorManager .getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); sensorManager.registerListener(this, magnetSensor, SensorManager.SENSOR_DELAY_GAME); Sensor accelSensor = sensorManager .getDefaultSensor(Sensor.TYPE_ACCELEROMETER); sensorManager.registerListener(this, accelSensor, SensorManager.SENSOR_DELAY_GAME); Sensor sensorFusion = sensorManager .getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR); sensorManager.registerListener(this, sensorFusion, SensorManager.SENSOR_DELAY_GAME); } else { // Register orientation Sensor Listener: Sensor orientationSensor = sensorManager.getDefaultSensor(11);// Sensor.TYPE_ROTATION_VECTOR); sensorManager.registerListener(this, orientationSensor, SensorManager.SENSOR_DELAY_GAME); } } /** * This method will try to find the best location source available (probably * GPS if enabled). Remember to wait some seconds before calling this if you * activated GPS programmatically using {@link GeoUtils#enableGPS(Activity)} * * @return true if the Eventmanager was registered correctly */ public boolean registerLocationUpdates() { if (myTargetActivity == null) { Log.e(LOG_TAG, "The target activity was undefined while " + "trying to register for location updates"); } try { return SimpleLocationManager.getInstance(myTargetActivity) .requestLocationUpdates(this); } catch (Exception e) { Log.e(LOG_TAG, "There was an error registering the " + "EventManger for location-updates. The phone might be " + "in airplane-mode.."); e.printStackTrace(); } return false; } @Override public void onAccuracyChanged(Sensor s, int accuracy) { // Log.d("sensor onAccuracyChanged", arg0 + " " + arg1); } @Override public void onSensorChanged(SensorEvent event) { if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) { return; } float[] values = event.values.clone(); if (onOrientationChangedList != null) { for (int i = 0; i < onOrientationChangedList.size(); i++) { if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { onOrientationChangedList.get(i).onAccelChanged(values); } if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) { onOrientationChangedList.get(i).onMagnetChanged(values); } // else sensor input is set to orientation mode if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) { onOrientationChangedList.get(i) .onOrientationChanged(values); } } } } @Override public void onLocationChanged(Location location) { if (onLocationChangedList != null) { for (int i = 0; i < onLocationChangedList.size(); i++) { LocationEventListener l = onLocationChangedList.get(i); if (!l.onLocationChanged(location)) { Log.w(LOG_TAG, "Action " + l + " returned false so it will be " + "removed from the location listener list!"); getOnLocationChangedAction().remove(l); } } } } @Override public void onProviderDisabled(String provider) { Log.w(LOG_TAG, "Didnt handle onProviderDisabled of " + provider); } @Override public void onProviderEnabled(String provider) { Log.w(LOG_TAG, "Didnt handle onProviderEnabled of " + provider); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { Log.i(LOG_TAG, "Status change of " + provider + ": " + status); if (myTargetActivity != null) { if (!registerLocationUpdates()) { Log.d(LOG_TAG, "EventManager was already contained in " + "to the listener list of SimpleLocationManager"); } } else { Log.w(LOG_TAG, "Didnt handle onStatusChanged of " + provider + "(status=" + status + ")"); } } public void addOnOrientationChangedAction(OrientationChangedListener action) { Log.d(LOG_TAG, "Adding onOrientationChangedAction"); if (onOrientationChangedList == null) { onOrientationChangedList = new ArrayList<OrientationChangedListener>(); } onOrientationChangedList.add(action); } public void addOnTrackballAction(TrackBallEventListener action) { Log.d(LOG_TAG, "Adding onTouchMoveAction"); if (onTrackballEventList == null) { onTrackballEventList = new ArrayList<TrackBallEventListener>(); } onTrackballEventList.add(action); } public void addOnLocationChangedAction(LocationEventListener action) { Log.d(LOG_TAG, "Adding onLocationChangedAction"); if (onLocationChangedList == null) { onLocationChangedList = new ArrayList<LocationEventListener>(); } onLocationChangedList.add(action); } public void addOnKeyPressedCommand(int keycode, Command c) { if (myOnKeyPressedCommandList == null) { myOnKeyPressedCommandList = new HashMap<Integer, Command>(); } myOnKeyPressedCommandList.put(keycode, c); } public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode >= 19 && keyCode <= 22) { /* * if the keycode is on of the numbers from 19 to 22 it is a pseudo * trackball event (eg the motorola milestone has pseudo trackball). * here hare the codes (lets hope they are the same on each phone;): * * top=19 down=20 left=21 right=22 */ if (onTrackballEventList != null) { final float stepLength = 0.3f; float x = 0, y = 0; switch (keyCode) { case 19: y = -stepLength; break; case 20: y = stepLength; break; case 21: x = -stepLength; break; case 22: x = stepLength; break; } boolean result = true; for (int i = 0; i < onTrackballEventList.size(); i++) { result &= onTrackballEventList.get(i).onTrackballEvent(x, y, null); } return result; } return false; } if (myOnKeyPressedCommandList == null) { return false; } Command commandForThisKey = myOnKeyPressedCommandList.get(keyCode); if (commandForThisKey != null) { Log.d("Command", "Key with command was pressed so executing " + commandForThisKey); return commandForThisKey.execute(); } return false; } /** * This will return the current position of the device according to the * Android system values. * * The resulting coordinates can differ from * {@link GLCamera#getGPSLocation()} if the camera was not moved according * to the GPS input (eg moved via trackball). * * Also check the {@link EventManager#getZeroPositionLocationObject()} * method, if you want to know where the virtual zero position (of the * OpenGL world) is. */ public GeoObj getCurrentLocationObject() { Location locaction = getCurrentLocation(); if (locaction != null) { if (currentLocation == null) { currentLocation = new GeoObj(locaction, false); } else { currentLocation.setLocation(locaction); } return currentLocation; } else { Log.e(LOG_TAG, "Couldn't receive Location object for current location"); } // if its still null set it to a default geo-object: if (currentLocation == null) { Log.e(LOG_TAG, "Current position set to default 0,0 position"); currentLocation = new GeoObj(false); } return currentLocation; } /** * use SimpleLocationManager.getCurrentLocation(Context) instead This method * will try to get the most accurate position currently available. This * includes also the last known position of the device if no current * position sources can't be accessed so the returned position might be * outdated * * Uses {@link GeoUtils#getCurrentLocation(Context)}. <br> * <br> * If you need permanent location updates better create a * {@link LocationEventListener} and register it at * {@link EventManager#addOnLocationChangedAction(LocationEventListener)} * instead of calling this method here frequently. * * @return */ @Deprecated public Location getCurrentLocation() { return GeoUtils.getCurrentLocation(myTargetActivity); } // /** // * The Android system will be asked directly and if the external location // * manager knows where the device is located at the moment, this location // * will be returned // * // * @return a new {@link GeoObj} or null if there could be no current // * location calculated // */ // public GeoObj getNewCurrentLocationObjectFromSystem() { // return getAutoupdatingCurrentLocationObjectFromSystem().copy(); // } public boolean onTrackballEvent(MotionEvent event) { if (onTrackballEventList != null) { boolean result = true; for (int i = 0; i < onTrackballEventList.size(); i++) { result &= onTrackballEventList.get(i).onTrackballEvent( event.getX(), event.getY(), event); } return result; } return false; } @Deprecated public void setCurrentLocation(Location location) { currentLocation.setLocation(location); } /** * This method returns true if the device is a tablet, can be used to handle * the different default orientation * * @param c * @return */ public static boolean deviceHasLargeScreenAndOrientationFlipped(Context c) { /* * Configuration.SCREENLAYOUT_SIZE_XLARGE only available for higher * Android versions, constant value is 4 so hardcoded here */ int Configuration_SCREENLAYOUT_SIZE_XLARGE = 4; return (c.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration_SCREENLAYOUT_SIZE_XLARGE; } /** * This method differs from the normal * {@link EventManager#getCurrentLocationObject()} because it will return * the geoPos of the virtual (0,0,0) position. The other method would return * the current device position (and because of this also the current camera * position) * * @return the zero position. This will NOT be a copy so do not modify it! */ public GeoObj getZeroPositionLocationObject() { if (zeroPos == null) { Log.d(LOG_TAG, "Zero pos was not yet received! " + "The last known position of the device will be used " + "at the zero position."); zeroPos = getCurrentLocationObject().copy(); } return zeroPos; } public void setZeroLocation(Location location) { if (zeroPos == null) { zeroPos = new GeoObj(location); } else { zeroPos.setLocation(location); } } public void resumeEventListeners(Activity targetActivity, boolean useAccelAndMagnetoSensors) { registerListeners(targetActivity, useAccelAndMagnetoSensors); } public void pauseEventListeners() { SensorManager sensorManager = (SensorManager) myTargetActivity .getSystemService(Context.SENSOR_SERVICE); sensorManager.unregisterListener(this); SimpleLocationManager.getInstance(myTargetActivity) .pauseLocationManagerUpdates(); } /** * see {@link SimpleLocationManager#setMaxNrOfBufferedLocations(int)} * * @param maxNrOfBufferedLocations */ public void setMaxNrOfBufferedLocations(int maxNrOfBufferedLocations) { SimpleLocationManager.getInstance(myTargetActivity) .setMaxNrOfBufferedLocations(maxNrOfBufferedLocations); } }