forked from jens/Automation
Initial commit
This commit is contained in:
@ -0,0 +1,407 @@
|
||||
package com.jens.automation2.location;
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.Criteria;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import android.location.LocationManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.telephony.CellLocation;
|
||||
import android.telephony.PhoneStateListener;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.jens.automation2.Action;
|
||||
import com.jens.automation2.ActivityPermissions;
|
||||
import com.jens.automation2.AutomationService;
|
||||
import com.jens.automation2.Miscellaneous;
|
||||
import com.jens.automation2.PointOfInterest;
|
||||
import com.jens.automation2.R;
|
||||
import com.jens.automation2.Rule;
|
||||
import com.jens.automation2.Settings;
|
||||
import com.jens.automation2.receivers.ConnectivityReceiver;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class CellLocationChangedReceiver extends PhoneStateListener
|
||||
{
|
||||
private LocationManager myLocationManager;
|
||||
private Location currentLocation;
|
||||
public MyLocationListener myLocationListener = new MyLocationListener();
|
||||
public Boolean locationListenerArmed = false;
|
||||
public Date lastCellLocationUpdate;
|
||||
protected static boolean followUpdate = true;
|
||||
protected static TimeoutHandler timeoutHandler = null;
|
||||
protected static boolean timeoutHandlerActive = false;
|
||||
protected static boolean cellLocationListenerActive = false;
|
||||
protected static CellLocationChangedReceiver instance;
|
||||
protected static TelephonyManager telephonyManager;
|
||||
|
||||
public static boolean isCellLocationListenerActive()
|
||||
{
|
||||
return cellLocationListenerActive;
|
||||
}
|
||||
|
||||
protected static CellLocationChangedReceiver getInstance()
|
||||
{
|
||||
if(instance == null)
|
||||
instance = new CellLocationChangedReceiver();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCellLocationChanged(CellLocation location)
|
||||
{
|
||||
super.onCellLocationChanged(location);
|
||||
|
||||
if(Settings.useAccelerometerForPositioning)
|
||||
SensorActivity.startAccelerometerTimer();
|
||||
|
||||
if(followUpdate)
|
||||
{
|
||||
Date currentDate = new Date();
|
||||
|
||||
Miscellaneous.logEvent("i", "CellLocation", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.cellMastChanged), location.toString()), 3);
|
||||
|
||||
if(Settings.useAccelerometerForPositioning) //and last cell mast change longer than x minutes in the past
|
||||
{
|
||||
PointOfInterest possiblyActivePoi = PointOfInterest.getActivePoi();
|
||||
if( possiblyActivePoi != null ) //if any poi is active
|
||||
{
|
||||
// Did the last activated rule activate wifi? Then we don't need accelerometer, we'll use wifiReceiver
|
||||
try
|
||||
{
|
||||
for(Action action : Rule.getLastActivatedRule().getActionSet())
|
||||
{
|
||||
if(action.getAction() == Action.Action_Enum.turnWifiOn)
|
||||
{
|
||||
// we will be using wifiReceiver, deactivate AccelerometerTimer if applicable
|
||||
SensorActivity.stopAccelerometerTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(NullPointerException ne)
|
||||
{
|
||||
// Nothing to do, there is no last activated rule. Wifi hasn't been activated so we don't
|
||||
// deactive accelerometer receiver.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(lastCellLocationUpdate == null)
|
||||
SensorActivity.startAccelerometerTimer();
|
||||
else
|
||||
{
|
||||
long timeSinceLastUpdate = currentDate.getTime() - lastCellLocationUpdate.getTime(); //in milliseconds
|
||||
if(timeSinceLastUpdate > Settings.useAccelerometerAfterIdleTime*60*1000)
|
||||
{
|
||||
SensorActivity.startAccelerometerTimer();
|
||||
}
|
||||
else
|
||||
{
|
||||
//reset timer
|
||||
SensorActivity.resetAccelerometerTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lastCellLocationUpdate = currentDate;
|
||||
|
||||
myLocationManager = (LocationManager) AutomationService.getInstance().getSystemService(Context.LOCATION_SERVICE);
|
||||
currentLocation = getLocation("coarse");
|
||||
AutomationService.getInstance().getLocationProvider().setCurrentLocation(currentLocation, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", "CellLocation", "Cell mast changed, but only initial update, ignoring this one.", 4);
|
||||
followUpdate = true; //for next run
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Location getLocation(String accuracy)
|
||||
{
|
||||
Criteria crit = new Criteria();
|
||||
|
||||
String myProviderName;
|
||||
|
||||
// If privacy mode or no data connection available
|
||||
if(Settings.privacyLocationing | !ConnectivityReceiver.isDataConnectionAvailable(AutomationService.getInstance()))
|
||||
{
|
||||
Miscellaneous.logEvent("i", "CellLocation", Miscellaneous.getAnyContext().getResources().getString(R.string.enforcingGps), 4);
|
||||
myProviderName = LocationManager.GPS_PROVIDER;
|
||||
}
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", "CellLocation", Miscellaneous.getAnyContext().getResources().getString(R.string.notEnforcingGps), 4);
|
||||
|
||||
if(accuracy.equals("coarse"))
|
||||
{
|
||||
crit.setPowerRequirement(Criteria.POWER_LOW);
|
||||
crit.setAltitudeRequired(false);
|
||||
crit.setSpeedRequired(false);
|
||||
crit.setBearingRequired(false);
|
||||
crit.setCostAllowed(false);
|
||||
crit.setAccuracy(Criteria.ACCURACY_COARSE);
|
||||
}
|
||||
else //equals "fine"
|
||||
{
|
||||
crit.setPowerRequirement(Criteria.POWER_LOW);
|
||||
crit.setAltitudeRequired(false);
|
||||
crit.setSpeedRequired(false);
|
||||
crit.setBearingRequired(false);
|
||||
//crit.setCostAllowed(false);
|
||||
crit.setAccuracy(Criteria.ACCURACY_FINE);
|
||||
}
|
||||
|
||||
myProviderName = myLocationManager.getBestProvider(crit, true);
|
||||
}
|
||||
|
||||
if(myProviderName == null)
|
||||
{
|
||||
Toast.makeText(Miscellaneous.getAnyContext(), "No suitable location provider could be used.", Toast.LENGTH_LONG).show();
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!myLocationManager.isProviderEnabled(myProviderName))
|
||||
{
|
||||
if(myProviderName.equals(LocationManager.NETWORK_PROVIDER))
|
||||
myProviderName = LocationManager.GPS_PROVIDER;
|
||||
}
|
||||
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
||||
myProviderName = LocationManager.GPS_PROVIDER;
|
||||
|
||||
// Arm location updates
|
||||
if(!locationListenerArmed)
|
||||
startLocationListener(myProviderName);
|
||||
|
||||
try
|
||||
{
|
||||
return myLocationManager.getLastKnownLocation(myProviderName);
|
||||
}
|
||||
catch(NullPointerException e)
|
||||
{
|
||||
Toast.makeText(Miscellaneous.getAnyContext(), "No last known location. Aborting...", Toast.LENGTH_LONG).show();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startLocationListener(String providerToBeUsed)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "LocationListener", "Arming location listener, Provider " + providerToBeUsed, 4);
|
||||
myLocationManager.requestLocationUpdates(providerToBeUsed, Settings.minimumTimeBetweenUpdate, Settings.minimumDistanceChangeForNetworkUpdate, myLocationListener);
|
||||
locationListenerArmed = true;
|
||||
|
||||
// (re)set timeout
|
||||
if(timeoutHandlerActive)
|
||||
stopTimeOutHandler();
|
||||
startTimeOutHandler();
|
||||
}
|
||||
private void stopLocationListener()
|
||||
{
|
||||
Miscellaneous.logEvent("i", "LocationListener", "Disarming location listener.", 4);
|
||||
myLocationManager.removeUpdates(myLocationListener);
|
||||
locationListenerArmed = false;
|
||||
|
||||
if(timeoutHandlerActive)
|
||||
stopTimeOutHandler();
|
||||
}
|
||||
|
||||
public Location getCurrentLocation()
|
||||
{
|
||||
return currentLocation;
|
||||
}
|
||||
|
||||
|
||||
public void setCurrentLocation(Location currentLocation)
|
||||
{
|
||||
this.currentLocation = currentLocation;
|
||||
}
|
||||
|
||||
|
||||
public class MyLocationListener implements LocationListener
|
||||
{
|
||||
@Override
|
||||
public void onLocationChanged(Location up2DateLocation)
|
||||
{
|
||||
if(timeoutHandlerActive)
|
||||
{
|
||||
stopTimeOutHandler();
|
||||
}
|
||||
|
||||
setCurrentLocation(up2DateLocation);
|
||||
AutomationService.getInstance().getLocationProvider().setCurrentLocation(up2DateLocation, false);
|
||||
// This is relevant if the program just started, knows where it is, but hasn't reached any POI.
|
||||
// The below PointOfInterest.positionUpdate() will not update the notification in that case.
|
||||
// if(!currentLocation.equals(up2DateLocation))
|
||||
// parentLocationProvider.parentService.updateNotification();
|
||||
|
||||
if(up2DateLocation.getAccuracy() < Settings.satisfactoryAccuracyNetwork)
|
||||
{
|
||||
myLocationManager.removeUpdates(this);
|
||||
locationListenerArmed = false;
|
||||
Miscellaneous.logEvent("i", "LocationListener", "Disarmed location listener, accuracy reached", 4);
|
||||
}
|
||||
|
||||
// Miscellaneous.logEvent("i", "LocationListener", "Giving update to POI class");
|
||||
// PointOfInterest.positionUpdate(up2DateLocation, parentLocationProvider.parentService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderDisabled(String provider)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderEnabled(String provider)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class TimeoutHandler extends Handler
|
||||
{
|
||||
@Override
|
||||
public void handleMessage(Message msg)
|
||||
{
|
||||
super.handleMessage(msg);
|
||||
|
||||
if(msg.what == 1)
|
||||
{
|
||||
Context context = Miscellaneous.getAnyContext();
|
||||
Miscellaneous.logEvent("i", context.getResources().getString(R.string.gpsMeasurement), context.getResources().getString(R.string.gpsMeasurementTimeout), 4);
|
||||
stopLocationListener();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startTimeOutHandler()
|
||||
{
|
||||
if(timeoutHandler == null)
|
||||
timeoutHandler = new TimeoutHandler();
|
||||
|
||||
Message message = new Message();
|
||||
message.what = 1;
|
||||
timeoutHandler.sendMessageDelayed(message, Settings.gpsTimeout * 1000);
|
||||
timeoutHandlerActive = true;
|
||||
}
|
||||
private void stopTimeOutHandler()
|
||||
{
|
||||
if(timeoutHandler == null)
|
||||
timeoutHandler = new TimeoutHandler();
|
||||
|
||||
timeoutHandler.removeMessages(1);
|
||||
timeoutHandlerActive = false;
|
||||
}
|
||||
|
||||
public static void startCellLocationChangedReceiver()
|
||||
{
|
||||
if(telephonyManager == null)
|
||||
telephonyManager = (TelephonyManager) AutomationService.getInstance().getSystemService(Context.TELEPHONY_SERVICE);
|
||||
|
||||
try
|
||||
{
|
||||
if(!cellLocationListenerActive)
|
||||
{
|
||||
if(!ConnectivityReceiver.isAirplaneMode(AutomationService.getInstance()))
|
||||
{
|
||||
if(WifiBroadcastReceiver.mayCellLocationReceiverBeActivated())
|
||||
{
|
||||
// if(!ConnectivityReceiver.isDataConnectionAvailable(parentService))
|
||||
// {
|
||||
telephonyManager.listen(getInstance(), PhoneStateListener.LISTEN_CELL_LOCATION);
|
||||
cellLocationListenerActive = true;
|
||||
Miscellaneous.logEvent("i", "cellReceiver", "Starting cellLocationListener", 4);
|
||||
|
||||
SensorActivity.stopAccelerometerTimer();
|
||||
SensorActivity.stopAccelerometerReceiver();
|
||||
// this.stopWifiReceiver();
|
||||
|
||||
/*
|
||||
We could now set a timer when we could activate a location check.
|
||||
If that fires we need to check if maybe another location check has been performed.
|
||||
*/
|
||||
|
||||
if(!LocationProvider.speedTimerActive)
|
||||
LocationProvider.startSpeedTimer(LocationProvider.getEtaAtNextPoi());
|
||||
// }
|
||||
// else
|
||||
// Miscellaneous.logEvent("i", "cellReceiver", "Not starting cellLocationListener because we have no data connection.", 4);
|
||||
}
|
||||
else
|
||||
Miscellaneous.logEvent("w", "cellReceiver", "Wanted to activate CellLocationChangedReceiver, but Wifi-Receiver says not to.", 4);
|
||||
}
|
||||
else
|
||||
Miscellaneous.logEvent("i", "cellReceiver", "Not starting cellLocationListener because Airplane mode is active.", 4);
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "Wifi Listener", "Error starting cellLocationListener: " + Log.getStackTraceString(ex), 3);
|
||||
}
|
||||
}
|
||||
|
||||
public static void stopCellLocationChangedReceiver()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(cellLocationListenerActive)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "cellReceiver", "Stopping cellLocationListener", 4);
|
||||
|
||||
getInstance().stopTimeOutHandler();
|
||||
getInstance().stopLocationListener();
|
||||
|
||||
if(LocationProvider.speedTimerActive)
|
||||
LocationProvider.stopSpeedTimer();
|
||||
|
||||
telephonyManager.listen(instance, PhoneStateListener.LISTEN_NONE);
|
||||
cellLocationListenerActive = false;
|
||||
|
||||
// May have comparison measurements active.
|
||||
PointOfInterest.stopRoutine();
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "Wifi Listener", "Error stopping cellLocationListener: " + Log.getStackTraceString(ex), 3);
|
||||
}
|
||||
}
|
||||
|
||||
public static void resetFollowUpdate()
|
||||
{
|
||||
followUpdate = false;
|
||||
}
|
||||
|
||||
public static boolean haveAllPermission()
|
||||
{
|
||||
return ActivityPermissions.havePermission("android.permission.ACCESS_FINE_LOCATION", Miscellaneous.getAnyContext())
|
||||
&&
|
||||
ActivityPermissions.havePermission("android.permission.ACCESS_COARSE_LOCATION", Miscellaneous.getAnyContext())
|
||||
&&
|
||||
ActivityPermissions.havePermission("android.permission.ACCESS_NETWORK_STATE", Miscellaneous.getAnyContext())
|
||||
&&
|
||||
ActivityPermissions.havePermission("android.permission.INTERNET", Miscellaneous.getAnyContext())
|
||||
&&
|
||||
ActivityPermissions.havePermission("android.permission.ACCESS_WIFI_STATE", Miscellaneous.getAnyContext());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
package com.jens.automation2.location;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.location.Geofence;
|
||||
import com.google.android.gms.location.GeofencingEvent;
|
||||
import com.jens.automation2.Miscellaneous;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static eu.chainfire.libsuperuser.Debug.TAG;
|
||||
|
||||
public class GeofenceBroadcastReceiver extends BroadcastReceiver
|
||||
{
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent)
|
||||
{
|
||||
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
|
||||
if (geofencingEvent.hasError())
|
||||
{
|
||||
// Miscellaneous.logEvent("i", "Geofence", geofenceTransitionDetails, 2);
|
||||
// String errorMessage = GeofenceStatusCodes.getErrorString(geofencingEvent.getErrorCode());
|
||||
Log.e(TAG, "Geofence error");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the transition type.
|
||||
int geofenceTransition = geofencingEvent.getGeofenceTransition();
|
||||
|
||||
// Test that the reported transition was of interest.
|
||||
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER || geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT)
|
||||
{
|
||||
// Get the geofences that were triggered. A single event can trigger
|
||||
// multiple geofences.
|
||||
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
|
||||
|
||||
// Get the transition details as a String.
|
||||
String geofenceTransitionDetails = "something happened";//getGeofenceTransitionDetails(this, geofenceTransition, triggeringGeofences);
|
||||
|
||||
// Send notification and log the transition details.
|
||||
Miscellaneous.logEvent("i", "Geofence", geofenceTransitionDetails, 2);
|
||||
Log.i(TAG, geofenceTransitionDetails);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Log the error.
|
||||
// Log.e(TAG, getString(R.string.geofence_transition_invalid_type, geofenceTransition));
|
||||
Log.e("Geofence", String.valueOf(geofenceTransition));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
package com.jens.automation2.location;
|
||||
|
||||
import android.app.IntentService;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
import com.google.android.gms.location.GeofencingClient;
|
||||
import com.google.android.gms.location.GeofencingRequest;
|
||||
import com.google.android.gms.location.LocationServices;
|
||||
import com.jens.automation2.PointOfInterest;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GeofenceIntentService extends IntentService
|
||||
{
|
||||
private GeofencingClient mGeofencingClient;
|
||||
protected static GoogleApiClient googleApiClient = null;
|
||||
PendingIntent geofencePendingIntent;
|
||||
|
||||
static GeofenceIntentService instance;
|
||||
|
||||
List<com.google.android.gms.location.Geofence> geoFenceList = new ArrayList<>();
|
||||
|
||||
public static GeofenceIntentService getInstance()
|
||||
{
|
||||
if (instance == null)
|
||||
instance = new GeofenceIntentService("Automation");
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public GeofenceIntentService(String name)
|
||||
{
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandleIntent(@Nullable Intent intent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate()
|
||||
{
|
||||
mGeofencingClient = LocationServices.getGeofencingClient(this);
|
||||
|
||||
}
|
||||
|
||||
public void addFence(PointOfInterest poi)
|
||||
{
|
||||
com.google.android.gms.location.Geofence geofence = new com.google.android.gms.location.Geofence.Builder()
|
||||
.setRequestId(poi.getName()) // Geofence ID
|
||||
.setCircularRegion(poi.getLocation().getLatitude(), poi.getLocation().getLongitude(), (float) poi.getRadius()) // defining fence region
|
||||
.setExpirationDuration(com.google.android.gms.location.Geofence.NEVER_EXPIRE) // expiring date
|
||||
// Transition types that it should look for
|
||||
.setTransitionTypes(com.google.android.gms.location.Geofence.GEOFENCE_TRANSITION_ENTER | com.google.android.gms.location.Geofence.GEOFENCE_TRANSITION_EXIT)
|
||||
.build();
|
||||
|
||||
geoFenceList.add(geofence);
|
||||
|
||||
GeofencingRequest request = new GeofencingRequest.Builder()
|
||||
// Notification to trigger when the Geofence is created
|
||||
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
|
||||
.addGeofence(geofence) // add a Geofence
|
||||
.build();
|
||||
|
||||
mGeofencingClient.removeGeofences(getGeofencePendingIntent());
|
||||
}
|
||||
|
||||
public static void startService()
|
||||
{
|
||||
for (PointOfInterest poi : PointOfInterest.getPointOfInterestCollection())
|
||||
getInstance().addFence(poi);
|
||||
}
|
||||
|
||||
public static void stopService()
|
||||
{
|
||||
for (PointOfInterest poi : PointOfInterest.getPointOfInterestCollection())
|
||||
getInstance().addFence(poi);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a PendingIntent to send with the request to add or remove Geofences. Location Services
|
||||
* issues the Intent inside this PendingIntent whenever a geofence transition occurs for the
|
||||
* current list of geofences.
|
||||
*
|
||||
* @return A PendingIntent for the IntentService that handles geofence transitions.
|
||||
*/
|
||||
|
||||
private PendingIntent getGeofencePendingIntent()
|
||||
{
|
||||
// Reuse the PendingIntent if we already have it.
|
||||
if (geofencePendingIntent != null)
|
||||
{
|
||||
return geofencePendingIntent;
|
||||
}
|
||||
Intent intent = new Intent(this, GeofenceBroadcastReceiver.class);
|
||||
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when
|
||||
// calling addGeofences() and removeGeofences().
|
||||
geofencePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
return geofencePendingIntent;
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,506 @@
|
||||
package com.jens.automation2.location;
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import android.location.LocationManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
|
||||
import com.jens.automation2.ActivityMainScreen;
|
||||
import com.jens.automation2.AutomationService;
|
||||
import com.jens.automation2.Miscellaneous;
|
||||
import com.jens.automation2.PointOfInterest;
|
||||
import com.jens.automation2.R;
|
||||
import com.jens.automation2.Rule;
|
||||
import com.jens.automation2.Settings;
|
||||
import com.jens.automation2.Trigger.Trigger_Enum;
|
||||
import com.jens.automation2.receivers.ConnectivityReceiver;
|
||||
import com.jens.automation2.receivers.PhoneStatusListener;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
|
||||
public class LocationProvider
|
||||
{
|
||||
|
||||
protected static boolean passiveLocationListenerActive = false;
|
||||
|
||||
protected static LocationListener passiveLocationListener;
|
||||
|
||||
protected static LocationProvider locationProviderInstance = null;
|
||||
|
||||
protected AutomationService parentService;
|
||||
public AutomationService getParentService()
|
||||
{
|
||||
return parentService;
|
||||
}
|
||||
|
||||
protected Location currentLocation;
|
||||
protected static Location currentLocationStaticCopy;
|
||||
protected static double speed;
|
||||
protected ArrayList<Location> locationList = new ArrayList<Location>();
|
||||
protected static Handler speedHandler = null;
|
||||
protected static boolean speedTimerActive = false;
|
||||
protected static Calendar etaAtNextPoi = null;
|
||||
|
||||
public static Calendar getEtaAtNextPoi()
|
||||
{
|
||||
return etaAtNextPoi;
|
||||
}
|
||||
|
||||
public LocationProvider(AutomationService parent)
|
||||
{
|
||||
parentService = parent;
|
||||
locationProviderInstance = this;
|
||||
|
||||
startLocationService();
|
||||
}
|
||||
|
||||
public static LocationProvider getInstance()
|
||||
{
|
||||
return locationProviderInstance;
|
||||
}
|
||||
|
||||
public Location getCurrentLocation()
|
||||
{
|
||||
return currentLocation;
|
||||
}
|
||||
public static Location getLastKnownLocation()
|
||||
{
|
||||
return currentLocationStaticCopy;
|
||||
}
|
||||
|
||||
public static double getSpeed()
|
||||
{
|
||||
return speed;
|
||||
}
|
||||
|
||||
public static void setSpeed(double speed)
|
||||
{
|
||||
LocationProvider.speed = speed;
|
||||
|
||||
/*
|
||||
Check if the last location update may be to old.
|
||||
It could be that for whatever reason we didn't get a recent location, but the current speed
|
||||
indicates we have moved quite a bit.
|
||||
*/
|
||||
|
||||
Calendar now = Calendar.getInstance();
|
||||
|
||||
float distanceToClosestPoi = PointOfInterest.getClosestPOI(getLastKnownLocation()).getLocation().distanceTo(getLastKnownLocation());
|
||||
long timeInSecondsPassedSinceLastLocationUpdate = (now.getTimeInMillis() - getLastKnownLocation().getTime()) / 1000;
|
||||
|
||||
// Could be we were driving towards it instead of away, but we'll ignore that for the moment.
|
||||
|
||||
long secondsRequiredForArrival = now.getTimeInMillis()/1000 / (1000 / 60 * 60);
|
||||
now.add(Calendar.SECOND, (int)secondsRequiredForArrival);
|
||||
|
||||
etaAtNextPoi = now;
|
||||
|
||||
if(speedTimerActive)
|
||||
resetSpeedTimer(etaAtNextPoi);
|
||||
else
|
||||
startSpeedTimer(etaAtNextPoi);
|
||||
}
|
||||
|
||||
public void setCurrentLocation(Location newLocation, boolean skipVerification)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Location", "Setting location.", 4);
|
||||
|
||||
currentLocation = newLocation;
|
||||
currentLocationStaticCopy = newLocation;
|
||||
|
||||
Miscellaneous.logEvent("i", "LocationListener", "Giving update to POI class", 4);
|
||||
PointOfInterest.positionUpdate(newLocation, parentService, false, skipVerification);
|
||||
|
||||
try
|
||||
{
|
||||
if(
|
||||
locationList.size() >= 1
|
||||
&&
|
||||
locationList.get(locationList.size()-1).getTime() == newLocation.getTime()
|
||||
&&
|
||||
locationList.get(locationList.size()-1).getProvider().equals(newLocation.getProvider())
|
||||
)
|
||||
{
|
||||
// This is a duplicate update, do not store it
|
||||
Miscellaneous.logEvent("i", "LocationListener", "Duplicate location, ignoring.", 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Speed", "Commencing speed calculation.", 4);
|
||||
// This part keeps the last two location entries to determine the current speed.
|
||||
|
||||
locationList.add(newLocation);
|
||||
|
||||
if(newLocation.hasSpeed())
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Speed", "Location has speed, taking that: " + String.valueOf(newLocation.getSpeed()) + " km/h", 4);
|
||||
setSpeed(newLocation.getSpeed()); // Take the value that came with the location, that should be more precise
|
||||
}
|
||||
else
|
||||
{
|
||||
if (locationList.size() >= 2)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Speed", "Trying to calculate speed based on the last locations.", 4);
|
||||
|
||||
double currentSpeed;
|
||||
long timeDifferenceInSeconds = (Math.abs(locationList.get(locationList.size() - 2).getTime() - locationList.get(locationList.size() - 1).getTime())) / 1000; //milliseconds
|
||||
if (timeDifferenceInSeconds <= Settings.speedMaximumTimeBetweenLocations * 60)
|
||||
{
|
||||
double distanceTraveled = locationList.get(locationList.size() - 2).distanceTo(locationList.get(locationList.size() - 1)); //results in meters
|
||||
|
||||
if (timeDifferenceInSeconds == 0)
|
||||
{
|
||||
Miscellaneous.logEvent("w", "Speed", "No time passed since last position. Can't calculate speed here.", 4);
|
||||
return;
|
||||
}
|
||||
|
||||
currentSpeed = distanceTraveled / timeDifferenceInSeconds * 3.6; // convert m/s --> km/h
|
||||
|
||||
/*
|
||||
Due to strange factors the time difference might be 0 resulting in mathematical error.
|
||||
*/
|
||||
if (Double.isInfinite(currentSpeed) | Double.isNaN(currentSpeed))
|
||||
Miscellaneous.logEvent("i", "Speed", "Error while calculating speed.", 4);
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Speed", "Current speed: " + String.valueOf(currentSpeed) + " km/h", 2);
|
||||
|
||||
setSpeed(currentSpeed);
|
||||
|
||||
// execute matching rules containing speed
|
||||
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesBySpeed();
|
||||
for (Rule oneRule : ruleCandidates)
|
||||
{
|
||||
if (oneRule.applies(this.getParentService()))
|
||||
oneRule.activate(getParentService(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
Miscellaneous.logEvent("i", "Speed", "Last two locations are too far apart in terms of time. Cannot use them for speed calculation.", 4);
|
||||
|
||||
|
||||
while (locationList.size() > 2)
|
||||
{
|
||||
// Remove all entries except for the last 2
|
||||
Miscellaneous.logEvent("i", "Speed", "About to delete oldest position record until only 2 left. Currently have " + String.valueOf(locationList.size()) + " records.", 4);
|
||||
locationList.remove(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("w", "Speed", "Don't have enough values for speed calculation, yet.", 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "Speed", "Error during speed calculation: " + Log.getStackTraceString(e), 3);
|
||||
}
|
||||
|
||||
AutomationService.updateNotification();
|
||||
|
||||
if(AutomationService.isMainActivityRunning(parentService))
|
||||
ActivityMainScreen.updateMainScreen();
|
||||
}
|
||||
|
||||
public void startLocationService()
|
||||
{
|
||||
// if(Settings.useAccelerometerForPositioning && !Miscellaneous.isAndroidEmulator())
|
||||
// {
|
||||
// accelerometerHandler = new AccelerometerHandler();
|
||||
// mySensorActivity = new SensorActivity(this);
|
||||
// }
|
||||
|
||||
// startPhoneStateListener
|
||||
PhoneStatusListener.startPhoneStatusListener(parentService); // also used to mute anouncements during calls
|
||||
|
||||
// startConnectivityReceiver
|
||||
ConnectivityReceiver.startConnectivityReceiver(parentService);
|
||||
|
||||
if(Settings.positioningEngine == 0)
|
||||
{
|
||||
// startCellLocationChangedReceiver
|
||||
if (!ConnectivityReceiver.isAirplaneMode(this.parentService) && WifiBroadcastReceiver.mayCellLocationReceiverBeActivated() && (Rule.isAnyRuleUsing(Trigger_Enum.pointOfInterest) | Rule.isAnyRuleUsing(Trigger_Enum.speed)))
|
||||
CellLocationChangedReceiver.startCellLocationChangedReceiver();
|
||||
|
||||
// startPassiveLocationListener
|
||||
if(Rule.isAnyRuleUsing(Trigger_Enum.pointOfInterest) | Rule.isAnyRuleUsing(Trigger_Enum.speed))
|
||||
startPassiveLocationListener();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Rule.isAnyRuleUsing(Trigger_Enum.pointOfInterest))
|
||||
GeofenceIntentService.startService();
|
||||
}
|
||||
}
|
||||
|
||||
public void stopLocationService()
|
||||
{
|
||||
try
|
||||
{
|
||||
PhoneStatusListener.stopPhoneStatusListener(parentService);
|
||||
CellLocationChangedReceiver.stopCellLocationChangedReceiver();
|
||||
SensorActivity.stopAccelerometerReceiver();
|
||||
WifiBroadcastReceiver.stopWifiReceiver();
|
||||
SensorActivity.stopAccelerometerReceiver();
|
||||
stopPassiveLocationListener();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "cellReceiver", "Error stopping LocationReceiver: " + Log.getStackTraceString(e), 3);
|
||||
}
|
||||
}
|
||||
|
||||
public void startPassiveLocationListener()
|
||||
{
|
||||
if(!passiveLocationListenerActive)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "LocationListener", "Arming passive location listener.", 4);
|
||||
LocationManager myLocationManager = (LocationManager) parentService.getSystemService(Context.LOCATION_SERVICE);
|
||||
passiveLocationListener = new MyPassiveLocationListener();
|
||||
try
|
||||
{
|
||||
myLocationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, Settings.minimumTimeBetweenUpdate, Settings.minimumDistanceChangeForNetworkUpdate, passiveLocationListener);
|
||||
}
|
||||
catch(SecurityException e)
|
||||
{}
|
||||
passiveLocationListenerActive = true;
|
||||
}
|
||||
}
|
||||
public void stopPassiveLocationListener()
|
||||
{
|
||||
if(passiveLocationListenerActive)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "LocationListener", "Disarming passive location listener.", 4);
|
||||
LocationManager myLocationManager = (LocationManager) parentService.getSystemService(Context.LOCATION_SERVICE);
|
||||
myLocationManager.removeUpdates(passiveLocationListener);
|
||||
passiveLocationListenerActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
public class MyPassiveLocationListener implements LocationListener
|
||||
{
|
||||
@Override
|
||||
public void onLocationChanged(Location up2DateLocation)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Location", "Got passive location update, provider: " + up2DateLocation.getProvider(), 3);
|
||||
setCurrentLocation(up2DateLocation, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderDisabled(String provider)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderEnabled(String provider)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void handleAirplaneMode(boolean state)
|
||||
{
|
||||
if(state)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Airplane mode", "CellLocationChangedReceiver will be deactivated due to Airplane mode.", 2);
|
||||
CellLocationChangedReceiver.stopCellLocationChangedReceiver();
|
||||
}
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Airplane mode", "CellLocationChangedReceiver will be activated due to end of Airplane mode.", 2);
|
||||
CellLocationChangedReceiver.startCellLocationChangedReceiver();
|
||||
}
|
||||
}
|
||||
|
||||
public void handleRoaming(Boolean roaming)
|
||||
{
|
||||
if(roaming)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Roaming", "We're on roaming.", 4);
|
||||
if(CellLocationChangedReceiver.isCellLocationListenerActive())
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Roaming", "Disabling CellLocationChangedReceiver because we're on roaming.", 3);
|
||||
CellLocationChangedReceiver.stopCellLocationChangedReceiver();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Roaming", "We're not on roaming.", 4);
|
||||
if(!CellLocationChangedReceiver.isCellLocationListenerActive())
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Roaming", "Enabling CellLocationChangedReceiver because we're not on roaming.", 3);
|
||||
CellLocationChangedReceiver.startCellLocationChangedReceiver();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void applySettingsAndRules()
|
||||
{
|
||||
/*
|
||||
* This method's purpose is to check settings and rules and determine
|
||||
* if changes in them require monitors to be started or stopped.
|
||||
* It takes care only of those which are more expensive.
|
||||
*/
|
||||
|
||||
// TextToSpeech is handled in AutomationService class
|
||||
|
||||
Miscellaneous.logEvent("i", "LocationProvider", this.getParentService().getResources().getString(R.string.applyingSettingsAndRules), 3);
|
||||
|
||||
// *********** SETTING CHANGES ***********
|
||||
if(Settings.useWifiForPositioning && !WifiBroadcastReceiver.isWifiListenerActive())
|
||||
{
|
||||
Miscellaneous.logEvent("i", "LocationProvider", "Starting WifiReceiver because settings now allow to.", 4);
|
||||
WifiBroadcastReceiver.startWifiReceiver(this);
|
||||
}
|
||||
else if(!Settings.useWifiForPositioning && WifiBroadcastReceiver.isWifiListenerActive())
|
||||
{
|
||||
Miscellaneous.logEvent("i", "LocationProvider", "Shutting down WifiReceiver because settings forbid to.", 4);
|
||||
WifiBroadcastReceiver.stopWifiReceiver();
|
||||
}
|
||||
|
||||
if(Settings.useAccelerometerForPositioning && !SensorActivity.isAccelerometerReceiverActive())
|
||||
{
|
||||
Miscellaneous.logEvent("i", "LocationProvider", "Starting accelerometerReceiver because settings now allow to.", 4);
|
||||
SensorActivity.startAccelerometerReceiver();
|
||||
}
|
||||
else if(!Settings.useAccelerometerForPositioning && SensorActivity.isAccelerometerReceiverActive())
|
||||
{
|
||||
Miscellaneous.logEvent("i", "LocationProvider", "Shutting down accelerometerReceiver because settings forbid to.", 4);
|
||||
SensorActivity.stopAccelerometerReceiver();
|
||||
}
|
||||
|
||||
// *********** RULE CHANGES ***********
|
||||
if(!CellLocationChangedReceiver.isCellLocationListenerActive() && (Rule.isAnyRuleUsing(Trigger_Enum.pointOfInterest) | Rule.isAnyRuleUsing(Trigger_Enum.speed)))
|
||||
{
|
||||
Miscellaneous.logEvent("i", "LocationProvider", "Starting NoiseListener CellLocationChangedReceiver because used in a new/changed rule.", 4);
|
||||
if(CellLocationChangedReceiver.haveAllPermission())
|
||||
CellLocationChangedReceiver.startCellLocationChangedReceiver();
|
||||
}
|
||||
else
|
||||
{
|
||||
Miscellaneous.logEvent("i", "LocationProvider", "Shutting down CellLocationChangedReceiver because not used in any rule.", 4);
|
||||
CellLocationChangedReceiver.stopCellLocationChangedReceiver();
|
||||
}
|
||||
|
||||
AutomationService.updateNotification();
|
||||
}
|
||||
|
||||
public static void startSpeedTimer(Calendar timeOfForcedLocationCheck)
|
||||
{
|
||||
if(!speedTimerActive)
|
||||
{
|
||||
if(timeOfForcedLocationCheck == null)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "SpeedTimer", "Have no value for speed timer. Using 5 minutes in the future.", 4);
|
||||
timeOfForcedLocationCheck = Calendar.getInstance();
|
||||
timeOfForcedLocationCheck.add(Calendar.MINUTE, 5);
|
||||
}
|
||||
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(Settings.dateFormat);
|
||||
|
||||
Miscellaneous.logEvent("i", "SpeedTimer", "Starting SpeedTimer. Next forced location check would be at " + sdf.format(calendar.getTime()), 4);
|
||||
|
||||
Message msg = new Message();
|
||||
msg.what = 1;
|
||||
|
||||
if(speedHandler == null)
|
||||
speedHandler = new SpeedHandler();
|
||||
|
||||
speedHandler.sendMessageAtTime(msg, timeOfForcedLocationCheck.getTimeInMillis());
|
||||
// speedHandler.sendMessageDelayed(msg, delayTime);
|
||||
speedTimerActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void stopSpeedTimer()
|
||||
{
|
||||
if(speedTimerActive)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "SpeedTimer", "Stopping SpeedTimer.", 4);
|
||||
|
||||
// Message msg = new Message();
|
||||
// msg.what = 0;
|
||||
|
||||
if(speedHandler == null)
|
||||
speedHandler = new SpeedHandler();
|
||||
else
|
||||
speedHandler.removeMessages(1);
|
||||
|
||||
speedTimerActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void resetSpeedTimer(Calendar timeOfForcedLocationCheck)
|
||||
{
|
||||
if(speedTimerActive)
|
||||
{
|
||||
if(timeOfForcedLocationCheck == null)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "SpeedTimer", "Have no value for speed timer. Using 5 minutes in the future.", 4);
|
||||
timeOfForcedLocationCheck = Calendar.getInstance();
|
||||
timeOfForcedLocationCheck.add(Calendar.MINUTE, 5);
|
||||
}
|
||||
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(Settings.dateFormat);
|
||||
|
||||
Miscellaneous.logEvent("i", "SpeedTimer", "Resetting SpeedTimer. Next forced location check would be at " + sdf.format(calendar.getTime()), 5);
|
||||
speedHandler.removeMessages(1);
|
||||
|
||||
Message msg = new Message();
|
||||
msg.what = 1;
|
||||
speedHandler.sendMessageAtTime(msg, timeOfForcedLocationCheck.getTimeInMillis());
|
||||
// speedHandler.sendMessageDelayed(msg, delayTime);
|
||||
speedTimerActive = true;
|
||||
}
|
||||
else
|
||||
startSpeedTimer(timeOfForcedLocationCheck);
|
||||
}
|
||||
|
||||
static class SpeedHandler extends Handler
|
||||
{
|
||||
@Override
|
||||
public void handleMessage(Message msg)
|
||||
{
|
||||
super.handleMessage(msg);
|
||||
|
||||
if(msg.what == 1)
|
||||
{
|
||||
// time is up, no cell location updates since x minutes, start accelerometer
|
||||
String text = "Timer triggered. Based on the last location and speed we may be at a POI. Forcing location update in case CellLocationChangedReceiver didn\'t fire.";
|
||||
// Miscellaneous.logEvent("i", "AccelerometerHandler", text, 5);
|
||||
// CellLocationChangedReceiver.stopCellLocationChangedReceiver();
|
||||
// startAccelerometerReceiver();
|
||||
Location currentLocation = CellLocationChangedReceiver.getInstance().getLocation("coarse");
|
||||
AutomationService.getInstance().getLocationProvider().setCurrentLocation(currentLocation, false);
|
||||
}
|
||||
/*else if(msg.what == 0)
|
||||
{
|
||||
String text = "Abort command received, deactivating SpeedReceiver";
|
||||
Miscellaneous.logEvent("i", "SpeedHandler", text, 4);
|
||||
stopAccelerometerReceiver();
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,220 @@
|
||||
package com.jens.automation2.location;
|
||||
|
||||
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
|
||||
import com.jens.automation2.AutomationService;
|
||||
import com.jens.automation2.Miscellaneous;
|
||||
import com.jens.automation2.Settings;
|
||||
|
||||
public class SensorActivity implements SensorEventListener
|
||||
{
|
||||
protected static SensorActivity instance;
|
||||
private final SensorManager mSensorManager;
|
||||
private final Sensor mAccelerometer;
|
||||
public LocationProvider parentLocationProvider;
|
||||
public static boolean mInitialized = false;
|
||||
public static float lastX, lastY, lastZ, deltaX, deltaY, deltaZ;
|
||||
protected static Handler accelerometerHandler = null;
|
||||
protected static boolean accelerometerReceiverActive = false;
|
||||
protected static boolean accelerometerTimerActive = false;
|
||||
|
||||
public static boolean isAccelerometerReceiverActive()
|
||||
{
|
||||
return accelerometerReceiverActive;
|
||||
}
|
||||
|
||||
public static boolean isAccelerometerTimerActive()
|
||||
{
|
||||
return accelerometerTimerActive;
|
||||
}
|
||||
|
||||
public static SensorActivity getInstance()
|
||||
{
|
||||
if(instance == null)
|
||||
instance = new SensorActivity(AutomationService.getInstance().getLocationProvider());
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public SensorActivity(LocationProvider parent)
|
||||
{
|
||||
this.parentLocationProvider = parent;
|
||||
mSensorManager = (SensorManager)parentLocationProvider.parentService.getSystemService(parentLocationProvider.parentService.SENSOR_SERVICE);
|
||||
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||
}
|
||||
|
||||
protected void start()
|
||||
{
|
||||
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
|
||||
}
|
||||
|
||||
protected void stop()
|
||||
{
|
||||
mSensorManager.unregisterListener(this);
|
||||
}
|
||||
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy)
|
||||
{
|
||||
}
|
||||
|
||||
public void onSensorChanged(SensorEvent event)
|
||||
{
|
||||
// Device has been moved
|
||||
|
||||
float x = event.values[0];
|
||||
float y = event.values[1];
|
||||
float z = event.values[2];
|
||||
|
||||
if(mInitialized)
|
||||
{
|
||||
deltaX = Math.abs(lastX-x);
|
||||
deltaY = Math.abs(lastY-y);
|
||||
deltaZ = Math.abs(lastZ-z);
|
||||
//Wenn das jetzt einen gewissen Grenzwert übersteigt, müßten wir den CellListener wieder aktivieren
|
||||
if(deltaX > Settings.accelerometerMovementThreshold | deltaY > Settings.accelerometerMovementThreshold | deltaZ > Settings.accelerometerMovementThreshold)
|
||||
{
|
||||
String text = "Device has been moved. " + String.valueOf(deltaX)+" / "+String.valueOf(deltaY)+" / "+String.valueOf(deltaZ);
|
||||
Miscellaneous.logEvent("i", "Accelerometer", text, 5);
|
||||
CellLocationChangedReceiver.resetFollowUpdate();
|
||||
CellLocationChangedReceiver.startCellLocationChangedReceiver();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
lastZ = z;
|
||||
mInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected static void startAccelerometerReceiver()
|
||||
{
|
||||
if(Settings.useAccelerometerForPositioning && !Miscellaneous.isAndroidEmulator())
|
||||
{
|
||||
if(!accelerometerReceiverActive)
|
||||
{
|
||||
try
|
||||
{
|
||||
getInstance().start();
|
||||
accelerometerReceiverActive = true;
|
||||
Miscellaneous.logEvent("i", "AccelerometerReceiver", "Starting AccelerometerReceiver", 4);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "AccelerometerReceiver", "Error starting AccelerometerReceiver: " + Log.getStackTraceString(ex), 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
protected static void stopAccelerometerReceiver()
|
||||
{
|
||||
if(Settings.useAccelerometerForPositioning && !Miscellaneous.isAndroidEmulator() && accelerometerReceiverActive)
|
||||
{
|
||||
try
|
||||
{
|
||||
getInstance().stop();
|
||||
accelerometerReceiverActive = false;
|
||||
Miscellaneous.logEvent("i", "AccelerometerReceiver", "Stopping AccelerometerReceiver", 4);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "AccelerometerReceiver", "Error stopping AccelerometerReceiver: " + Log.getStackTraceString(ex), 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void startAccelerometerTimer()
|
||||
{
|
||||
if(Settings.useAccelerometerForPositioning && !Miscellaneous.isAndroidEmulator())
|
||||
{
|
||||
if(!accelerometerTimerActive)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "AccelerometerTimer", "Starting AccelerometerTimer", 4);
|
||||
|
||||
long delayTime = Settings.useAccelerometerAfterIdleTime * 60 * 1000;
|
||||
|
||||
Message msg = new Message();
|
||||
msg.what = 1;
|
||||
|
||||
if(accelerometerHandler == null)
|
||||
accelerometerHandler = new AccelerometerHandler();
|
||||
|
||||
accelerometerHandler.sendMessageDelayed(msg, delayTime);
|
||||
accelerometerTimerActive = true;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* else
|
||||
* reset timer
|
||||
*/
|
||||
}
|
||||
public static void stopAccelerometerTimer()
|
||||
{
|
||||
if(accelerometerTimerActive)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "AccelerometerTimer", "Stopping AccelerometerTimer", 4);
|
||||
|
||||
// Message msg = new Message();
|
||||
// msg.what = 0;
|
||||
|
||||
if(accelerometerHandler == null)
|
||||
accelerometerHandler = new AccelerometerHandler();
|
||||
else
|
||||
accelerometerHandler.removeMessages(1);
|
||||
|
||||
// accelerometerHandler.sendMessageDelayed(msg, 0);
|
||||
accelerometerTimerActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void resetAccelerometerTimer()
|
||||
{
|
||||
if(accelerometerTimerActive)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "AccelerometerTimer", "Resetting AccelerometerTimer", 5);
|
||||
accelerometerHandler.removeMessages(1);
|
||||
|
||||
long delayTime = Settings.useAccelerometerAfterIdleTime * 60 * 1000;
|
||||
// Toast.makeText(parentService, "Sending message, delayed for " + String.valueOf(delayTime), Toast.LENGTH_LONG).show();
|
||||
|
||||
Message msg = new Message();
|
||||
msg.what = 1;
|
||||
accelerometerHandler.sendMessageDelayed(msg, delayTime);
|
||||
accelerometerTimerActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
static class AccelerometerHandler extends Handler
|
||||
{
|
||||
@Override
|
||||
public void handleMessage(Message msg)
|
||||
{
|
||||
super.handleMessage(msg);
|
||||
|
||||
if(msg.what == 1)
|
||||
{
|
||||
// time is up, no cell location updates since x minutes, start accelerometer
|
||||
String text = String.valueOf(Settings.useAccelerometerAfterIdleTime) + " minutes passed";
|
||||
Miscellaneous.logEvent("i", "AccelerometerHandler", text, 5);
|
||||
CellLocationChangedReceiver.stopCellLocationChangedReceiver();
|
||||
startAccelerometerReceiver();
|
||||
}
|
||||
else if(msg.what == 0)
|
||||
{
|
||||
String text = "Abort command received, deactivating accelerometerReceiver";
|
||||
Miscellaneous.logEvent("i", "AccelerometerHandler", text, 4);
|
||||
stopAccelerometerReceiver();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,229 @@
|
||||
package com.jens.automation2.location;
|
||||
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.util.Log;
|
||||
|
||||
import com.jens.automation2.Miscellaneous;
|
||||
import com.jens.automation2.PointOfInterest;
|
||||
import com.jens.automation2.R;
|
||||
import com.jens.automation2.Rule;
|
||||
import com.jens.automation2.Settings;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class WifiBroadcastReceiver extends BroadcastReceiver
|
||||
{
|
||||
public static LocationProvider parentLocationProvider;
|
||||
public static Boolean wasConnected = false;
|
||||
protected static String lastWifiSsid = "";
|
||||
public static boolean lastConnectedState = false;
|
||||
protected static boolean mayCellLocationChangedReceiverBeActivatedFromWifiPointOfWifi = true;
|
||||
protected static WifiBroadcastReceiver wifiBrInstance;
|
||||
protected static IntentFilter wifiListenerIntentFilter;
|
||||
protected static boolean wifiListenerActive=false;
|
||||
|
||||
|
||||
|
||||
public static String getLastWifiSsid()
|
||||
{
|
||||
return lastWifiSsid;
|
||||
}
|
||||
|
||||
public static void setLastWifiSsid(String newWifiSsid)
|
||||
{
|
||||
if(newWifiSsid.startsWith("\"") && newWifiSsid.endsWith("\""))
|
||||
newWifiSsid = newWifiSsid.substring(1, newWifiSsid.length()-1);
|
||||
|
||||
WifiBroadcastReceiver.lastWifiSsid = newWifiSsid;
|
||||
}
|
||||
|
||||
public static boolean isWifiListenerActive()
|
||||
{
|
||||
return wifiListenerActive;
|
||||
}
|
||||
|
||||
public static boolean mayCellLocationReceiverBeActivated()
|
||||
{
|
||||
return mayCellLocationChangedReceiverBeActivatedFromWifiPointOfWifi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent)
|
||||
{
|
||||
try
|
||||
{
|
||||
// int state = -1;
|
||||
NetworkInfo myWifi = null;
|
||||
|
||||
// if(intent.getAction().equals(WifiManager.RSSI_CHANGED_ACTION)) //gefeuert bei Verbindung
|
||||
// {
|
||||
// Miscellaneous.logEvent("i", "WifiReceiver", "RSSI_CHANGED_ACTION: " + String.valueOf(intent.getIntExtra(WifiManager.RSSI_CHANGED_ACTION, -1)));
|
||||
// }
|
||||
// else
|
||||
if(intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) //gefeuert bei Trennung
|
||||
{
|
||||
// state = intent.getIntExtra(WifiManager.NETWORK_STATE_CHANGED_ACTION, -1);
|
||||
// Miscellaneous.logEvent("i", "WifiReceiver", "NETWORK_STATE_CHANGED_ACTION: " + String.valueOf(state));
|
||||
myWifi = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
|
||||
}
|
||||
|
||||
|
||||
WifiManager myWifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
|
||||
// ConnectivityManager connManager = (ConnectivityManager)context.getSystemService(context.CONNECTIVITY_SERVICE);
|
||||
// myWifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
|
||||
// myWifi = state
|
||||
// WifiInfo wifiInfo = myWifiManager.getConnectionInfo();
|
||||
|
||||
// SupplicantState supState = wifiInfo.getSupplicantState();
|
||||
|
||||
if(intent.getAction().equals(WifiManager.RSSI_CHANGED_ACTION)) // fired upon connection
|
||||
{
|
||||
String ssid = myWifiManager.getConnectionInfo().getSSID();
|
||||
setLastWifiSsid(ssid);
|
||||
Miscellaneous.logEvent("i", "WifiReceiver", String.format(context.getResources().getString(R.string.connectedToWifi), getLastWifiSsid()), 2);
|
||||
wasConnected = true;
|
||||
lastConnectedState = true;
|
||||
|
||||
if(Settings.useWifiForPositioning && PointOfInterest.reachedPoiWithActivateWifiRule()) // Poi has wifi
|
||||
{
|
||||
Miscellaneous.logEvent("i", "WifiReceiver", context.getResources().getString(R.string.poiHasWifiStoppingCellLocationListener), 2);
|
||||
mayCellLocationChangedReceiverBeActivatedFromWifiPointOfWifi = false;
|
||||
CellLocationChangedReceiver.stopCellLocationChangedReceiver();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!PointOfInterest.reachedPoiWithActivateWifiRule()) // Poi has no wifi
|
||||
Miscellaneous.logEvent("i", "WifiReceiver", context.getResources().getString(R.string.poiHasNoWifiNotStoppingCellLocationListener), 2);
|
||||
}
|
||||
|
||||
findRules(parentLocationProvider);
|
||||
}
|
||||
else if(myWifi.isConnectedOrConnecting()) // first time connect from wifi-listener-perspective
|
||||
{
|
||||
wasConnected = true;
|
||||
Miscellaneous.logEvent("i", "WifiReceiver", "WifiReceiver just activated. Wifi already connected. Stopping CellLocationReceiver", 3);
|
||||
mayCellLocationChangedReceiverBeActivatedFromWifiPointOfWifi = false;
|
||||
CellLocationChangedReceiver.stopCellLocationChangedReceiver();
|
||||
SensorActivity.stopAccelerometerTimer();
|
||||
String ssid = myWifiManager.getConnectionInfo().getSSID();
|
||||
setLastWifiSsid(ssid);
|
||||
lastConnectedState = true;
|
||||
findRules(parentLocationProvider);
|
||||
}
|
||||
else if(!myWifi.isConnectedOrConnecting()) // really disconnected? because sometimes also fires on connect
|
||||
{
|
||||
if(wasConnected) // wir könnten einfach noch nicht daheim sein
|
||||
{
|
||||
try
|
||||
{
|
||||
wasConnected = false;
|
||||
Miscellaneous.logEvent("i", "WifiReceiver", String.format(context.getResources().getString(R.string.disconnectedFromWifi), getLastWifiSsid()) + " Switching to CellLocationChangedReceiver.", 3);
|
||||
mayCellLocationChangedReceiverBeActivatedFromWifiPointOfWifi = true;
|
||||
CellLocationChangedReceiver.startCellLocationChangedReceiver();
|
||||
lastConnectedState = false;
|
||||
findRules(parentLocationProvider);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "WifiReceiver", "Error starting CellLocationChangedReceiver", 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "WifiReceiver", "Error in WifiReceiver->onReceive(): " + e.getMessage(), 3);
|
||||
}
|
||||
}
|
||||
|
||||
public static void findRules(LocationProvider parentLocationProvider)
|
||||
{
|
||||
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidatesByWifiConnection();
|
||||
for(Rule oneRule : ruleCandidates)
|
||||
{
|
||||
if(oneRule.applies(parentLocationProvider.parentService))
|
||||
oneRule.activate(parentLocationProvider.parentService, false);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isWifiEnabled(Context context)
|
||||
{
|
||||
try
|
||||
{
|
||||
WifiManager myWifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
|
||||
return myWifiManager.isWifiEnabled();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "WifiReceiver->isWifiEnabled()", Log.getStackTraceString(e), 3);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isWifiConnected(Context context)
|
||||
{
|
||||
try
|
||||
{
|
||||
ConnectivityManager connManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo myWifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
|
||||
return myWifi.isConnected();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "WifiReceiver->isWifiConnected()", Log.getStackTraceString(e), 3);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void startWifiReceiver(LocationProvider loc)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(!wifiListenerActive)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Wifi Listener", "Starting wifiListener", 4);
|
||||
if(wifiListenerIntentFilter == null)
|
||||
{
|
||||
wifiListenerIntentFilter = new IntentFilter();
|
||||
wifiListenerIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
|
||||
wifiListenerIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
|
||||
}
|
||||
if(wifiBrInstance == null)
|
||||
{
|
||||
wifiBrInstance = new WifiBroadcastReceiver();
|
||||
WifiBroadcastReceiver.parentLocationProvider = loc;
|
||||
}
|
||||
loc.getParentService().registerReceiver(wifiBrInstance, wifiListenerIntentFilter);
|
||||
wifiListenerActive = true;
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "Wifi Listener", "Error starting wifiListener: " + Log.getStackTraceString(ex), 3);
|
||||
}
|
||||
}
|
||||
public static void stopWifiReceiver()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(wifiListenerActive)
|
||||
{
|
||||
Miscellaneous.logEvent("i", "Wifi Listener", "Stopping wifiListener", 4);
|
||||
wifiListenerActive = false;
|
||||
parentLocationProvider.getParentService().unregisterReceiver(wifiBrInstance);
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Miscellaneous.logEvent("e", "Wifi Listener", "Error stopping wifiListener: " + Log.getStackTraceString(ex), 3);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user