implement showing compass

git-svn-id: https://osmand.googlecode.com/svn/trunk@90 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8
This commit is contained in:
Victor Shcherb 2010-05-27 21:06:46 +00:00
parent 5e30a13588
commit 8555ac76ee
11 changed files with 177 additions and 47 deletions

View file

@ -13,27 +13,28 @@ public class ToDoConstants {
public int DESCRIBE_ABOUT_AUTHORS = 8;
// TODO ANDROID
// 1. POI search near to map location (show categories & type). First cut. (implement incremental search)
// 3. Revise osmand UI. Preparing new icons.
// 2. Showing compass on the map : use device compass if exists(?)
// 5. Search for city/streets/buildings
// 9. Configure file log & see log from file (when exception happened to see from device)
// 11. Print out additional info speed, altitude, number of satellites
// 8. Enable change POI directly on map (requires OSM login)
// 25. POI search near to map location (show categories & type). Second cut. (implement incremental search)
// 3. Revise osmand UI. Preparing new icons (revise UI 18, 2, ).
// 13. Save point as favorite & introduce favorite points dialog
// 14. Show zoom level on map
// 24. Implement ResourceManager, load cities/streets/buildings on Low memory (clear previous all addresses cities).
// 5. Search for city/streets/buildings
// 9. Configure file log & see log from file (when exception happened to see from device)
// 15. Investigate interruption of any long running operation & implement where it is needed
// 16. Support open street bugs api.
// 17. Enable go to location by specifying coordinates
// 18. Implement go to point
// 19. Show how map is rotated where north/south on map (do not consider compass)
// 20. Implement save track/route to gpx (?)
// 21. Implement zooming tile (if tile doesn't exist local, we can zoom in previous tile).
// 23. Implement moving point from center to bottom (for rotating map).
// It is not very useful to see what was before.
// 24. Implement ResourceManager on Low memory (clear previous all addresses cities, remove all amenities cache)
// Use async loading tile thread, to preload amenities also.
// 17. Enable go to location by specifying coordinates
// 11. Print out additional info speed, altitude, number of satellites
// 19. Show how map is rotated where north/south on map (do not consider compass)
// 23. Implement moving point from center to bottom (for rotating map). (+)
// 21. Implement zooming tile (if tile doesn't exist local, we can zoom in previous tile).
// 8. Enable change POI directly on map (requires OSM login)
// 16. Support open street bugs api.
// 20. Implement save track/route to gpx (?)
// FIXME Bugs Android :
// 0. FIX TODO for partial loading rotated map
@ -41,6 +42,11 @@ public class ToDoConstants {
// No chance to close application
// 3. Fix progress information (loading indices) for android version
// 4. Fix when POI selected & enable button backToLocation
// 5. Call ResourceManager.close when it is needed
// 6. Understand concept of application where to save/restore global setting
// (for example reset navigate to point, reset link map with location). It should be reset after user call exit.
// 7. Implement search amenities by type (!).
// Rewrite search activity in order to limit amenities not to all types.
// TODO SWING:
// 1. Download tiles without using dir tiles
@ -49,16 +55,9 @@ public class ToDoConstants {
// DONE ANDROID :
// 12. Show information of where are you going (the arrow on the map)
// 10. Specify auto-rotating map (bearing of your direction)
// 22. Investigate 3D tile view (how it is done in osmand). Looking not very good, because of
// angle of perspective (best perspective angle = 60) use
// android.graphics.Camera.rotateX(60), getMatrix(m), canvas.concat(m) (find example in internet)
// Problems : to calculate how to drag point on map, to calculate how many tiles are needed, is location visible ....
// 0. Minimize memory used for index & improve time for reading index
// 18. Implement go to point
// 2. Showing compass on the map : use device compass if exists(?)
// DONE SWING
// 3. Reinvent index mechanism (save in zip file with tile indexes, save city/town addresses separately, read partially !)
// 4. Invent different file extensions for poi.index, address.index,...
}

View file

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="show_view_angle_descr">Show aspect of vew based on compass</string>
<string name="show_view_angle">Show aspect of view</string>
<string name="stop_navigation">Unmark location</string>
<string name="navigate_to_point">Mark location</string>
<string name="map_view_3d_descr">Enable 3D view of the map</string>

View file

@ -6,6 +6,7 @@
<CheckBoxPreference android:key="use_internet_to_download_tiles" android:title="@string/use_internet" android:summary="@string/use_internet_to_download_tile"></CheckBoxPreference>
<CheckBoxPreference android:key="show_poi_over_map" android:title="@string/show_poi_over_map" android:summary="@string/show_poi_over_map_description"></CheckBoxPreference>
<CheckBoxPreference android:key="rotate_map_to_bearing" android:title="@string/rotate_map_to_bearing" android:summary="@string/rotate_map_to_bearing_descr"></CheckBoxPreference>
<CheckBoxPreference android:key="show_view_angle" android:title="@string/show_view_angle" android:summary="@string/show_view_angle_descr"></CheckBoxPreference>
</PreferenceCategory>
<PreferenceCategory android:title="@string/map_source"><ListPreference android:title="@string/map_tile_source" android:summary="@string/map_tile_source_descr" android:key="map_tile_sources"></ListPreference>
</PreferenceCategory>

View file

@ -58,7 +58,7 @@ public class AmenityIndexRepository {
}
} while(query.moveToNext());
}
query.deactivate();
query.close();
if (log.isDebugEnabled()) {
log.debug(String.format("Search for %s done in %s ms found %s.",
@ -128,6 +128,12 @@ public class AmenityIndexRepository {
}
public void close(){
if(db != null){
db.close();
}
}
public String getName() {
return name;
}

View file

@ -30,6 +30,13 @@ public class OsmandSettings {
return prefs.getBoolean(SHOW_POI_OVER_MAP, false);
}
// this value string is synchronized with android.xml preference name
public static final String SHOW_VIEW_ANGLE = "show_view_angle";
public static boolean isShowingViewAngle(Context ctx){
SharedPreferences prefs = ctx.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_WORLD_READABLE);
return prefs.getBoolean(SHOW_VIEW_ANGLE, true);
}
// this value string is synchronized with android.xml preference name
public static final String ROTATE_MAP_TO_BEARING = "rotate_map_to_bearing";
public static boolean isRotateMapToBearing(Context ctx){

View file

@ -148,7 +148,7 @@ public class ResourceManager {
// POI INDEX //
public void indexingPoi(final IProgress progress) {
File file = new File(Environment.getExternalStorageDirectory(), POI_PATH);
amenityRepositories.clear();
clearAmenities();
if (file.exists() && file.canRead()) {
for (File f : file.listFiles()) {
if (f.getName().endsWith(IndexConstants.POI_INDEX_EXT)) {
@ -164,7 +164,7 @@ public class ResourceManager {
public void indexingAddresses(final IProgress progress){
File file = new File(Environment.getExternalStorageDirectory(), ADDRESS_PATH);
addressMap.clear();
clearAddresses();
if (file.exists() && file.canRead()) {
for (File f : file.listFiles()) {
if (f.getName().endsWith(IndexConstants.ADDRESS_INDEX_EXT)) {
@ -207,7 +207,24 @@ public class ResourceManager {
}
////////////////////////////////////////////// Working with amenities ////////////////////////////////////////////////
public void clearAmenities(){
for(AmenityIndexRepository r : amenityRepositories){
r.close();
}
amenityRepositories.clear();
}
public void clearAddresses(){
// TODO close db connections
addressMap.clear();
}
public synchronized void close(){
clearAmenities();
clearAddresses();
}
/// On low memory method ///
public void onLowMemory() {
log.info("On low memory : cleaning tiles - size = " + cacheOfImages.size());

View file

@ -5,6 +5,10 @@ import java.text.MessageFormat;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
@ -33,13 +37,12 @@ import com.osmand.views.POIMapLayer;
import com.osmand.views.PointLocationLayer;
import com.osmand.views.PointNavigationLayer;
public class MapActivity extends Activity implements LocationListener, IMapLocationListener {
public class MapActivity extends Activity implements LocationListener, IMapLocationListener, SensorEventListener {
/** Called when the activity is first created. */
private OsmandMapTileView mapView;
private boolean linkLocationWithMap = true;
private ImageButton backToLocation;
private ImageButton backToMenu;
@ -48,7 +51,16 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
private POIMapLayer poiMapLayer;
private WakeLock wakeLock;
private boolean sensorRegistered = false;
private final static String BACK_TO_LOCATION = "BACK_TO_LOCATION";
private final static String POINT_NAVIGATE_LAT = "POINT_NAVIGATE_LAT";
private final static String POINT_NAVIGATE_LON = "POINT_NAVIGATE_LON";
private boolean getBackToLocation(){
return getPreferences(MODE_WORLD_READABLE).getBoolean(BACK_TO_LOCATION, true);
}
@Override
public void onCreate(Bundle savedInstanceState) {
@ -58,7 +70,6 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
// getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
// WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
mapView = (OsmandMapTileView) findViewById(R.id.MapView);
MapTileDownloader.getInstance().addDownloaderCallback(mapView);
@ -69,6 +80,11 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
mapView.addLayer(navigationLayer);
locationLayer = new PointLocationLayer();
mapView.addLayer(locationLayer);
SharedPreferences lprefs = getPreferences(MODE_WORLD_READABLE);
if(lprefs.contains(POINT_NAVIGATE_LAT)){
navigationLayer.setPointToNavigate(new LatLon(lprefs.getFloat(POINT_NAVIGATE_LAT, 0),
lprefs.getFloat(POINT_NAVIGATE_LON, 0)));
}
SharedPreferences prefs = getSharedPreferences(OsmandSettings.SHARED_PREFERENCES_NAME, MODE_WORLD_READABLE);
if(prefs != null && prefs.contains(OsmandSettings.LAST_KNOWN_MAP_LAT)){
@ -99,14 +115,13 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
mapView.setZoom(mapView.getZoom() - 1);
}
});
backToLocation = (ImageButton)findViewById(R.id.BackToLocation);
backToLocation.setVisibility(linkLocationWithMap ? View.INVISIBLE : View.VISIBLE);
backToLocation.setVisibility(View.INVISIBLE);
backToLocation.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
if(!linkLocationWithMap){
linkLocationWithMap = true;
if(!getBackToLocation()){
getPreferences(MODE_WORLD_READABLE).edit().putBoolean(BACK_TO_LOCATION, true).commit();
backToLocation.setVisibility(View.INVISIBLE);
if(locationLayer.getLastKnownLocation() != null){
Location lastKnownLocation = locationLayer.getLastKnownLocation();
@ -132,14 +147,41 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
@Override
protected void onDestroy() {
super.onDestroy();
SharedPreferences lprefs = getPreferences(MODE_WORLD_READABLE);
if(navigationLayer.getPointToNavigate() == null){
lprefs.edit().remove(POINT_NAVIGATE_LAT).remove(POINT_NAVIGATE_LON).commit();
} else {
LatLon p = navigationLayer.getPointToNavigate();
lprefs.edit().putFloat(POINT_NAVIGATE_LAT, (float) p.getLatitude()).
putFloat(POINT_NAVIGATE_LON, (float) p.getLongitude()).commit();
}
MapTileDownloader.getInstance().removeDownloaderCallback(mapView);
}
public void setLocation(Location location){
// Do very strange manipulation to call redraw only once
// show point view only if gps enabled
if(location == null){
if(sensorRegistered) {
((SensorManager) getSystemService(SENSOR_SERVICE)).unregisterListener(this);
sensorRegistered = false;
locationLayer.setHeading(null, true);
}
} else {
if(!sensorRegistered && OsmandSettings.isShowingViewAngle(this)){
SensorManager sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
Sensor s = sensorMgr.getDefaultSensor(Sensor.TYPE_ORIENTATION);
if (s != null) {
sensorMgr.registerListener(this, s, SensorManager.SENSOR_DELAY_UI);
}
sensorRegistered = true;
}
}
locationLayer.setLastKnownLocation(location, true);
if (location != null) {
if (linkLocationWithMap) {
if (getBackToLocation()) {
if (location.hasBearing() && OsmandSettings.isRotateMapToBearing(this)) {
mapView.setRotateWithLocation(-location.getBearing(), location.getLatitude(), location.getLongitude());
} else {
@ -149,7 +191,7 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
mapView.prepareImage();
}
} else {
if (!linkLocationWithMap) {
if (!getBackToLocation()) {
backToLocation.setVisibility(View.VISIBLE);
}
}
@ -195,6 +237,11 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
super.onPause();
LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE);
service.removeUpdates(this);
SensorManager sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
sensorMgr.unregisterListener(this);
sensorRegistered = false;
OsmandSettings.setLastKnownMapLocation(this, (float) mapView.getLatitude(), (float) mapView.getLongitude());
OsmandSettings.setLastKnownMapZoom(this, mapView.getZoom());
if (wakeLock != null) {
@ -212,6 +259,7 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
if(!OsmandSettings.isRotateMapToBearing(this)){
mapView.setRotate(0);
}
if(mapView.getLayers().contains(poiMapLayer) != OsmandSettings.isShowingPoiOverMap(this)){
if(OsmandSettings.isShowingPoiOverMap(this)){
mapView.addLayer(poiMapLayer);
@ -222,6 +270,7 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE);
service.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, 0, this);
if (wakeLock == null) {
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "com.osmand.map");
@ -242,7 +291,7 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
public void locationChanged(double newLatitude, double newLongitude, Object source) {
// when user start dragging
if(locationLayer.getLastKnownLocation() != null){
linkLocationWithMap = false;
getPreferences(MODE_WORLD_READABLE).edit().putBoolean(BACK_TO_LOCATION, false).commit();
if (backToLocation.getVisibility() != View.VISIBLE) {
runOnUiThread(new Runnable() {
@Override
@ -284,5 +333,14 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
}
return super.onOptionsItemSelected(item);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
@Override
public void onSensorChanged(SensorEvent event) {
locationLayer.setHeading(event.values[0], false);
}
}

View file

@ -70,7 +70,7 @@ public class SearchActivity extends ListActivity {
filter = new TreeMap<AmenityType, List<Amenity>>();
LatLon lastKnownMapLocation = OsmandSettings.getLastKnownMapLocation(this);
List<Amenity> closestAmenities = resourceManager.searchAmenities(lastKnownMapLocation.getLatitude(),
lastKnownMapLocation.getLongitude(), 13, 500);
lastKnownMapLocation.getLongitude(), 12, 500);
MapUtils.sortListOfMapObject(closestAmenities, lastKnownMapLocation.getLatitude(), lastKnownMapLocation.getLongitude());
for (Amenity n : closestAmenities) {
AmenityType type = n.getType();

View file

@ -24,6 +24,7 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
private CheckBoxPreference useInternetToDownloadTiles;
private ListPreference tileSourcePreference;
private CheckBoxPreference rotateMapToBearing;
private CheckBoxPreference showViewAngle;
@Override
public void onCreate(Bundle savedInstanceState) {
@ -36,6 +37,8 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
showPoiOnMap.setOnPreferenceChangeListener(this);
rotateMapToBearing =(CheckBoxPreference) screen.findPreference(OsmandSettings.ROTATE_MAP_TO_BEARING);
rotateMapToBearing.setOnPreferenceChangeListener(this);
showViewAngle =(CheckBoxPreference) screen.findPreference(OsmandSettings.SHOW_VIEW_ANGLE);
showViewAngle.setOnPreferenceChangeListener(this);
tileSourcePreference =(ListPreference) screen.findPreference(OsmandSettings.MAP_TILE_SOURCES);
tileSourcePreference.setOnPreferenceChangeListener(this);
@ -49,6 +52,7 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
useInternetToDownloadTiles.setChecked(OsmandSettings.isUsingInternetToDownloadTiles(this));
showPoiOnMap.setChecked(OsmandSettings.isShowingPoiOverMap(this));
rotateMapToBearing.setChecked(OsmandSettings.isRotateMapToBearing(this));
showViewAngle.setChecked(OsmandSettings.isShowingViewAngle(this));
List<TileSourceTemplate> list = TileSourceManager.getKnownSourceTemplates();
String[] entries = new String[list.size()];
@ -77,6 +81,9 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
} else if(preference == rotateMapToBearing){
edit.putBoolean(OsmandSettings.ROTATE_MAP_TO_BEARING, (Boolean) newValue);
edit.commit();
} else if(preference == showViewAngle){
edit.putBoolean(OsmandSettings.SHOW_VIEW_ANGLE, (Boolean) newValue);
edit.commit();
} else if (preference == tileSourcePreference) {
edit.putString(OsmandSettings.MAP_TILE_SOURCES, (String) newValue);
edit.commit();

View file

@ -5,6 +5,7 @@ import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Paint.Style;
import android.location.Location;
import android.view.MotionEvent;
@ -12,14 +13,22 @@ import android.view.MotionEvent;
import com.osmand.osm.MapUtils;
public class PointLocationLayer implements OsmandMapLayer {
protected final static int RADIUS = 7;
protected final static int HEADING_RADIUS = 60;
protected final static float HEADING_ANGLE = 60;
private Paint location;
private Paint bearing;
private Paint area;
private Paint headingPaint;
private Path pathForDirection;
protected Location lastKnownLocation = null;
protected final static int RADIUS = 7;
private OsmandMapTileView view;
private Path pathForDirection;
private Float heading = null;
private void initUI() {
location = new Paint();
@ -31,6 +40,12 @@ public class PointLocationLayer implements OsmandMapLayer {
area.setColor(Color.BLUE);
area.setAlpha(40);
headingPaint = new Paint();
headingPaint.setColor(Color.BLUE);
headingPaint.setAlpha(50);
headingPaint.setAntiAlias(true);
headingPaint.setStyle(Style.FILL);
bearing = new Paint();
bearing.setColor(Color.BLUE);
bearing.setAlpha(150);
@ -51,6 +66,10 @@ public class PointLocationLayer implements OsmandMapLayer {
return false;
}
private RectF getHeadingRect(int locationX, int locationY){
int rad = Math.min(3*view.getWidth()/8, 3*view.getHeight()/8);
return new RectF(locationX - rad, locationY - rad, locationX + rad, locationY + rad);
}
// TODO simplify calculation if possible
@Override
@ -67,6 +86,11 @@ public class PointLocationLayer implements OsmandMapLayer {
if (radius > RADIUS) {
canvas.drawCircle(locationX, locationY, radius, area);
}
if(heading != null){
canvas.drawArc(getHeadingRect(locationX, locationY),
heading - HEADING_ANGLE/ 2 - 90, HEADING_ANGLE, true, headingPaint);
}
if(lastKnownLocation.hasBearing()){
float bearing = lastKnownLocation.getBearing();
int radiusBearing = 30;
@ -84,7 +108,7 @@ public class PointLocationLayer implements OsmandMapLayer {
pathForDirection.lineTo(0, 0);
Matrix m = new Matrix();
m.reset();
m.postScale(1, radiusBearing*0.5f);
m.postScale(1, radiusBearing * 0.5f);
m.postTranslate(0, -radiusBearing);
m.postTranslate(locationX, locationY);
m.postRotate(bearing, locationX, locationY);
@ -93,8 +117,6 @@ public class PointLocationLayer implements OsmandMapLayer {
canvas.drawPath(pathForDirection, this.bearing);
}
}
}
@ -110,6 +132,17 @@ public class PointLocationLayer implements OsmandMapLayer {
return lastKnownLocation;
}
public void setHeading(Float heading, boolean doNotRedraw){
this.heading = heading;
if(!doNotRedraw && isLocationVisible(this.lastKnownLocation)){
view.prepareImage();
}
}
public Float getHeading() {
return heading;
}
public void setLastKnownLocation(Location lastKnownLocation, boolean doNotRedraw) {
this.lastKnownLocation = lastKnownLocation;
if (!doNotRedraw) {

View file

@ -64,8 +64,8 @@ public class PointNavigationLayer implements OsmandMapLayer {
float bearing = calculations[1];
pathForDirection.reset();
pathForDirection.moveTo(0, 0);
pathForDirection.lineTo(0.5f, 1f);
pathForDirection.lineTo(-0.5f, 1f);
pathForDirection.lineTo(0.5f, 1.5f);
pathForDirection.lineTo(-0.5f, 1.5f);
pathForDirection.lineTo(0, 0);
float radiusBearing = DIST_TO_SHOW ;
Matrix m = new Matrix();