Initial commit

This commit is contained in:
2021-02-16 13:42:49 +01:00
commit a8950597d0
190 changed files with 30846 additions and 0 deletions

View File

@ -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());
}
}

View File

@ -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));
}
}
}

View File

@ -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;
}
}

View File

@ -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();
}*/
}
}
}

View File

@ -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();
}
}
}
}

View File

@ -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);
}
}
}