Merge branch 'master' into srtmf_dialogs
# Conflicts: # OsmAnd/res/values/strings.xml
This commit is contained in:
commit
ac3aeacca1
32 changed files with 868 additions and 199 deletions
|
@ -1,9 +1,14 @@
|
||||||
package net.osmand.router;
|
package net.osmand.router;
|
||||||
|
|
||||||
import net.osmand.GPXUtilities;
|
import net.osmand.GPXUtilities.GPXFile;
|
||||||
|
import net.osmand.GPXUtilities.GPXTrackAnalysis;
|
||||||
|
import net.osmand.GPXUtilities.Track;
|
||||||
|
import net.osmand.GPXUtilities.TrkSegment;
|
||||||
|
import net.osmand.GPXUtilities.WptPt;
|
||||||
import net.osmand.PlatformUtil;
|
import net.osmand.PlatformUtil;
|
||||||
import net.osmand.osm.edit.Node;
|
import net.osmand.osm.edit.Node;
|
||||||
import net.osmand.osm.edit.OsmMapUtils;
|
import net.osmand.osm.edit.OsmMapUtils;
|
||||||
|
import net.osmand.util.Algorithms;
|
||||||
import net.osmand.util.MapUtils;
|
import net.osmand.util.MapUtils;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
|
@ -30,6 +35,8 @@ public class RouteColorize {
|
||||||
public static final int RED = rgbaToDecimal(243, 55, 77, 255);
|
public static final int RED = rgbaToDecimal(243, 55, 77, 255);
|
||||||
public static final int[] colors = new int[] {GREEN, YELLOW, RED};
|
public static final int[] colors = new int[] {GREEN, YELLOW, RED};
|
||||||
|
|
||||||
|
private static final int MAX_SLOPE_VALUE = 25;
|
||||||
|
|
||||||
public enum ColorizationType {
|
public enum ColorizationType {
|
||||||
ELEVATION,
|
ELEVATION,
|
||||||
SPEED,
|
SPEED,
|
||||||
|
@ -75,7 +82,11 @@ public class RouteColorize {
|
||||||
/**
|
/**
|
||||||
* @param type ELEVATION, SPEED, SLOPE
|
* @param type ELEVATION, SPEED, SLOPE
|
||||||
*/
|
*/
|
||||||
public RouteColorize(int zoom, GPXUtilities.GPXFile gpxFile, ColorizationType type) {
|
public RouteColorize(int zoom, GPXFile gpxFile, ColorizationType type) {
|
||||||
|
this(zoom, gpxFile, null, type, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RouteColorize(int zoom, GPXFile gpxFile, GPXTrackAnalysis analysis, ColorizationType type, float maxProfileSpeed) {
|
||||||
|
|
||||||
if (!gpxFile.hasTrkPt()) {
|
if (!gpxFile.hasTrkPt()) {
|
||||||
LOG.warn("GPX file is not consist of track points");
|
LOG.warn("GPX file is not consist of track points");
|
||||||
|
@ -85,21 +96,30 @@ public class RouteColorize {
|
||||||
List<Double> latList = new ArrayList<>();
|
List<Double> latList = new ArrayList<>();
|
||||||
List<Double> lonList = new ArrayList<>();
|
List<Double> lonList = new ArrayList<>();
|
||||||
List<Double> valList = new ArrayList<>();
|
List<Double> valList = new ArrayList<>();
|
||||||
for (GPXUtilities.Track t : gpxFile.tracks) {
|
int wptIdx = 0;
|
||||||
for (GPXUtilities.TrkSegment ts : t.segments) {
|
|
||||||
for (GPXUtilities.WptPt p : ts.points) {
|
if (analysis == null) {
|
||||||
|
analysis = Algorithms.isEmpty(gpxFile.path)
|
||||||
|
? gpxFile.getAnalysis(System.currentTimeMillis())
|
||||||
|
: gpxFile.getAnalysis(gpxFile.modifiedTime);
|
||||||
|
}
|
||||||
|
for (Track t : gpxFile.tracks) {
|
||||||
|
for (TrkSegment ts : t.segments) {
|
||||||
|
for (WptPt p : ts.points) {
|
||||||
latList.add(p.lat);
|
latList.add(p.lat);
|
||||||
lonList.add(p.lon);
|
lonList.add(p.lon);
|
||||||
if (type == ColorizationType.SPEED) {
|
if (type == ColorizationType.SPEED) {
|
||||||
valList.add(p.speed);
|
valList.add((double) analysis.speedData.get(wptIdx).speed);
|
||||||
} else {
|
} else {
|
||||||
valList.add(p.ele);
|
valList.add((double) analysis.elevationData.get(wptIdx).elevation);
|
||||||
}
|
}
|
||||||
|
wptIdx++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.zoom = zoom;
|
this.zoom = zoom;
|
||||||
|
colorizationType = type;
|
||||||
latitudes = listToArray(latList);
|
latitudes = listToArray(latList);
|
||||||
longitudes = listToArray(lonList);
|
longitudes = listToArray(lonList);
|
||||||
|
|
||||||
|
@ -108,9 +128,8 @@ public class RouteColorize {
|
||||||
} else {
|
} else {
|
||||||
values = listToArray(valList);
|
values = listToArray(valList);
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateMinMaxValue();
|
calculateMinMaxValue();
|
||||||
colorizationType = type;
|
maxValue = getMaxValue(colorizationType, analysis, minValue, maxProfileSpeed);
|
||||||
checkPalette();
|
checkPalette();
|
||||||
sortPalette();
|
sortPalette();
|
||||||
}
|
}
|
||||||
|
@ -194,7 +213,7 @@ public class RouteColorize {
|
||||||
return rgbaToDecimal((int) resultRed, (int) resultGreen, (int) resultBlue, (int) resultAlpha);
|
return rgbaToDecimal((int) resultRed, (int) resultGreen, (int) resultBlue, (int) resultAlpha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return getDefaultColor();
|
return getTransparentColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPalette(double[][] palette) {
|
public void setPalette(double[][] palette) {
|
||||||
|
@ -209,12 +228,12 @@ public class RouteColorize {
|
||||||
}
|
}
|
||||||
setPalette(new double[][] {
|
setPalette(new double[][] {
|
||||||
{minValue, gradientPalette[0]},
|
{minValue, gradientPalette[0]},
|
||||||
{colorizationType == ColorizationType.SLOPE ? 0 : (minValue + maxValue) / 2, gradientPalette[1]},
|
{(minValue + maxValue) / 2, gradientPalette[1]},
|
||||||
{maxValue, gradientPalette[2]}
|
{maxValue, gradientPalette[2]}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getDefaultColor() {
|
private int getTransparentColor() {
|
||||||
return rgbaToDecimal(0, 0, 0, 0);
|
return rgbaToDecimal(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,7 +314,7 @@ public class RouteColorize {
|
||||||
|
|
||||||
double[][] defaultPalette = {
|
double[][] defaultPalette = {
|
||||||
{minValue, GREEN},
|
{minValue, GREEN},
|
||||||
{colorizationType == ColorizationType.SLOPE ? 0 : (minValue + maxValue) / 2, YELLOW},
|
{(minValue + maxValue) / 2, YELLOW},
|
||||||
{maxValue, RED}
|
{maxValue, RED}
|
||||||
};
|
};
|
||||||
palette = defaultPalette;
|
palette = defaultPalette;
|
||||||
|
@ -397,6 +416,20 @@ public class RouteColorize {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static double getMinValue(ColorizationType type, GPXTrackAnalysis analysis) {
|
||||||
|
return type == ColorizationType.ELEVATION ? analysis.minElevation : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getMaxValue(ColorizationType type, GPXTrackAnalysis analysis, double minValue, double maxProfileSpeed) {
|
||||||
|
if (type == ColorizationType.SPEED) {
|
||||||
|
return Math.max(analysis.maxSpeed, maxProfileSpeed);
|
||||||
|
} else if (type == ColorizationType.ELEVATION) {
|
||||||
|
return Math.max(analysis.maxElevation, minValue + 50);
|
||||||
|
} else {
|
||||||
|
return MAX_SLOPE_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void calculateMinMaxValue() {
|
private void calculateMinMaxValue() {
|
||||||
if (values.length == 0)
|
if (values.length == 0)
|
||||||
return;
|
return;
|
||||||
|
@ -457,5 +490,4 @@ public class RouteColorize {
|
||||||
this.val = val;
|
this.val = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -5,10 +5,10 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:padding="0dp"
|
android:padding="0dp"
|
||||||
osmand:contentInsetLeft="0dp"
|
|
||||||
osmand:contentInsetStart="0dp"
|
|
||||||
osmand:contentInsetRight="0dp"
|
|
||||||
osmand:contentInsetEnd="0dp"
|
osmand:contentInsetEnd="0dp"
|
||||||
|
osmand:contentInsetLeft="0dp"
|
||||||
|
osmand:contentInsetRight="0dp"
|
||||||
|
osmand:contentInsetStart="0dp"
|
||||||
osmand:theme="@style/ThemeOverlay.AppCompat.ActionBar">
|
osmand:theme="@style/ThemeOverlay.AppCompat.ActionBar">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
@ -20,9 +20,9 @@
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:minHeight="@dimen/toolbar_height"
|
|
||||||
android:background="?attr/card_and_list_background_basic"
|
android:background="?attr/card_and_list_background_basic"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
|
android:minHeight="@dimen/toolbar_height"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
|
@ -31,22 +31,22 @@
|
||||||
android:layout_width="@dimen/toolbar_height"
|
android:layout_width="@dimen/toolbar_height"
|
||||||
android:layout_height="@dimen/toolbar_height"
|
android:layout_height="@dimen/toolbar_height"
|
||||||
android:contentDescription="@string/access_shared_string_navigate_up"
|
android:contentDescription="@string/access_shared_string_navigate_up"
|
||||||
osmand:srcCompat="@drawable/ic_arrow_back"
|
android:tint="?attr/default_icon_color"
|
||||||
android:tint="?attr/default_icon_color" />
|
osmand:srcCompat="@drawable/ic_arrow_back" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_weight="1"
|
|
||||||
android:layout_marginLeft="@dimen/content_padding"
|
|
||||||
android:layout_marginRight="@dimen/content_padding"
|
|
||||||
android:layout_marginStart="@dimen/content_padding"
|
android:layout_marginStart="@dimen/content_padding"
|
||||||
|
android:layout_marginLeft="@dimen/content_padding"
|
||||||
android:layout_marginEnd="@dimen/content_padding"
|
android:layout_marginEnd="@dimen/content_padding"
|
||||||
android:paddingTop="@dimen/content_padding_half"
|
android:layout_marginRight="@dimen/content_padding"
|
||||||
android:paddingBottom="@dimen/content_padding_half"
|
android:layout_weight="1"
|
||||||
android:background="?attr/card_and_list_background_basic"
|
android:background="?attr/card_and_list_background_basic"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical"
|
||||||
|
android:paddingTop="@dimen/content_padding_half"
|
||||||
|
android:paddingBottom="@dimen/content_padding_half">
|
||||||
|
|
||||||
<net.osmand.plus.widgets.TextViewEx
|
<net.osmand.plus.widgets.TextViewEx
|
||||||
android:id="@+id/toolbar_title"
|
android:id="@+id/toolbar_title"
|
||||||
|
@ -71,6 +71,7 @@
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<include
|
<include
|
||||||
|
android:id="@+id/toolbar_icon_container"
|
||||||
layout="@layout/profile_button_small"
|
layout="@layout/profile_button_small"
|
||||||
android:layout_width="@dimen/list_header_height"
|
android:layout_width="@dimen/list_header_height"
|
||||||
android:layout_height="@dimen/list_header_height"
|
android:layout_height="@dimen/list_header_height"
|
||||||
|
|
|
@ -88,7 +88,6 @@
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?attr/card_and_list_background_basic"
|
|
||||||
android:minHeight="@dimen/toolbar_height"
|
android:minHeight="@dimen/toolbar_height"
|
||||||
android:padding="0dp"
|
android:padding="0dp"
|
||||||
osmand:contentInsetEnd="0dp"
|
osmand:contentInsetEnd="0dp"
|
||||||
|
|
|
@ -144,6 +144,7 @@
|
||||||
<string name="poi_diplomatic_services_non_immigrant_visas_filter">Non-immigrant visas</string>
|
<string name="poi_diplomatic_services_non_immigrant_visas_filter">Non-immigrant visas</string>
|
||||||
<string name="poi_diplomatic_services_immigrant_visas_filter">Immigrant visas</string>
|
<string name="poi_diplomatic_services_immigrant_visas_filter">Immigrant visas</string>
|
||||||
<string name="poi_diplomatic_services_citizen_services_filter">Citizen services</string>
|
<string name="poi_diplomatic_services_citizen_services_filter">Citizen services</string>
|
||||||
|
<string name="poi_bay_filter">Bay type</string>
|
||||||
|
|
||||||
<!-- categories -->
|
<!-- categories -->
|
||||||
<string name="poi_shop">Store</string>
|
<string name="poi_shop">Store</string>
|
||||||
|
@ -284,7 +285,6 @@
|
||||||
<string name="poi_ship_chandler">Ship chandler</string>
|
<string name="poi_ship_chandler">Ship chandler</string>
|
||||||
<string name="poi_sports">Sporting goods</string>
|
<string name="poi_sports">Sporting goods</string>
|
||||||
<string name="poi_stationery">Stationery store</string>
|
<string name="poi_stationery">Stationery store</string>
|
||||||
<string name="poi_tableware">Tableware store</string>
|
|
||||||
<string name="poi_ticket">Ticket sales</string>
|
<string name="poi_ticket">Ticket sales</string>
|
||||||
<string name="poi_tobacco">Tobacco store</string>
|
<string name="poi_tobacco">Tobacco store</string>
|
||||||
<string name="poi_toys">Toyshop</string>
|
<string name="poi_toys">Toyshop</string>
|
||||||
|
@ -4379,4 +4379,6 @@
|
||||||
<string name="poi_horseshoes">Horseshoes</string>
|
<string name="poi_horseshoes">Horseshoes</string>
|
||||||
<string name="poi_kickboxing">Kickboxing</string>
|
<string name="poi_kickboxing">Kickboxing</string>
|
||||||
|
|
||||||
|
<string name="poi_office_diplomatic">Diplomatic office</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -12,6 +12,11 @@
|
||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
<string name="map_quick_action_pattern">%1$s → …</string>
|
||||||
|
<string name="output">Output</string>
|
||||||
|
<string name="user_points">User points</string>
|
||||||
|
<string name="announce_when_exceeded">Announce when exceeded</string>
|
||||||
|
<string name="exit_number">Exit number</string>
|
||||||
<string name="srtm_download_single_help_message">Please select the needed format. You will need to re-download the file to change the format.</string>
|
<string name="srtm_download_single_help_message">Please select the needed format. You will need to re-download the file to change the format.</string>
|
||||||
<string name="srtm_download_list_help_message">OsmAnd provides contour lines data in meters and feet. You will need to re-download the file to change the format.</string>
|
<string name="srtm_download_list_help_message">OsmAnd provides contour lines data in meters and feet. You will need to re-download the file to change the format.</string>
|
||||||
<string name="srtm_unit_format">Contour lines unit format</string>
|
<string name="srtm_unit_format">Contour lines unit format</string>
|
||||||
|
@ -2480,7 +2485,7 @@
|
||||||
<string name="traffic_warning_calming">Traffic calming</string>
|
<string name="traffic_warning_calming">Traffic calming</string>
|
||||||
<string name="traffic_warning_speed_camera">Speed camera</string>
|
<string name="traffic_warning_speed_camera">Speed camera</string>
|
||||||
<string name="traffic_warning">Traffic warning</string>
|
<string name="traffic_warning">Traffic warning</string>
|
||||||
<string name="speak_favorites">Favorites nearby</string>
|
<string name="speak_favorites">Nearby favorites</string>
|
||||||
<string name="speak_poi">Nearby POI</string>
|
<string name="speak_poi">Nearby POI</string>
|
||||||
<string name="way_alarms">Traffic warnings</string>
|
<string name="way_alarms">Traffic warnings</string>
|
||||||
<string name="background_service_is_enabled_question">OsmAnd background service still running. Stop it, too?</string>
|
<string name="background_service_is_enabled_question">OsmAnd background service still running. Stop it, too?</string>
|
||||||
|
|
|
@ -11,11 +11,41 @@
|
||||||
android:title="@string/voice_announces_info"
|
android:title="@string/voice_announces_info"
|
||||||
tools:icon="@drawable/ic_action_info_dark" />
|
tools:icon="@drawable/ic_action_info_dark" />
|
||||||
|
|
||||||
|
<net.osmand.plus.settings.preferences.ListPreferenceEx
|
||||||
|
android:key="voice_provider"
|
||||||
|
android:layout="@layout/preference_with_descr"
|
||||||
|
android:persistent="false"
|
||||||
|
android:title="@string/shared_string_languages"
|
||||||
|
tools:icon="@drawable/ic_action_volume_up" />
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:layout="@layout/simple_divider_item"
|
||||||
|
android:selectable="false" />
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:key="language_and_output"
|
||||||
|
android:layout="@layout/preference_category_with_descr"
|
||||||
|
android:title="@string/accessibility_announce" />
|
||||||
|
|
||||||
|
<net.osmand.plus.settings.preferences.SwitchPreferenceEx
|
||||||
|
android:key="turn_screen_on_navigation_instructions"
|
||||||
|
android:layout="@layout/preference_with_descr"
|
||||||
|
android:title="@string/turn_screen_on_navigation_instructions" />
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
android:key="speak_street_names"
|
android:key="speak_street_names"
|
||||||
android:layout="@layout/preference_switch"
|
android:layout="@layout/preference_switch"
|
||||||
android:title="@string/speak_street_names" />
|
android:title="@string/speak_street_names" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:key="exit_number_names"
|
||||||
|
android:layout="@layout/preference_switch"
|
||||||
|
android:title="@string/exit_number" />
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:layout="@layout/divider_half_item"
|
||||||
|
android:selectable="false" />
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
android:key="speak_traffic_warnings"
|
android:key="speak_traffic_warnings"
|
||||||
android:layout="@layout/preference_switch"
|
android:layout="@layout/preference_switch"
|
||||||
|
@ -26,42 +56,25 @@
|
||||||
android:layout="@layout/preference_switch"
|
android:layout="@layout/preference_switch"
|
||||||
android:title="@string/speak_pedestrian" />
|
android:title="@string/speak_pedestrian" />
|
||||||
|
|
||||||
<Preference
|
|
||||||
android:layout="@layout/simple_divider_item"
|
|
||||||
android:selectable="false" />
|
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
|
||||||
android:key="speak_speed_limit"
|
|
||||||
android:layout="@layout/preference_switch"
|
|
||||||
android:title="@string/speak_speed_limit" />
|
|
||||||
|
|
||||||
<net.osmand.plus.settings.preferences.ListPreferenceEx
|
|
||||||
android:key="speed_limit_exceed"
|
|
||||||
android:layout="@layout/preference_with_descr"
|
|
||||||
android:title="@string/speed_limit_exceed" />
|
|
||||||
|
|
||||||
<Preference
|
|
||||||
android:layout="@layout/simple_divider_item"
|
|
||||||
android:selectable="false" />
|
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
android:key="speak_cameras"
|
android:key="speak_cameras"
|
||||||
android:layout="@layout/preference_switch"
|
android:layout="@layout/preference_switch"
|
||||||
android:title="@string/speak_cameras" />
|
android:title="@string/speak_cameras" />
|
||||||
|
|
||||||
<Preference
|
|
||||||
android:key="speed_cameras_uninstalled"
|
|
||||||
android:layout="@layout/preference_permission"
|
|
||||||
android:persistent="false"
|
|
||||||
android:summary="@string/read_more"
|
|
||||||
android:title="@string/speed_cameras_alert"
|
|
||||||
tools:icon="@drawable/ic_action_alert" />
|
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
android:key="speak_tunnels"
|
android:key="speak_tunnels"
|
||||||
android:layout="@layout/preference_switch"
|
android:layout="@layout/preference_switch"
|
||||||
android:title="@string/show_tunnels" />
|
android:title="@string/show_tunnels" />
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:layout="@layout/divider_half_item"
|
||||||
|
android:selectable="false" />
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:key="language_and_output"
|
||||||
|
android:layout="@layout/preference_category_with_descr"
|
||||||
|
android:title="@string/user_points" />
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
android:key="announce_wpt"
|
android:key="announce_wpt"
|
||||||
android:layout="@layout/preference_switch"
|
android:layout="@layout/preference_switch"
|
||||||
|
@ -77,10 +90,38 @@
|
||||||
android:layout="@layout/preference_switch"
|
android:layout="@layout/preference_switch"
|
||||||
android:title="@string/speak_poi" />
|
android:title="@string/speak_poi" />
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:key="language_and_output"
|
||||||
|
android:layout="@layout/preference_category_with_descr"
|
||||||
|
android:title="@string/speak_speed_limit" />
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
android:layout="@layout/simple_divider_item"
|
android:layout="@layout/simple_divider_item"
|
||||||
android:selectable="false" />
|
android:selectable="false" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:key="speak_speed_limit"
|
||||||
|
android:layout="@layout/preference_switch"
|
||||||
|
android:title="@string/announce_when_exceeded" />
|
||||||
|
|
||||||
|
<net.osmand.plus.settings.preferences.ListPreferenceEx
|
||||||
|
android:key="speed_limit_exceed"
|
||||||
|
android:layout="@layout/preference_with_descr"
|
||||||
|
android:title="@string/speed_limit_exceed" />
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:layout="@layout/simple_divider_item"
|
||||||
|
android:selectable="false" />
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:layout="@layout/simple_divider_item"
|
||||||
|
android:selectable="false" />
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:key="language_and_output"
|
||||||
|
android:layout="@layout/preference_category_with_descr"
|
||||||
|
android:title="@string/shared_string_options" />
|
||||||
|
|
||||||
<net.osmand.plus.settings.preferences.ListPreferenceEx
|
<net.osmand.plus.settings.preferences.ListPreferenceEx
|
||||||
android:key="keep_informing"
|
android:key="keep_informing"
|
||||||
android:layout="@layout/preference_with_descr"
|
android:layout="@layout/preference_with_descr"
|
||||||
|
@ -98,13 +139,6 @@
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:key="language_and_output"
|
android:key="language_and_output"
|
||||||
android:layout="@layout/preference_category_with_descr"
|
android:layout="@layout/preference_category_with_descr"
|
||||||
android:title="@string/language_and_output" />
|
android:title="@string/output" />
|
||||||
|
|
||||||
<net.osmand.plus.settings.preferences.ListPreferenceEx
|
|
||||||
android:key="voice_provider"
|
|
||||||
android:layout="@layout/preference_with_descr"
|
|
||||||
android:persistent="false"
|
|
||||||
android:title="@string/voice_provider"
|
|
||||||
tools:icon="@drawable/ic_action_volume_up" />
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
|
@ -151,6 +151,10 @@ public class AndroidUtils {
|
||||||
return resizedBitmap;
|
return resizedBitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Bitmap createScaledBitmap(Drawable drawable, int width, int height) {
|
||||||
|
return scaleBitmap(drawableToBitmap(drawable), width, height, false);
|
||||||
|
}
|
||||||
|
|
||||||
public static ColorStateList createBottomNavColorStateList(Context ctx, boolean nightMode) {
|
public static ColorStateList createBottomNavColorStateList(Context ctx, boolean nightMode) {
|
||||||
return AndroidUtils.createCheckedColorStateList(ctx, nightMode,
|
return AndroidUtils.createCheckedColorStateList(ctx, nightMode,
|
||||||
R.color.icon_color_default_light, R.color.wikivoyage_active_light,
|
R.color.icon_color_default_light, R.color.wikivoyage_active_light,
|
||||||
|
|
|
@ -92,6 +92,8 @@ public class MapActivityKeyListener implements KeyEvent.Callback {
|
||||||
return true;
|
return true;
|
||||||
} else if (keyCode == KeyEvent.KEYCODE_C) {
|
} else if (keyCode == KeyEvent.KEYCODE_C) {
|
||||||
mapActivity.getMapViewTrackingUtilities().backToLocationImpl();
|
mapActivity.getMapViewTrackingUtilities().backToLocationImpl();
|
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_D) {
|
||||||
|
mapActivity.getMapViewTrackingUtilities().switchRotateMapMode();
|
||||||
} else if (settings.EXTERNAL_INPUT_DEVICE.get() == PARROT_EXTERNAL_DEVICE) {
|
} else if (settings.EXTERNAL_INPUT_DEVICE.get() == PARROT_EXTERNAL_DEVICE) {
|
||||||
// Parrot device has only dpad left and right
|
// Parrot device has only dpad left and right
|
||||||
if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
|
if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
|
||||||
|
|
|
@ -39,6 +39,8 @@ import java.util.Map;
|
||||||
|
|
||||||
public class MapViewTrackingUtilities implements OsmAndLocationListener, IMapLocationListener,
|
public class MapViewTrackingUtilities implements OsmAndLocationListener, IMapLocationListener,
|
||||||
OsmAndCompassListener, MapMarkerChangedListener {
|
OsmAndCompassListener, MapMarkerChangedListener {
|
||||||
|
|
||||||
|
private static final int COMPASS_REQUEST_TIME_INTERVAL_MS = 5000;
|
||||||
private static final int AUTO_FOLLOW_MSG_ID = OsmAndConstants.UI_HANDLER_LOCATION_SERVICE + 4;
|
private static final int AUTO_FOLLOW_MSG_ID = OsmAndConstants.UI_HANDLER_LOCATION_SERVICE + 4;
|
||||||
|
|
||||||
private long lastTimeAutoZooming = 0;
|
private long lastTimeAutoZooming = 0;
|
||||||
|
@ -59,6 +61,7 @@ public class MapViewTrackingUtilities implements OsmAndLocationListener, IMapLoc
|
||||||
private Float heading;
|
private Float heading;
|
||||||
private boolean drivingRegionUpdated = false;
|
private boolean drivingRegionUpdated = false;
|
||||||
private boolean movingToMyLocation = false;
|
private boolean movingToMyLocation = false;
|
||||||
|
private long compassRequest;
|
||||||
|
|
||||||
public MapViewTrackingUtilities(OsmandApplication app){
|
public MapViewTrackingUtilities(OsmandApplication app){
|
||||||
this.app = app;
|
this.app = app;
|
||||||
|
@ -425,6 +428,21 @@ public class MapViewTrackingUtilities implements OsmAndLocationListener, IMapLoc
|
||||||
}
|
}
|
||||||
|
|
||||||
public void switchRotateMapMode() {
|
public void switchRotateMapMode() {
|
||||||
|
if (app.getRoutingHelper().isFollowingMode()) {
|
||||||
|
if (compassRequest + COMPASS_REQUEST_TIME_INTERVAL_MS > System.currentTimeMillis()) {
|
||||||
|
compassRequest = 0;
|
||||||
|
switchRotateMapModeImpl();
|
||||||
|
} else {
|
||||||
|
compassRequest = System.currentTimeMillis();
|
||||||
|
app.showShortToastMessage(app.getString(R.string.press_again_to_change_the_map_orientation));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
compassRequest = 0;
|
||||||
|
switchRotateMapModeImpl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void switchRotateMapModeImpl(){
|
||||||
if (mapView != null) {
|
if (mapView != null) {
|
||||||
String rotMode = app.getString(R.string.rotate_map_none_opt);
|
String rotMode = app.getString(R.string.rotate_map_none_opt);
|
||||||
if (settings.ROTATE_MAP.get() == OsmandSettings.ROTATE_MAP_NONE && mapView.getRotate() != 0) {
|
if (settings.ROTATE_MAP.get() == OsmandSettings.ROTATE_MAP_NONE && mapView.getRotate() != 0) {
|
||||||
|
|
|
@ -2,9 +2,6 @@ package net.osmand.plus.measurementtool;
|
||||||
|
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import net.osmand.GPXUtilities.GPXFile;
|
import net.osmand.GPXUtilities.GPXFile;
|
||||||
import net.osmand.GPXUtilities.TrkSegment;
|
import net.osmand.GPXUtilities.TrkSegment;
|
||||||
import net.osmand.GPXUtilities.WptPt;
|
import net.osmand.GPXUtilities.WptPt;
|
||||||
|
@ -38,12 +35,18 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import static net.osmand.plus.measurementtool.MeasurementEditingContext.CalculationMode.NEXT_SEGMENT;
|
||||||
import static net.osmand.plus.measurementtool.MeasurementEditingContext.CalculationMode.WHOLE_TRACK;
|
import static net.osmand.plus.measurementtool.MeasurementEditingContext.CalculationMode.WHOLE_TRACK;
|
||||||
import static net.osmand.plus.measurementtool.command.MeasurementModeCommand.MeasurementCommandType.APPROXIMATE_POINTS;
|
import static net.osmand.plus.measurementtool.command.MeasurementModeCommand.MeasurementCommandType.APPROXIMATE_POINTS;
|
||||||
|
|
||||||
|
@ -1111,6 +1114,24 @@ public class MeasurementEditingContext implements IRouteSettingsListener {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isInMultiProfileMode() {
|
||||||
|
if (lastCalculationMode == CalculationMode.NEXT_SEGMENT) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Set<String> profiles = new HashSet<>();
|
||||||
|
for (RoadSegmentData segmentData : roadSegmentData.values()) {
|
||||||
|
String profile = segmentData.getAppMode().getStringKey();
|
||||||
|
if (!DEFAULT_APP_MODE.getStringKey().equals(profile)) {
|
||||||
|
profiles.add(profile);
|
||||||
|
if (profiles.size() >= 2) {
|
||||||
|
lastCalculationMode = NEXT_SEGMENT;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRouteSettingsChanged(@Nullable ApplicationMode mode) {
|
public void onRouteSettingsChanged(@Nullable ApplicationMode mode) {
|
||||||
recalculateRouteSegments(mode);
|
recalculateRouteSegments(mode);
|
||||||
|
|
|
@ -23,6 +23,8 @@ import net.osmand.plus.views.OsmandMapTileView;
|
||||||
import net.osmand.plus.views.Renderable;
|
import net.osmand.plus.views.Renderable;
|
||||||
import net.osmand.plus.views.layers.ContextMenuLayer;
|
import net.osmand.plus.views.layers.ContextMenuLayer;
|
||||||
import net.osmand.plus.views.layers.geometry.GeometryWay;
|
import net.osmand.plus.views.layers.geometry.GeometryWay;
|
||||||
|
import net.osmand.plus.views.layers.geometry.MultiProfileGeometryWay;
|
||||||
|
import net.osmand.plus.views.layers.geometry.MultiProfileGeometryWayContext;
|
||||||
import net.osmand.util.MapUtils;
|
import net.osmand.util.MapUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -33,20 +35,28 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL
|
||||||
|
|
||||||
private OsmandMapTileView view;
|
private OsmandMapTileView view;
|
||||||
private boolean inMeasurementMode;
|
private boolean inMeasurementMode;
|
||||||
|
|
||||||
private Bitmap centerIconDay;
|
private Bitmap centerIconDay;
|
||||||
private Bitmap centerIconNight;
|
private Bitmap centerIconNight;
|
||||||
private Bitmap pointIcon;
|
private Bitmap pointIcon;
|
||||||
private Bitmap applyingPointIcon;
|
private Bitmap applyingPointIcon;
|
||||||
private Paint bitmapPaint;
|
private Paint bitmapPaint;
|
||||||
private final RenderingLineAttributes lineAttrs = new RenderingLineAttributes("measureDistanceLine");
|
private final RenderingLineAttributes lineAttrs = new RenderingLineAttributes("measureDistanceLine");
|
||||||
|
private final RenderingLineAttributes multiProfileLineAttrs = new RenderingLineAttributes("multiProfileMeasureDistanceLine");
|
||||||
|
|
||||||
|
private MultiProfileGeometryWay multiProfileGeometry;
|
||||||
|
private MultiProfileGeometryWayContext multiProfileGeometryWayContext;
|
||||||
|
|
||||||
private int marginPointIconX;
|
private int marginPointIconX;
|
||||||
private int marginPointIconY;
|
private int marginPointIconY;
|
||||||
private int marginApplyingPointIconX;
|
private int marginApplyingPointIconX;
|
||||||
private int marginApplyingPointIconY;
|
private int marginApplyingPointIconY;
|
||||||
private final Path path = new Path();
|
private final Path path = new Path();
|
||||||
|
|
||||||
private final List<Float> tx = new ArrayList<>();
|
private final List<Float> tx = new ArrayList<>();
|
||||||
private final List<Float> ty = new ArrayList<>();
|
private final List<Float> ty = new ArrayList<>();
|
||||||
private OnMeasureDistanceToCenter measureDistanceToCenterListener;
|
private OnMeasureDistanceToCenter measureDistanceToCenterListener;
|
||||||
|
|
||||||
private OnSingleTapListener singleTapListener;
|
private OnSingleTapListener singleTapListener;
|
||||||
private OnEnterMovePointModeListener enterMovePointModeListener;
|
private OnEnterMovePointModeListener enterMovePointModeListener;
|
||||||
private LatLon pressedPointLatLon;
|
private LatLon pressedPointLatLon;
|
||||||
|
@ -63,6 +73,19 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL
|
||||||
pointIcon = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_measure_point_day);
|
pointIcon = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_measure_point_day);
|
||||||
applyingPointIcon = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_measure_point_move_day);
|
applyingPointIcon = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_measure_point_move_day);
|
||||||
|
|
||||||
|
float density = view.getDensity();
|
||||||
|
multiProfileLineAttrs.isPaint_1 = false;
|
||||||
|
multiProfileLineAttrs.paint_1.setColor(0xFFFFFFFF);
|
||||||
|
multiProfileLineAttrs.paint_1.setStyle(Paint.Style.FILL);
|
||||||
|
multiProfileLineAttrs.paint.setStrokeWidth(density * 14);
|
||||||
|
multiProfileLineAttrs.paint2.setStrokeWidth(density * 10);
|
||||||
|
multiProfileLineAttrs.isPaint3 = false;
|
||||||
|
multiProfileLineAttrs.paint3.setStrokeWidth(density * 2);
|
||||||
|
|
||||||
|
multiProfileGeometryWayContext = new MultiProfileGeometryWayContext(
|
||||||
|
view.getContext(), view.getApplication().getUIUtilities(), density);
|
||||||
|
multiProfileGeometry = new MultiProfileGeometryWay(multiProfileGeometryWayContext);
|
||||||
|
|
||||||
bitmapPaint = new Paint();
|
bitmapPaint = new Paint();
|
||||||
bitmapPaint.setAntiAlias(true);
|
bitmapPaint.setAntiAlias(true);
|
||||||
bitmapPaint.setDither(true);
|
bitmapPaint.setDither(true);
|
||||||
|
@ -194,16 +217,24 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (editingCtx.isInMultiProfileMode()) {
|
||||||
|
multiProfileGeometryWayContext.updatePaints(settings.isNightMode(), multiProfileLineAttrs);
|
||||||
|
multiProfileGeometry.updateRoute(tb, editingCtx.getRoadSegmentData(), editingCtx.getBeforeSegments(), editingCtx.getAfterSegments());
|
||||||
|
multiProfileGeometry.drawSegments(canvas, tb);
|
||||||
|
} else {
|
||||||
|
multiProfileGeometry.clearWay();
|
||||||
List<TrkSegment> before = editingCtx.getBeforeTrkSegmentLine();
|
List<TrkSegment> before = editingCtx.getBeforeTrkSegmentLine();
|
||||||
for (TrkSegment segment : before) {
|
for (TrkSegment segment : before) {
|
||||||
new Renderable.StandardTrack(new ArrayList<>(segment.points), 17.2).
|
new Renderable.StandardTrack(new ArrayList<>(segment.points), 17.2).
|
||||||
drawSegment(view.getZoom(), lineAttrs.paint, canvas, tb);
|
drawSegment(view.getZoom(), lineAttrs.paint, canvas, tb);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<TrkSegment> after = editingCtx.getAfterTrkSegmentLine();
|
List<TrkSegment> after = editingCtx.getAfterTrkSegmentLine();
|
||||||
for (TrkSegment segment : after) {
|
for (TrkSegment segment : after) {
|
||||||
new Renderable.StandardTrack(new ArrayList<>(segment.points), 17.2).
|
new Renderable.StandardTrack(new ArrayList<>(segment.points), 17.2).
|
||||||
drawSegment(view.getZoom(), lineAttrs.paint, canvas, tb);
|
drawSegment(view.getZoom(), lineAttrs.paint, canvas, tb);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
drawPoints(canvas, tb);
|
drawPoints(canvas, tb);
|
||||||
}
|
}
|
||||||
|
@ -237,10 +268,10 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL
|
||||||
List<WptPt> beforePoints = editingCtx.getBeforePoints();
|
List<WptPt> beforePoints = editingCtx.getBeforePoints();
|
||||||
List<WptPt> afterPoints = editingCtx.getAfterPoints();
|
List<WptPt> afterPoints = editingCtx.getAfterPoints();
|
||||||
if (beforePoints.size() > 0) {
|
if (beforePoints.size() > 0) {
|
||||||
drawPointIcon(canvas, tb, beforePoints.get(beforePoints.size() - 1));
|
drawPointIcon(canvas, tb, beforePoints.get(beforePoints.size() - 1), true);
|
||||||
}
|
}
|
||||||
if (afterPoints.size() > 0) {
|
if (afterPoints.size() > 0) {
|
||||||
drawPointIcon(canvas, tb, afterPoints.get(0));
|
drawPointIcon(canvas, tb, afterPoints.get(0), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (editingCtx.getSelectedPointPosition() != -1) {
|
if (editingCtx.getSelectedPointPosition() != -1) {
|
||||||
|
@ -287,25 +318,13 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL
|
||||||
}
|
}
|
||||||
if (overlapped) {
|
if (overlapped) {
|
||||||
WptPt pt = points.get(0);
|
WptPt pt = points.get(0);
|
||||||
if (pt != lastBeforePoint && pt != firstAfterPoint && isInTileBox(tb, pt)) {
|
drawPointIcon(canvas, tb, pt, false);
|
||||||
float locX = tb.getPixXFromLatLon(pt.lat, pt.lon);
|
|
||||||
float locY = tb.getPixYFromLatLon(pt.lat, pt.lon);
|
|
||||||
canvas.drawBitmap(pointIcon, locX - marginPointIconX, locY - marginPointIconY, bitmapPaint);
|
|
||||||
}
|
|
||||||
pt = points.get(points.size() - 1);
|
pt = points.get(points.size() - 1);
|
||||||
if (pt != lastBeforePoint && pt != firstAfterPoint && isInTileBox(tb, pt)) {
|
drawPointIcon(canvas, tb, pt, false);
|
||||||
float locX = tb.getPixXFromLatLon(pt.lat, pt.lon);
|
|
||||||
float locY = tb.getPixYFromLatLon(pt.lat, pt.lon);
|
|
||||||
canvas.drawBitmap(pointIcon, locX - marginPointIconX, locY - marginPointIconY, bitmapPaint);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < points.size(); i++) {
|
for (int i = 0; i < points.size(); i++) {
|
||||||
WptPt pt = points.get(i);
|
WptPt pt = points.get(i);
|
||||||
if (pt != lastBeforePoint && pt != firstAfterPoint && isInTileBox(tb, pt)) {
|
drawPointIcon(canvas, tb, pt, false);
|
||||||
float locX = tb.getPixXFromLatLon(pt.lat, pt.lon);
|
|
||||||
float locY = tb.getPixYFromLatLon(pt.lat, pt.lon);
|
|
||||||
canvas.drawBitmap(pointIcon, locX - marginPointIconX, locY - marginPointIconY, bitmapPaint);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,15 +389,24 @@ public class MeasurementToolLayer extends OsmandMapLayer implements ContextMenuL
|
||||||
canvas.rotate(tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY());
|
canvas.rotate(tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawPointIcon(Canvas canvas, RotatedTileBox tb, WptPt pt) {
|
private void drawPointIcon(Canvas canvas, RotatedTileBox tb, WptPt pt, boolean rotate) {
|
||||||
|
if (rotate) {
|
||||||
canvas.rotate(-tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY());
|
canvas.rotate(-tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY());
|
||||||
|
}
|
||||||
float locX = tb.getPixXFromLatLon(pt.lat, pt.lon);
|
float locX = tb.getPixXFromLatLon(pt.lat, pt.lon);
|
||||||
float locY = tb.getPixYFromLatLon(pt.lat, pt.lon);
|
float locY = tb.getPixYFromLatLon(pt.lat, pt.lon);
|
||||||
|
if (editingCtx.isInMultiProfileMode()) {
|
||||||
|
canvas.drawBitmap(multiProfileGeometryWayContext.getPointIcon(), locX - multiProfileGeometryWayContext.pointIconSize / 2,
|
||||||
|
locY - multiProfileGeometryWayContext.pointIconSize / 2, bitmapPaint);
|
||||||
|
} else {
|
||||||
if (tb.containsPoint(locX, locY, 0)) {
|
if (tb.containsPoint(locX, locY, 0)) {
|
||||||
canvas.drawBitmap(pointIcon, locX - marginPointIconX, locY - marginPointIconY, bitmapPaint);
|
canvas.drawBitmap(pointIcon, locX - marginPointIconX, locY - marginPointIconY, bitmapPaint);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (rotate) {
|
||||||
canvas.rotate(tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY());
|
canvas.rotate(tb.getRotate(), tb.getCenterPixelX(), tb.getCenterPixelY());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public WptPt addCenterPoint(boolean addPointBefore) {
|
public WptPt addCenterPoint(boolean addPointBefore) {
|
||||||
RotatedTileBox tb = view.getCurrentRotatedTileBox();
|
RotatedTileBox tb = view.getCurrentRotatedTileBox();
|
||||||
|
|
|
@ -245,4 +245,11 @@ public class MapStyleAction extends SwitchableAction<String> {
|
||||||
? filters.get(0) + " +" + (filters.size() - 1)
|
? filters.get(0) + " +" + (filters.size() - 1)
|
||||||
: filters.get(0);
|
: filters.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getActionText(OsmandApplication application) {
|
||||||
|
String currentSource = application.getSettings().RENDERER.get();
|
||||||
|
|
||||||
|
return application.getString(R.string.map_quick_action_pattern, getTranslatedItemName(application, currentSource));
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -104,7 +104,7 @@ public class MapOverlayAction extends SwitchableAction<Pair<String, String>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = -1;
|
int index = -1;
|
||||||
final String currentSource = settings.MAP_OVERLAY.get() == null ? KEY_NO_OVERLAY
|
String currentSource = settings.MAP_OVERLAY.get() == null ? KEY_NO_OVERLAY
|
||||||
: settings.MAP_OVERLAY.get();
|
: settings.MAP_OVERLAY.get();
|
||||||
|
|
||||||
for (int idx = 0; idx < sources.size(); idx++) {
|
for (int idx = 0; idx < sources.size(); idx++) {
|
||||||
|
@ -224,4 +224,12 @@ public class MapOverlayAction extends SwitchableAction<Pair<String, String>> {
|
||||||
getParams().put(KEY_DIALOG, Boolean.toString(((SwitchCompat) root.findViewById(R.id.saveButton)).isChecked()));
|
getParams().put(KEY_DIALOG, Boolean.toString(((SwitchCompat) root.findViewById(R.id.saveButton)).isChecked()));
|
||||||
return super.fillParams(root, activity);
|
return super.fillParams(root, activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getActionText(OsmandApplication application) {
|
||||||
|
String currentSource = application.getSettings().MAP_OVERLAY.get() == null ? KEY_NO_OVERLAY
|
||||||
|
: application.getSettings().MAP_OVERLAY.get();
|
||||||
|
|
||||||
|
return application.getString(R.string.map_quick_action_pattern, getTranslatedItemName(application, currentSource));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ public class MapSourceAction extends SwitchableAction<Pair<String, String>> {
|
||||||
OsmandSettings settings = activity.getMyApplication().getSettings();
|
OsmandSettings settings = activity.getMyApplication().getSettings();
|
||||||
List<Pair<String, String>> sources = loadListFromParams();
|
List<Pair<String, String>> sources = loadListFromParams();
|
||||||
if (sources.size() > 0) {
|
if (sources.size() > 0) {
|
||||||
boolean showBottomSheetStyles = Boolean.valueOf(getParams().get(KEY_DIALOG));
|
boolean showBottomSheetStyles = Boolean.parseBoolean(getParams().get(KEY_DIALOG));
|
||||||
if (showBottomSheetStyles) {
|
if (showBottomSheetStyles) {
|
||||||
showChooseDialog(activity.getSupportFragmentManager());
|
showChooseDialog(activity.getSupportFragmentManager());
|
||||||
return;
|
return;
|
||||||
|
@ -214,4 +214,13 @@ public class MapSourceAction extends SwitchableAction<Pair<String, String>> {
|
||||||
getParams().put(KEY_DIALOG, Boolean.toString(((SwitchCompat) root.findViewById(R.id.saveButton)).isChecked()));
|
getParams().put(KEY_DIALOG, Boolean.toString(((SwitchCompat) root.findViewById(R.id.saveButton)).isChecked()));
|
||||||
return super.fillParams(root, activity);
|
return super.fillParams(root, activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getActionText(OsmandApplication application) {
|
||||||
|
String currentSource = application.getSettings().MAP_ONLINE_DATA.get()
|
||||||
|
? application.getSettings().MAP_TILE_SOURCES.get()
|
||||||
|
: application.getString(R.string.vector_data);
|
||||||
|
|
||||||
|
return application.getString(R.string.map_quick_action_pattern, getTranslatedItemName(application, currentSource));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,4 +226,12 @@ public class MapUnderlayAction extends SwitchableAction<Pair<String, String>> {
|
||||||
getParams().put(KEY_DIALOG, Boolean.toString(((SwitchCompat) root.findViewById(R.id.saveButton)).isChecked()));
|
getParams().put(KEY_DIALOG, Boolean.toString(((SwitchCompat) root.findViewById(R.id.saveButton)).isChecked()));
|
||||||
return super.fillParams(root, activity);
|
return super.fillParams(root, activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getActionText(OsmandApplication application) {
|
||||||
|
String currentSource = application.getSettings().MAP_UNDERLAY.get() == null ? KEY_NO_UNDERLAY
|
||||||
|
: application.getSettings().MAP_UNDERLAY.get();
|
||||||
|
|
||||||
|
return application.getString(R.string.map_quick_action_pattern, getTranslatedItemName(application, currentSource));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -700,7 +700,7 @@ public class VoiceRouter {
|
||||||
boolean isPlay = true;
|
boolean isPlay = true;
|
||||||
ExitInfo exitInfo = next.getExitInfo();
|
ExitInfo exitInfo = next.getExitInfo();
|
||||||
if (tParam != null) {
|
if (tParam != null) {
|
||||||
if (exitInfo != null && !Algorithms.isEmpty(exitInfo.getRef())) {
|
if (exitInfo != null && !Algorithms.isEmpty(exitInfo.getRef()) && settings.SPEAK_EXIT_NUMBER_NAMES.get()) {
|
||||||
String stringRef = getSpeakableExitRef(exitInfo.getRef());
|
String stringRef = getSpeakableExitRef(exitInfo.getRef());
|
||||||
p.takeExit(tParam, dist, stringRef, getIntRef(exitInfo.getRef()), getSpeakableExitName(next, exitInfo, true));
|
p.takeExit(tParam, dist, stringRef, getIntRef(exitInfo.getRef()), getSpeakableExitName(next, exitInfo, true));
|
||||||
} else {
|
} else {
|
||||||
|
@ -775,7 +775,7 @@ public class VoiceRouter {
|
||||||
ExitInfo exitInfo = next.getExitInfo();
|
ExitInfo exitInfo = next.getExitInfo();
|
||||||
boolean isplay = true;
|
boolean isplay = true;
|
||||||
if (tParam != null) {
|
if (tParam != null) {
|
||||||
if (exitInfo != null && !Algorithms.isEmpty(exitInfo.getRef())) {
|
if (exitInfo != null && !Algorithms.isEmpty(exitInfo.getRef()) && settings.SPEAK_EXIT_NUMBER_NAMES.get()) {
|
||||||
String stringRef = getSpeakableExitRef(exitInfo.getRef());
|
String stringRef = getSpeakableExitRef(exitInfo.getRef());
|
||||||
p.takeExit(tParam, stringRef, getIntRef(exitInfo.getRef()), getSpeakableExitName(next, exitInfo, !suppressDest));
|
p.takeExit(tParam, stringRef, getIntRef(exitInfo.getRef()), getSpeakableExitName(next, exitInfo, !suppressDest));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -36,7 +36,7 @@ import java.util.List;
|
||||||
public class RouteLineWidthCard extends BaseCard {
|
public class RouteLineWidthCard extends BaseCard {
|
||||||
|
|
||||||
private final static int CUSTOM_WIDTH_MIN = 1;
|
private final static int CUSTOM_WIDTH_MIN = 1;
|
||||||
private final static int CUSTOM_WIDTH_MAX = 24;
|
private final static int CUSTOM_WIDTH_MAX = 36;
|
||||||
|
|
||||||
private RouteLineDrawInfo routeLineDrawInfo;
|
private RouteLineDrawInfo routeLineDrawInfo;
|
||||||
private OnNeedScrollListener onNeedScrollListener;
|
private OnNeedScrollListener onNeedScrollListener;
|
||||||
|
|
|
@ -1355,6 +1355,7 @@ public class OsmandSettings {
|
||||||
public final OsmandPreference<Boolean> SPEAK_SPEED_LIMIT = new BooleanPreference(this, "speak_speed_limit", false).makeProfile().cache();
|
public final OsmandPreference<Boolean> SPEAK_SPEED_LIMIT = new BooleanPreference(this, "speak_speed_limit", false).makeProfile().cache();
|
||||||
public final OsmandPreference<Boolean> SPEAK_SPEED_CAMERA = new BooleanPreference(this, "speak_cameras", false).makeProfile().cache();
|
public final OsmandPreference<Boolean> SPEAK_SPEED_CAMERA = new BooleanPreference(this, "speak_cameras", false).makeProfile().cache();
|
||||||
public final OsmandPreference<Boolean> SPEAK_TUNNELS = new BooleanPreference(this, "speak_tunnels", false).makeProfile().cache();
|
public final OsmandPreference<Boolean> SPEAK_TUNNELS = new BooleanPreference(this, "speak_tunnels", false).makeProfile().cache();
|
||||||
|
public final OsmandPreference<Boolean> SPEAK_EXIT_NUMBER_NAMES = new BooleanPreference(this, "exit_number_names", true).makeProfile().cache();
|
||||||
|
|
||||||
public final OsmandPreference<Boolean> SPEED_CAMERAS_UNINSTALLED = new BooleanPreference(this, "speed_cameras_uninstalled", false).makeGlobal().makeShared();
|
public final OsmandPreference<Boolean> SPEED_CAMERAS_UNINSTALLED = new BooleanPreference(this, "speed_cameras_uninstalled", false).makeGlobal().makeShared();
|
||||||
public final OsmandPreference<Boolean> SPEED_CAMERAS_ALERT_SHOWED = new BooleanPreference(this, "speed_cameras_alert_showed", false).makeGlobal().makeShared();
|
public final OsmandPreference<Boolean> SPEED_CAMERAS_ALERT_SHOWED = new BooleanPreference(this, "speed_cameras_alert_showed", false).makeGlobal().makeShared();
|
||||||
|
|
|
@ -234,7 +234,7 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
|
||||||
ivIcon.setImageDrawable(icon);
|
ivIcon.setImageDrawable(icon);
|
||||||
|
|
||||||
if (currentKey.equals(MANUALLY_SPECIFIED)) {
|
if (currentKey.equals(MANUALLY_SPECIFIED)) {
|
||||||
tvSummary.setText(item.getDirectory());
|
setFormattedPath(item, tvSummary);
|
||||||
secondPart.setVisibility(View.GONE);
|
secondPart.setVisibility(View.GONE);
|
||||||
tvAdditionalDescription.setVisibility(View.GONE);
|
tvAdditionalDescription.setVisibility(View.GONE);
|
||||||
divider.setVisibility(View.GONE);
|
divider.setVisibility(View.GONE);
|
||||||
|
@ -252,15 +252,8 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
|
||||||
}
|
}
|
||||||
if (currentKey.equals(INTERNAL_STORAGE)) {
|
if (currentKey.equals(INTERNAL_STORAGE)) {
|
||||||
tvAdditionalDescription.setText(item.getDescription());
|
tvAdditionalDescription.setText(item.getDescription());
|
||||||
} else if (currentKey.equals(SHARED_STORAGE)) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
|
||||||
BidiFormatter rtlFormatter = BidiFormatter.getInstance();
|
|
||||||
tvAdditionalDescription.setText(rtlFormatter.unicodeWrap(item.getDirectory()));
|
|
||||||
} else {
|
} else {
|
||||||
tvAdditionalDescription.setText(String.format("\u200E%s", item.getDirectory()));
|
setFormattedPath(item, tvAdditionalDescription);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tvAdditionalDescription.setText(item.getDirectory());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -310,6 +303,15 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setFormattedPath(StorageItem item, TextView tvAdditionalDescription) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||||
|
BidiFormatter pathRtlFormatter = BidiFormatter.getInstance();
|
||||||
|
tvAdditionalDescription.setText(pathRtlFormatter.unicodeWrap(item.getDirectory()));
|
||||||
|
} else {
|
||||||
|
tvAdditionalDescription.setText(String.format("\u200E%s", item.getDirectory()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
if (!activity.isChangingConfigurations()) {
|
if (!activity.isChangingConfigurations()) {
|
||||||
|
|
|
@ -924,12 +924,6 @@ public abstract class BaseSettingsFragment extends PreferenceFragmentCompat impl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setupSpeedCamerasAlert() {
|
|
||||||
Preference speedCamerasAlert = findPreference(settings.SPEED_CAMERAS_UNINSTALLED.getId());
|
|
||||||
speedCamerasAlert.setIcon(getContentIcon(R.drawable.ic_action_alert));
|
|
||||||
speedCamerasAlert.setVisible(!settings.SPEED_CAMERAS_UNINSTALLED.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setupPrefRoundedBg(PreferenceViewHolder holder) {
|
public void setupPrefRoundedBg(PreferenceViewHolder holder) {
|
||||||
View selectableView = holder.itemView.findViewById(R.id.selectable_list_item);
|
View selectableView = holder.itemView.findViewById(R.id.selectable_list_item);
|
||||||
if (selectableView != null) {
|
if (selectableView != null) {
|
||||||
|
|
|
@ -15,6 +15,7 @@ import android.widget.ScrollView;
|
||||||
import androidx.activity.OnBackPressedCallback;
|
import androidx.activity.OnBackPressedCallback;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
|
||||||
|
@ -32,7 +33,6 @@ import net.osmand.plus.routing.cards.RouteLineColorCard;
|
||||||
import net.osmand.plus.routing.cards.RouteLineColorCard.OnMapThemeUpdateListener;
|
import net.osmand.plus.routing.cards.RouteLineColorCard.OnMapThemeUpdateListener;
|
||||||
import net.osmand.plus.routing.cards.RouteLineColorCard.OnSelectedColorChangeListener;
|
import net.osmand.plus.routing.cards.RouteLineColorCard.OnSelectedColorChangeListener;
|
||||||
import net.osmand.plus.routing.cards.RouteLineWidthCard;
|
import net.osmand.plus.routing.cards.RouteLineWidthCard;
|
||||||
import net.osmand.plus.settings.backend.ApplicationMode;
|
|
||||||
import net.osmand.plus.track.CustomColorBottomSheet.ColorPickerListener;
|
import net.osmand.plus.track.CustomColorBottomSheet.ColorPickerListener;
|
||||||
import net.osmand.plus.track.TrackAppearanceFragment.OnNeedScrollListener;
|
import net.osmand.plus.track.TrackAppearanceFragment.OnNeedScrollListener;
|
||||||
|
|
||||||
|
@ -203,6 +203,8 @@ public class RouteLineAppearanceFragment extends ContextMenuScrollFragment imple
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
closeButton.setImageResource(AndroidUtils.getNavigationIconResId(toolbarContainer.getContext()));
|
closeButton.setImageResource(AndroidUtils.getNavigationIconResId(toolbarContainer.getContext()));
|
||||||
|
int bgColorId = isNightMode() ? R.color.app_bar_color_dark : R.color.list_background_color_light;
|
||||||
|
toolbarContainer.setBackgroundColor(ContextCompat.getColor(requireContext(), bgColorId));
|
||||||
updateToolbarVisibility(toolbarContainer);
|
updateToolbarVisibility(toolbarContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +214,7 @@ public class RouteLineAppearanceFragment extends ContextMenuScrollFragment imple
|
||||||
if (Build.VERSION.SDK_INT >= 23 && !isNightMode() && view != null) {
|
if (Build.VERSION.SDK_INT >= 23 && !isNightMode() && view != null) {
|
||||||
view.setSystemUiVisibility(view.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
|
view.setSystemUiVisibility(view.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
|
||||||
}
|
}
|
||||||
return isNightMode() ? R.color.divider_color_dark : R.color.divider_color_light;
|
return isNightMode() ? R.color.status_bar_color_dark : R.color.divider_color_light;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -164,4 +164,10 @@ public class ScreenAlertsFragment extends BaseSettingsFragment implements OnPref
|
||||||
showCameras.setIcon(getIcon(R.drawable.list_warnings_speed_camera));
|
showCameras.setIcon(getIcon(R.drawable.list_warnings_speed_camera));
|
||||||
showCameras.setVisible(!settings.SPEED_CAMERAS_UNINSTALLED.get());
|
showCameras.setVisible(!settings.SPEED_CAMERAS_UNINSTALLED.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setupSpeedCamerasAlert() {
|
||||||
|
Preference speedCamerasAlert = findPreference(settings.SPEED_CAMERAS_UNINSTALLED.getId());
|
||||||
|
speedCamerasAlert.setIcon(getContentIcon(R.drawable.ic_action_alert));
|
||||||
|
speedCamerasAlert.setVisible(!settings.SPEED_CAMERAS_UNINSTALLED.get());
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -5,6 +5,7 @@ import android.content.Intent;
|
||||||
import android.graphics.drawable.ColorDrawable;
|
import android.graphics.drawable.ColorDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
|
import android.net.Uri;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
@ -20,7 +21,6 @@ import androidx.preference.SwitchPreferenceCompat;
|
||||||
import net.osmand.AndroidUtils;
|
import net.osmand.AndroidUtils;
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.UiUtilities;
|
import net.osmand.plus.UiUtilities;
|
||||||
import net.osmand.plus.Version;
|
|
||||||
import net.osmand.plus.activities.MapActivity;
|
import net.osmand.plus.activities.MapActivity;
|
||||||
import net.osmand.plus.dialogs.SpeedCamerasBottomSheet;
|
import net.osmand.plus.dialogs.SpeedCamerasBottomSheet;
|
||||||
import net.osmand.plus.download.DownloadActivity;
|
import net.osmand.plus.download.DownloadActivity;
|
||||||
|
@ -31,6 +31,8 @@ import net.osmand.plus.settings.backend.ApplicationMode;
|
||||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||||
import net.osmand.plus.settings.bottomsheets.AnnouncementTimeBottomSheet;
|
import net.osmand.plus.settings.bottomsheets.AnnouncementTimeBottomSheet;
|
||||||
import net.osmand.plus.settings.preferences.ListPreferenceEx;
|
import net.osmand.plus.settings.preferences.ListPreferenceEx;
|
||||||
|
import net.osmand.plus.settings.preferences.SwitchPreferenceEx;
|
||||||
|
import net.osmand.plus.wikipedia.WikipediaDialogFragment;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -43,6 +45,8 @@ public class VoiceAnnouncesFragment extends BaseSettingsFragment implements OnPr
|
||||||
|
|
||||||
private static final String MORE_VALUE = "MORE_VALUE";
|
private static final String MORE_VALUE = "MORE_VALUE";
|
||||||
|
|
||||||
|
private static final String OSMAND_VOICE_NAVIGATION_URL = "https://docs.osmand.net/en/main@latest/osmand/troubleshooting/navigation#voice-navigation";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void createToolbar(LayoutInflater inflater, View view) {
|
protected void createToolbar(LayoutInflater inflater, View view) {
|
||||||
super.createToolbar(inflater, view);
|
super.createToolbar(inflater, view);
|
||||||
|
@ -64,6 +68,17 @@ public class VoiceAnnouncesFragment extends BaseSettingsFragment implements OnPr
|
||||||
@Override
|
@Override
|
||||||
protected void updateToolbar() {
|
protected void updateToolbar() {
|
||||||
super.updateToolbar();
|
super.updateToolbar();
|
||||||
|
View view = getView();
|
||||||
|
ImageView profileIcon = view.findViewById(R.id.profile_icon);
|
||||||
|
profileIcon.setImageDrawable(app.getUIUtilities().getIcon(R.drawable.ic_action_help_online, isNightMode() ? R.color.icon_color_default_dark : R.color.icon_color_default_light));
|
||||||
|
profileIcon.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (getContext() != null) {
|
||||||
|
WikipediaDialogFragment.showFullArticle(getContext(), Uri.parse(OSMAND_VOICE_NAVIGATION_URL), isNightMode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
updateToolbarSwitch();
|
updateToolbarSwitch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +93,7 @@ public class VoiceAnnouncesFragment extends BaseSettingsFragment implements OnPr
|
||||||
View switchContainer = view.findViewById(R.id.toolbar_switch_container);
|
View switchContainer = view.findViewById(R.id.toolbar_switch_container);
|
||||||
AndroidUtils.setBackground(switchContainer, new ColorDrawable(color));
|
AndroidUtils.setBackground(switchContainer, new ColorDrawable(color));
|
||||||
|
|
||||||
SwitchCompat switchView = (SwitchCompat) switchContainer.findViewById(R.id.switchWidget);
|
SwitchCompat switchView = switchContainer.findViewById(R.id.switchWidget);
|
||||||
switchView.setChecked(checked);
|
switchView.setChecked(checked);
|
||||||
UiUtilities.setupCompoundButton(switchView, isNightMode(), TOOLBAR);
|
UiUtilities.setupCompoundButton(switchView, isNightMode(), TOOLBAR);
|
||||||
|
|
||||||
|
@ -102,7 +117,7 @@ public class VoiceAnnouncesFragment extends BaseSettingsFragment implements OnPr
|
||||||
|
|
||||||
enableDisablePreferences(!settings.VOICE_MUTE.getModeValue(getSelectedAppMode()));
|
enableDisablePreferences(!settings.VOICE_MUTE.getModeValue(getSelectedAppMode()));
|
||||||
setupSpeakCamerasPref();
|
setupSpeakCamerasPref();
|
||||||
setupSpeedCamerasAlert();
|
setupTurnScreenOnNavigationInstructionsPref();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupSpeedLimitExceedPref() {
|
private void setupSpeedLimitExceedPref() {
|
||||||
|
@ -121,7 +136,7 @@ public class VoiceAnnouncesFragment extends BaseSettingsFragment implements OnPr
|
||||||
names[i] = valuesMph[i].intValue() + " " + getString(R.string.mile_per_hour);
|
names[i] = valuesMph[i].intValue() + " " + getString(R.string.mile_per_hour);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ListPreferenceEx voiceProvider = (ListPreferenceEx) findPreference(settings.SPEED_LIMIT_EXCEED_KMH.getId());
|
ListPreferenceEx voiceProvider = findPreference(settings.SPEED_LIMIT_EXCEED_KMH.getId());
|
||||||
voiceProvider.setEntries(names);
|
voiceProvider.setEntries(names);
|
||||||
voiceProvider.setEntryValues(valuesKmh);
|
voiceProvider.setEntryValues(valuesKmh);
|
||||||
}
|
}
|
||||||
|
@ -134,7 +149,7 @@ public class VoiceAnnouncesFragment extends BaseSettingsFragment implements OnPr
|
||||||
keepInformingNames[i] = keepInformingValues[i] + " " + getString(R.string.int_min);
|
keepInformingNames[i] = keepInformingValues[i] + " " + getString(R.string.int_min);
|
||||||
}
|
}
|
||||||
|
|
||||||
ListPreferenceEx keepInforming = (ListPreferenceEx) findPreference(settings.KEEP_INFORMING.getId());
|
ListPreferenceEx keepInforming = findPreference(settings.KEEP_INFORMING.getId());
|
||||||
keepInforming.setEntries(keepInformingNames);
|
keepInforming.setEntries(keepInformingNames);
|
||||||
keepInforming.setEntryValues(keepInformingValues);
|
keepInforming.setEntryValues(keepInformingValues);
|
||||||
}
|
}
|
||||||
|
@ -148,7 +163,7 @@ public class VoiceAnnouncesFragment extends BaseSettingsFragment implements OnPr
|
||||||
getString(R.string.arrival_distance_factor_at_last)
|
getString(R.string.arrival_distance_factor_at_last)
|
||||||
};
|
};
|
||||||
|
|
||||||
ListPreferenceEx arrivalDistanceFactor = (ListPreferenceEx) findPreference(settings.ARRIVAL_DISTANCE_FACTOR.getId());
|
ListPreferenceEx arrivalDistanceFactor = findPreference(settings.ARRIVAL_DISTANCE_FACTOR.getId());
|
||||||
arrivalDistanceFactor.setEntries(arrivalNames);
|
arrivalDistanceFactor.setEntries(arrivalNames);
|
||||||
arrivalDistanceFactor.setEntryValues(arrivalValues);
|
arrivalDistanceFactor.setEntryValues(arrivalValues);
|
||||||
}
|
}
|
||||||
|
@ -178,7 +193,7 @@ public class VoiceAnnouncesFragment extends BaseSettingsFragment implements OnPr
|
||||||
Drawable enabled = getActiveIcon(R.drawable.ic_action_volume_up);
|
Drawable enabled = getActiveIcon(R.drawable.ic_action_volume_up);
|
||||||
Drawable icon = getPersistentPrefIcon(enabled, disabled);
|
Drawable icon = getPersistentPrefIcon(enabled, disabled);
|
||||||
|
|
||||||
ListPreferenceEx voiceProvider = (ListPreferenceEx) findPreference(settings.VOICE_PROVIDER.getId());
|
ListPreferenceEx voiceProvider = findPreference(settings.VOICE_PROVIDER.getId());
|
||||||
voiceProvider.setEntries(entries);
|
voiceProvider.setEntries(entries);
|
||||||
voiceProvider.setEntryValues(entryValues);
|
voiceProvider.setEntryValues(entryValues);
|
||||||
voiceProvider.setIcon(icon);
|
voiceProvider.setIcon(icon);
|
||||||
|
@ -208,6 +223,11 @@ public class VoiceAnnouncesFragment extends BaseSettingsFragment implements OnPr
|
||||||
getPreferenceScreen().addPreference(interruptMusicPref);
|
getPreferenceScreen().addPreference(interruptMusicPref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupTurnScreenOnNavigationInstructionsPref() {
|
||||||
|
SwitchPreferenceEx turnScreenOnNavigationInstructions = findPreference(settings.TURN_SCREEN_ON_NAVIGATION_INSTRUCTIONS.getId());
|
||||||
|
turnScreenOnNavigationInstructions.setDescription(R.string.turn_screen_on_navigation_instructions_descr);
|
||||||
|
}
|
||||||
|
|
||||||
private void updateMenu() {
|
private void updateMenu() {
|
||||||
MapActivity mapActivity = getMapActivity();
|
MapActivity mapActivity = getMapActivity();
|
||||||
if (mapActivity != null) {
|
if (mapActivity != null) {
|
||||||
|
@ -319,12 +339,11 @@ public class VoiceAnnouncesFragment extends BaseSettingsFragment implements OnPr
|
||||||
public void onPreferenceChanged(String prefId) {
|
public void onPreferenceChanged(String prefId) {
|
||||||
if (prefId.equals(settings.SPEED_CAMERAS_UNINSTALLED.getId())) {
|
if (prefId.equals(settings.SPEED_CAMERAS_UNINSTALLED.getId())) {
|
||||||
setupSpeakCamerasPref();
|
setupSpeakCamerasPref();
|
||||||
setupSpeedCamerasAlert();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupSpeakCamerasPref() {
|
private void setupSpeakCamerasPref() {
|
||||||
SwitchPreferenceCompat showCameras = (SwitchPreferenceCompat) findPreference(settings.SPEAK_SPEED_CAMERA.getId());
|
SwitchPreferenceCompat showCameras = findPreference(settings.SPEAK_SPEED_CAMERA.getId());
|
||||||
showCameras.setVisible(!settings.SPEED_CAMERAS_UNINSTALLED.get());
|
showCameras.setVisible(!settings.SPEED_CAMERAS_UNINSTALLED.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -21,7 +21,6 @@ import android.widget.TextView;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.widget.SwitchCompat;
|
import androidx.appcompat.widget.SwitchCompat;
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
|
|
||||||
import com.github.ksoichiro.android.observablescrollview.ObservableListView;
|
import com.github.ksoichiro.android.observablescrollview.ObservableListView;
|
||||||
import com.google.android.material.slider.RangeSlider;
|
import com.google.android.material.slider.RangeSlider;
|
||||||
|
@ -50,14 +49,16 @@ import org.apache.commons.logging.Log;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import static net.osmand.plus.UiUtilities.CustomRadioButtonType.*;
|
import static net.osmand.plus.UiUtilities.CustomRadioButtonType.END;
|
||||||
|
import static net.osmand.plus.UiUtilities.CustomRadioButtonType.START;
|
||||||
import static net.osmand.plus.download.DownloadActivityType.HILLSHADE_FILE;
|
import static net.osmand.plus.download.DownloadActivityType.HILLSHADE_FILE;
|
||||||
import static net.osmand.plus.download.DownloadActivityType.SLOPE_FILE;
|
import static net.osmand.plus.download.DownloadActivityType.SLOPE_FILE;
|
||||||
import static net.osmand.plus.srtmplugin.TerrainMode.HILLSHADE;
|
|
||||||
import static net.osmand.plus.srtmplugin.TerrainMode.SLOPE;
|
|
||||||
import static net.osmand.plus.srtmplugin.SRTMPlugin.TERRAIN_MAX_ZOOM;
|
import static net.osmand.plus.srtmplugin.SRTMPlugin.TERRAIN_MAX_ZOOM;
|
||||||
import static net.osmand.plus.srtmplugin.SRTMPlugin.TERRAIN_MIN_ZOOM;
|
import static net.osmand.plus.srtmplugin.SRTMPlugin.TERRAIN_MIN_ZOOM;
|
||||||
|
import static net.osmand.plus.srtmplugin.TerrainMode.HILLSHADE;
|
||||||
|
import static net.osmand.plus.srtmplugin.TerrainMode.SLOPE;
|
||||||
|
|
||||||
|
|
||||||
public class TerrainFragment extends BaseOsmAndFragment implements View.OnClickListener,
|
public class TerrainFragment extends BaseOsmAndFragment implements View.OnClickListener,
|
||||||
|
@ -102,7 +103,7 @@ public class TerrainFragment extends BaseOsmAndFragment implements View.OnClickL
|
||||||
|
|
||||||
private ArrayAdapter<ContextMenuItem> listAdapter;
|
private ArrayAdapter<ContextMenuItem> listAdapter;
|
||||||
|
|
||||||
private Slider.OnChangeListener transparencySliderChangeListener = new Slider.OnChangeListener() {
|
private final Slider.OnChangeListener transparencySliderChangeListener = new Slider.OnChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) {
|
public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) {
|
||||||
if (fromUser) {
|
if (fromUser) {
|
||||||
|
@ -114,7 +115,7 @@ public class TerrainFragment extends BaseOsmAndFragment implements View.OnClickL
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private RangeSlider.OnChangeListener zoomSliderChangeListener = new RangeSlider.OnChangeListener() {
|
private final RangeSlider.OnChangeListener zoomSliderChangeListener = new RangeSlider.OnChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onValueChange(@NonNull RangeSlider slider, float value, boolean fromUser) {
|
public void onValueChange(@NonNull RangeSlider slider, float value, boolean fromUser) {
|
||||||
List<Float> values = slider.getValues();
|
List<Float> values = slider.getValues();
|
||||||
|
@ -186,11 +187,7 @@ public class TerrainFragment extends BaseOsmAndFragment implements View.OnClickL
|
||||||
getString(R.string.slope_read_more),
|
getString(R.string.slope_read_more),
|
||||||
wikiString
|
wikiString
|
||||||
);
|
);
|
||||||
String emptyStateText = String.format(
|
String emptyStateText = getString(R.string.terrain_empty_state_text) + "\n" + PLUGIN_URL;
|
||||||
getString(R.string.ltr_or_rtl_combine_via_space),
|
|
||||||
getString(R.string.terrain_empty_state_text),
|
|
||||||
PLUGIN_URL
|
|
||||||
);
|
|
||||||
setupClickableText(slopeReadMoreTv, readMoreText, wikiString, SLOPES_WIKI_URL, false);
|
setupClickableText(slopeReadMoreTv, readMoreText, wikiString, SLOPES_WIKI_URL, false);
|
||||||
setupClickableText(emptyStateDescriptionTv, emptyStateText, PLUGIN_URL, PLUGIN_URL, true);
|
setupClickableText(emptyStateDescriptionTv, emptyStateText, PLUGIN_URL, PLUGIN_URL, true);
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import net.osmand.plus.R;
|
||||||
import net.osmand.plus.activities.MapActivity;
|
import net.osmand.plus.activities.MapActivity;
|
||||||
import net.osmand.plus.helpers.AndroidUiHelper;
|
import net.osmand.plus.helpers.AndroidUiHelper;
|
||||||
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
|
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
|
||||||
|
import net.osmand.router.RouteColorize;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
@ -42,8 +43,9 @@ public class GradientCard extends BaseCard {
|
||||||
AndroidUiHelper.updateVisibility(view, true);
|
AndroidUiHelper.updateVisibility(view, true);
|
||||||
TextView minValue = view.findViewById(R.id.min_value);
|
TextView minValue = view.findViewById(R.id.min_value);
|
||||||
TextView maxValue = view.findViewById(R.id.max_value);
|
TextView maxValue = view.findViewById(R.id.max_value);
|
||||||
float min = getMinValue();
|
double min = RouteColorize.getMinValue(selectedScaleType.toColorizationType(), gpxTrackAnalysis);
|
||||||
float max = getMaxValue(min);
|
double max = RouteColorize.getMaxValue(selectedScaleType.toColorizationType(),
|
||||||
|
gpxTrackAnalysis, min, app.getSettings().getApplicationMode().getMaxSpeed());
|
||||||
minValue.setText(formatValue(min));
|
minValue.setText(formatValue(min));
|
||||||
maxValue.setText(formatValue(max));
|
maxValue.setText(formatValue(max));
|
||||||
}
|
}
|
||||||
|
@ -53,27 +55,13 @@ public class GradientCard extends BaseCard {
|
||||||
updateContent();
|
updateContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private float getMinValue() {
|
private CharSequence formatValue(double value) {
|
||||||
return (float) (selectedScaleType == GradientScaleType.ALTITUDE ? gpxTrackAnalysis.minElevation : 0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private float getMaxValue(float minValue) {
|
|
||||||
if (selectedScaleType == GradientScaleType.SPEED) {
|
|
||||||
return (Math.max(gpxTrackAnalysis.maxSpeed, app.getSettings().getApplicationMode().getMaxSpeed()));
|
|
||||||
} else if (selectedScaleType == GradientScaleType.ALTITUDE) {
|
|
||||||
return (float) Math.max(gpxTrackAnalysis.maxElevation, minValue + 50);
|
|
||||||
} else {
|
|
||||||
return 25;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private CharSequence formatValue(float value) {
|
|
||||||
if (selectedScaleType == GradientScaleType.ALTITUDE) {
|
if (selectedScaleType == GradientScaleType.ALTITUDE) {
|
||||||
return OsmAndFormatter.getFormattedAlt(value, app);
|
return OsmAndFormatter.getFormattedAlt(value, app);
|
||||||
} else if (selectedScaleType == GradientScaleType.SLOPE) {
|
} else if (selectedScaleType == GradientScaleType.SLOPE) {
|
||||||
return (int) value + " %";
|
return (int) value + " %";
|
||||||
}
|
}
|
||||||
String speed = OsmAndFormatter.getFormattedSpeed(value, app);
|
String speed = OsmAndFormatter.getFormattedSpeed((float) value, app);
|
||||||
String speedUnit = app.getSettings().SPEED_SYSTEM.get().toShortString(app);
|
String speedUnit = app.getSettings().SPEED_SYSTEM.get().toShortString(app);
|
||||||
Spannable formattedSpeed = new SpannableString(speed);
|
Spannable formattedSpeed = new SpannableString(speed);
|
||||||
formattedSpeed.setSpan(
|
formattedSpeed.setSpan(
|
||||||
|
|
|
@ -61,6 +61,7 @@ public class Renderable {
|
||||||
|
|
||||||
public List<WptPt> points = null; // Original list of points
|
public List<WptPt> points = null; // Original list of points
|
||||||
protected List<WptPt> culled = new ArrayList<>(); // Reduced/resampled list of points
|
protected List<WptPt> culled = new ArrayList<>(); // Reduced/resampled list of points
|
||||||
|
protected List<WptPt> oldCulled = new ArrayList<>();
|
||||||
protected int pointSize;
|
protected int pointSize;
|
||||||
protected double segmentSize;
|
protected double segmentSize;
|
||||||
|
|
||||||
|
@ -116,7 +117,7 @@ public class Renderable {
|
||||||
updateLocalPaint(p);
|
updateLocalPaint(p);
|
||||||
canvas.rotate(-tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
|
canvas.rotate(-tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
|
||||||
if (scaleType != null) {
|
if (scaleType != null) {
|
||||||
drawGradient(getPointsForDrawing(), p, canvas, tileBox);
|
drawGradient(getPointsForDrawingWithBorder(), p, canvas, tileBox);
|
||||||
} else {
|
} else {
|
||||||
drawSolid(getPointsForDrawing(), p, canvas, tileBox);
|
drawSolid(getPointsForDrawing(), p, canvas, tileBox);
|
||||||
}
|
}
|
||||||
|
@ -126,6 +127,9 @@ public class Renderable {
|
||||||
|
|
||||||
public void drawSegment(double zoom, Paint p, Canvas canvas, RotatedTileBox tileBox) {
|
public void drawSegment(double zoom, Paint p, Canvas canvas, RotatedTileBox tileBox) {
|
||||||
if (QuadRect.trivialOverlap(tileBox.getLatLonBounds(), trackBounds)) { // is visible?
|
if (QuadRect.trivialOverlap(tileBox.getLatLonBounds(), trackBounds)) { // is visible?
|
||||||
|
if (tileBox.getZoomAnimation() > 0 && !Algorithms.isEmpty(culled) && scaleType != null) {
|
||||||
|
oldCulled = new ArrayList<>(culled);
|
||||||
|
}
|
||||||
startCuller(zoom);
|
startCuller(zoom);
|
||||||
drawSingleSegment(zoom, p, canvas, tileBox);
|
drawSingleSegment(zoom, p, canvas, tileBox);
|
||||||
}
|
}
|
||||||
|
@ -139,6 +143,16 @@ public class Renderable {
|
||||||
return culled.isEmpty() ? points : culled;
|
return culled.isEmpty() ? points : culled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<WptPt> getPointsForDrawingWithBorder() {
|
||||||
|
if (!culled.isEmpty()) {
|
||||||
|
return culled;
|
||||||
|
} else if (!oldCulled.isEmpty()) {
|
||||||
|
return oldCulled;
|
||||||
|
} else {
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void drawGeometry(Canvas canvas, RotatedTileBox tileBox, QuadRect quadRect, int arrowColor, int trackColor, float trackWidth) {
|
public void drawGeometry(Canvas canvas, RotatedTileBox tileBox, QuadRect quadRect, int arrowColor, int trackColor, float trackWidth) {
|
||||||
if (geometryWay != null) {
|
if (geometryWay != null) {
|
||||||
List<WptPt> points = getPointsForDrawing();
|
List<WptPt> points = getPointsForDrawing();
|
||||||
|
@ -290,7 +304,8 @@ public class Renderable {
|
||||||
super(pt, 0);
|
super(pt, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void drawSegment(double zoom, Paint p, Canvas canvas, RotatedTileBox tileBox) {
|
@Override
|
||||||
|
public void drawSegment(double zoom, Paint p, Canvas canvas, RotatedTileBox tileBox) {
|
||||||
if (points.size() != pointSize) {
|
if (points.size() != pointSize) {
|
||||||
int prevSize = pointSize;
|
int prevSize = pointSize;
|
||||||
pointSize = points.size();
|
pointSize = points.size();
|
||||||
|
|
|
@ -680,15 +680,19 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
|
||||||
|
|
||||||
private void drawSelectedFileSegments(SelectedGpxFile selectedGpxFile, boolean currentTrack, Canvas canvas,
|
private void drawSelectedFileSegments(SelectedGpxFile selectedGpxFile, boolean currentTrack, Canvas canvas,
|
||||||
RotatedTileBox tileBox, DrawSettings settings) {
|
RotatedTileBox tileBox, DrawSettings settings) {
|
||||||
|
OsmandApplication app = view.getApplication();
|
||||||
GPXFile gpxFile = selectedGpxFile.getGpxFile();
|
GPXFile gpxFile = selectedGpxFile.getGpxFile();
|
||||||
List<TrkSegment> segments = selectedGpxFile.getPointsToDisplay();
|
List<TrkSegment> segments = selectedGpxFile.getPointsToDisplay();
|
||||||
GradientScaleType scaleType = getGradientScaleType(gpxFile);
|
GradientScaleType scaleType = getGradientScaleType(gpxFile);
|
||||||
List<RouteColorize.RouteColorizationPoint> colorsOfPoints = null;
|
List<RouteColorize.RouteColorizationPoint> colorsOfPoints = null;
|
||||||
if (scaleType != null) {
|
|
||||||
RouteColorize colorize = new RouteColorize(view.getZoom(), gpxFile, scaleType.toColorizationType());
|
if (needCalculatePointsColors(segments, scaleType)) {
|
||||||
|
RouteColorize colorize = new RouteColorize(view.getZoom(), gpxFile, selectedGpxFile.getTrackAnalysis(app),
|
||||||
|
scaleType.toColorizationType(), app.getSettings().getApplicationMode().getMaxSpeed());
|
||||||
colorize.setPalette(getColorizationPalette(gpxFile, scaleType));
|
colorize.setPalette(getColorizationPalette(gpxFile, scaleType));
|
||||||
colorsOfPoints = colorize.getResult(false);
|
colorsOfPoints = colorize.getResult(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
int startIdx = 0;
|
int startIdx = 0;
|
||||||
for (TrkSegment ts : segments) {
|
for (TrkSegment ts : segments) {
|
||||||
String width = getTrackWidthName(gpxFile, defaultTrackWidthPref.get());
|
String width = getTrackWidthName(gpxFile, defaultTrackWidthPref.get());
|
||||||
|
@ -716,6 +720,25 @@ public class GPXLayer extends OsmandMapLayer implements IContextMenuProvider, IM
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean needCalculatePointsColors(List<TrkSegment> segments, GradientScaleType scaleType) {
|
||||||
|
if (scaleType == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
RouteColorize.ColorizationType colorizationType = scaleType.toColorizationType();
|
||||||
|
for (int segIdx = segments.size() - 1; segIdx >= 0; segIdx--) {
|
||||||
|
List<WptPt> pts = segments.get(segIdx).points;
|
||||||
|
if (!Algorithms.isEmpty(pts)) {
|
||||||
|
for (int wptIdx = pts.size() - 1; wptIdx >= 0; wptIdx--) {
|
||||||
|
WptPt pt = pts.get(wptIdx);
|
||||||
|
if (pt.getColor(colorizationType) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private int setColorsToPoints(TrkSegment segment, List<RouteColorize.RouteColorizationPoint> colors, GradientScaleType scaleType, int startIdx) {
|
private int setColorsToPoints(TrkSegment segment, List<RouteColorize.RouteColorizationPoint> colors, GradientScaleType scaleType, int startIdx) {
|
||||||
int pointsSize = segment.points.size();
|
int pointsSize = segment.points.size();
|
||||||
RouteColorize.RouteColorizationPoint startColor = colors.get(startIdx);
|
RouteColorize.RouteColorizationPoint startColor = colors.get(startIdx);
|
||||||
|
|
|
@ -97,8 +97,6 @@ public class MapControlsLayer extends OsmandMapLayer {
|
||||||
private static final int REQUEST_LOCATION_FOR_NAVIGATION_FAB_PERMISSION = 201;
|
private static final int REQUEST_LOCATION_FOR_NAVIGATION_FAB_PERMISSION = 201;
|
||||||
private static final int REQUEST_LOCATION_FOR_ADD_DESTINATION_PERMISSION = 202;
|
private static final int REQUEST_LOCATION_FOR_ADD_DESTINATION_PERMISSION = 202;
|
||||||
|
|
||||||
private static final int COMPASS_PRESSED_TIME_INTERVAL_MS = 5000;
|
|
||||||
|
|
||||||
public MapHudButton createHudButton(View iv, int resId, String id) {
|
public MapHudButton createHudButton(View iv, int resId, String id) {
|
||||||
MapHudButton mc = new MapHudButton();
|
MapHudButton mc = new MapHudButton();
|
||||||
mc.iv = iv;
|
mc.iv = iv;
|
||||||
|
@ -139,7 +137,6 @@ public class MapControlsLayer extends OsmandMapLayer {
|
||||||
private MapQuickActionLayer mapQuickActionLayer;
|
private MapQuickActionLayer mapQuickActionLayer;
|
||||||
private boolean forceShowCompass;
|
private boolean forceShowCompass;
|
||||||
private LatLon requestedLatLon;
|
private LatLon requestedLatLon;
|
||||||
private long compassPressed;
|
|
||||||
private Set<String> themeInfoProviderTags = new HashSet<>();
|
private Set<String> themeInfoProviderTags = new HashSet<>();
|
||||||
|
|
||||||
public MapControlsLayer(MapActivity activity) {
|
public MapControlsLayer(MapActivity activity) {
|
||||||
|
@ -292,20 +289,7 @@ public class MapControlsLayer extends OsmandMapLayer {
|
||||||
compass.setOnClickListener(new View.OnClickListener() {
|
compass.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
boolean followingMode = app.getRoutingHelper().isFollowingMode();
|
|
||||||
|
|
||||||
if (followingMode) {
|
|
||||||
if (compassPressed + COMPASS_PRESSED_TIME_INTERVAL_MS > System.currentTimeMillis()) {
|
|
||||||
compassPressed = 0;
|
|
||||||
mapActivity.getMapViewTrackingUtilities().switchRotateMapMode();
|
mapActivity.getMapViewTrackingUtilities().switchRotateMapMode();
|
||||||
} else {
|
|
||||||
compassPressed = System.currentTimeMillis();
|
|
||||||
app.showShortToastMessage(app.getString(R.string.press_again_to_change_the_map_orientation));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
compassPressed = 0;
|
|
||||||
mapActivity.getMapViewTrackingUtilities().switchRotateMapMode();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,8 @@ import net.osmand.Location;
|
||||||
import net.osmand.data.RotatedTileBox;
|
import net.osmand.data.RotatedTileBox;
|
||||||
import net.osmand.util.MapAlgorithms;
|
import net.osmand.util.MapAlgorithms;
|
||||||
import net.osmand.util.MapUtils;
|
import net.osmand.util.MapUtils;
|
||||||
|
import net.osmand.plus.views.layers.geometry.MultiProfileGeometryWay.GeometryMultiProfileWayStyle;
|
||||||
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -174,8 +176,8 @@ public abstract class GeometryWay<T extends GeometryWayContext, D extends Geomet
|
||||||
}
|
}
|
||||||
double lat = locationProvider.getLatitude(i);
|
double lat = locationProvider.getLatitude(i);
|
||||||
double lon = locationProvider.getLongitude(i);
|
double lon = locationProvider.getLongitude(i);
|
||||||
if (leftLongitude <= lon && lon <= rightLongitude && bottomLatitude <= lat
|
if (shouldAddLocation(tb, leftLongitude, rightLongitude, bottomLatitude, topLatitude,
|
||||||
&& lat <= topLatitude) {
|
locationProvider, i)) {
|
||||||
double dist = previous == -1 ? 0 : odistances.get(i);
|
double dist = previous == -1 ? 0 : odistances.get(i);
|
||||||
if (!previousVisible) {
|
if (!previousVisible) {
|
||||||
double prevLat = Double.NaN;
|
double prevLat = Double.NaN;
|
||||||
|
@ -188,7 +190,7 @@ public abstract class GeometryWay<T extends GeometryWayContext, D extends Geomet
|
||||||
prevLon = lastProjection.getLongitude();
|
prevLon = lastProjection.getLongitude();
|
||||||
}
|
}
|
||||||
if (!Double.isNaN(prevLat) && !Double.isNaN(prevLon)) {
|
if (!Double.isNaN(prevLat) && !Double.isNaN(prevLon)) {
|
||||||
addLocation(tb, prevLat, prevLon, style, tx, ty, angles, distances, dist, styles); // first point
|
addLocation(tb, prevLat, prevLon, getStyle(i - 1, style), tx, ty, angles, distances, dist, styles); // first point
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addLocation(tb, lat, lon, style, tx, ty, angles, distances, dist, styles);
|
addLocation(tb, lat, lon, style, tx, ty, angles, distances, dist, styles);
|
||||||
|
@ -208,6 +210,13 @@ public abstract class GeometryWay<T extends GeometryWayContext, D extends Geomet
|
||||||
drawRouteSegment(tb, canvas, tx, ty, angles, distances, 0, styles);
|
drawRouteSegment(tb, canvas, tx, ty, angles, distances, 0, styles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean shouldAddLocation(RotatedTileBox tileBox, double leftLon, double rightLon, double bottomLat,
|
||||||
|
double topLat, GeometryWayProvider provider, int currLocationIdx) {
|
||||||
|
double lat = provider.getLatitude(currLocationIdx);
|
||||||
|
double lon = provider.getLongitude(currLocationIdx);
|
||||||
|
return leftLon <= lon && lon <= rightLon && bottomLat <= lat && lat <= topLat;
|
||||||
|
}
|
||||||
|
|
||||||
private void addLocation(RotatedTileBox tb, double latitude, double longitude, GeometryWayStyle<?> style,
|
private void addLocation(RotatedTileBox tb, double latitude, double longitude, GeometryWayStyle<?> style,
|
||||||
List<Float> tx, List<Float> ty, List<Double> angles, List<Double> distances,
|
List<Float> tx, List<Float> ty, List<Double> angles, List<Double> distances,
|
||||||
double dist, List<GeometryWayStyle<?>> styles) {
|
double dist, List<GeometryWayStyle<?>> styles) {
|
||||||
|
@ -333,7 +342,7 @@ public abstract class GeometryWay<T extends GeometryWayContext, D extends Geomet
|
||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawRouteSegment(RotatedTileBox tb, Canvas canvas, List<Float> tx, List<Float> ty,
|
protected void drawRouteSegment(RotatedTileBox tb, Canvas canvas, List<Float> tx, List<Float> ty,
|
||||||
List<Double> angles, List<Double> distances, double distToFinish, List<GeometryWayStyle<?>> styles) {
|
List<Double> angles, List<Double> distances, double distToFinish, List<GeometryWayStyle<?>> styles) {
|
||||||
if (tx.size() < 2) {
|
if (tx.size() < 2) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -0,0 +1,261 @@
|
||||||
|
package net.osmand.plus.views.layers.geometry;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import net.osmand.GPXUtilities.TrkSegment;
|
||||||
|
import net.osmand.GPXUtilities.WptPt;
|
||||||
|
import net.osmand.Location;
|
||||||
|
import net.osmand.data.LatLon;
|
||||||
|
import net.osmand.data.QuadRect;
|
||||||
|
import net.osmand.data.RotatedTileBox;
|
||||||
|
import net.osmand.osm.edit.Node;
|
||||||
|
import net.osmand.osm.edit.Way;
|
||||||
|
import net.osmand.plus.R;
|
||||||
|
import net.osmand.plus.measurementtool.RoadSegmentData;
|
||||||
|
import net.osmand.plus.profiles.ProfileIconColors;
|
||||||
|
import net.osmand.plus.settings.backend.ApplicationMode;
|
||||||
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
import androidx.annotation.ColorInt;
|
||||||
|
import androidx.annotation.DrawableRes;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.core.graphics.ColorUtils;
|
||||||
|
|
||||||
|
public class MultiProfileGeometryWay extends GeometryWay<MultiProfileGeometryWayContext, MultiProfileGeometryWayDrawer> {
|
||||||
|
|
||||||
|
private static final String DEFAULT_PROFILE_KEY = ApplicationMode.DEFAULT.getStringKey();
|
||||||
|
|
||||||
|
private Map<Pair<WptPt, WptPt>, RoadSegmentData> segmentData;
|
||||||
|
private List<TrkSegment> beforeSegments;
|
||||||
|
private List<TrkSegment> afterSegments;
|
||||||
|
|
||||||
|
public MultiProfileGeometryWay(MultiProfileGeometryWayContext context) {
|
||||||
|
super(context, new MultiProfileGeometryWayDrawer(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawSegments(Canvas canvas, RotatedTileBox tileBox) {
|
||||||
|
QuadRect bounds = tileBox.getLatLonBounds();
|
||||||
|
drawSegments(tileBox, canvas, bounds.top, bounds.left, bounds.bottom, bounds.right, null, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateRoute(RotatedTileBox tileBox, Map<Pair<WptPt, WptPt>, RoadSegmentData> segmentData,
|
||||||
|
List<TrkSegment> beforeSegments, List<TrkSegment> afterSegments) {
|
||||||
|
boolean shouldUpdateRoute = tileBox.getMapDensity() != getMapDensity() || segmentDataChanged(segmentData)
|
||||||
|
|| this.beforeSegments != beforeSegments || this.afterSegments != afterSegments || getLocationProvider() == null;
|
||||||
|
if (shouldUpdateRoute) {
|
||||||
|
this.segmentData = segmentData;
|
||||||
|
this.beforeSegments = beforeSegments;
|
||||||
|
this.afterSegments = afterSegments;
|
||||||
|
|
||||||
|
List<Location> locations;
|
||||||
|
Map<Integer, GeometryWayStyle<?>> styleMap;
|
||||||
|
List<Way> ways = new ArrayList<>();
|
||||||
|
List<GeometryWayStyle<?>> styles = new ArrayList<>();
|
||||||
|
locations = new ArrayList<>();
|
||||||
|
|
||||||
|
List<TrkSegment> allSegments = new ArrayList<>();
|
||||||
|
allSegments.addAll(beforeSegments);
|
||||||
|
allSegments.addAll(afterSegments);
|
||||||
|
setStyles(allSegments, ways, styles);
|
||||||
|
|
||||||
|
styleMap = new TreeMap<>();
|
||||||
|
int i = 0;
|
||||||
|
int k = 0;
|
||||||
|
if (ways.size() > 0) {
|
||||||
|
for (Way w : ways) {
|
||||||
|
styleMap.put(k, styles.get(i++));
|
||||||
|
for (Node n : w.getNodes()) {
|
||||||
|
Location ln = new Location("");
|
||||||
|
ln.setLatitude(n.getLatitude());
|
||||||
|
ln.setLongitude(n.getLongitude());
|
||||||
|
locations.add(ln);
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateWay(locations, styleMap, tileBox);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearWay() {
|
||||||
|
super.clearWay();
|
||||||
|
if (segmentData != null) {
|
||||||
|
segmentData.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setStyles(List<TrkSegment> segments, List<Way> ways, List<GeometryWayStyle<?>> styles) {
|
||||||
|
for (TrkSegment segment : segments) {
|
||||||
|
List<WptPt> points = segment.points;
|
||||||
|
for (int i = 0; i < points.size() - 1; i++) {
|
||||||
|
setStylesInternal(points, i, ways, styles);
|
||||||
|
}
|
||||||
|
styles.add(new GeometryMultiProfileWayStyle(getContext(), new ArrayList<LatLon>(), 0, 0, true));
|
||||||
|
Way way = new Way(-1);
|
||||||
|
WptPt last = points.get(points.size() - 1);
|
||||||
|
way.addNode(new Node(last.lat, last.lon, -1));
|
||||||
|
ways.add(way);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setStylesInternal(List<WptPt> points, int idx, List<Way> ways, List<GeometryWayStyle<?>> styles) {
|
||||||
|
WptPt startPt = points.get(idx);
|
||||||
|
WptPt endPt = points.get(idx + 1);
|
||||||
|
List<LatLon> routePoints = getRoutePoints(startPt, endPt);
|
||||||
|
boolean isSecondToLast = idx + 2 == points.size();
|
||||||
|
|
||||||
|
Way way = new Way(-1);
|
||||||
|
String currProfileKey = getProfileKey(startPt);
|
||||||
|
Pair<Integer, Integer> profileData = getProfileData(currProfileKey);
|
||||||
|
GeometryMultiProfileWayStyle style = new GeometryMultiProfileWayStyle(
|
||||||
|
getContext(), routePoints, profileData.first, profileData.second);
|
||||||
|
styles.add(style);
|
||||||
|
ways.add(way);
|
||||||
|
|
||||||
|
for (LatLon routePt : routePoints) {
|
||||||
|
if (isSecondToLast || routePt.getLatitude() != endPt.getLatitude()
|
||||||
|
&& routePt.getLongitude() != endPt.getLongitude()) {
|
||||||
|
way.addNode(new Node(routePt.getLatitude(), routePt.getLongitude(), -1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<LatLon> getRoutePoints(WptPt start, WptPt end) {
|
||||||
|
Pair<WptPt, WptPt> userLine = new Pair<>(start, end);
|
||||||
|
RoadSegmentData roadSegmentData = segmentData.get(userLine);
|
||||||
|
List<LatLon> routePoints = new ArrayList<>();
|
||||||
|
|
||||||
|
if (roadSegmentData == null || Algorithms.isEmpty(roadSegmentData.getPoints())) {
|
||||||
|
routePoints.add(new LatLon(start.lat, start.lon));
|
||||||
|
routePoints.add(new LatLon(end.lat, end.lon));
|
||||||
|
} else {
|
||||||
|
for (WptPt routePt : roadSegmentData.getPoints()) {
|
||||||
|
routePoints.add(new LatLon(routePt.lat, routePt.lon));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return routePoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean shouldAddLocation(RotatedTileBox tileBox, double leftLon, double rightLon,
|
||||||
|
double bottomLat, double topLat, GeometryWayProvider provider,
|
||||||
|
int currLocationIdx) {
|
||||||
|
float currX = tileBox.getPixXFromLatLon(provider.getLatitude(currLocationIdx), provider.getLongitude(currLocationIdx));
|
||||||
|
float currY = tileBox.getPixYFromLatLon(provider.getLatitude(currLocationIdx), provider.getLongitude(currLocationIdx));
|
||||||
|
if (tileBox.containsPoint(currX, currY, getContext().circleSize)) {
|
||||||
|
return true;
|
||||||
|
} else if (currLocationIdx + 1 >= provider.getSize()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
float nextX = tileBox.getPixXFromLatLon(provider.getLatitude(currLocationIdx + 1), provider.getLongitude(currLocationIdx + 1));
|
||||||
|
float nextY = tileBox.getPixXFromLatLon(provider.getLatitude(currLocationIdx + 1), provider.getLongitude(currLocationIdx + 1));
|
||||||
|
return tileBox.containsPoint(nextX, nextY, getContext().circleSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean segmentDataChanged(Map<Pair<WptPt, WptPt>, RoadSegmentData> other) {
|
||||||
|
if (other.size() != segmentData.size()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (Pair<WptPt, WptPt> data : other.keySet()) {
|
||||||
|
if (other.get(data) != segmentData.get(data)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private String getProfileKey(WptPt pt) {
|
||||||
|
String key = pt.getProfileType();
|
||||||
|
return key == null ? DEFAULT_PROFILE_KEY : key;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Pair<Integer, Integer> getProfileData(String profileKey) {
|
||||||
|
boolean night = getContext().isNightMode();
|
||||||
|
ApplicationMode mode = ApplicationMode.valueOfStringKey(profileKey, ApplicationMode.DEFAULT);
|
||||||
|
return ApplicationMode.DEFAULT.getStringKey().equals(mode.getStringKey()) ?
|
||||||
|
new Pair<>(ContextCompat.getColor(getContext().getCtx(), ProfileIconColors.DARK_YELLOW.getColor(night)), R.drawable.ic_action_split_interval) :
|
||||||
|
new Pair<>(mode.getProfileColor(night), mode.getIconRes());
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public GeometryWayStyle<?> getDefaultWayStyle() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class GeometryMultiProfileWayStyle extends GeometryWayStyle<MultiProfileGeometryWayContext> {
|
||||||
|
|
||||||
|
@ColorInt
|
||||||
|
private final int lineColor;
|
||||||
|
@ColorInt
|
||||||
|
private final int borderColor;
|
||||||
|
@DrawableRes
|
||||||
|
private final int profileIconRes;
|
||||||
|
|
||||||
|
private final boolean isGap;
|
||||||
|
|
||||||
|
private final List<LatLon> routePoints;
|
||||||
|
|
||||||
|
public GeometryMultiProfileWayStyle(MultiProfileGeometryWayContext context, List<LatLon> routePoints,
|
||||||
|
@ColorInt int profileColor, @DrawableRes int profileIconRes,
|
||||||
|
boolean isGap) {
|
||||||
|
super(context);
|
||||||
|
this.routePoints = routePoints;
|
||||||
|
this.lineColor = profileColor;
|
||||||
|
this.borderColor = ColorUtils.blendARGB(profileColor, Color.BLACK, 0.2f);
|
||||||
|
this.profileIconRes = profileIconRes;
|
||||||
|
this.isGap = isGap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public GeometryMultiProfileWayStyle(MultiProfileGeometryWayContext context, List<LatLon> routePoints,
|
||||||
|
@ColorInt int profileColor, @DrawableRes int profileIconRes) {
|
||||||
|
this(context, routePoints, profileColor, profileIconRes, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ColorInt
|
||||||
|
public int getBorderColor() {
|
||||||
|
return borderColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ColorInt
|
||||||
|
public int getLineColor() {
|
||||||
|
return lineColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bitmap getPointBitmap() {
|
||||||
|
return getContext().getProfileIconBitmap(profileIconRes, borderColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<LatLon> getRoutePoints() {
|
||||||
|
return routePoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isGap() {
|
||||||
|
return isGap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
return this == other;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPathLine() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
package net.osmand.plus.views.layers.geometry;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
|
||||||
|
import net.osmand.AndroidUtils;
|
||||||
|
import net.osmand.plus.R;
|
||||||
|
import net.osmand.plus.UiUtilities;
|
||||||
|
import net.osmand.plus.views.OsmandMapLayer.RenderingLineAttributes;
|
||||||
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import androidx.annotation.ColorInt;
|
||||||
|
import androidx.annotation.DrawableRes;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
public class MultiProfileGeometryWayContext extends GeometryWayContext {
|
||||||
|
|
||||||
|
private final UiUtilities iconsCache;
|
||||||
|
|
||||||
|
public final float minIconMargin;
|
||||||
|
public final float circleSize;
|
||||||
|
public final float pointIconSize;
|
||||||
|
|
||||||
|
private static final String pointColorHex = "#637EFB";
|
||||||
|
|
||||||
|
private RenderingLineAttributes multiProfileAttrs;
|
||||||
|
|
||||||
|
private Bitmap pointIcon;
|
||||||
|
private final Map<String, Bitmap> profileIconsBitmapCache;
|
||||||
|
|
||||||
|
public MultiProfileGeometryWayContext(Context ctx, UiUtilities iconsCache, float density) {
|
||||||
|
super(ctx, density);
|
||||||
|
this.iconsCache = iconsCache;
|
||||||
|
profileIconsBitmapCache = new HashMap<>();
|
||||||
|
minIconMargin = density * 30;
|
||||||
|
circleSize = density * 70;
|
||||||
|
pointIconSize = density * 22f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updatePaints(boolean nightMode, @NonNull RenderingLineAttributes multiProfileAttrs) {
|
||||||
|
this.multiProfileAttrs = multiProfileAttrs;
|
||||||
|
super.updatePaints(nightMode, multiProfileAttrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void recreateBitmaps() {
|
||||||
|
float density = getDensity();
|
||||||
|
float outerRadius = density * 11f;
|
||||||
|
float centerRadius = density * 10.5f;
|
||||||
|
float innerRadius = density * 6.5f;
|
||||||
|
float centerXY = pointIconSize / 2;
|
||||||
|
|
||||||
|
pointIcon = Bitmap.createBitmap((int) pointIconSize, (int) pointIconSize, Bitmap.Config.ARGB_8888);
|
||||||
|
Canvas canvas = new Canvas(pointIcon);
|
||||||
|
Paint paint = new Paint();
|
||||||
|
paint.setStyle(Paint.Style.FILL);
|
||||||
|
|
||||||
|
paint.setColor(Color.BLACK);
|
||||||
|
canvas.drawCircle(centerXY, centerXY, outerRadius, paint);
|
||||||
|
|
||||||
|
paint.setColor(Color.WHITE);
|
||||||
|
canvas.drawCircle(centerXY, centerXY, centerRadius, paint);
|
||||||
|
|
||||||
|
paint.setColor(Algorithms.parseColor(pointColorHex));
|
||||||
|
canvas.drawCircle(centerXY, centerXY, innerRadius, paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public Bitmap getProfileIconBitmap(@DrawableRes int iconRes, @ColorInt int color) {
|
||||||
|
String key = iconRes + "_" + color;
|
||||||
|
Bitmap bitmap = profileIconsBitmapCache.get(key);
|
||||||
|
if (bitmap == null) {
|
||||||
|
bitmap = Bitmap.createBitmap((int) circleSize, (int) circleSize, Bitmap.Config.ARGB_8888);
|
||||||
|
Canvas canvas = new Canvas(bitmap);
|
||||||
|
float center = bitmap.getWidth() / 2f;
|
||||||
|
|
||||||
|
canvas.drawCircle(center, center, center / 2, multiProfileAttrs.paint_1);
|
||||||
|
multiProfileAttrs.paint3.setColor(color);
|
||||||
|
canvas.drawCircle(center, center, center / 2, multiProfileAttrs.paint3);
|
||||||
|
|
||||||
|
float iconSize = center - getDensity() * 10;
|
||||||
|
Bitmap profileIconBitmap = AndroidUtils.createScaledBitmap(
|
||||||
|
iconsCache.getPaintedIcon(iconRes, color), (int) iconSize, (int) iconSize);
|
||||||
|
canvas.drawBitmap(profileIconBitmap, center - iconSize / 2, center - iconSize / 2, multiProfileAttrs.paint3);
|
||||||
|
|
||||||
|
profileIconsBitmapCache.put(key, bitmap);
|
||||||
|
}
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public Bitmap getPointIcon() {
|
||||||
|
return pointIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getArrowBitmapResId() {
|
||||||
|
return R.drawable.ic_action_split_interval;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
package net.osmand.plus.views.layers.geometry;
|
||||||
|
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Path;
|
||||||
|
import android.graphics.PathMeasure;
|
||||||
|
import android.graphics.PointF;
|
||||||
|
|
||||||
|
import net.osmand.data.LatLon;
|
||||||
|
import net.osmand.data.RotatedTileBox;
|
||||||
|
import net.osmand.plus.views.OsmandMapLayer.RenderingLineAttributes;
|
||||||
|
import net.osmand.plus.views.layers.geometry.MultiProfileGeometryWay.GeometryMultiProfileWayStyle;
|
||||||
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class MultiProfileGeometryWayDrawer extends GeometryWayDrawer<MultiProfileGeometryWayContext> {
|
||||||
|
|
||||||
|
public MultiProfileGeometryWayDrawer(MultiProfileGeometryWayContext context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawPath(Canvas canvas, Path path, GeometryWayStyle<?> style) {
|
||||||
|
if (style instanceof GeometryMultiProfileWayStyle && !((GeometryMultiProfileWayStyle) style).isGap()) {
|
||||||
|
RenderingLineAttributes attrs = getContext().getAttrs();
|
||||||
|
|
||||||
|
attrs.paint.setColor(((GeometryMultiProfileWayStyle) style).getBorderColor());
|
||||||
|
canvas.drawPath(path, attrs.paint);
|
||||||
|
|
||||||
|
attrs.paint2.setColor(((GeometryMultiProfileWayStyle) style).getLineColor());
|
||||||
|
canvas.drawPath(path, attrs.paint2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawArrowsOverPath(Canvas canvas, RotatedTileBox tb, List<Float> tx, List<Float> ty, List<Double> angles, List<Double> distances, double distPixToFinish, List<GeometryWayStyle<?>> styles) {
|
||||||
|
Path path = new Path();
|
||||||
|
PathMeasure pathMeasure = new PathMeasure();
|
||||||
|
MultiProfileGeometryWayContext context = getContext();
|
||||||
|
GeometryMultiProfileWayStyle style = null;
|
||||||
|
|
||||||
|
for (int i = 0; i < styles.size(); i++) {
|
||||||
|
GeometryWayStyle<?> s = styles.get(i);
|
||||||
|
if (s != null && !s.equals(style) || !((GeometryMultiProfileWayStyle) s).isGap()) {
|
||||||
|
style = (GeometryMultiProfileWayStyle) styles.get(i);
|
||||||
|
PointF center = getIconCenter(tb, style.getRoutePoints(), path, pathMeasure);
|
||||||
|
if (center != null && tb.containsPoint(center.x, center.y, context.circleSize)) {
|
||||||
|
float x = center.x - context.circleSize / 2;
|
||||||
|
float y = center.y - context.circleSize / 2;
|
||||||
|
canvas.drawBitmap(style.getPointBitmap(), x, y, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private PointF getIconCenter(RotatedTileBox tileBox, List<LatLon> routePoints, Path path, PathMeasure pathMeasure) {
|
||||||
|
if (Algorithms.isEmpty(routePoints)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
path.reset();
|
||||||
|
PointF first = getPoint(tileBox, routePoints.get(0));
|
||||||
|
path.moveTo(first.x, first.y);
|
||||||
|
for (int i = 1; i < routePoints.size(); i++) {
|
||||||
|
PointF pt = getPoint(tileBox, routePoints.get(i));
|
||||||
|
path.lineTo(pt.x, pt.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
pathMeasure.setPath(path, false);
|
||||||
|
float routeLength = pathMeasure.getLength();
|
||||||
|
if ((routeLength - getContext().circleSize) / 2 < getContext().minIconMargin) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
float[] xy = new float[2];
|
||||||
|
pathMeasure.getPosTan(routeLength * 0.5f, xy, null);
|
||||||
|
return new PointF(xy[0], xy[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PointF getPoint(RotatedTileBox tileBox, LatLon latLon) {
|
||||||
|
return new PointF(tileBox.getPixXFromLatLon(latLon.getLatitude(), latLon.getLongitude()),
|
||||||
|
tileBox.getPixYFromLatLon(latLon.getLatitude(), latLon.getLongitude()));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue