Skip to content

Commit

Permalink
Text to speech:
Browse files Browse the repository at this point in the history
    - Speech rate can be adjusted in the apps settings
    - Message queue implemented, prevent navigation instruction interrupts  (#6)
    - Announce bearing updates to the next route point in addition to the continuous distance updates while navigating
    - Fixed a bug where Talkback took presents over the distance and bearing announcements from the
      apps tts and interrupted them frequently (#5)

Other:
    - Added additional tasks in the start tab
    - Auto-resolve the current coordinates to their closest address when they are used as start point of a route calculation
    - Additional talkback actions have been added to the location button in the tool bar.
    - Fixed a bug in the tab bar below the tool bar: Sometimes the tabs in there got multiplied
  • Loading branch information
Eric Scheibler committed Nov 18, 2024
1 parent 44c97fa commit 284a68b
Show file tree
Hide file tree
Showing 49 changed files with 1,563 additions and 544 deletions.
6 changes: 3 additions & 3 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ android {
namespace "org.walkersguide.android"

defaultConfig {
versionCode 41
versionName '3.2.0-b4'
versionCode 42
versionName '3.2.0-b5'
minSdkVersion 21
targetSdkVersion 35
multiDexEnabled true
Expand Down Expand Up @@ -140,7 +140,7 @@ android.applicationVariants.all { variant ->
group = 'Open'
description "Installs and opens the APK for ${variant.description}."
doFirst {
String activityClass = ".ui.activity.MainActivity"
String activityClass = "org.walkersguide.android.ui.activity.MainActivity"
commandLine android.adbExe, 'shell', 'am', 'start', '-n',
"${variant.applicationId}/${activityClass}"
}
Expand Down
50 changes: 32 additions & 18 deletions app/src/main/java/org/walkersguide/android/data/ObjectWithId.java
Original file line number Diff line number Diff line change
Expand Up @@ -325,31 +325,37 @@ public boolean setUserAnnotation(String newAnnotation) {

public abstract Coordinates getCoordinates();

public String formatRelativeBearingFromCurrentLocation(boolean showPreciseBearingValues) {
RelativeBearing relativeBearing = relativeBearingFromCurrentLocation();
if (relativeBearing != null) {
String output = relativeBearing.getDirection().toString();
if (showPreciseBearingValues) {
output += " ";
output += String.format(
Locale.ROOT,
GlobalInstance.getStringResource(R.string.preciseBearingValues),
relativeBearing.getDegree());
}
return output;
}
return "";
}

public String formatDistanceAndRelativeBearingFromCurrentLocation(int distancePluralResourceId) {
return formatDistanceAndRelativeBearingFromCurrentLocation(distancePluralResourceId, false);
}

public String formatDistanceAndRelativeBearingFromCurrentLocation(
int distancePluralResourceId, boolean showPreciseBearingValues) {
Integer distance = distanceFromCurrentLocation();
Bearing bearing = bearingFromCurrentLocation();
if (distance != null && bearing != null) {
RelativeBearing relativeBearing = bearing.relativeToCurrentBearing();
if (relativeBearing != null) {
String output = String.format(
Locale.getDefault(),
"%1$s, %2$s",
GlobalInstance.getPluralResource(distancePluralResourceId, distance),
relativeBearing.getDirection());
if (showPreciseBearingValues) {
output += " ";
output += String.format(
Locale.ROOT,
GlobalInstance.getStringResource(R.string.preciseBearingValues),
relativeBearing.getDegree());
}
return output;
}
String relativeBearingFromCurrentLocationFormatted = formatRelativeBearingFromCurrentLocation(showPreciseBearingValues);
if (distance != null
&& ! TextUtils.isEmpty(relativeBearingFromCurrentLocationFormatted)) {
return String.format(
Locale.getDefault(),
"%1$s, %2$s",
GlobalInstance.getPluralResource(distancePluralResourceId, distance),
relativeBearingFromCurrentLocationFormatted);
}
return "";
}
Expand Down Expand Up @@ -377,6 +383,14 @@ public Bearing bearingFromCurrentLocation() {
return null;
}

public RelativeBearing relativeBearingFromCurrentLocation() {
Bearing bearing = bearingFromCurrentLocation();
if (bearing != null) {
return bearing.relativeToCurrentBearing();
}
return null;
}

public Bearing bearingTo(ObjectWithId other) {
if (other != null) {
return this.getCoordinates().bearingTo(other.getCoordinates());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.walkersguide.android.R;
import org.walkersguide.android.tts.TTSWrapper;
import org.walkersguide.android.tts.TTSWrapper.MessageType;
import org.walkersguide.android.util.Helper;
import timber.log.Timber;
import org.walkersguide.android.data.angle.Bearing;
Expand Down Expand Up @@ -213,8 +214,8 @@ private void announceBearingSensorChange() {
String.format(
"%1$s: %2$s",
GlobalInstance.getStringResource(R.string.bearingSensor),
getSelectedBearingSensor())
);
getSelectedBearingSensor()),
MessageType.DISTANCE_OR_BEARING);
}

public void deviceOrientationChanged() {
Expand Down Expand Up @@ -293,7 +294,7 @@ private void broadcastCurrentBearing(boolean isImportant) {
public static final String ACTION_NEW_BEARING_VALUE_FROM_COMPASS = "new_bearing_value_from_compass";

// min time difference between compass values
private static final int MIN_COMPASS_VALUE_DELAY = 250; // 250 ms
private static final int MIN_COMPASS_VALUE_DELAY = 250; // in ms

private BearingSensorAccuracyRating bearingSensorAccuracyRating = null;
// accelerometer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -427,30 +427,4 @@ public void setSimulatedLocation(Point newPoint) {
}
}


/**
* log to text file
*/
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss", Locale.ROOT);

private static void appendToLog(String fileName, String message) {
File file = new File(
GlobalInstance.getContext().getExternalFilesDir(null),
String.format("%1$s.log", fileName));
try {
FileWriter fw = new FileWriter(file, true);
BufferedWriter bw = new BufferedWriter(fw);
bw.write(
String.format(
"%1$s\t%2$s\n",
message,
sdf.format(new Date(System.currentTimeMillis())))
);
bw.close();
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,23 @@ public class AcceptNewBearing implements Serializable {
private static final long serialVersionUID = 1l;

public static AcceptNewBearing newInstanceForObjectListUpdate() {
return new AcceptNewBearing(45, 1);
return new AcceptNewBearing(45, 1000l);
}

public static AcceptNewBearing newInstanceForDistanceLabelUpdate() {
return new AcceptNewBearing(23, 1);
public static AcceptNewBearing newInstanceForBearingLabelUpdate() {
return new AcceptNewBearing(4, 500l);
}


private final int angleThreshold, timeThreshold;
private final int angleThreshold;
private final long timeThreshold;

private Bearing lastAcceptedBearing;
private long lastAcceptedBearingTimestamp;

public AcceptNewBearing(int angleeThresholdInDegree, int timeThresholdInSeconds) {
this.angleThreshold = angleeThresholdInDegree;
this.timeThreshold = timeThresholdInSeconds;
public AcceptNewBearing(int angleThresholdInDegree, long timeThresholdInMs) {
this.angleThreshold = angleThresholdInDegree;
this.timeThreshold = timeThresholdInMs;
this.lastAcceptedBearing = DeviceSensorManager.getInstance().getCurrentBearing();
this.lastAcceptedBearingTimestamp = 0l;
}
Expand Down Expand Up @@ -62,7 +63,7 @@ private boolean checkBearing(Bearing newBearing) {
return true;
} else if (this.lastAcceptedBearing.differenceTo(newBearing) < angleThreshold) {
return false;
} else if (System.currentTimeMillis() - this.lastAcceptedBearingTimestamp < this.timeThreshold * 1000l) {
} else if (System.currentTimeMillis() - this.lastAcceptedBearingTimestamp < this.timeThreshold) {
return false;
}
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,35 @@ public class AcceptNewPosition implements Serializable {

public static AcceptNewPosition newInstanceForObjectListUpdate() {
return new AcceptNewPosition(
50, 30, PositionManager.getInstance().getCurrentLocation());
50, 30000l, PositionManager.getInstance().getCurrentLocation());
}

public static AcceptNewPosition newInstanceForDistanceLabelUpdate() {
return new AcceptNewPosition(2, 1000l, null);
}

public static AcceptNewPosition newInstanceForTtsAnnouncement() {
return new AcceptNewPosition(
SettingsManager.getInstance().getTtsSettings().getDistanceAnnouncementInterval(),
10,
10000l,
PositionManager.getInstance().getCurrentLocation());
}

public static AcceptNewPosition newInstanceForDistanceLabelUpdate() {
return new AcceptNewPosition(3, 3, null);
public static AcceptNewPosition newInstanceForTtsAnnouncementOnFocus() {
return new AcceptNewPosition(
4, 3000l, PositionManager.getInstance().getCurrentLocation());
}


private final int distanceThreshold, timeThreshold;
private final int distanceThreshold;
private final long timeThreshold;

private Point lastAcceptedPoint;
private long lastAcceptedPointTimestamp;

public AcceptNewPosition(int distanceThresholdInMeters, int timeThresholdInSeconds, Point initAcceptedPoint) {
public AcceptNewPosition(int distanceThresholdInMeters, long timeThresholdInMs, Point initAcceptedPoint) {
this.distanceThreshold = distanceThresholdInMeters;
this.timeThreshold = timeThresholdInSeconds;
this.timeThreshold = timeThresholdInMs;
this.lastAcceptedPoint = initAcceptedPoint;
this.lastAcceptedPointTimestamp = 0l;
}
Expand Down Expand Up @@ -71,7 +77,7 @@ private boolean checkPoint(Point newPoint) {
return true;
} else if (this.lastAcceptedPoint.distanceTo(newPoint) < this.distanceThreshold) {
return false;
} else if (System.currentTimeMillis() - this.lastAcceptedPointTimestamp < this.timeThreshold * 1000l) {
} else if (System.currentTimeMillis() - this.lastAcceptedPointTimestamp < this.timeThreshold) {
return false;
}
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,12 @@
import java.util.Locale;
import org.json.JSONObject;
import org.walkersguide.android.data.object_with_id.Point;
import org.walkersguide.android.util.Helper;


public class ResolveCoordinatesTask extends ServerTask {

private Point point;

public ResolveCoordinatesTask(Point point) {
this.point = point;
}

@Override public void execute() throws AddressException {
public static StreetAddress getAddress(Point coordinatesPoint) throws AddressException {
final HistoryProfile addressPointProfile = HistoryProfile.addressPoints();

// first look into local database
Expand All @@ -36,11 +31,11 @@ public ResolveCoordinatesTask(Point point) {
StreetAddress address = (StreetAddress) objectWithId;
// calculate distance
// and select, if within 20m radius
if (this.point.distanceTo(address) < 20) {
ServerTaskExecutor.sendResolveCoordinatesTaskSuccessfulBroadcast(getId(), address);
return;
if (coordinatesPoint.distanceTo(address) < 20) {
return address;
}
// closest street address from cache is to far away
// that's possible to say because the request above sorts by distance
break;
}
}
Expand All @@ -51,9 +46,9 @@ public ResolveCoordinatesTask(Point point) {
Locale.ROOT,
"%1$s/reverse?format=jsonv2&lat=%2$f&lon=%3$f&accept-language=%4$s&addressdetails=1&zoom=18",
AddressUtility.ADDRESS_RESOLVER_URL,
this.point.getCoordinates().getLatitude(),
this.point.getCoordinates().getLongitude(),
Locale.getDefault().getLanguage());
coordinatesPoint.getCoordinates().getLatitude(),
coordinatesPoint.getCoordinates().getLongitude(),
Helper.getAppLocale().getLanguage());
JSONObject jsonStreetAddress = ServerUtility.performRequestAndReturnJsonObject(
requestUrl, null, AddressException.class);
if (jsonStreetAddress.has("error")) {
Expand All @@ -68,15 +63,27 @@ public ResolveCoordinatesTask(Point point) {
AddressException.RC_BAD_RESPONSE);
}

if (! isCancelled()) {
// check for accuracy of address
if (this.point.distanceTo(newAddress) > 100) {
// if the address differs for more than 100 meters, don't take it
throw new AddressException(
AddressException.RC_NO_ADDRESS_FOR_COORDINATES);
}
// check for accuracy of address
if (coordinatesPoint.distanceTo(newAddress) > 100) {
// if the address differs for more than 100 meters, don't take it
throw new AddressException(
AddressException.RC_NO_ADDRESS_FOR_COORDINATES);
}

addressPointProfile.addObject(newAddress);
return newAddress;
}


private Point point;

addressPointProfile.addObject(newAddress);
public ResolveCoordinatesTask(Point point) {
this.point = point;
}

@Override public void execute() throws AddressException {
StreetAddress newAddress = getAddress(this.point);
if (! isCancelled() && newAddress != null) {
ServerTaskExecutor.sendResolveCoordinatesTaskSuccessfulBroadcast(getId(), newAddress);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.Locale;


import org.json.JSONArray;
Expand All @@ -24,6 +23,7 @@
import org.walkersguide.android.server.wg.poi.PoiCategory;
import org.walkersguide.android.util.GlobalInstance;
import org.walkersguide.android.util.SettingsManager;
import org.walkersguide.android.util.Helper;


public class WgUtility {
Expand Down Expand Up @@ -184,7 +184,7 @@ public static JSONObject createServerParamList() throws JSONException {
requestJson.put(
"session_id", GlobalInstance.getInstance().getSessionId());
requestJson.put(
"language", Locale.getDefault().getLanguage());
"language", Helper.getAppLocale().getLanguage());
requestJson.put(
"prefer_translated_strings_in_osm_tags", SettingsManager.getInstance().getPreferTranslatedStrings());
// selected map id
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.walkersguide.android.server.wg.p2p;

import org.walkersguide.android.server.address.AddressException;
import org.walkersguide.android.R;
import org.walkersguide.android.database.profile.StaticProfile;
import org.walkersguide.android.server.wg.poi.PoiProfile;
Expand All @@ -24,6 +25,9 @@
import org.walkersguide.android.util.GlobalInstance;
import org.walkersguide.android.data.object_with_id.segment.RouteSegment;
import org.walkersguide.android.data.angle.Turn;
import org.walkersguide.android.data.object_with_id.point.GPS;
import org.walkersguide.android.data.object_with_id.point.point_with_address_data.StreetAddress;
import org.walkersguide.android.server.address.ResolveCoordinatesTask;


public class P2pRouteTask extends ServerTask {
Expand All @@ -43,6 +47,24 @@ public P2pRouteTask(P2pRouteRequest request, WayClassWeightSettings wayClassWeig
throw new WgException(WgException.RC_START_OR_DESTINATION_MISSING);
}

// if the start point is a nameless gps point then try to replace its name with the closest address nearby
if (startPoint instanceof GPS
&& ! startPoint.hasCustomName()) {
Timber.d("start point gps: %1$s", startPoint.getName());
StreetAddress closestAddress = null;
try {
closestAddress = ResolveCoordinatesTask.getAddress(startPoint);
} catch (AddressException e) {}
if (closestAddress != null) {
startPoint.rename(
String.format(
"%1$s %2$s",
GlobalInstance.getStringResource(R.string.labelNearby),
closestAddress.getName()));
Timber.d("renamed to %1$s", startPoint.getName());
}
}

// create server param list
JSONObject jsonServerParams = null;
try {
Expand Down
Loading

0 comments on commit 284a68b

Please sign in to comment.