Implement dynamic view setup

This commit is contained in:
Victor Shcherb 2012-07-26 20:26:32 +02:00
parent 62f877320d
commit db09ed83f4
16 changed files with 1217 additions and 796 deletions

View file

@ -14,7 +14,6 @@
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/list_activities_poi"
android:gravity="center_vertical"
android:text="@string/layer_poi"
android:textAppearance="?android:attr/textAppearanceMedium"

View file

@ -9,6 +9,19 @@
1. All your modified/created strings are in the top of the file (to make easier find what's translated).
PLEASE: Have a look at http://code.google.com/p/osmand/wiki/UIConsistency, it may really improve your and our work :-) Thx - Hardy
-->
<string name="map_widget_reset">Reset to default</string>
<string name="map_widget_right_stack">Right side</string>
<string name="map_widget_left_stack">Left side</string>
<string name="map_widget_parking">Parking</string>
<string name="map_widget_monitoring">Monitoring</string>
<string name="map_widget_speed">Speed</string>
<string name="map_widget_distance">Target</string>
<string name="map_widget_altitude">Altitude</string>
<string name="map_widget_time">Time to go</string>
<string name="map_widget_next_turn">Next turn</string>
<string name="map_widget_next_turn_small">Next turn (small)</string>
<string name="map_widget_next_next_turn">Second next turn</string>
<string name="map_widget_mini_route">Mini route map</string>
<string name="bg_service_screen_lock">Lock/unlock screen</string>
<string name="bg_service_screen_lock_toast">The screen is locked</string>
<string name="bg_service_sleep_mode">Set sleep mode on/off</string>
@ -39,8 +52,6 @@
<string name="use_compass_navigation_descr">Use compass when direction is not detected</string>
<string name="use_compass_navigation">Use compass</string>
<string name="select_animate_speedup">Select animate route acceleration</string>
<string name="monitoring_info_control">Show logging button</string>
<string name="monitoring_info_control_desc">Display logging button on the map screen</string>
<string name="global_app_allocated_memory_descr">Allocated memory %1$s MB (Android limit %2$s MB, Dalvik %3$s MB).</string>
<string name="global_app_allocated_memory">Allocated memory</string>
@ -366,8 +377,6 @@ You can enable (online or cached) tile map sources, tracking settings, and many
\n\t- Other small features
</string>
<string name="show_altitude_info_descr">Show current altitude information on map</string>
<string name="show_altitude_info">Show altitude</string>
<string name="use_transparent_map_theme_descr">Use transparent map controls</string>
<string name="use_transparent_map_theme">Transparent theme</string>

View file

@ -10,7 +10,6 @@
<ListPreference android:key="daynight_mode" android:title="@string/daynight" android:summary="@string/daynight_descr"></ListPreference>
<CheckBoxPreference android:key="show_view_angle" android:title="@string/show_view_angle" android:summary="@string/show_view_angle_descr"></CheckBoxPreference>
<CheckBoxPreference android:title="@string/auto_zoom_map" android:summary="@string/auto_zoom_map_descr" android:key="auto_zoom_map"></CheckBoxPreference>
<CheckBoxPreference android:key="show_altitude_info" android:title="@string/show_altitude_info" android:summary="@string/show_altitude_info_descr"/>
<PreferenceCategory android:title="@string/pref_vector_map">
<ListPreference android:key="renderer" android:title="@string/renderers" android:summary="@string/renderers_descr"></ListPreference>

View file

@ -59,6 +59,8 @@ public class OsmandSettings {
boolean set(T obj);
T getModeValue(ApplicationMode m);
String getId();
}
@ -130,6 +132,11 @@ public class OsmandSettings {
}
return changed;
}
@Override
public ApplicationMode getModeValue(ApplicationMode m) {
return m;
}
};
public ApplicationMode getApplicationMode(){
@ -260,6 +267,18 @@ public class OsmandSettings {
protected abstract boolean setValue(SharedPreferences prefs, T val);
@Override
public T getModeValue(ApplicationMode mode) {
if(global) {
return get();
}
T defaultV = defaultValue;
if(defaultValues != null && defaultValues.containsKey(currentMode)){
defaultV = defaultValues.get(currentMode);
}
return getValue(getProfilePreferences(mode), defaultV);
}
@Override
public T get() {
if(cache && cachedValue != null && cachedPreference == getPreferences()){
@ -587,17 +606,12 @@ public class OsmandSettings {
public final CommonPreference<String> LIVE_MONITORING_URL = new StringPreference("live_monitoring_url",
"http://example.com?lat={0}&lon={1}&timestamp={2}&hdop={3}&altitude={4}&speed={5}").makeGlobal();
// this value string is synchronized with settings_pref.xml preference name
public final CommonPreference<Boolean> SHOW_MONITORING_CONTROL = new BooleanPreference("show_monitoring_control", false).makeProfile().cache();
{
SHOW_MONITORING_CONTROL.setModeDefaultValue(ApplicationMode.BICYCLE, true);
SHOW_MONITORING_CONTROL.setModeDefaultValue(ApplicationMode.CAR, false);
SHOW_MONITORING_CONTROL.setModeDefaultValue(ApplicationMode.PEDESTRIAN, true);
}
// this value string is synchronized with settings_pref.xml preference name
public final OsmandPreference<Boolean> SHOW_OSM_BUGS = new BooleanPreference("show_osm_bugs", false).makeGlobal();
public final OsmandPreference<String> MAP_INFO_CONTROLS = new StringPreference("map_info_controls", "").makeProfile();
// this value string is synchronized with settings_pref.xml preference name
public final OsmandPreference<Boolean> DEBUG_RENDERING_INFO = new BooleanPreference("debug_rendering", false).makeGlobal();
@ -1261,13 +1275,6 @@ public class OsmandSettings {
public final CommonPreference<Boolean> FLUORESCENT_OVERLAYS =
new BooleanPreference("fluorescent_overlays", false).makeGlobal().cache();
public final CommonPreference<Boolean> SHOW_ALTITUDE_INFO =
new BooleanPreference("show_altitude_info", false).makeProfile().cache();
{
SHOW_ALTITUDE_INFO.setModeDefaultValue(ApplicationMode.CAR, false);
SHOW_ALTITUDE_INFO.setModeDefaultValue(ApplicationMode.BICYCLE, true);
SHOW_ALTITUDE_INFO.setModeDefaultValue(ApplicationMode.PEDESTRIAN, true);
}
public final CommonPreference<Boolean> SHOW_RULER =
new BooleanPreference("show_ruler", true).makeProfile().cache();

View file

@ -426,7 +426,7 @@ public class MapActivity extends AccessibleActivity implements IMapLocationListe
}
OsmandApplication getMyApplication() {
public OsmandApplication getMyApplication() {
return ((OsmandApplication) getApplication());
}

View file

@ -989,15 +989,10 @@ public class MapActivityActions implements DialogProvider {
} else {
AlertDialog.Builder builder = new AccessibleAlertBuilder(mapActivity);
builder.setMessage(getString(R.string.gps_status_app_not_found));
builder.setPositiveButton(
getString(R.string.default_buttons_yes),
new DialogInterface.OnClickListener() {
builder.setPositiveButton(getString(R.string.default_buttons_yes), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse("market://search?q=pname:"
+ GPS_STATUS_COMPONENT));
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:" + GPS_STATUS_COMPONENT));
try {
mapActivity.startActivity(intent);
} catch (ActivityNotFoundException e) {

View file

@ -269,7 +269,6 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
registerBooleanPreference(osmandSettings.SHOW_SPEED_LIMITS, screen);
registerBooleanPreference(osmandSettings.AVOID_TOLL_ROADS, screen);
registerBooleanPreference(osmandSettings.SHOW_ALTITUDE_INFO, screen);
CheckBoxPreference nativeCheckbox = registerBooleanPreference(osmandSettings.NATIVE_RENDERING,screen);
//disable the checkbox if the library cannot be used

View file

@ -1,5 +1,7 @@
package net.osmand.plus.monitoring;
import java.util.EnumSet;
import net.osmand.LogUtil;
import net.osmand.OsmAndFormatter;
import net.osmand.plus.ContextMenuAdapter;
@ -9,6 +11,7 @@ import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.ProgressDialogImplementation;
import net.osmand.plus.R;
import net.osmand.plus.activities.ApplicationMode;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.activities.SavingTrackHelper;
import net.osmand.plus.activities.SettingsActivity;
@ -21,11 +24,8 @@ import org.apache.commons.logging.Log;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.drawable.Drawable;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceCategory;
@ -66,15 +66,19 @@ public class OsmandMonitoringPlugin extends OsmandPlugin {
@Override
public void registerLayers(MapActivity activity) {
monitoringControl = createMonitoringControl(activity);
MapInfoLayer layer = activity.getMapLayers().getMapInfoLayer();
layer.addRightStack(monitoringControl);
monitoringControl = createMonitoringControl(activity, layer.getPaintText(), layer.getPaintSubText());
layer.getMapInfoControls().registerSideWidget(monitoringControl,
R.drawable.monitoring_rec_small, R.string.map_widget_monitoring, "monitoring", false,
EnumSet.of(ApplicationMode.BICYCLE, ApplicationMode.PEDESTRIAN), EnumSet.noneOf(ApplicationMode.class), 18);
layer.recreateControls();
}
@Override
public void updateLayers(OsmandMapTileView mapView, MapActivity activity) {
if(monitoringControl != null) {
monitoringControl.updateInfo();
if(monitoringControl == null) {
registerLayers(activity);
}
}
@ -133,10 +137,6 @@ public class OsmandMonitoringPlugin extends OsmandPlugin {
});
cat.addPreference(pref);
CheckBoxPreference infoControlPreference = activity.createCheckBoxPreference(settings.SHOW_MONITORING_CONTROL,
R.string.monitoring_info_control, R.string.monitoring_info_control_desc);
cat.addPreference(infoControlPreference);
cat = new PreferenceCategory(activity);
cat.setTitle(R.string.live_monitoring);
grp.addPreference(cat);
@ -174,18 +174,7 @@ public class OsmandMonitoringPlugin extends OsmandPlugin {
/**
* creates (if it wasn't created previously) the control to be added on a MapInfoLayer that shows a monitoring state (recorded/stopped)
*/
private MapInfoControl createMonitoringControl(final MapActivity map) {
Paint paintText = new Paint();
paintText.setStyle(Style.FILL_AND_STROKE);
paintText.setColor(Color.BLACK);
paintText.setTextSize(23 * MapInfoLayer.scaleCoefficient);
paintText.setAntiAlias(true);
paintText.setStrokeWidth(4);
Paint paintSubText = new Paint();
paintSubText.setStyle(Style.FILL_AND_STROKE);
paintSubText.setColor(Color.BLACK);
paintSubText.setTextSize(15 * MapInfoLayer.scaleCoefficient);
paintSubText.setAntiAlias(true);
private MapInfoControl createMonitoringControl(final MapActivity map, Paint paintText, Paint paintSubText) {
final Drawable monitoringBig = map.getResources().getDrawable(R.drawable.monitoring_rec_big);
final Drawable monitoringSmall = map.getResources().getDrawable(R.drawable.monitoring_rec_small);
final Drawable monitoringInactive = map.getResources().getDrawable(R.drawable.monitoring_rec_inactive);
@ -193,9 +182,7 @@ public class OsmandMonitoringPlugin extends OsmandPlugin {
long lastUpdateTime;
@Override
public boolean updateInfo() {
boolean visible = false;
if (settings.SHOW_MONITORING_CONTROL.get()) {
visible = true;
boolean visible = true;
String txt = "start";
String subtxt = null;
Drawable d = monitoringInactive;
@ -219,7 +206,6 @@ public class OsmandMonitoringPlugin extends OsmandPlugin {
lastUpdateTime = last;
blink();
}
}
updateVisibility(visible);
return true;
}

View file

@ -3,33 +3,25 @@ package net.osmand.plus.parkingpoint;
import java.util.ArrayList;
import java.util.List;
import net.osmand.OsmAndFormatter;
import net.osmand.access.AccessibleToast;
import net.osmand.osm.LatLon;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.views.AnimateDraggingMapThread;
import net.osmand.plus.views.ContextMenuLayer;
import net.osmand.plus.views.MapInfoLayer;
import net.osmand.plus.views.OsmandMapLayer;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.plus.views.TextInfoControl;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.PointF;
import android.graphics.RectF;
import android.location.Location;
import android.text.format.DateFormat;
import android.text.format.Time;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;
@ -54,20 +46,20 @@ public class ParkingPositionLayer extends OsmandMapLayer implements ContextMenuL
private OsmandSettings settings;
private Paint bitmapPaint;
private Paint paintText;
private Paint paintSubText;
private Bitmap parkingNoLimitIcon;
private Bitmap parkingLimitIcon;
private TextInfoControl parkingPlaceControl;
private boolean timeLimit;
public ParkingPositionLayer(MapActivity map) {
this.map = map;
}
public LatLon getParkingPoint() {
return parkingPoint;
}
@Override
public void initLayer(OsmandMapTileView view) {
this.view = view;
@ -77,19 +69,6 @@ public class ParkingPositionLayer extends OsmandMapLayer implements ContextMenuL
WindowManager wmgr = (WindowManager) view.getContext().getSystemService(Context.WINDOW_SERVICE);
wmgr.getDefaultDisplay().getMetrics(dm);
paintText = new Paint();
paintText.setStyle(Style.FILL_AND_STROKE);
paintText.setColor(Color.BLACK);
paintText.setTextSize(23 * MapInfoLayer.scaleCoefficient);
paintText.setAntiAlias(true);
paintText.setStrokeWidth(4);
paintSubText = new Paint();
paintSubText.setStyle(Style.FILL_AND_STROKE);
paintSubText.setColor(Color.BLACK);
paintSubText.setTextSize(15 * MapInfoLayer.scaleCoefficient);
paintSubText.setAntiAlias(true);
bitmapPaint = new Paint();
bitmapPaint.setDither(true);
bitmapPaint.setAntiAlias(true);
@ -97,10 +76,6 @@ public class ParkingPositionLayer extends OsmandMapLayer implements ContextMenuL
parkingNoLimitIcon = BitmapFactory.decodeResource(view.getResources(), R.drawable.poi_parking_pos_no_limit);
parkingLimitIcon = BitmapFactory.decodeResource(view.getResources(), R.drawable.poi_parking_pos_limit);
MapInfoLayer mapInfoLayer = map.getMapLayers().getMapInfoLayer();
if ((mapInfoLayer != null) && (parkingPlaceControl == null))
mapInfoLayer.addRightStack(createParkingPlaceInfoControl());
}
@Override
@ -247,76 +222,6 @@ public class ParkingPositionLayer extends OsmandMapLayer implements ContextMenuL
}
}
/**
* @return the control to be added on a MapInfoLayer
* that shows a distance between
* the current position on the map
* and the location of the parked car
*/
private TextInfoControl createParkingPlaceInfoControl() {
parkingPlaceControl = new TextInfoControl(map, 0, paintText, paintSubText) {
private float[] calculations = new float[1];
private int cachedMeters = 0;
@Override
public boolean updateInfo() {
if( parkingPoint != null && !map.getRoutingHelper().isFollowingMode()) {
int d = 0;
if (d == 0) {
Location.distanceBetween(view.getLatitude(), view.getLongitude(), parkingPoint.getLatitude(), parkingPoint.getLongitude(), calculations);
d = (int) calculations[0];
}
if (distChanged(cachedMeters, d)) {
cachedMeters = d;
if (cachedMeters <= 20) {
cachedMeters = 0;
setText(null, null);
} else {
String ds = OsmAndFormatter.getFormattedDistance(cachedMeters, map);
int ls = ds.lastIndexOf(' ');
if (ls == -1) {
setText(ds, null);
} else {
setText(ds.substring(0, ls), ds.substring(ls + 1));
}
}
return true;
}
} else if (cachedMeters != 0) {
cachedMeters = 0;
setText(null, null);
return true;
}
return false;
}
/**
* Utility method.
* @param oldDist
* @param dist
* @return
*/
private boolean distChanged(int oldDist, int dist){
if(oldDist != 0 && oldDist - dist < 100 && Math.abs(((float) dist - oldDist)/oldDist) < 0.01){
return false;
}
return true;
}
};
parkingPlaceControl.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AnimateDraggingMapThread thread = view.getAnimatedDraggingThread();
LatLon parkingPoint = view.getSettings().getParkingPosition();
if (parkingPoint != null) {
float fZoom = view.getFloatZoom() < 15 ? 15 : view.getFloatZoom();
thread.startMoving(parkingPoint.getLatitude(), parkingPoint.getLongitude(), fZoom, true);
}
}
});
parkingPlaceControl.setText(null, null);
parkingPlaceControl.setImageDrawable(view.getResources().getDrawable(R.drawable.poi_parking_pos_info));
return parkingPlaceControl;
}
}

View file

@ -1,7 +1,9 @@
package net.osmand.plus.parkingpoint;
import java.util.Calendar;
import java.util.EnumSet;
import net.osmand.OsmAndFormatter;
import net.osmand.osm.LatLon;
import net.osmand.plus.ContextMenuAdapter;
import net.osmand.plus.ContextMenuAdapter.OnContextMenuClick;
@ -10,13 +12,20 @@ import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.activities.ApplicationMode;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.views.AnimateDraggingMapThread;
import net.osmand.plus.views.MapInfoControl;
import net.osmand.plus.views.MapInfoLayer;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.plus.views.TextInfoControl;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Paint;
import android.location.Location;
import android.text.format.DateFormat;
import android.view.Menu;
import android.view.MenuItem;
@ -39,6 +48,7 @@ public class ParkingPositionPlugin extends OsmandPlugin {
private ParkingPositionLayer parkingLayer;
private OsmandSettings settings;
private MapInfoControl parkingPlaceControl;
public ParkingPositionPlugin(OsmandApplication app) {
this.app = app;
@ -67,19 +77,36 @@ public class ParkingPositionPlugin extends OsmandPlugin {
@Override
public void registerLayers(MapActivity activity) {
if(parkingLayer == null) {
parkingLayer = new ParkingPositionLayer(activity);
}
registerWidget(activity);
}
@Override
public void updateLayers(OsmandMapTileView mapView, MapActivity activity) {
if ((settings.getParkingPosition() == null)
&& (mapView.getLayers().contains(parkingLayer))) {
if ((settings.getParkingPosition() == null) && (mapView.getLayers().contains(parkingLayer))) {
mapView.removeLayer(parkingLayer);
} else {
if (parkingLayer == null)
if (parkingLayer == null) {
registerLayers(activity);
}
mapView.addLayer(parkingLayer, 5);
}
if(parkingPlaceControl == null){
registerWidget(activity);
}
}
private void registerWidget(MapActivity activity) {
MapInfoLayer mapInfoLayer = activity.getMapLayers().getMapInfoLayer();
if (mapInfoLayer != null) {
parkingPlaceControl = createParkingPlaceInfoControl(activity, mapInfoLayer.getPaintText(), mapInfoLayer.getPaintSubText());
mapInfoLayer.getMapInfoControls().registerSideWidget(parkingPlaceControl,
R.drawable.poi_parking_pos_info, R.string.map_widget_parking, "parking", false,
EnumSet.allOf(ApplicationMode.class), EnumSet.noneOf(ApplicationMode.class), 8);
mapInfoLayer.recreateControls();
}
}
@Override
@ -333,4 +360,79 @@ public class ParkingPositionPlugin extends OsmandPlugin {
}
}
}
/**
* @return the control to be added on a MapInfoLayer
* that shows a distance between
* the current position on the map
* and the location of the parked car
*/
private TextInfoControl createParkingPlaceInfoControl(final MapActivity map, Paint paintText, Paint paintSubText) {
TextInfoControl parkingPlaceControl = new TextInfoControl(map, 0, paintText, paintSubText) {
private float[] calculations = new float[1];
private int cachedMeters = 0;
@Override
public boolean updateInfo() {
LatLon parkingPoint = parkingLayer.getParkingPoint();
if( parkingPoint != null && !map.getRoutingHelper().isFollowingMode()) {
OsmandMapTileView view = map.getMapView();
int d = 0;
if (d == 0) {
Location.distanceBetween(view.getLatitude(), view.getLongitude(), parkingPoint.getLatitude(), parkingPoint.getLongitude(), calculations);
d = (int) calculations[0];
}
if (distChanged(cachedMeters, d)) {
cachedMeters = d;
if (cachedMeters <= 20) {
cachedMeters = 0;
setText(null, null);
} else {
String ds = OsmAndFormatter.getFormattedDistance(cachedMeters, map);
int ls = ds.lastIndexOf(' ');
if (ls == -1) {
setText(ds, null);
} else {
setText(ds.substring(0, ls), ds.substring(ls + 1));
}
}
return true;
}
} else if (cachedMeters != 0) {
cachedMeters = 0;
setText(null, null);
return true;
}
return false;
}
/**
* Utility method.
* @param oldDist
* @param dist
* @return
*/
private boolean distChanged(int oldDist, int dist){
if(oldDist != 0 && oldDist - dist < 100 && Math.abs(((float) dist - oldDist)/oldDist) < 0.01){
return false;
}
return true;
}
};
parkingPlaceControl.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
OsmandMapTileView view = map.getMapView();
AnimateDraggingMapThread thread = view.getAnimatedDraggingThread();
LatLon parkingPoint = view.getSettings().getParkingPosition();
if (parkingPoint != null) {
float fZoom = view.getFloatZoom() < 15 ? 15 : view.getFloatZoom();
thread.startMoving(parkingPoint.getLatitude(), parkingPoint.getLongitude(), fZoom, true);
}
}
});
parkingPlaceControl.setText(null, null);
parkingPlaceControl.setImageDrawable(map.getResources().getDrawable(R.drawable.poi_parking_pos_info));
return parkingPlaceControl;
}
}

View file

@ -0,0 +1,224 @@
package net.osmand.plus.views;
import java.util.EnumSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.activities.ApplicationMode;
import android.graphics.Paint;
public class MapInfoControls {
private Set<MapInfoControlRegInfo> left = new TreeSet<MapInfoControls.MapInfoControlRegInfo>();
private Set<MapInfoControlRegInfo> right = new TreeSet<MapInfoControls.MapInfoControlRegInfo>();
private Map<ApplicationMode, Set<String>> visibleElements = new LinkedHashMap<ApplicationMode, Set<String>>();
private final OsmandSettings settings;
public interface MapInfoControlFactoryMethod {
/**
* @param mapView
* @param paints array of paints (4) 0 - normal, 1 - subtext, 2 - small, 3 - small subtext
*/
public MapInfoControl createControl(OsmandMapTileView mapView, Paint[] paints);
}
public MapInfoControls(OsmandSettings settings) {
this.settings = settings;
for(ApplicationMode ms : ApplicationMode.values() ) {
String mpf = settings.MAP_INFO_CONTROLS.getModeValue(ms);
if(mpf.equals("")) {
visibleElements.put(ms, null);
} else {
LinkedHashSet<String> set = new LinkedHashSet<String>();
visibleElements.put(ms, set);
for(String s : mpf.split(";")){
set.add(s);
}
}
}
}
public void registerSideWidget(MapInfoControl m, int drawable, int messageId, String key, boolean left,
EnumSet<ApplicationMode> appDefaultModes, EnumSet<ApplicationMode> defaultCollapsible, int priorityOrder) {
MapInfoControlRegInfo ii = new MapInfoControlRegInfo();
ii.defaultModes = appDefaultModes.clone();
ii.defaultCollapsible = defaultCollapsible.clone();
ii.key = key;
ii.visibleModes = EnumSet.noneOf(ApplicationMode.class);
ii.visibleCollapsible = EnumSet.noneOf(ApplicationMode.class);
for(ApplicationMode ms : ApplicationMode.values() ) {
boolean collapse = defaultCollapsible.contains(ms);;
boolean def = appDefaultModes.contains(ms);
Set<String> set = visibleElements.get(ms);
if(set != null) {
def = set.contains(key);
collapse = set.contains("+"+key);
}
if(def){
ii.visibleModes.add(ms);
} else if(collapse) {
ii.visibleCollapsible.add(ms);
}
}
ii.drawable = drawable;
ii.messageId = messageId;
ii.m = m;
ii.priorityOrder = priorityOrder;
if(left) {
this.left.add(ii);
} else {
this.right.add(ii);
}
}
private void restoreModes(Set<String> set, Set<MapInfoControlRegInfo> mi, ApplicationMode mode) {
for(MapInfoControlRegInfo m : mi){
if(m.visibleModes.contains(mode)) {
set.add(m.key) ;
} else if(m.visibleCollapsible.contains(mode)) {
set.add("+"+m.key) ;
}
}
}
public void changeVisibility(MapInfoControlRegInfo m, boolean visible, boolean collapse) {
ApplicationMode mode = settings.APPLICATION_MODE.get();
if(this.visibleElements.get(mode) == null){
LinkedHashSet<String> set = new LinkedHashSet<String>();
restoreModes(set, left, mode);
restoreModes(set, right, mode);
this.visibleElements.put(mode, set);
}
this.visibleElements.get(mode).remove(m.key);
this.visibleElements.get(mode).remove("+" + m.key);
m.visibleModes.remove(mode);
m.visibleCollapsible.remove(mode);
if(visible) {
if(collapse) {
m.visibleCollapsible.add(mode);
this.visibleElements.get(mode).add("+" + m.key);
} else {
m.visibleModes.add(mode);
this.visibleElements.get(mode).add(m.key);
}
}
StringBuilder bs = new StringBuilder();
for(String ks : this.visibleElements.get(mode)){
bs.append(ks).append(";");
}
settings.MAP_INFO_CONTROLS.set(bs.toString());
}
public Set<MapInfoControlRegInfo> getLeft() {
return left;
}
public Set<MapInfoControlRegInfo> getRight() {
return right;
}
public void registerTopBarButton(MapInfoControlFactoryMethod m, int drawable, int messageId, boolean left,
EnumSet<ApplicationMode> appModes, int priorityOrder) {
}
public void populateStackControl(MapStackControl stack, OsmandMapTileView v, boolean left){
ApplicationMode appMode = settings.getApplicationMode();
Set<MapInfoControlRegInfo> st = left ? this.left : this.right;
for (MapInfoControlRegInfo r : st) {
if (r.visibleCollapsible.contains(appMode)) {
stack.addCollapsedView(r.m);
} else if (r.visibleModes.contains(appMode)) {
stack.addStackView(r.m);
}
}
}
private void resetDefault(ApplicationMode mode, Set<MapInfoControlRegInfo> set ){
for(MapInfoControlRegInfo ri : set) {
ri.visibleCollapsible.remove(mode);
ri.visibleModes.remove(mode);
if(ri.defaultCollapsible.contains(mode)) {
ri.visibleCollapsible.add(mode);
}
if(ri.defaultModes.contains(mode)) {
ri.visibleModes.add(mode);
}
}
}
public void resetToDefault() {
ApplicationMode appMode = settings.getApplicationMode();
resetDefault(appMode, left);
resetDefault(appMode, right);
this.visibleElements.put(appMode, null);
settings.MAP_INFO_CONTROLS.set("");
}
public static boolean distChanged(int oldDist, int dist){
if(oldDist != 0 && oldDist - dist < 100 && Math.abs(((float) dist - oldDist)/oldDist) < 0.01){
return false;
}
return true;
}
public static class MapInfoControlRegInfo implements Comparable<MapInfoControlRegInfo> {
public MapInfoControl m;
public int drawable;
public int messageId;
private String key;
private EnumSet<ApplicationMode> defaultModes;
private EnumSet<ApplicationMode> defaultCollapsible;
private EnumSet<ApplicationMode> visibleModes;
private EnumSet<ApplicationMode> visibleCollapsible;
public int priorityOrder;
public boolean visibleCollapsed(ApplicationMode mode){
return visibleCollapsible.contains(mode);
}
public boolean visible(ApplicationMode mode){
return visibleModes.contains(mode);
}
@Override
public int hashCode() {
return messageId;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MapInfoControlRegInfo other = (MapInfoControlRegInfo) obj;
if (messageId != other.messageId)
return false;
return true;
}
@Override
public int compareTo(MapInfoControlRegInfo another) {
if (messageId == another.messageId) {
return 0;
}
if(priorityOrder == another.priorityOrder) {
return messageId - another.messageId;
}
return priorityOrder - another.priorityOrder;
}
}
}

View file

@ -1,35 +1,32 @@
package net.osmand.plus.views;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.EnumSet;
import net.osmand.Algoritms;
import net.osmand.OsmAndFormatter;
import net.osmand.osm.LatLon;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.activities.ApplicationMode;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.background.OsmandBackgroundServicePlugin;
import net.osmand.plus.routing.AlarmInfo;
import net.osmand.plus.routing.RouteDirectionInfo;
import net.osmand.plus.routing.RoutingHelper;
import net.osmand.plus.routing.RouteCalculationResult.NextDirectionInfo;
import net.osmand.router.TurnType;
import net.osmand.plus.views.MapInfoControls.MapInfoControlRegInfo;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.text.TextPaint;
import android.text.format.DateFormat;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Gravity;
@ -37,10 +34,15 @@ import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ListAdapter;
import android.widget.TextView;
public class MapInfoLayer extends OsmandMapLayer {
@ -58,11 +60,9 @@ public class MapInfoLayer extends OsmandMapLayer {
private Paint paintImg;
private float cachedRotate = 0;
private boolean showArrivalTime = true;
private boolean showAltitude = false;
// layout pseudo-constants
private int STATUS_BAR_MARGIN_X = 4;
private int STATUS_BAR_MARGIN_X = -4;
private ImageView backToLocation;
private ImageView compassView;
@ -76,15 +76,13 @@ public class MapInfoLayer extends OsmandMapLayer {
private MapInfoControl alarmControl;
private TextView topText;
private MapInfoControls mapInfoControls;
public MapInfoLayer(MapActivity map, RouteLayer layer){
this.map = map;
this.routeLayer = layer;
}
@Override
public void initLayer(final OsmandMapTileView view) {
this.view = view;
WindowManager mgr = (WindowManager) view.getContext().getSystemService(Context.WINDOW_SERVICE);
WindowManager mgr = (WindowManager) map.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
mgr.getDefaultDisplay().getMetrics(dm);
scaleCoefficient = dm.density;
@ -124,8 +122,37 @@ public class MapInfoLayer extends OsmandMapLayer {
paintImg.setFilterBitmap(true);
paintImg.setAntiAlias(true);
createTopBarElements();
mapInfoControls = new MapInfoControls(map.getMyApplication().getSettings());
}
public Paint getPaintSmallSubText() {
return paintSmallSubText;
}
public Paint getPaintText() {
return paintText;
}
public Paint getPaintSmallText() {
return paintSmallText;
}
public Paint getPaintSubText() {
return paintSubText;
}
public MapInfoControls getMapInfoControls() {
return mapInfoControls;
}
@Override
public void initLayer(final OsmandMapTileView view) {
this.view = view;
registerAllControls();
createControls();
applyTheme();
}
@ -149,29 +176,59 @@ public class MapInfoLayer extends OsmandMapLayer {
leftStack.setExpandImageDrawable(view.getResources().getDrawable(expand));
rightStack.setExpandImageDrawable(view.getResources().getDrawable(expand));
statusBar.setBackgroundDrawable(view.getResources().getDrawable(boxTop));
showAltitude = view.getSettings().SHOW_ALTITUDE_INFO.get();
}
public void createTopBarElements() {
// 1. Create view groups and controls
public void registerAllControls(){
statusBar = createStatusBar();
statusBar.setBackgroundDrawable(view.getResources().getDrawable(R.drawable.box_top));
lanesControl = createLanesControl();
RouteInfoControls ric = new RouteInfoControls(scaleCoefficient);
lanesControl = ric.createLanesControl(view.getApplication().getRoutingHelper(), view);
lanesControl.setBackgroundDrawable(view.getResources().getDrawable(R.drawable.box_free));
alarmControl = createAlarmInfoControl();
alarmControl = ric.createAlarmInfoControl(view.getApplication().getRoutingHelper(),
view.getContext(), view.getSettings());
// register right stack
EnumSet<ApplicationMode> all = EnumSet.allOf(ApplicationMode.class);
EnumSet<ApplicationMode> bicyclePedestrian = EnumSet.of(ApplicationMode.BICYCLE, ApplicationMode.PEDESTRIAN);
EnumSet<ApplicationMode> none = EnumSet.noneOf(ApplicationMode.class);
RoutingHelper routingHelper = view.getApplication().getRoutingHelper();
NextTurnInfoControl bigInfoControl = ric.createNextInfoControl(routingHelper, view.getApplication(), view.getSettings(), paintText,
paintSubText, false);
mapInfoControls.registerSideWidget(bigInfoControl, 0, R.string.map_widget_next_turn,"next_turn", true, all, none, 5);
NextTurnInfoControl smallInfoControl = ric.createNextInfoControl(routingHelper, view.getApplication(), view.getSettings(),
paintSmallText, paintSmallSubText, true);
mapInfoControls.registerSideWidget(smallInfoControl, 0, R.string.map_widget_next_turn_small, "next_turn_small", true, bicyclePedestrian, none, 10);
NextTurnInfoControl nextNextInfoControl = ric.createNextNextInfoControl(routingHelper, view.getApplication(), view.getSettings(),
paintSmallText, paintSmallSubText, true);
mapInfoControls.registerSideWidget(nextNextInfoControl, 0, R.string.map_widget_next_next_turn, "next_next_turn",true, all, none, 15);
MiniMapControl miniMap = ric.createMiniMapControl(routingHelper, view);
mapInfoControls.registerSideWidget(miniMap, 0, R.string.map_widget_mini_route, "mini_route", true, none, none, 20);
// right stack
TextInfoControl dist = ric.createDistanceControl(map, paintText, paintSubText);
mapInfoControls.registerSideWidget(dist, R.drawable.info_target, R.string.map_widget_distance, "distance", false, all, none, 5);
TextInfoControl time = ric.createTimeControl(map, paintText, paintSubText);
mapInfoControls.registerSideWidget(time, R.drawable.info_time, R.string.map_widget_time, "time",false, all, none, 10);
TextInfoControl speed = ric.createSpeedControl(map, paintText, paintSubText);
mapInfoControls.registerSideWidget(speed, R.drawable.info_speed, R.string.map_widget_speed, "speed", false, all, none, 15);
TextInfoControl alt = ric.createAltitudeControl(map, paintText, paintSubText);
mapInfoControls.registerSideWidget(alt, R.drawable.ic_altitude, R.string.map_widget_altitude, "altitude", false, EnumSet.of(ApplicationMode.PEDESTRIAN), none, 20);
}
public void recreateControls(){
rightStack.clearAllViews();
mapInfoControls.populateStackControl(rightStack, view, false);
leftStack.clearAllViews();
mapInfoControls.populateStackControl(leftStack, view, true);
leftStack.requestLayout();
rightStack.requestLayout();
}
public void createControls() {
// 1. Create view groups and controls
statusBar.setBackgroundDrawable(view.getResources().getDrawable(R.drawable.box_top));
rightStack = new MapStackControl(view.getContext());
rightStack.addStackView(createAltitudeControl());
rightStack.addStackView(createDistanceControl());
rightStack.addCollapsedView(createSpeedControl());
rightStack.addCollapsedView(createTimeControl());
leftStack = new MapStackControl(view.getContext());
leftStack.addStackView(createNextInfoControl());
leftStack.addStackView(createMiniMapControl());
leftStack.addStackView(createNextNextInfoControl());
// 2. Preparations
Rect topRectPadding = new Rect();
@ -227,16 +284,99 @@ public class MapInfoLayer extends OsmandMapLayer {
parent.addView(alarmControl);
alarmControl.setVisibility(View.GONE);
lanesControl.setVisibility(View.GONE);
applyTheme();
recreateControls();
}
public void openViewConfigureDialog() {
final OsmandSettings settings = view.getSettings();
public boolean distChanged(int oldDist, int dist){
if(oldDist != 0 && oldDist - dist < 100 && Math.abs(((float) dist - oldDist)/oldDist) < 0.01){
return false;
final ArrayList<Object> list = new ArrayList<Object>();
list.add(map.getString(R.string.map_widget_reset));
list.add(map.getString(R.string.map_widget_right_stack));
list.addAll(mapInfoControls.getRight());
list.add(map.getString(R.string.map_widget_left_stack));
list.addAll(mapInfoControls.getLeft());
// final LayerMenuListener listener = new LayerMenuListener(adapter, mapView, settings);
Builder b = new AlertDialog.Builder(map);
final ApplicationMode mode = settings.getApplicationMode();
ListAdapter listAdapter = new ArrayAdapter<Object>(map, R.layout.layers_list_activity_item, R.id.title, list) {
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
v = map.getLayoutInflater().inflate(R.layout.layers_list_activity_item, null);
}
return true;
TextView tv = (TextView) v.findViewById(R.id.title);
final CheckBox ch = ((CheckBox) v.findViewById(R.id.check_item));
Object o = list.get(position);
if(o instanceof MapInfoControlRegInfo) {
final MapInfoControlRegInfo mi = (MapInfoControlRegInfo) o;
tv.setText(map.getString(mi.messageId));
// Put the image on the TextView
if (mi.drawable != 0) {
tv.setPadding((int) (12 *scaleCoefficient), 0, 0, 0);
tv.setCompoundDrawablesWithIntrinsicBounds(mi.drawable, 0, 0, 0);
} else {
tv.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
tv.setPadding((int) (27 *scaleCoefficient), 0, 0, 0);
}
boolean check = mi.visibleCollapsed(mode) || mi.visible(mode);
ch.setOnCheckedChangeListener(null);
ch.setChecked(check);
ch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(!isChecked) {
mapInfoControls.changeVisibility(mi, false, false);
} else {
mapInfoControls.changeVisibility(mi, true, false);
}
recreateControls();
}
});
ch.setVisibility(View.VISIBLE);
} else {
tv.setText(o.toString());
tv.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
tv.setPadding((int) (5 *scaleCoefficient), 0, 0, 0);
ch.setVisibility(View.INVISIBLE);
}
return v;
}
};
b.setAdapter(listAdapter, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int position) {
Object o = list.get(position);
if (o instanceof MapInfoControlRegInfo) {
final MapInfoControlRegInfo mi = (MapInfoControlRegInfo) o;
boolean check = mi.visibleCollapsed(mode) || mi.visible(mode);
if (check) {
mapInfoControls.changeVisibility(mi, false, false);
} else {
mapInfoControls.changeVisibility(mi, true, false);
}
recreateControls();
} else if(o.toString().equals(map.getString(R.string.map_widget_reset))) {
mapInfoControls.resetToDefault();
recreateControls();
}
}
});
final AlertDialog dlg = b.create();
// listener.setDialog(dlg);
dlg.setCanceledOnTouchOutside(true);
dlg.show();
}
@Override
public void onDraw(Canvas canvas, RectF latlonBounds, RectF tilesRect, DrawSettings nightMode) {
boolean bold = routeLayer.getHelper().isFollowingMode();
@ -331,453 +471,6 @@ public class MapInfoLayer extends OsmandMapLayer {
return progressBar;
}
private TextInfoControl createSpeedControl(){
final TextInfoControl speedControl = new TextInfoControl(map, 3, paintText, paintSubText) {
private float cachedSpeed = 0;
@Override
public boolean updateInfo() {
// draw speed
if (map.getLastKnownLocation() != null && map.getLastKnownLocation().hasSpeed()) {
// .3 mps == 1.08 kph
float minDelta = .3f;
// Update more often at walk/run speeds, since we give higher resolution
// and use .02 instead of .03 to account for rounding effects.
if (cachedSpeed < 6) minDelta = .015f;
if (Math.abs(map.getLastKnownLocation().getSpeed() - cachedSpeed) > minDelta) {
cachedSpeed = map.getLastKnownLocation().getSpeed();
String ds = OsmAndFormatter.getFormattedSpeed(cachedSpeed, map);
int ls = ds.lastIndexOf(' ');
if (ls == -1) {
setText(ds, null);
} else {
setText(ds.substring(0, ls), ds.substring(ls + 1));
}
return true;
}
} else if (cachedSpeed != 0) {
cachedSpeed = 0;
setText(null, null);
return true;
}
return false;
}
};
speedControl.setImageDrawable(view.getResources().getDrawable(R.drawable.info_speed));
speedControl.setText(null, null);
return speedControl;
}
private TextInfoControl createAltitudeControl(){
final TextInfoControl altitudeControl = new TextInfoControl(map, 0, paintText, paintSubText) {
private int cachedAlt = 0;
@Override
public boolean updateInfo() {
// draw speed
if (showAltitude &&
map.getLastKnownLocation() != null && map.getLastKnownLocation().hasAltitude()) {
if (cachedAlt != (int) map.getLastKnownLocation().getAltitude()) {
cachedAlt = (int) map.getLastKnownLocation().getAltitude();
String ds = OsmAndFormatter.getFormattedAlt(cachedAlt, map);
int ls = ds.lastIndexOf(' ');
if (ls == -1) {
setText(ds, null);
} else {
setText(ds.substring(0, ls), ds.substring(ls + 1));
}
return true;
}
} else if (cachedAlt != 0) {
cachedAlt = 0;
setText(null, null);
return true;
}
return false;
}
};
altitudeControl.setText(null, null);
altitudeControl.setImageDrawable(view.getResources().getDrawable(R.drawable.ic_altitude));
return altitudeControl;
}
private TextInfoControl createTimeControl(){
final Drawable time = view.getResources().getDrawable(R.drawable.info_time);
final Drawable timeToGo = view.getResources().getDrawable(R.drawable.info_time_to_go);
showArrivalTime = view.getSettings().SHOW_ARRIVAL_TIME_OTHERWISE_EXPECTED_TIME.get();
final TextInfoControl leftTimeControl = new TextInfoControl(map, 0, paintText, paintSubText) {
private long cachedLeftTime = 0;
@Override
public boolean updateInfo() {
int time = 0;
if (routeLayer != null && routeLayer.getHelper().isRouteCalculated()) {
boolean followingMode = routeLayer.getHelper().isFollowingMode();
time = routeLayer.getHelper().getLeftTime();
if (time != 0) {
if (followingMode && showArrivalTime) {
long toFindTime = time * 1000 + System.currentTimeMillis();
if (Math.abs(toFindTime - cachedLeftTime) > 30000) {
cachedLeftTime = toFindTime;
if (DateFormat.is24HourFormat(map)) {
setText(DateFormat.format("k:mm", toFindTime).toString(), null); //$NON-NLS-1$
} else {
setText(DateFormat.format("h:mm", toFindTime).toString(),
DateFormat.format("aa", toFindTime).toString()); //$NON-NLS-1$
}
return true;
}
} else {
if (Math.abs(time - cachedLeftTime) > 30) {
cachedLeftTime = time;
int hours = time / (60 * 60);
int minutes = (time / 60) % 60;
setText(String.format("%d:%02d", hours, minutes), null); //$NON-NLS-1$
return true;
}
}
}
}
if (time == 0 && cachedLeftTime != 0) {
cachedLeftTime = 0;
setText(null, null);
return true;
}
return false;
};
};
leftTimeControl.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showArrivalTime = !showArrivalTime;
leftTimeControl.setImageDrawable(showArrivalTime? time : timeToGo);
view.getSettings().SHOW_ARRIVAL_TIME_OTHERWISE_EXPECTED_TIME.set(showArrivalTime);
view.refreshMap();
}
});
leftTimeControl.setText(null, null);
leftTimeControl.setImageDrawable(showArrivalTime? time : timeToGo);
return leftTimeControl;
}
private TextInfoControl createDistanceControl() {
TextInfoControl distanceControl = new TextInfoControl(map, 0, paintText, paintSubText) {
private float[] calculations = new float[1];
private int cachedMeters = 0;
@Override
public boolean updateInfo() {
if (map.getPointToNavigate() != null) {
int d = 0;
if (map.getRoutingHelper().isRouteCalculated()) {
d = map.getRoutingHelper().getLeftDistance();
}
if (d == 0) {
Location.distanceBetween(view.getLatitude(), view.getLongitude(), map.getPointToNavigate().getLatitude(), map
.getPointToNavigate().getLongitude(), calculations);
d = (int) calculations[0];
}
if (distChanged(cachedMeters, d)) {
cachedMeters = d;
if (cachedMeters <= 20) {
cachedMeters = 0;
setText(null, null);
} else {
String ds = OsmAndFormatter.getFormattedDistance(cachedMeters, map);
int ls = ds.lastIndexOf(' ');
if (ls == -1) {
setText(ds, null);
} else {
setText(ds.substring(0, ls), ds.substring(ls + 1));
}
}
return true;
}
} else if (cachedMeters != 0) {
cachedMeters = 0;
setText(null, null);
return true;
}
return false;
}
};
distanceControl.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AnimateDraggingMapThread thread = view.getAnimatedDraggingThread();
LatLon pointToNavigate = view.getSettings().getPointToNavigate();
if (pointToNavigate != null) {
float fZoom = view.getFloatZoom() < 15 ? 15 : view.getFloatZoom();
thread.startMoving(pointToNavigate.getLatitude(), pointToNavigate.getLongitude(), fZoom, true);
}
}
});
distanceControl.setText(null, null);
distanceControl.setImageDrawable(view.getResources().getDrawable(R.drawable.info_target));
return distanceControl;
}
protected MiniMapControl createMiniMapControl() {
final MiniMapControl miniMapControl = new MiniMapControl(map, view) {
@Override
public boolean updateInfo() {
boolean visible = false;
updateVisibility(visible);
return super.updateInfo();
}
};
miniMapControl.setVisibility(View.GONE);
miniMapControl.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// showMiniMap = false;
miniMapControl.invalidate();
view.refreshMap();
}
});
return miniMapControl;
}
private NextTurnInfoControl createNextNextInfoControl() {
final RoutingHelper routingHelper = routeLayer.getHelper();
final NextTurnInfoControl nextTurnInfo = new NextTurnInfoControl(map, paintSmallText, paintSmallSubText, true) {
NextDirectionInfo calc1 = new NextDirectionInfo();
@Override
public boolean updateInfo() {
boolean visible = false;
if (routeLayer != null && routingHelper.isRouteCalculated() && routingHelper.isFollowingMode()) {
boolean uturnWhenPossible = routingHelper.makeUturnWhenPossible() ;
NextDirectionInfo r = routingHelper.getNextRouteDirectionInfo(calc1, true);
if (!uturnWhenPossible) {
if (r != null) {
// next turn is very close (show next next with false to speak)
// if (r.imminent >= 0 && r.imminent < 2) {
// r = routingHelper.getNextRouteDirectionInfoAfter(r, calc1, false);
// } else {
r = routingHelper.getNextRouteDirectionInfo(calc1, true);
if (r != null) {
r = routingHelper.getNextRouteDirectionInfoAfter(r, calc1, true);
}
// }
}
}
if (r != null && r.distanceTo > 0) {
visible = true;
if (r == null || r.directionInfo == null) {
if (turnType != null) {
turnType = null;
invalidate();
}
} else if (!Algoritms.objectEquals(turnType, r.directionInfo.getTurnType())) {
turnType = r.directionInfo.getTurnType();
TurnPathHelper.calcTurnPath(pathForTurn, turnType, pathTransform);
invalidate();
requestLayout();
}
if (distChanged(r.distanceTo, nextTurnDirection)) {
invalidate();
requestLayout();
nextTurnDirection = r.distanceTo;
}
int imminent = r.imminent;
if (turnImminent != imminent) {
turnImminent = imminent;
invalidate();
}
}
}
updateVisibility(visible);
return true;
}
};
nextTurnInfo.setOnClickListener(new View.OnClickListener() {
// int i = 0;
@Override
public void onClick(View v) {
// uncomment to test turn info rendering
// final int l = TurnType.predefinedTypes.length;
// final int exits = 5;
// i++;
// if (i % (l + exits) >= l ) {
// nextTurnInfo.turnType = TurnType.valueOf("EXIT" + (i % (l + exits) - l + 1), true);
// nextTurnInfo.exitOut = (i % (l + exits) - l + 1)+"";
// float a = 180 - (i % (l + exits) - l + 1) * 50;
// nextTurnInfo.turnType.setTurnAngle(a < 0 ? a + 360 : a);
// } else {
// nextTurnInfo.turnType = TurnType.valueOf(TurnType.predefinedTypes[i % (TurnType.predefinedTypes.length + exits)], true);
// nextTurnInfo.exitOut = "";
// }
// nextTurnInfo.turnImminent = (nextTurnInfo.turnImminent + 1) % 3;
// nextTurnInfo.nextTurnDirection = 580;
// TurnPathHelper.calcTurnPath(nextTurnInfo.pathForTurn, nexsweepAngletTurnInfo.turnType,nextTurnInfo.pathTransform);
// showMiniMap = true;
view.refreshMap();
}
});
// initial state
// nextTurnInfo.setVisibility(View.GONE);
return nextTurnInfo;
}
private MapInfoControl createAlarmInfoControl() {
final RoutingHelper routingHelper = routeLayer.getHelper();
final Paint paintCircle = new Paint();
final float th = 11 * scaleCoefficient;
paintCircle.setColor(Color.rgb(225, 15, 15));
paintCircle.setStrokeWidth(11 * scaleCoefficient);
paintCircle.setStyle(Style.STROKE);
paintCircle.setAntiAlias(true);
final Paint content = new Paint();
content.setColor(Color.WHITE);
content.setStyle(Style.FILL);
final Paint ptext = new Paint();
ptext.setTextSize(27 * scaleCoefficient);
ptext.setFakeBoldText(true);
ptext.setAntiAlias(true);
ptext.setTextAlign(Align.CENTER);
final OsmandSettings settings = view.getSettings();
final MapInfoControl alarm = new MapInfoControl(map) {
private String text = "";
@Override
public boolean updateInfo() {
boolean limits = settings.SHOW_SPEED_LIMITS.get();
boolean cams = settings.SHOW_CAMERAS.get();
boolean visible = false;
if ((limits || cams) && routeLayer != null && routingHelper.isFollowingMode()) {
AlarmInfo alarm = routingHelper.getMostImportantAlarm(view.getSettings().METRIC_SYSTEM.get());
if(alarm != null) {
if(alarm.getType() == AlarmInfo.SPEED_LIMIT) {
text = alarm.getIntValue() +"";
} else if(alarm.getType() == AlarmInfo.SPEED_CAMERA) {
text = "CAM";
} else if(alarm.getType() == AlarmInfo.BORDER_CONTROL) {
text = "CLO";
} else if(alarm.getType() == AlarmInfo.TOLL_BOOTH) {
text = "$";
} else if(alarm.getType() == AlarmInfo.TRAFFIC_CALMING) {
// temporary omega
text = "~^~";
} else if(alarm.getType() == AlarmInfo.STOP) {
// text = "STOP";
}
visible = text.length() > 0;
if (visible) {
if (alarm.getType() == AlarmInfo.SPEED_CAMERA) {
visible = cams;
} else {
visible = limits;
}
}
}
}
updateVisibility(visible);
return true;
}
@Override
protected void onDraw(Canvas canvas) {
RectF f = new RectF(th / 2, th / 2, getWidth() - th / 2, getHeight() - th / 2);
canvas.drawOval(f, content);
canvas.drawOval(f, paintCircle);
canvas.drawText(text, getWidth() / 2, getHeight() / 2 + ptext.descent() + 3 * scaleCoefficient, ptext);
}
};
// initial state
// nextTurnInfo.setVisibility(View.GONE);
return alarm;
}
private NextTurnInfoControl createNextInfoControl() {
final RoutingHelper routingHelper = routeLayer.getHelper();
final NextTurnInfoControl nextTurnInfo = new NextTurnInfoControl(map, paintText, paintSubText, false) {
NextDirectionInfo calc1 = new NextDirectionInfo();
TurnType straight = TurnType.valueOf(TurnType.C, true);
@Override
public boolean updateInfo() {
boolean visible = false;
if (routeLayer != null && routingHelper.isRouteCalculated() && routingHelper.isFollowingMode()) {
makeUturnWhenPossible = routingHelper.makeUturnWhenPossible() ;
if (makeUturnWhenPossible) {
visible = true;
turnImminent = 0;
turnType = TurnType.valueOf(TurnType.TU, view.getSettings().LEFT_SIDE_NAVIGATION.get());
TurnPathHelper.calcTurnPath(pathForTurn, turnType, pathTransform);
invalidate();
} else {
boolean showStraight = false;
NextDirectionInfo r = routingHelper.getNextRouteDirectionInfo(calc1, true);
if (r != null && r.distanceTo > 0) {
visible = true;
if (r.directionInfo == null) {
if (turnType != null) {
turnType = null;
invalidate();
}
} else if (!Algoritms.objectEquals(turnType, showStraight ? straight : r.directionInfo.getTurnType())) {
turnType = showStraight ? straight : r.directionInfo.getTurnType();
TurnPathHelper.calcTurnPath(pathForTurn, turnType, pathTransform);
if (turnType.getExitOut() > 0) {
exitOut = turnType.getExitOut() + ""; //$NON-NLS-1$
} else {
exitOut = null;
}
requestLayout();
invalidate();
}
if (distChanged(r.distanceTo, nextTurnDirection)) {
invalidate();
requestLayout();
nextTurnDirection = r.distanceTo;
}
if (turnImminent != r.imminent) {
turnImminent = r.imminent;
invalidate();
}
}
}
}
updateVisibility(visible);
return true;
}
};
nextTurnInfo.setOnClickListener(new View.OnClickListener() {
// int i = 0;
// boolean leftSide = false;
@Override
public void onClick(View v) {
// for test rendering purposes
// final int l = TurnType.predefinedTypes.length;
// final int exits = 5;
// i++;
// if (i % (l + exits) >= l ) {
// nextTurnInfo.turnType = TurnType.valueOf("EXIT" + (i % (l + exits) - l + 1), leftSide);
// float a = leftSide? -180 + (i % (l + exits) - l + 1) * 50: 180 - (i % (l + exits) - l + 1) * 50;
// nextTurnInfo.turnType.setTurnAngle(a < 0 ? a + 360 : a);
// nextTurnInfo.exitOut = (i % (l + exits) - l + 1)+"";
// } else {
// nextTurnInfo.turnType = TurnType.valueOf(TurnType.predefinedTypes[i % (TurnType.predefinedTypes.length + exits)], leftSide);
// nextTurnInfo.exitOut = "";
// }
// nextTurnInfo.turnImminent = (nextTurnInfo.turnImminent + 1) % 3;
// nextTurnInfo.nextTurnDirection = 580;
// TurnPathHelper.calcTurnPath(nextTurnInfo.pathForTurn, nextTurnInfo.turnType,nextTurnInfo.pathTransform);
// showMiniMap = true;
nextTurnInfo.requestLayout();
view.refreshMap();
}
});
// initial state
nextTurnInfo.setVisibility(View.GONE);
return nextTurnInfo;
}
private ViewGroup createStatusBar() {
LinearLayout statusBar = new LinearLayout(view.getContext());
statusBar.setOrientation(LinearLayout.HORIZONTAL);
@ -832,7 +525,9 @@ public class MapInfoLayer extends OsmandMapLayer {
globus.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
map.getMapLayers().selectMapLayer(view);
// TODO
openViewConfigureDialog();
// map.getMapLayers().selectMapLayer(view);
}
});
fl.addView(globus, fparams);
@ -870,109 +565,5 @@ public class MapInfoLayer extends OsmandMapLayer {
}
}
private static final float miniCoeff = 2f;
private MapInfoControl createLanesControl() {
final Path laneStraight = new Path();
Matrix pathTransform = new Matrix();
pathTransform.postScale(scaleCoefficient / miniCoeff, scaleCoefficient / miniCoeff);
TurnPathHelper.calcTurnPath(laneStraight, TurnType.valueOf(TurnType.C, false), pathTransform);
final Paint paintBlack = new Paint();
paintBlack.setStyle(Style.STROKE);
paintBlack.setColor(Color.BLACK);
paintBlack.setAntiAlias(true);
paintBlack.setStrokeWidth(2.5f);
final Paint paintRouteDirection = new Paint();
paintRouteDirection.setStyle(Style.FILL);
paintRouteDirection.setColor(view.getResources().getColor(R.color.nav_arrow));
paintRouteDirection.setAntiAlias(true);
final float w = 72 * scaleCoefficient / miniCoeff;
final RoutingHelper routingHelper = routeLayer.getHelper();
final MapInfoControl lanesControl = new MapInfoControl(map) {
int[] lanes = null;
boolean imminent = false;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int ls = (int) (lanes == null ? 0 : lanes.length * w);
setWDimensions(ls, (int)( w + 3 * scaleCoefficient));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//to change color immediately when needed
if (lanes != null && lanes.length > 0) {
canvas.save();
// canvas.translate((int) (16 * scaleCoefficient), 0);
for (int i = 0; i < lanes.length; i++) {
if ((lanes[i] & 1) == 1) {
paintRouteDirection.setColor(imminent ? getResources().getColor(R.color.nav_arrow_imminent) : getResources().getColor(R.color.nav_arrow));
} else {
paintRouteDirection.setColor(getResources().getColor(R.color.nav_arrow_distant));
}
canvas.drawPath(laneStraight, paintBlack);
canvas.drawPath(laneStraight, paintRouteDirection);
canvas.translate(w, 0);
}
canvas.restore();
}
}
@Override
public boolean updateInfo() {
boolean visible = false;
int locimminent = -1;
int[] loclanes = null;
if (routeLayer != null && routingHelper.isRouteCalculated()) {
if (routingHelper.isFollowingMode()) {
NextDirectionInfo r = routingHelper.getNextRouteDirectionInfo(new NextDirectionInfo(), false);
if(r != null && r.directionInfo != null && r.directionInfo.getTurnType() != null) {
loclanes = r.directionInfo.getTurnType().getLanes();
locimminent = r.imminent;
// Do not show too far
if ((r.distanceTo > 700 && r.directionInfo.getTurnType().isSkipToSpeak()) || r.distanceTo > 1200) {
loclanes = null;
}
}
} else {
int di = map.getMapLayers().getRouteInfoLayer().getDirectionInfo();
if (di >= 0 && map.getMapLayers().getRouteInfoLayer().isVisible()) {
RouteDirectionInfo next = routingHelper.getRouteDirections().get(di);
if(next != null) {
loclanes = next.getTurnType().getLanes();
}
}
}
}
visible = loclanes != null && loclanes.length > 0;
if (visible) {
if (!Arrays.equals(lanes, loclanes)) {
lanes = loclanes;
requestLayout();
invalidate();
}
if ((locimminent == 0) != imminent) {
imminent = (locimminent == 0);
invalidate();
}
}
updateVisibility(visible);
return true;
}
};
return lanesControl;
}
public void addRightStack(MapInfoControl v){
rightStack.addStackView(v);
}
public MapStackControl getRightStack(){
return rightStack;
}
}

View file

@ -85,12 +85,20 @@ public class MapStackControl extends ViewGroup {
public void addStackView(MapInfoControl v) {
stackViews.add(v);
MapStackControl.this.addView(v, 1);
MapStackControl.this.addView(v, getChildCount());
}
public void addCollapsedView(MapInfoControl v) {
collapsedViews.add(v);
MapStackControl.this.addView(v, 1);
MapStackControl.this.addView(v, getChildCount());
}
public void clearAllViews(){
stackViews.clear();
collapsedViews.clear();
while(getChildCount() > 1){
removeViewAt(1);
}
}
public List<MapInfoControl> getStackViews() {

View file

@ -9,6 +9,7 @@ import android.graphics.Paint.Cap;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.view.View;
public class MiniMapControl extends MapInfoControl {
private float scaleCoefficient = MapInfoLayer.scaleCoefficient;
@ -48,7 +49,9 @@ public class MiniMapControl extends MapInfoControl {
@Override
public boolean updateInfo() {
if(getVisibility() == View.VISIBLE) {
invalidate();
}
return true;
}

View file

@ -16,8 +16,8 @@ import android.graphics.Path;
public class NextTurnInfoControl extends MapInfoControl {
private float scaleCoefficient = MapInfoLayer.scaleCoefficient;
private final float width;
private final float height ;
private float width;
private float height ;
private static final float miniCoeff = 2.5f;
protected Path pathForTurn = new Path();
@ -27,20 +27,20 @@ public class NextTurnInfoControl extends MapInfoControl {
protected int nextTurnDirection = 0;
private final Paint textPaint;
private final Paint subtextPaint;
protected Paint textPaint;
protected Paint subtextPaint;
private Paint paintBlack;
private Paint paintRouteDirection;
protected boolean makeUturnWhenPossible;
protected int turnImminent;
private final boolean horisontalMini;
protected boolean horisontalMini;
public NextTurnInfoControl(Context ctx, Paint textPaint, Paint subtextPaint, boolean horisontalMini) {
super(ctx);
this.textPaint = textPaint;
this.subtextPaint = subtextPaint;
this.horisontalMini = horisontalMini;
paintBlack = new Paint();
paintBlack.setStyle(Style.STROKE);
@ -54,6 +54,12 @@ public class NextTurnInfoControl extends MapInfoControl {
paintRouteDirection.setAntiAlias(true);
pathTransform = new Matrix();
updateHorisontalMini(horisontalMini);
}
protected void updateHorisontalMini(boolean horisontalMini) {
this.horisontalMini = horisontalMini;
if (horisontalMini) {
pathTransform.postScale(scaleCoefficient / miniCoeff, scaleCoefficient / miniCoeff);
width = 72 * scaleCoefficient / miniCoeff;
@ -63,9 +69,10 @@ public class NextTurnInfoControl extends MapInfoControl {
width = 72 * scaleCoefficient;
height = 72 * scaleCoefficient;
}
requestLayout();
}
protected Matrix pathTransform = new Matrix();
@Override

View file

@ -0,0 +1,587 @@
package net.osmand.plus.views;
import java.util.Arrays;
import net.osmand.Algoritms;
import net.osmand.OsmAndFormatter;
import net.osmand.osm.LatLon;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.OsmandSettings.OsmandPreference;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.routing.AlarmInfo;
import net.osmand.plus.routing.RouteCalculationResult.NextDirectionInfo;
import net.osmand.plus.routing.RouteDirectionInfo;
import net.osmand.plus.routing.RoutingHelper;
import net.osmand.router.TurnType;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.text.format.DateFormat;
import android.view.View;
public class RouteInfoControls {
public float scaleCoefficient = 1;
public RouteInfoControls(float scaleCoefficient){
this.scaleCoefficient = scaleCoefficient;
}
public NextTurnInfoControl createNextInfoControl(final RoutingHelper routingHelper, Context ctx,
final OsmandSettings settings, Paint textPaint, Paint subtextPaint, boolean horisontalMini) {
final NextTurnInfoControl nextTurnInfo = new NextTurnInfoControl(ctx, textPaint, subtextPaint, horisontalMini) {
NextDirectionInfo calc1 = new NextDirectionInfo();
TurnType straight = TurnType.valueOf(TurnType.C, true);
@Override
public boolean updateInfo() {
boolean visible = false;
if (routingHelper != null && routingHelper.isRouteCalculated() && routingHelper.isFollowingMode()) {
makeUturnWhenPossible = routingHelper.makeUturnWhenPossible() ;
if (makeUturnWhenPossible) {
visible = true;
turnImminent = 0;
turnType = TurnType.valueOf(TurnType.TU, settings.LEFT_SIDE_NAVIGATION.get());
TurnPathHelper.calcTurnPath(pathForTurn, turnType, pathTransform);
invalidate();
} else {
boolean showStraight = false;
NextDirectionInfo r = routingHelper.getNextRouteDirectionInfo(calc1, true);
if (r != null && r.distanceTo > 0) {
visible = true;
if (r.directionInfo == null) {
if (turnType != null) {
turnType = null;
invalidate();
}
} else if (!Algoritms.objectEquals(turnType, showStraight ? straight : r.directionInfo.getTurnType())) {
turnType = showStraight ? straight : r.directionInfo.getTurnType();
TurnPathHelper.calcTurnPath(pathForTurn, turnType, pathTransform);
if (turnType.getExitOut() > 0) {
exitOut = turnType.getExitOut() + ""; //$NON-NLS-1$
} else {
exitOut = null;
}
requestLayout();
invalidate();
}
if (distChanged(r.distanceTo, nextTurnDirection)) {
invalidate();
requestLayout();
nextTurnDirection = r.distanceTo;
}
if (turnImminent != r.imminent) {
turnImminent = r.imminent;
invalidate();
}
}
}
}
updateVisibility(visible);
return true;
}
};
nextTurnInfo.setOnClickListener(new View.OnClickListener() {
// int i = 0;
// boolean leftSide = false;
@Override
public void onClick(View v) {
// for test rendering purposes
// final int l = TurnType.predefinedTypes.length;
// final int exits = 5;
// i++;
// if (i % (l + exits) >= l ) {
// nextTurnInfo.turnType = TurnType.valueOf("EXIT" + (i % (l + exits) - l + 1), leftSide);
// float a = leftSide? -180 + (i % (l + exits) - l + 1) * 50: 180 - (i % (l + exits) - l + 1) * 50;
// nextTurnInfo.turnType.setTurnAngle(a < 0 ? a + 360 : a);
// nextTurnInfo.exitOut = (i % (l + exits) - l + 1)+"";
// } else {
// nextTurnInfo.turnType = TurnType.valueOf(TurnType.predefinedTypes[i % (TurnType.predefinedTypes.length + exits)], leftSide);
// nextTurnInfo.exitOut = "";
// }
// nextTurnInfo.turnImminent = (nextTurnInfo.turnImminent + 1) % 3;
// nextTurnInfo.nextTurnDirection = 580;
// TurnPathHelper.calcTurnPath(nextTurnInfo.pathForTurn, nextTurnInfo.turnType,nextTurnInfo.pathTransform);
// showMiniMap = true;
nextTurnInfo.requestLayout();
nextTurnInfo.invalidate();
}
});
// initial state
nextTurnInfo.setVisibility(View.GONE);
return nextTurnInfo;
}
public NextTurnInfoControl createNextNextInfoControl(final RoutingHelper routingHelper, Context ctx,
final OsmandSettings settings, Paint textPaint, Paint subtextPaint, boolean horisontalMini) {
final NextTurnInfoControl nextTurnInfo = new NextTurnInfoControl(ctx, textPaint, subtextPaint, horisontalMini) {
NextDirectionInfo calc1 = new NextDirectionInfo();
@Override
public boolean updateInfo() {
boolean visible = false;
if (routingHelper != null && routingHelper.isRouteCalculated() && routingHelper.isFollowingMode()
) {
boolean uturnWhenPossible = routingHelper.makeUturnWhenPossible() ;
NextDirectionInfo r = routingHelper.getNextRouteDirectionInfo(calc1, true);
if (!uturnWhenPossible) {
if (r != null) {
// next turn is very close (show next next with false to speak)
// if (r.imminent >= 0 && r.imminent < 2) {
// r = routingHelper.getNextRouteDirectionInfoAfter(r, calc1, false);
// } else {
r = routingHelper.getNextRouteDirectionInfo(calc1, true);
if (r != null) {
r = routingHelper.getNextRouteDirectionInfoAfter(r, calc1, true);
}
// }
}
}
if (r != null && r.distanceTo > 0) {
visible = true;
if (r == null || r.directionInfo == null) {
if (turnType != null) {
turnType = null;
invalidate();
}
} else if (!Algoritms.objectEquals(turnType, r.directionInfo.getTurnType())) {
turnType = r.directionInfo.getTurnType();
TurnPathHelper.calcTurnPath(pathForTurn, turnType, pathTransform);
invalidate();
requestLayout();
}
if (distChanged(r.distanceTo, nextTurnDirection)) {
invalidate();
requestLayout();
nextTurnDirection = r.distanceTo;
}
int imminent = r.imminent;
if (turnImminent != imminent) {
turnImminent = imminent;
invalidate();
}
}
}
updateVisibility(visible);
return true;
}
};
nextTurnInfo.setOnClickListener(new View.OnClickListener() {
// int i = 0;
@Override
public void onClick(View v) {
// uncomment to test turn info rendering
// final int l = TurnType.predefinedTypes.length;
// final int exits = 5;
// i++;
// if (i % (l + exits) >= l ) {
// nextTurnInfo.turnType = TurnType.valueOf("EXIT" + (i % (l + exits) - l + 1), true);
// nextTurnInfo.exitOut = (i % (l + exits) - l + 1)+"";
// float a = 180 - (i % (l + exits) - l + 1) * 50;
// nextTurnInfo.turnType.setTurnAngle(a < 0 ? a + 360 : a);
// } else {
// nextTurnInfo.turnType = TurnType.valueOf(TurnType.predefinedTypes[i % (TurnType.predefinedTypes.length + exits)], true);
// nextTurnInfo.exitOut = "";
// }
// nextTurnInfo.turnImminent = (nextTurnInfo.turnImminent + 1) % 3;
// nextTurnInfo.nextTurnDirection = 580;
// TurnPathHelper.calcTurnPath(nextTurnInfo.pathForTurn, nexsweepAngletTurnInfo.turnType,nextTurnInfo.pathTransform);
// showMiniMap = true;
}
});
// initial state
// nextTurnInfo.setVisibility(View.GONE);
return nextTurnInfo;
}
protected TextInfoControl createTimeControl(final MapActivity map, Paint paintText, Paint paintSubText){
final RoutingHelper routingHelper = map.getRoutingHelper();
final Drawable time = map.getResources().getDrawable(R.drawable.info_time);
final Drawable timeToGo = map.getResources().getDrawable(R.drawable.info_time_to_go);
final OsmandApplication ctx = map.getMyApplication();
final OsmandPreference<Boolean> showArrival = ctx.getSettings().SHOW_ARRIVAL_TIME_OTHERWISE_EXPECTED_TIME;
final TextInfoControl leftTimeControl = new TextInfoControl(map, 0, paintText, paintSubText) {
private long cachedLeftTime = 0;
@Override
public boolean updateInfo() {
int time = 0;
if (routingHelper != null && routingHelper.isRouteCalculated()) {
boolean followingMode = routingHelper.isFollowingMode();
time = routingHelper.getLeftTime();
if (time != 0) {
if (followingMode && showArrival.get()) {
long toFindTime = time * 1000 + System.currentTimeMillis();
if (Math.abs(toFindTime - cachedLeftTime) > 30000) {
cachedLeftTime = toFindTime;
if (DateFormat.is24HourFormat(ctx)) {
setText(DateFormat.format("k:mm", toFindTime).toString(), null); //$NON-NLS-1$
} else {
setText(DateFormat.format("h:mm", toFindTime).toString(),
DateFormat.format("aa", toFindTime).toString()); //$NON-NLS-1$
}
return true;
}
} else {
if (Math.abs(time - cachedLeftTime) > 30) {
cachedLeftTime = time;
int hours = time / (60 * 60);
int minutes = (time / 60) % 60;
setText(String.format("%d:%02d", hours, minutes), null); //$NON-NLS-1$
return true;
}
}
}
}
if (time == 0 && cachedLeftTime != 0) {
cachedLeftTime = 0;
setText(null, null);
return true;
}
return false;
};
};
leftTimeControl.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showArrival.set(!showArrival.get());
leftTimeControl.setImageDrawable(showArrival.get()? time : timeToGo);
leftTimeControl.requestLayout();
}
});
leftTimeControl.setText(null, null);
leftTimeControl.setImageDrawable(showArrival.get()? time : timeToGo);
return leftTimeControl;
}
protected TextInfoControl createAltitudeControl(final MapActivity map, Paint paintText, Paint paintSubText) {
final TextInfoControl altitudeControl = new TextInfoControl(map, 0, paintText, paintSubText) {
private int cachedAlt = 0;
@Override
public boolean updateInfo() {
// draw speed
if (map.getLastKnownLocation() != null && map.getLastKnownLocation().hasAltitude()) {
if (cachedAlt != (int) map.getLastKnownLocation().getAltitude()) {
cachedAlt = (int) map.getLastKnownLocation().getAltitude();
String ds = OsmAndFormatter.getFormattedAlt(cachedAlt, map);
int ls = ds.lastIndexOf(' ');
if (ls == -1) {
setText(ds, null);
} else {
setText(ds.substring(0, ls), ds.substring(ls + 1));
}
return true;
}
} else if (cachedAlt != 0) {
cachedAlt = 0;
setText(null, null);
return true;
}
return false;
}
};
altitudeControl.setText(null, null);
altitudeControl.setImageDrawable(map.getResources().getDrawable(R.drawable.ic_altitude));
return altitudeControl;
}
protected TextInfoControl createSpeedControl(final MapActivity map, Paint paintText, Paint paintSubText) {
final TextInfoControl speedControl = new TextInfoControl(map, 3, paintText, paintSubText) {
private float cachedSpeed = 0;
@Override
public boolean updateInfo() {
// draw speed
if (map.getLastKnownLocation() != null && map.getLastKnownLocation().hasSpeed()) {
// .3 mps == 1.08 kph
float minDelta = .3f;
// Update more often at walk/run speeds, since we give higher resolution
// and use .02 instead of .03 to account for rounding effects.
if (cachedSpeed < 6) minDelta = .015f;
if (Math.abs(map.getLastKnownLocation().getSpeed() - cachedSpeed) > minDelta) {
cachedSpeed = map.getLastKnownLocation().getSpeed();
String ds = OsmAndFormatter.getFormattedSpeed(cachedSpeed, map);
int ls = ds.lastIndexOf(' ');
if (ls == -1) {
setText(ds, null);
} else {
setText(ds.substring(0, ls), ds.substring(ls + 1));
}
return true;
}
} else if (cachedSpeed != 0) {
cachedSpeed = 0;
setText(null, null);
return true;
}
return false;
}
};
speedControl.setImageDrawable(map.getResources().getDrawable(R.drawable.info_speed));
speedControl.setText(null, null);
return speedControl;
}
protected TextInfoControl createDistanceControl(final MapActivity map, Paint paintText, Paint paintSubText) {
final OsmandMapTileView view = map.getMapView();
TextInfoControl distanceControl = new TextInfoControl(map, 0, paintText, paintSubText) {
private float[] calculations = new float[1];
private int cachedMeters = 0;
@Override
public boolean updateInfo() {
if (map.getPointToNavigate() != null) {
int d = 0;
if (map.getRoutingHelper().isRouteCalculated()) {
d = map.getRoutingHelper().getLeftDistance();
}
if (d == 0) {
Location.distanceBetween(view.getLatitude(), view.getLongitude(), map.getPointToNavigate().getLatitude(), map
.getPointToNavigate().getLongitude(), calculations);
d = (int) calculations[0];
}
if (distChanged(cachedMeters, d)) {
cachedMeters = d;
if (cachedMeters <= 20) {
cachedMeters = 0;
setText(null, null);
} else {
String ds = OsmAndFormatter.getFormattedDistance(cachedMeters, map);
int ls = ds.lastIndexOf(' ');
if (ls == -1) {
setText(ds, null);
} else {
setText(ds.substring(0, ls), ds.substring(ls + 1));
}
}
return true;
}
} else if (cachedMeters != 0) {
cachedMeters = 0;
setText(null, null);
return true;
}
return false;
}
};
distanceControl.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AnimateDraggingMapThread thread = view.getAnimatedDraggingThread();
LatLon pointToNavigate = view.getSettings().getPointToNavigate();
if (pointToNavigate != null) {
float fZoom = view.getFloatZoom() < 15 ? 15 : view.getFloatZoom();
thread.startMoving(pointToNavigate.getLatitude(), pointToNavigate.getLongitude(), fZoom, true);
}
}
});
distanceControl.setText(null, null);
distanceControl.setImageDrawable(view.getResources().getDrawable(R.drawable.info_target));
return distanceControl;
}
protected MiniMapControl createMiniMapControl(final RoutingHelper routingHelper, OsmandMapTileView view) {
final MiniMapControl miniMapControl = new MiniMapControl(view.getContext(), view) {
@Override
public boolean updateInfo() {
boolean visible = routingHelper.isFollowingMode();
updateVisibility(visible);
return super.updateInfo();
}
};
miniMapControl.setVisibility(View.GONE);
return miniMapControl;
}
private static final float miniCoeff = 2f;
protected MapInfoControl createLanesControl(final RoutingHelper routingHelper, final OsmandMapTileView view) {
final Path laneStraight = new Path();
Matrix pathTransform = new Matrix();
pathTransform.postScale(scaleCoefficient / miniCoeff, scaleCoefficient / miniCoeff);
TurnPathHelper.calcTurnPath(laneStraight, TurnType.valueOf(TurnType.C, false), pathTransform);
final Paint paintBlack = new Paint();
paintBlack.setStyle(Style.STROKE);
paintBlack.setColor(Color.BLACK);
paintBlack.setAntiAlias(true);
paintBlack.setStrokeWidth(2.5f);
final Paint paintRouteDirection = new Paint();
paintRouteDirection.setStyle(Style.FILL);
paintRouteDirection.setColor(view.getResources().getColor(R.color.nav_arrow));
paintRouteDirection.setAntiAlias(true);
final float w = 72 * scaleCoefficient / miniCoeff;
final MapInfoControl lanesControl = new MapInfoControl(view.getContext()) {
int[] lanes = null;
boolean imminent = false;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int ls = (int) (lanes == null ? 0 : lanes.length * w);
setWDimensions(ls, (int)( w + 3 * scaleCoefficient));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//to change color immediately when needed
if (lanes != null && lanes.length > 0) {
canvas.save();
// canvas.translate((int) (16 * scaleCoefficient), 0);
for (int i = 0; i < lanes.length; i++) {
if ((lanes[i] & 1) == 1) {
paintRouteDirection.setColor(imminent ? getResources().getColor(R.color.nav_arrow_imminent) : getResources().getColor(R.color.nav_arrow));
} else {
paintRouteDirection.setColor(getResources().getColor(R.color.nav_arrow_distant));
}
canvas.drawPath(laneStraight, paintBlack);
canvas.drawPath(laneStraight, paintRouteDirection);
canvas.translate(w, 0);
}
canvas.restore();
}
}
@Override
public boolean updateInfo() {
boolean visible = false;
int locimminent = -1;
int[] loclanes = null;
if (routingHelper != null && routingHelper.isRouteCalculated()) {
if (routingHelper.isFollowingMode()) {
NextDirectionInfo r = routingHelper.getNextRouteDirectionInfo(new NextDirectionInfo(), false);
if(r != null && r.directionInfo != null && r.directionInfo.getTurnType() != null) {
loclanes = r.directionInfo.getTurnType().getLanes();
locimminent = r.imminent;
// Do not show too far
if ((r.distanceTo > 700 && r.directionInfo.getTurnType().isSkipToSpeak()) || r.distanceTo > 1200) {
loclanes = null;
}
}
} else {
RouteInfoLayer ls = view.getLayerByClass(RouteInfoLayer.class);
if (ls != null) {
int di = ls.getDirectionInfo();
if (di >= 0 && ls.isVisible()) {
RouteDirectionInfo next = routingHelper.getRouteDirections().get(di);
if (next != null) {
loclanes = next.getTurnType().getLanes();
}
}
}
}
}
visible = loclanes != null && loclanes.length > 0;
if (visible) {
if (!Arrays.equals(lanes, loclanes)) {
lanes = loclanes;
requestLayout();
invalidate();
}
if ((locimminent == 0) != imminent) {
imminent = (locimminent == 0);
invalidate();
}
}
updateVisibility(visible);
return true;
}
};
return lanesControl;
}
protected MapInfoControl createAlarmInfoControl(final RoutingHelper routingHelper, Context ctx,
final OsmandSettings settings) {
final Paint paintCircle = new Paint();
final float th = 11 * scaleCoefficient;
paintCircle.setColor(Color.rgb(225, 15, 15));
paintCircle.setStrokeWidth(11 * scaleCoefficient);
paintCircle.setStyle(Style.STROKE);
paintCircle.setAntiAlias(true);
final Paint content = new Paint();
content.setColor(Color.WHITE);
content.setStyle(Style.FILL);
final Paint ptext = new Paint();
ptext.setTextSize(27 * scaleCoefficient);
ptext.setFakeBoldText(true);
ptext.setAntiAlias(true);
ptext.setTextAlign(Align.CENTER);
final MapInfoControl alarm = new MapInfoControl(ctx) {
private String text = "";
@Override
public boolean updateInfo() {
boolean limits = settings.SHOW_SPEED_LIMITS.get();
boolean cams = settings.SHOW_CAMERAS.get();
boolean visible = false;
if ((limits || cams) && routingHelper != null && routingHelper.isFollowingMode()) {
AlarmInfo alarm = routingHelper.getMostImportantAlarm(settings.METRIC_SYSTEM.get());
if(alarm != null) {
if(alarm.getType() == AlarmInfo.SPEED_LIMIT) {
text = alarm.getIntValue() +"";
} else if(alarm.getType() == AlarmInfo.SPEED_CAMERA) {
text = "CAM";
} else if(alarm.getType() == AlarmInfo.BORDER_CONTROL) {
text = "CLO";
} else if(alarm.getType() == AlarmInfo.TOLL_BOOTH) {
text = "$";
} else if(alarm.getType() == AlarmInfo.TRAFFIC_CALMING) {
// temporary omega
text = "~^~";
} else if(alarm.getType() == AlarmInfo.STOP) {
// text = "STOP";
}
visible = text.length() > 0;
if (visible) {
if (alarm.getType() == AlarmInfo.SPEED_CAMERA) {
visible = cams;
} else {
visible = limits;
}
}
}
}
updateVisibility(visible);
return true;
}
@Override
protected void onDraw(Canvas canvas) {
RectF f = new RectF(th / 2, th / 2, getWidth() - th / 2, getHeight() - th / 2);
canvas.drawOval(f, content);
canvas.drawOval(f, paintCircle);
canvas.drawText(text, getWidth() / 2, getHeight() / 2 + ptext.descent() + 3 * scaleCoefficient, ptext);
}
};
// initial state
// nextTurnInfo.setVisibility(View.GONE);
return alarm;
}
public boolean distChanged(int oldDist, int dist){
if(oldDist != 0 && oldDist - dist < 100 && Math.abs(((float) dist - oldDist)/oldDist) < 0.01){
return false;
}
return true;
}
}