Location without Cell Radio

This commit is contained in:
jens 2021-09-07 17:30:45 +02:00
parent cb430b957f
commit a6edab75ce
6 changed files with 156 additions and 109 deletions

View File

@ -29,6 +29,7 @@ import androidx.core.text.HtmlCompat;
import com.jens.automation2.AutomationService.serviceCommands; import com.jens.automation2.AutomationService.serviceCommands;
import com.jens.automation2.Trigger.Trigger_Enum; import com.jens.automation2.Trigger.Trigger_Enum;
import com.jens.automation2.location.CellLocationChangedReceiver;
import com.jens.automation2.location.LocationProvider; import com.jens.automation2.location.LocationProvider;
import java.io.File; import java.io.File;

View File

@ -22,6 +22,8 @@ import android.widget.EditText;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.Toast; import android.widget.Toast;
import com.jens.automation2.receivers.ConnectivityReceiver;
import java.util.Calendar; import java.util.Calendar;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
@ -163,7 +165,7 @@ public class ActivityManagePoi extends Activity
locationSearchStart = Calendar.getInstance(); locationSearchStart = Calendar.getInstance();
startTimeout(); startTimeout();
if(!Settings.privacyLocationing) if(!Settings.privacyLocationing || !ConnectivityReceiver.isDataConnectionAvailable(AutomationService.getInstance()))
{ {
Miscellaneous.logEvent("i", "POI Manager", getResources().getString(R.string.logGettingPositionWithProvider) + " " + provider1, 3); Miscellaneous.logEvent("i", "POI Manager", getResources().getString(R.string.logGettingPositionWithProvider) + " " + provider1, 3);
myLocationManager.requestLocationUpdates(provider1, 500, Settings.satisfactoryAccuracyNetwork, myLocationListenerNetwork); myLocationManager.requestLocationUpdates(provider1, 500, Settings.satisfactoryAccuracyNetwork, myLocationListenerNetwork);

View File

@ -333,7 +333,7 @@ public class AutomationService extends Service implements OnInitListener
protected void startLocationProvider() protected void startLocationProvider()
{ {
if(ActivityPermissions.havePermission("android.permission.ACCESS_COARSE_LOCATION", AutomationService.this)) if(ActivityPermissions.havePermission(Manifest.permission.ACCESS_COARSE_LOCATION, AutomationService.this))
myLocationProvider = new LocationProvider(this); //autostart with this (only) constructor myLocationProvider = new LocationProvider(this); //autostart with this (only) constructor
} }
@ -632,6 +632,9 @@ public class AutomationService extends Service implements OnInitListener
// } // }
// else // else
// { // {
if(notificationBuilder == null)
notificationBuilder = createDefaultNotificationBuilder();
notificationBuilder.setContentText(textToDisplay); notificationBuilder.setContentText(textToDisplay);
notificationBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(textToDisplay)); notificationBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(textToDisplay));

View File

@ -144,14 +144,14 @@ public class ReceiverCoordinator
ConnectivityReceiver.startConnectivityReceiver(AutomationService.getInstance()); ConnectivityReceiver.startConnectivityReceiver(AutomationService.getInstance());
// startCellLocationChangedReceiver // startCellLocationChangedReceiver
if(!ConnectivityReceiver.isAirplaneMode(AutomationService.getInstance()) && WifiBroadcastReceiver.mayCellLocationReceiverBeActivated() && (Rule.isAnyRuleUsing(Trigger.Trigger_Enum.pointOfInterest) | Rule.isAnyRuleUsing(Trigger.Trigger_Enum.speed))) if(!ConnectivityReceiver.isAirplaneMode(AutomationService.getInstance()) && WifiBroadcastReceiver.mayCellLocationReceiverBeActivated() && (Rule.isAnyRuleUsing(Trigger.Trigger_Enum.pointOfInterest) || Rule.isAnyRuleUsing(Trigger.Trigger_Enum.speed)))
{ {
if(!Miscellaneous.googleToBlameForLocation(true)) if(!Miscellaneous.googleToBlameForLocation(true))
CellLocationChangedReceiver.startCellLocationChangedReceiver(); CellLocationChangedReceiver.startCellLocationChangedReceiver();
} }
// startBatteryReceiver // startBatteryReceiver
if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.charging) | Rule.isAnyRuleUsing(Trigger.Trigger_Enum.usb_host_connection) | Rule.isAnyRuleUsing(Trigger.Trigger_Enum.batteryLevel)) if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.charging) || Rule.isAnyRuleUsing(Trigger.Trigger_Enum.usb_host_connection) || Rule.isAnyRuleUsing(Trigger.Trigger_Enum.batteryLevel))
BatteryReceiver.startBatteryReceiver(AutomationService.getInstance()); BatteryReceiver.startBatteryReceiver(AutomationService.getInstance());
// startAlarmListener // startAlarmListener

View File

@ -130,6 +130,21 @@ public class CellLocationChangedReceiver extends PhoneStateListener
} }
} }
public static boolean isCellLocationChangedReceiverPossible()
{
if(telephonyManager == null)
telephonyManager = (TelephonyManager) AutomationService.getInstance().getSystemService(Context.TELEPHONY_SERVICE);
if(
ConnectivityReceiver.isAirplaneMode(AutomationService.getInstance())
||
telephonyManager.getSimState() != TelephonyManager.SIM_STATE_READY
)
return false;
else
return true;
}
public Location getLocation(String accuracy) public Location getLocation(String accuracy)
{ {
Criteria crit = new Criteria(); Criteria crit = new Criteria();
@ -137,7 +152,7 @@ public class CellLocationChangedReceiver extends PhoneStateListener
String myProviderName; String myProviderName;
// If privacy mode or no data connection available // If privacy mode or no data connection available
if(Settings.privacyLocationing | !ConnectivityReceiver.isDataConnectionAvailable(AutomationService.getInstance())) if(Settings.privacyLocationing || !ConnectivityReceiver.isDataConnectionAvailable(AutomationService.getInstance()))
{ {
Miscellaneous.logEvent("i", "CellLocation", Miscellaneous.getAnyContext().getResources().getString(R.string.enforcingGps), 4); Miscellaneous.logEvent("i", "CellLocation", Miscellaneous.getAnyContext().getResources().getString(R.string.enforcingGps), 4);
myProviderName = LocationManager.GPS_PROVIDER; myProviderName = LocationManager.GPS_PROVIDER;
@ -175,6 +190,9 @@ public class CellLocationChangedReceiver extends PhoneStateListener
} }
else else
{ {
if(myLocationManager == null)
myLocationManager = (LocationManager) AutomationService.getInstance().getSystemService(Context.LOCATION_SERVICE);
if(!myLocationManager.isProviderEnabled(myProviderName)) if(!myLocationManager.isProviderEnabled(myProviderName))
{ {
if(myProviderName.equals(LocationManager.NETWORK_PROVIDER)) if(myProviderName.equals(LocationManager.NETWORK_PROVIDER))
@ -226,13 +244,11 @@ public class CellLocationChangedReceiver extends PhoneStateListener
return currentLocation; return currentLocation;
} }
public void setCurrentLocation(Location currentLocation) public void setCurrentLocation(Location currentLocation)
{ {
this.currentLocation = currentLocation; this.currentLocation = currentLocation;
} }
public class MyLocationListener implements LocationListener public class MyLocationListener implements LocationListener
{ {
@Override @Override
@ -327,7 +343,7 @@ public class CellLocationChangedReceiver extends PhoneStateListener
{ {
if(!cellLocationListenerActive) if(!cellLocationListenerActive)
{ {
if(!ConnectivityReceiver.isAirplaneMode(AutomationService.getInstance())) if(!ConnectivityReceiver.isAirplaneMode(AutomationService.getInstance()) && telephonyManager.getSimState() == TelephonyManager.SIM_STATE_READY)
{ {
if(WifiBroadcastReceiver.mayCellLocationReceiverBeActivated()) if(WifiBroadcastReceiver.mayCellLocationReceiverBeActivated())
{ {
@ -356,7 +372,7 @@ public class CellLocationChangedReceiver extends PhoneStateListener
Miscellaneous.logEvent("w", "cellReceiver", "Wanted to activate CellLocationChangedReceiver, but Wifi-Receiver says not to.", 4); Miscellaneous.logEvent("w", "cellReceiver", "Wanted to activate CellLocationChangedReceiver, but Wifi-Receiver says not to.", 4);
} }
else else
Miscellaneous.logEvent("i", "cellReceiver", "Not starting cellLocationListener because Airplane mode is active.", 4); Miscellaneous.logEvent("i", "cellReceiver", "Not starting cellLocationListener because Airplane mode is active or SIM_STATE is not ready.", 4);
} }
} }
catch(Exception ex) catch(Exception ex)
@ -410,4 +426,3 @@ public class CellLocationChangedReceiver extends PhoneStateListener
ActivityPermissions.havePermission("android.permission.ACCESS_WIFI_STATE", Miscellaneous.getAnyContext()); ActivityPermissions.havePermission("android.permission.ACCESS_WIFI_STATE", Miscellaneous.getAnyContext());
} }
} }

View File

@ -7,6 +7,7 @@ import android.location.LocationManager;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.telephony.TelephonyManager;
import android.util.Log; import android.util.Log;
import com.jens.automation2.ActivityMainScreen; import com.jens.automation2.ActivityMainScreen;
@ -26,13 +27,9 @@ import java.util.Calendar;
public class LocationProvider public class LocationProvider
{ {
protected static boolean passiveLocationListenerActive = false; protected static boolean passiveLocationListenerActive = false;
protected static LocationListener passiveLocationListener; protected static LocationListener passiveLocationListener;
protected static LocationProvider locationProviderInstance = null; protected static LocationProvider locationProviderInstance = null;
protected AutomationService parentService; protected AutomationService parentService;
public AutomationService getParentService() public AutomationService getParentService()
{ {
@ -109,123 +106,128 @@ public class LocationProvider
public void setCurrentLocation(Location newLocation, boolean skipVerification) public void setCurrentLocation(Location newLocation, boolean skipVerification)
{ {
Miscellaneous.logEvent("i", "Location", "Setting location.", 4); if(newLocation != null)
currentLocation = newLocation;
currentLocationStaticCopy = newLocation;
Miscellaneous.logEvent("i", "LocationListener", "Giving update to POI class", 4);
PointOfInterest.positionUpdate(newLocation, parentService, false, skipVerification);
try
{ {
if( Miscellaneous.logEvent("i", "Location", "Setting location.", 4);
locationList.size() >= 1
&& currentLocation = newLocation;
locationList.get(locationList.size()-1).getTime() == newLocation.getTime() currentLocationStaticCopy = newLocation;
&&
locationList.get(locationList.size()-1).getProvider().equals(newLocation.getProvider()) 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); // This is a duplicate update, do not store it
setSpeed(newLocation.getSpeed()); // Take the value that came with the location, that should be more precise Miscellaneous.logEvent("i", "LocationListener", "Duplicate location, ignoring.", 4);
} }
else else
{ {
speedCalculation: Miscellaneous.logEvent("i", "Speed", "Commencing speed calculation.", 4);
if (locationList.size() >= 2) // This part keeps the last two location entries to determine the current speed.
locationList.add(newLocation);
if (newLocation.hasSpeed())
{ {
while (locationList.size() > 2) 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
{
speedCalculation:
if (locationList.size() >= 2)
{ {
// Remove all entries except for the last 2 while (locationList.size() > 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); // 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);
}
/* /*
The two most recent locations in the list must have a usable accuracy. The two most recent locations in the list must have a usable accuracy.
*/ */
for(int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
{ {
if if
( (
(locationList.get(i).getProvider().equals(LocationManager.GPS_PROVIDER) && locationList.get(i).getAccuracy() > Settings.satisfactoryAccuracyGps) (locationList.get(i).getProvider().equals(LocationManager.GPS_PROVIDER) && locationList.get(i).getAccuracy() > Settings.satisfactoryAccuracyGps)
|| ||
(locationList.get(i).getProvider().equals(LocationManager.NETWORK_PROVIDER) && locationList.get(i).getAccuracy() > Settings.satisfactoryAccuracyNetwork) (locationList.get(i).getProvider().equals(LocationManager.NETWORK_PROVIDER) && locationList.get(i).getAccuracy() > Settings.satisfactoryAccuracyNetwork)
) )
{ {
Miscellaneous.logEvent("i", "Speed", "Not using 2 most recent locations for speed calculation because at least one does not have a satisfactory accuracy: " + locationList.get(i).toString(), 4); Miscellaneous.logEvent("i", "Speed", "Not using 2 most recent locations for speed calculation because at least one does not have a satisfactory accuracy: " + locationList.get(i).toString(), 4);
break speedCalculation; break speedCalculation;
} }
}
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 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. Due to strange factors the time difference might be 0 resulting in mathematical error.
*/ */
if (Double.isInfinite(currentSpeed) | Double.isNaN(currentSpeed)) if (Double.isInfinite(currentSpeed) | Double.isNaN(currentSpeed))
Miscellaneous.logEvent("i", "Speed", "Error while calculating speed.", 4); Miscellaneous.logEvent("i", "Speed", "Error while calculating speed.", 4);
else 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())) Miscellaneous.logEvent("i", "Speed", "Current speed: " + String.valueOf(currentSpeed) + " km/h", 2);
oneRule.activate(getParentService(), false);
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);
} }
else else
Miscellaneous.logEvent("i", "Speed", "Last two locations are too far apart in terms of time. Cannot use them for speed calculation.", 4); {
} Miscellaneous.logEvent("w", "Speed", "Don't have enough values for speed calculation, yet.", 3);
else }
{
Miscellaneous.logEvent("w", "Speed", "Don't have enough values for speed calculation, yet.", 3);
} }
} }
} }
} catch (Exception e)
catch(Exception e) {
{ Miscellaneous.logEvent("e", "Speed", "Error during speed calculation: " + Log.getStackTraceString(e), 3);
Miscellaneous.logEvent("e", "Speed", "Error during speed calculation: " + Log.getStackTraceString(e), 3); }
}
AutomationService.updateNotification(); AutomationService.updateNotification();
if(AutomationService.isMainActivityRunning(parentService)) if (AutomationService.isMainActivityRunning(parentService))
ActivityMainScreen.updateMainScreen(); ActivityMainScreen.updateMainScreen();
}
else
Miscellaneous.logEvent("w", "Location", "New location given is null. Ignoring.", 5);
} }
public void startLocationService() public void startLocationService()
@ -244,13 +246,37 @@ public class LocationProvider
if(Settings.positioningEngine == 0) 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)) if(Rule.isAnyRuleUsing(Trigger_Enum.pointOfInterest) | Rule.isAnyRuleUsing(Trigger_Enum.speed))
{
// TelephonyManager telephonyManager = (TelephonyManager) AutomationService.getInstance().getSystemService(Context.TELEPHONY_SERVICE);
// startCellLocationChangedReceiver
if (CellLocationChangedReceiver.isCellLocationChangedReceiverPossible())
{
if (WifiBroadcastReceiver.mayCellLocationReceiverBeActivated())
CellLocationChangedReceiver.startCellLocationChangedReceiver();
}
else
{
/*
Reasons why we may end up here:
- Airplane mode is active
- No phone module present (pure wifi device)
- No SIM card is inserted or it's not unlocked
We'd have to try GPS now to get an initial position.
For permanent use there is no way we could know when it
would make sense to check the position again.
*/
// Trigger a one-time-position-search
Location loc = CellLocationChangedReceiver.getInstance().getLocation("fine");
LocationProvider.getInstance().setCurrentLocation(loc, true);
}
// startPassiveLocationListener
startPassiveLocationListener(); startPassiveLocationListener();
}
} }
else else
{ {