1. fix performance issues

2. change touch layer map strategy


git-svn-id: https://osmand.googlecode.com/svn/trunk@101 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8
This commit is contained in:
Victor Shcherb 2010-05-30 16:54:46 +00:00
parent 88a8da98b1
commit b726918d38
12 changed files with 194 additions and 79 deletions

View file

@ -20,8 +20,6 @@ public class ToDoConstants {
// 24. Implement ResourceManager, load cities/streets/buildings on Low memory (clear previous all addresses cities).
// 5. Search for city/streets/buildings
// 15. Investigate interruption of any long running operation & implement where it is needed.
// Fix progress information (loading indices).
// 8. Enable change POI directly on map (requires OSM login)
// 16. Support open street bugs api.
@ -37,14 +35,19 @@ public class ToDoConstants {
// 9. When all features will be ready we can remove show location from context menu
// TODO SWING:
// 1. Download tiles without using dir tiles
// 2. Configure file log & see log from file (add uncaught exception handling)
// 5. Implement suppress warning for duplicate id
// 6. Implement renaming/deleting street/building/city
// 8. Implement basic transliteration version
// 7. Implement saving bundle of tiles in different folder
// 1. Download tiles without using dir tiles
// DONE ANDROID :
// 15. Investigate interruption of any long running operation & implement where it is needed.
// ProgressDialogImplementation should support setOnCancelListener or obtain CANCEL message &
// throw InterruptedException in all methods (remaining, progress, startTask, ...) when call it.
// Otherwise thread could be stopped however it is not good method.
// 21. Implement zooming tile (if tile doesn't exist local, we can zoom in previous tile).
// 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)

View file

@ -80,13 +80,20 @@ public class AmenityIndexRepository {
cLeftLongitude = 0;
}
public synchronized void evaluateCachedAmenities(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, List<Amenity> toFill){
public void evaluateCachedAmenities(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, List<Amenity> toFill){
cachedAmenities.clear();
cTopLatitude = topLatitude + (topLatitude -bottomLatitude);
cBottomLatitude = bottomLatitude - (topLatitude -bottomLatitude);
cLeftLongitude = leftLongitude - (rightLongitude - leftLongitude);
cRightLongitude = rightLongitude + (rightLongitude - leftLongitude);
searchAmenities(cTopLatitude, cLeftLongitude, cBottomLatitude, cRightLongitude, -1, null, cachedAmenities);
// first of all put all entities in temp list in order to not freeze other read threads
ArrayList<Amenity> tempList = new ArrayList<Amenity>();
searchAmenities(cTopLatitude, cLeftLongitude, cBottomLatitude, cRightLongitude, -1, null, tempList);
synchronized (this) {
cachedAmenities.clear();
cachedAmenities.addAll(tempList);
}
checkCachedAmenities(topLatitude, leftLongitude, bottomLatitude, rightLongitude, toFill);
}

View file

@ -14,6 +14,7 @@ public class ProgressDialogImplementation implements IProgress {
private String message = "";
private Handler mViewUpdateHandler;
private Thread run;
public ProgressDialogImplementation(final ProgressDialog dlg){
mViewUpdateHandler = new Handler(){
@ -25,6 +26,17 @@ public class ProgressDialogImplementation implements IProgress {
};
}
public void setRunnable(String threadName, Runnable run){
this.run = new Thread(run, threadName);
}
public void run(){
if(run == null){
throw new IllegalStateException();
}
run.start();
}
@Override
public void progress(int deltaWork) {
this.deltaWork += deltaWork;

View file

@ -93,12 +93,14 @@ public class ResourceManager {
return getTileImageForMap(map, x, y, zoom, loadFromInternetIfNeeded, true, true);
}
protected Bitmap getTileImageForMap(ITileSource map, int x, int y, int zoom,
// introduce cache in order save memory
protected StringBuilder builder = new StringBuilder(40);
protected synchronized Bitmap getTileImageForMap(ITileSource map, int x, int y, int zoom,
boolean loadFromInternetIfNeeded, boolean sync, boolean loadFromFs) {
if (map == null) {
return null;
}
StringBuilder builder = new StringBuilder(40);
builder.setLength(0);
builder.append(map.getName()).append('/').append(zoom). append('/').append(x).
append('/').append(y).append(map.getTileFormat()).append(".tile");
String file = builder.toString();

View file

@ -47,9 +47,9 @@ public class MainMenuActivity extends Activity {
public void startApplication(){
if(!applicationAlreadyStarted){
// TODO exception!!! has leaked window ?
final ProgressDialog dlg = ProgressDialog.show(this, "Loading data", "Reading indices...");
final ProgressDialog dlg = ProgressDialog.show(this, "Loading data", "Reading indices...", true);
final ProgressDialogImplementation impl = new ProgressDialogImplementation(dlg);
new Thread("Reader indexes") {
impl.setRunnable("Initializing app", new Runnable(){
@Override
public void run() {
try {
@ -59,7 +59,8 @@ public class MainMenuActivity extends Activity {
dlg.dismiss();
}
}
}.start();
});
impl.run();
applicationAlreadyStarted = true;
Thread.setDefaultUncaughtExceptionHandler(new DefaultExceptionHandler());

View file

@ -18,6 +18,7 @@ import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@ -28,6 +29,7 @@ import android.widget.ImageButton;
import android.widget.Toast;
import android.widget.ZoomControls;
import com.osmand.LogUtil;
import com.osmand.OsmandSettings;
import com.osmand.R;
import com.osmand.ResourceManager;
@ -125,9 +127,9 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
backToLocation.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
backToLocation.setVisibility(View.INVISIBLE);
if(!isMapLinkedToLocation()){
getPreferences(MODE_WORLD_READABLE).edit().putBoolean(BACK_TO_LOCATION, true).commit();
backToLocation.setVisibility(View.INVISIBLE);
if(locationLayer.getLastKnownLocation() != null){
Location lastKnownLocation = locationLayer.getLastKnownLocation();
mapView.setLatLon(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude());
@ -152,14 +154,6 @@ 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);
}
@ -169,12 +163,14 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
// show point view only if gps enabled
if(location == null){
if(sensorRegistered) {
Log.d(LogUtil.TAG, "Disable sensor");
((SensorManager) getSystemService(SENSOR_SERVICE)).unregisterListener(this);
sensorRegistered = false;
locationLayer.setHeading(null, true);
}
} else {
if(!sensorRegistered && OsmandSettings.isShowingViewAngle(this)){
Log.d(LogUtil.TAG, "Enable sensor");
SensorManager sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
Sensor s = sensorMgr.getDefaultSensor(Sensor.TYPE_ORIENTATION);
if (s != null) {
@ -183,7 +179,7 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
sensorRegistered = true;
}
}
Log.d(LogUtil.TAG, "Location changed");
locationLayer.setLastKnownLocation(location, true);
if (location != null) {
if (isMapLinkedToLocation()) {
@ -267,6 +263,9 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
if(!OsmandSettings.isRotateMapToBearing(this)){
mapView.setRotate(0);
}
if(!OsmandSettings.isShowingViewAngle(this)){
locationLayer.setHeading(null, true);
}
mapView.setMapPosition(OsmandSettings.getPositionOnMap(this));
SharedPreferences prefs = getSharedPreferences(OsmandSettings.SHARED_PREFERENCES_NAME, MODE_WORLD_READABLE);
if(prefs != null && prefs.contains(OsmandSettings.LAST_KNOWN_MAP_LAT)){
@ -274,7 +273,7 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
mapView.setLatLon(l.getLatitude(), l.getLongitude());
mapView.setZoom(OsmandSettings.getLastKnownMapZoom(this));
}
if(getLastKnownLocation() != null){
if(getLastKnownLocation() != null && !isMapLinkedToLocation()){
backToLocation.setVisibility(View.VISIBLE);
} else {
backToLocation.setVisibility(View.INVISIBLE);
@ -312,7 +311,9 @@ 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){
if(isMapLinkedToLocation()){
getPreferences(MODE_WORLD_READABLE).edit().putBoolean(BACK_TO_LOCATION, false).commit();
}
if (backToLocation.getVisibility() != View.VISIBLE) {
runOnUiThread(new Runnable() {
@Override
@ -328,6 +329,14 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.map_menu, menu);
MenuItem item = menu.findItem(R.id.map_navigate_to_point);
if (item != null) {
if (getPreferences(MODE_WORLD_READABLE).contains(POINT_NAVIGATE_LAT)) {
item.setTitle(R.string.stop_navigation);
} else {
item.setTitle(R.string.navigate_to_point);
}
}
return true;
}
@ -348,9 +357,13 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
return true;
} else if (item.getItemId() == R.id.map_navigate_to_point) {
if(navigationLayer.getPointToNavigate() != null){
getPreferences(MODE_WORLD_READABLE).edit().remove(POINT_NAVIGATE_LAT).remove(POINT_NAVIGATE_LON).commit();
item.setTitle(R.string.navigate_to_point);
navigateToPoint(null);
} else {
getPreferences(MODE_WORLD_READABLE).edit().
putFloat(POINT_NAVIGATE_LAT, (float) mapView.getLatitude()).
putFloat(POINT_NAVIGATE_LON, (float) mapView.getLongitude()).commit();
item.setTitle(R.string.stop_navigation);
navigateToPoint(new LatLon(mapView.getLatitude(), mapView.getLongitude()));
}
@ -371,7 +384,7 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat
public void onSensorChanged(SensorEvent event) {
// using that strange technique because sensor produces a lot of events & hangs the system
locationLayer.setHeading(event.values[0], true);
if(!sensorHandler.hasMessages(1)){
if(!sensorHandler.hasMessages(1) && locationLayer.isLocationVisible(locationLayer.getLastKnownLocation())){
Message m = Message.obtain(sensorHandler, new Runnable(){
@Override
public void run() {

View file

@ -4,10 +4,10 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.Paint.Style;
import android.location.Location;
import android.view.MotionEvent;
import com.osmand.activities.MapActivity;
import com.osmand.osm.MapUtils;
@ -130,10 +130,6 @@ public class MapInfoLayer implements OsmandMapLayer {
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return false;
}
@Override
public void destroyLayer() {
@ -144,5 +140,15 @@ public class MapInfoLayer implements OsmandMapLayer {
return true;
}
@Override
public boolean onLongPressEvent(PointF point) {
return false;
}
@Override
public boolean onTouchEvent(PointF point) {
return false;
}
}

View file

@ -1,7 +1,7 @@
package com.osmand.views;
import android.graphics.Canvas;
import android.view.MotionEvent;
import android.graphics.PointF;
public interface OsmandMapLayer {
@ -12,7 +12,9 @@ public interface OsmandMapLayer {
public void destroyLayer();
public boolean onTouchEvent(MotionEvent event);
public boolean onTouchEvent(PointF point);
public boolean onLongPressEvent(PointF point);
public boolean drawInScreenPixels();

View file

@ -20,7 +20,10 @@ import android.util.FloatMath;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.SurfaceHolder.Callback;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import com.osmand.LogUtil;
import com.osmand.OsmandSettings;
@ -33,7 +36,8 @@ import com.osmand.map.ITileSource;
import com.osmand.osm.MapUtils;
import com.osmand.views.AnimateDraggingMapThread.AnimateDraggingCallback;
public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCallback, Callback, AnimateDraggingCallback{
public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCallback,
Callback, AnimateDraggingCallback, OnLongClickListener, OnClickListener{
protected final int emptyTileDivisor = 16;
protected final int timeForDraggingAnimation = 300;
@ -67,6 +71,7 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
private PointF startDragging = null;
private PointF autoStartDragging = null;
private long autoStartDraggingTime = 0;
private boolean wasMapDraggedOnTouch = false;
Paint paintGrayFill;
Paint paintWhiteFill;
@ -109,6 +114,10 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
paintBitmap.setFilterBitmap(true);
setClickable(true);
setLongClickable(true);
setOnLongClickListener(this);
setOnClickListener(this);
getHolder().addCallback(this);
animatedDraggingThread = new AnimateDraggingMapThread();
@ -520,24 +529,27 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
return false;
}
public boolean isDifferenceSmallToDrag(PointF point, MotionEvent event){
return Math.abs(point.x - event.getX()) + Math.abs(point.y - event.getY()) <= 10;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
for (int i = layers.size() - 1; i >= 0; i--) {
if (layers.get(i).onTouchEvent(event)) {
return true;
}
}
if(event.getAction() == MotionEvent.ACTION_DOWN) {
animatedDraggingThread.stopDragging();
// possibly solution to always reset start dragging ? (in order someone forget to do it)
if(startDragging == null){
autoStartDragging = new PointF(event.getX(), event.getY());
autoStartDraggingTime = event.getEventTime();
startDragging = new PointF(event.getX(), event.getY());
wasMapDraggedOnTouch = false;
}
// registering long press action
return super.onTouchEvent(event);
} else if(event.getAction() == MotionEvent.ACTION_UP) {
if(startDragging != null){
if (wasMapDraggedOnTouch || !isDifferenceSmallToDrag(startDragging, event)) {
dragTo(startDragging.x, startDragging.y, event.getX(), event.getY());
startDragging = null;
if (wasMapDraggingAccelerated(event)) {
@ -545,13 +557,22 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
if (timeDist < 20) {
timeDist = 20;
}
animatedDraggingThread.startDragging(timeDist, autoStartDragging.x, autoStartDragging.y,
event.getX(), event.getY());
animatedDraggingThread.startDragging(timeDist, autoStartDragging.x, autoStartDragging.y, event.getX(), event.getY());
}
} else {
// Do not forget to reset startDragging = null in performClick()
// give chance to run performClick() or performLongClick()
return super.onTouchEvent(event);
}
}
} else if(event.getAction() == MotionEvent.ACTION_MOVE) {
if(startDragging != null){
if(startDragging != null && !isDifferenceSmallToDrag(startDragging, event)){
// try to not drag map if that first time & diff small
if (wasMapDraggedOnTouch || !isDifferenceSmallToDrag(startDragging, event)) {
if(!wasMapDraggedOnTouch){
cancelLongPress();
wasMapDraggedOnTouch = true;
}
dragTo(startDragging.x, startDragging.y, event.getX(), event.getY());
// save memory do not create new PointF
startDragging.x = event.getX();
@ -563,7 +584,36 @@ public class OsmandMapTileView extends SurfaceView implements IMapDownloaderCall
}
}
}
return super.onTouchEvent(event);
}
return true;
}
@Override
public boolean onLongClick(View v) {
PointF point = startDragging;
if (point != null) {
startDragging = null;
for (int i = layers.size() - 1; i >= 0; i--) {
if (layers.get(i).onLongPressEvent(point)) {
return true;
}
}
}
return false;
}
@Override
public void onClick(View v) {
PointF point = startDragging;
if (point != null) {
startDragging = null;
for (int i = layers.size() - 1; i >= 0; i--) {
if (layers.get(i).onTouchEvent(point)) {
return;
}
}
}
}

View file

@ -6,9 +6,9 @@ import java.util.List;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.view.MotionEvent;
import android.widget.Toast;
import com.osmand.ResourceManager;
@ -16,7 +16,8 @@ import com.osmand.data.Amenity;
import com.osmand.osm.MapUtils;
public class POIMapLayer implements OsmandMapLayer {
private static final int radiusClick = 2; // for 15 level zoom
// it is very slow to use with 15 level
private static final int startZoom = 16;
private Paint pointAltUI;
private OsmandMapTileView view;
@ -24,13 +25,17 @@ public class POIMapLayer implements OsmandMapLayer {
private ResourceManager resourceManager;
@Override
public boolean onLongPressEvent(PointF point) {
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN && objects != null) {
int ex = (int) event.getX();
int ey = (int) event.getY();
public boolean onTouchEvent(PointF point) {
if (objects != null) {
int ex = (int) point.x;
int ey = (int) point.y;
int radius = getRadiusPoi(view.getZoom()) * 3 / 2;
try {
for (int i = 0; i < objects.size(); i++) {
@ -46,7 +51,6 @@ public class POIMapLayer implements OsmandMapLayer {
// that's really rare case, but is much efficient than introduce synchronized block
}
}
// return super.onTouchEvent(event);
return false;
}
@ -68,10 +72,14 @@ public class POIMapLayer implements OsmandMapLayer {
}
public int getRadiusPoi(int zoom){
if(zoom < 15){
if(zoom < startZoom){
return 0;
} else if(zoom == 16){
return 6;
} else if(zoom == 17){
return 10;
} else {
return radiusClick << (zoom - 15);
return 14;
}
}
@ -80,7 +88,7 @@ public class POIMapLayer implements OsmandMapLayer {
@Override
public void onDraw(Canvas canvas) {
if (view.getZoom() >= 15) {
if (view.getZoom() >= startZoom) {
pixRect.set(0, 0, view.getWidth(), view.getHeight());
view.calculateTileRectangle(pixRect, view.getCenterPointX(),
view.getCenterPointY(), view.getXTile(), view.getYTile(), tileRect);

View file

@ -5,10 +5,10 @@ import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.Paint.Style;
import android.location.Location;
import android.view.MotionEvent;
import com.osmand.osm.MapUtils;
@ -61,10 +61,6 @@ public class PointLocationLayer implements OsmandMapLayer {
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return false;
}
private RectF getHeadingRect(int locationX, int locationY){
int rad = Math.min(3*view.getWidth()/8, 3*view.getHeight()/8);
@ -160,6 +156,16 @@ public class PointLocationLayer implements OsmandMapLayer {
return false;
}
@Override
public boolean onLongPressEvent(PointF point) {
return false;
}
@Override
public boolean onTouchEvent(PointF point) {
return false;
}

View file

@ -5,9 +5,9 @@ import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Paint.Style;
import android.location.Location;
import android.view.MotionEvent;
import com.osmand.osm.LatLon;
@ -39,11 +39,6 @@ public class PointNavigationLayer implements OsmandMapLayer {
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return false;
}
@Override
public void onDraw(Canvas canvas) {
@ -103,4 +98,14 @@ public class PointNavigationLayer implements OsmandMapLayer {
return false;
}
@Override
public boolean onLongPressEvent(PointF point) {
return false;
}
@Override
public boolean onTouchEvent(PointF point) {
return false;
}
}