/* * ShareNav - Copyright (c) 2009 Kai Krueger apmonkey at users dot sourceforge dot net * Copyright (c) 2011,2012 Jyrki Kuoppala jkpj at users dot sourceforge dot net * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * See COPYING */ package net.sharenav.gps.location; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Date; import java.util.Random; import java.util.Timer; import java.util.TimerTask; import javax.microedition.io.Connector; import javax.microedition.io.HttpConnection; import javax.microedition.rms.RecordEnumeration; import javax.microedition.rms.RecordStore; //#if polish.api.locationapi import javax.microedition.location.LocationException; import javax.microedition.location.Orientation; //#endif //#if polish.android import java.util.List; import android.content.Context; import de.enough.polish.android.midlet.MidletBridge; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.hardware.SensorListener; //#endif import net.sharenav.midlet.ui.UploadListener; import net.sharenav.util.IntTree; import net.sharenav.util.Logger; import net.sharenav.util.StringTokenizer; import net.sharenav.sharenav.data.Configuration; import net.sharenav.sharenav.data.Position; import net.sharenav.sharenav.ui.ShareNav; import de.enough.polish.util.Locale; /** * Compass implementation * */ public class GetCompass implements CompassProducer { private static final int COMPASSMETHOD_NONE = 0; private static final int COMPASSMETHOD_SE = 1; private static final int COMPASSMETHOD_S60FP5 = 2; private static final int COMPASSMETHOD_MOTO = 3; private static final int COMPASSMETHOD_SOCKET = 4; private static final int COMPASSMETHOD_DEBUG = 5; private static final int COMPASSMETHOD_ANDROID = 6; private static final int COMPASSMETHOD_ORIENTATION = 7; private static GetCompass singelton; private static final Logger logger = Logger.getInstance(GetCompass.class, Logger.TRACE); protected Thread processorThread; protected CompassReceiverList receiverList; protected boolean closed = false; private String message; private RetrievePosition rp; //#if polish.android boolean sensorrunning = false; //#endif public boolean needsPolling = true; private int compassRetrievelMethod = -1; volatile float direction = 0.0f; static boolean inited = false; Compass cachedCompass = null; public void triggerLastKnownPositionUpdate() { } public void triggerPositionUpdate() { } public class RetrievePosition extends TimerTask { public void run() { Compass compass = null; try { if (closed) { this.cancel(); return; } compass = obtainCurrentCompass(); if (compass == null) { //#debug debug logger.debug("No compass direction available"); receiverList.receiveCompassStatus(0); return; } //#debug info logger.info("Obtained a compass reading " + compass.direction); receiverList.receiveCompassStatus(1); receiverList.receiveCompass(compass.direction); } catch (Exception e) { logger.silentexception("Could not retrieve compass direction", e); this.cancel(); close(Locale.get("getcompass.CompDirFailed")/*Compass direction retrieval failed*/); } } } public GetCompass() { this.receiverList = new CompassReceiverList(); } public void getCompassMethod() { //#debug info logger.info("Trying to find a suitable compass id provider"); //#if polish.android try { //#debug info logger.info("Trying to see if android method is available"); Compass compass = obtainAndroidCompass(); if (compass != null) { compassRetrievelMethod = COMPASSMETHOD_ANDROID; //#debug info logger.info(" Yes, the Android method works"); return; } else { //#debug info logger.info(" No, need to use a different method"); } } catch (Exception e) { logger.silentexception("Retrieving Compass as Android failed", e); //Nothing to do here, just fall through to the next method } //#endif try { //#debug info logger.info("Trying to see if Sony-Ericcson method is available"); //#debug info logger.info(" No, need to use a different method"); } catch (Exception e) { logger.silentexception("Retrieving Compass as a Sony-Ericsson failed", e); //Nothing to do here, just fall through to the next method } try { //#debug info logger.info("Trying to see if Motorola method is available"); //#debug info logger.info(" No, need to use a different method"); } catch (Exception e) { logger.silentexception("Retrieving Compass as a Motorola failed", e); //Nothing to do here, just fall through to the next method } try { //#debug info logger.info("Trying to see if Orientation method is available"); Compass compass = obtainOrientationCompass(); if (compass != null) { compassRetrievelMethod = COMPASSMETHOD_ORIENTATION; //#debug info logger.info(" Yes, the JSR179 Orientation class method works"); return; } else { //#debug info logger.info(" No, need to use a different method"); } } catch (Exception e) { logger.silentexception("Retrieving Compass with JSR179 Orientation class failed", e); //Nothing to do here, just fall through to the next method } try { //#debug info logger.info("Trying to see if there is a compassid server running on this device"); Compass compass = obtainSocketCompass(); // FIXME // compassRetrievelMethod = COMPASSMETHOD_SOCKET; if (compass != null) { compassRetrievelMethod = COMPASSMETHOD_SOCKET; logger.info(" Yes, there is a server running and we can get a compass from it"); return; } else { logger.info(" No, need to use a different method"); } } catch (Exception e) { logger.silentexception("Could not connect to socket", e); //Nothing to do here, just fall through to the next method } try { //#debug info logger.info("Trying to see if S60 3rd FP5 method is available"); Compass compass = obtainS60FP5Compass(); if (compass != null) { compassRetrievelMethod = COMPASSMETHOD_S60FP5; logger.info(" Yes, the S60 3rd FP5 method works"); return; } else { logger.info(" No, need to use a different method"); } } catch (Exception e) { logger.silentexception("Retrieving Compass as a Nokia S60 3rd FP2 failed", e); } compassRetrievelMethod = COMPASSMETHOD_NONE; //#debug info logger.error(Locale.get("compassprovider.NoMethodForCompass")/*No method of retrieving Compass is valid, can not use Compass*/); } public boolean init(CompassReceiver receiver) { getCompassMethod(); try { this.receiverList.addReceiver(receiver); if (obtainCurrentCompass() == null) { //#debug info logger.info("No valid compass direction, closing down"); //this.receiverList.locationDecoderEnd(Locale.get("getcompass.NoValidCompass")/*No valid compass direction*/); return false; } closed = false; return true; } catch (Exception e) { logger.silentexception("Could not retrieve compass direction", e); } //this.receiverList.locationDecoderEnd(Locale.get("getcompass.CompassFail")/*Can't use compass for direction*/); return false; } public void enableRawLogging(OutputStream os) { //rawDataLogger = os; } public void disableRawLogging() { } public boolean activate(CompassReceiver receiver) { Compass compass = null; try { compass = obtainCurrentCompass(); } catch (Exception e) { logger.silentexception("Could not retrieve compass direction", e); } if (compass == null) { //#debug debug logger.debug("No compass direction available"); receiverList.receiveCompassStatus(0); return false; } receiverList.receiveCompassStatus(1); receiverList.receiveCompass(compass.direction); if (needsPolling) { rp = new RetrievePosition(); ShareNav.getTimer().schedule(rp, 250, 250); } return true; } public boolean deactivate(CompassReceiver receiver) { return true; } public void close() { logger.info("Location producer closing"); closed = true; if (processorThread != null) processorThread.interrupt(); //receiverList.locationDecoderEnd(); } public void close(String message) { this.message = message; close(); } public void addCompassReceiver(CompassReceiver receiver) { receiverList.addReceiver(receiver); } public boolean removeCompassReceiver(CompassReceiver receiver) { return receiverList.removeReceiver(receiver); } public void setProgress(String message) { // TODO Auto-generated method stub } public void startProgress(String title) { // TODO Auto-generated method stub } public void updateProgress(String message) { // TODO Auto-generated method stub } public void updateProgressValue(int increment) { // TODO Auto-generated method stub } public void uploadAborted() { // TODO Auto-generated method stub } public synchronized static GetCompass getInstance() { if (singelton == null) { singelton = new GetCompass(); } return singelton; } //#if polish.android private Compass obtainAndroidCompass() { Compass compass = new Compass(); SensorManager mySensorManager = (SensorManager)MidletBridge.instance.getSystemService(Context.SENSOR_SERVICE); List<Sensor> mySensors = mySensorManager.getSensorList(Sensor.TYPE_ORIENTATION); if (mySensors.size() > 0) { mySensorManager.registerListener(mySensorEventListener, mySensors.get(0), SensorManager.SENSOR_DELAY_NORMAL); sensorrunning = true; needsPolling = false; } else { sensorrunning = false; } if (! inited) { // wait for compass try { Thread.sleep(200); } catch (Exception ex) {} inited = true; } compass.direction = direction; return compass; } private SensorEventListener mySensorEventListener = new SensorEventListener(){ @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { // handle accuracy here } @Override public void onSensorChanged(SensorEvent event) { Compass compass = new Compass(); compass.direction = event.values[0]; receiverList.receiveCompass(compass.direction); } }; //#endif private Compass obtainSECompass() { Compass compass = new Compass(); return null; } private Compass obtainS60FP5Compass() { Compass compass = new Compass(); return null; } private Compass obtainMotoCompass() { Compass compass = new Compass(); return null; } private Compass obtainOrientationCompass() { Compass compass = new Compass(); //#if polish.api.locationapi Orientation orientation; float azimuth; try { Class.forName("javax.microedition.location.Orientation"); orientation = Orientation.getOrientation(); compass.direction = orientation.getCompassAzimuth(); return compass; } catch (NullPointerException np) { // Calibration needed // FIXME signal this to the user, tell them to calibrate & try // again } catch (NoClassDefFoundError ncdfe) { //#debug info logger.info("JSR179 Orientation class for compass is not available"); } catch (LocationException le) { //#debug info logger.info("JSR179 Orientation class for compass is not available"); } catch (Exception e) { //#debug info logger.info("JSR179 Orientation class for compass is not available"); } //#endif return null; } private Compass obtainSocketCompass() { int retval; retval = SocketGateway.getSocketData(SocketGateway.TYPE_COMPASS); if (retval == SocketGateway.RETURN_OK) { return SocketGateway.getCompass(); } if (compassRetrievelMethod == COMPASSMETHOD_SOCKET && retval == SocketGateway.RETURN_IOE) { /* * The local helper daemon seems to have died. * No point in trying to continue trying, * as otherwise we will get an exception every time */ //compassRetrievelMethod = COMPASSMETHOD_NONE; return null; } return null; } private Compass obtainDebugCompass() { /* * This code is a stub for debugging compass data on the emulator */ Compass compass = new Compass(); Random r = new Random(); return null; } public Compass obtainCachedCompass() { return cachedCompass; } public Compass obtainCurrentCompass() throws Exception { //#debug info logger.info("Tring to retrieve compass-id"); if (compassRetrievelMethod == COMPASSMETHOD_NONE) { //#debug info logger.info("Can't retrieve Compass, as there is no valid method available"); return null; } if (compassRetrievelMethod == COMPASSMETHOD_SE) { cachedCompass = obtainSECompass(); } //#if polish.android if (compassRetrievelMethod == COMPASSMETHOD_ANDROID) { cachedCompass = obtainAndroidCompass(); } //#endif if (compassRetrievelMethod == COMPASSMETHOD_MOTO) { cachedCompass = obtainMotoCompass(); } if (compassRetrievelMethod == COMPASSMETHOD_S60FP5) { cachedCompass = obtainS60FP5Compass(); } if (compassRetrievelMethod == COMPASSMETHOD_ORIENTATION) { cachedCompass = obtainOrientationCompass(); } if (compassRetrievelMethod == COMPASSMETHOD_SOCKET) { cachedCompass = obtainSocketCompass(); } if (compassRetrievelMethod == COMPASSMETHOD_DEBUG) { cachedCompass = obtainDebugCompass(); } //#debug debug logger.debug("Retrieved " + cachedCompass); return cachedCompass; } }