From db007efb75be810a5083e446d972926c2c3d4072 Mon Sep 17 00:00:00 2001 From: Fabien Carrion Date: Thu, 24 Nov 2011 16:43:26 -0600 Subject: [PATCH] Add list, delete and upload POI to Openstreetmap Offline POI edition activity --- .../layout/local_openstreetmap_list_item.xml | 7 + ...local_openstreetmap_list_item_category.xml | 8 + OsmAnd/res/values/strings.xml | 6 +- .../net/osmand/OpenstreetmapLocalUtil.java | 6 +- OsmAnd/src/net/osmand/OpenstreetmapPoint.java | 18 +- .../net/osmand/OpenstreetmapRemoteUtil.java | 33 ++- .../osmand/plus/OpenstreetmapsDbHelper.java | 27 +- .../plus/activities/EditingPOIActivity.java | 2 +- .../LocalOpenstreetmapActivity.java | 258 +++++++++++++++++- 9 files changed, 351 insertions(+), 14 deletions(-) create mode 100644 OsmAnd/res/layout/local_openstreetmap_list_item.xml create mode 100644 OsmAnd/res/layout/local_openstreetmap_list_item_category.xml diff --git a/OsmAnd/res/layout/local_openstreetmap_list_item.xml b/OsmAnd/res/layout/local_openstreetmap_list_item.xml new file mode 100644 index 0000000000..e9f5fe5143 --- /dev/null +++ b/OsmAnd/res/layout/local_openstreetmap_list_item.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/OsmAnd/res/layout/local_openstreetmap_list_item_category.xml b/OsmAnd/res/layout/local_openstreetmap_list_item_category.xml new file mode 100644 index 0000000000..a96308db9b --- /dev/null +++ b/OsmAnd/res/layout/local_openstreetmap_list_item_category.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index d03e673757..291090a91a 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -1,6 +1,10 @@ - Asynchrone Openstreetmap POI Edition: + + Show POI on Map + Upload modification to OSM + Delete POI modification + Asynchrone Openstreetmap POI Edition: Local Openstreetmap Points Local Points Saved in DB diff --git a/OsmAnd/src/net/osmand/OpenstreetmapLocalUtil.java b/OsmAnd/src/net/osmand/OpenstreetmapLocalUtil.java index 8fd20688ae..5d1b3c21b2 100644 --- a/OsmAnd/src/net/osmand/OpenstreetmapLocalUtil.java +++ b/OsmAnd/src/net/osmand/OpenstreetmapLocalUtil.java @@ -15,21 +15,21 @@ import net.osmand.osm.Node; import net.osmand.osm.OSMSettings.OSMTagKey; import net.osmand.plus.R; import net.osmand.plus.OpenstreetmapsDbHelper; -import net.osmand.plus.activities.MapActivity; import org.apache.commons.logging.Log; +import android.content.Context; import android.util.Xml; import android.widget.Toast; public class OpenstreetmapLocalUtil implements OpenstreetmapUtil { - private final MapActivity ctx; + private final Context ctx; private final OpenstreetmapsDbHelper db; public final static Log log = LogUtil.getLog(OpenstreetmapLocalUtil.class); - public OpenstreetmapLocalUtil(MapActivity uiContext){ + public OpenstreetmapLocalUtil(Context uiContext){ this.ctx = uiContext; this.db = new OpenstreetmapsDbHelper(ctx); } diff --git a/OsmAnd/src/net/osmand/OpenstreetmapPoint.java b/OsmAnd/src/net/osmand/OpenstreetmapPoint.java index c06ae9a2f2..961cc90c43 100644 --- a/OsmAnd/src/net/osmand/OpenstreetmapPoint.java +++ b/OsmAnd/src/net/osmand/OpenstreetmapPoint.java @@ -22,7 +22,10 @@ public class OpenstreetmapPoint implements Serializable { } public String getName() { - return entity.getTag(OSMTagKey.NAME.getValue()); + String ret = entity.getTag(OSMTagKey.NAME.getValue()); + if (ret == null) + return ""; + return ret; } public String getType() { @@ -50,7 +53,10 @@ public class OpenstreetmapPoint implements Serializable { } public String getOpeninghours() { - return entity.getTag(OSMTagKey.OPENING_HOURS.getValue()); + String ret = entity.getTag(OSMTagKey.OPENING_HOURS.getValue()); + if (ret == null) + return ""; + return entity.getTag(ret); } public Node getEntity() { @@ -88,4 +94,12 @@ public class OpenstreetmapPoint implements Serializable { public void setStored(boolean stored) { this.stored = stored; } + + public String toString() { + return new StringBuffer("Openstreetmap Point ").append(this.getAction()).append(" ").append(this.getName()) + .append(" (").append(this.getId()).append("): [") + .append(this.getType()).append("/").append(this.getSubtype()) + .append(" (").append(this.getLatitude()).append(", ").append(this.getLongitude()) + .append(")]").toString(); + } } diff --git a/OsmAnd/src/net/osmand/OpenstreetmapRemoteUtil.java b/OsmAnd/src/net/osmand/OpenstreetmapRemoteUtil.java index 1fef744d5e..106f2ca962 100644 --- a/OsmAnd/src/net/osmand/OpenstreetmapRemoteUtil.java +++ b/OsmAnd/src/net/osmand/OpenstreetmapRemoteUtil.java @@ -47,7 +47,9 @@ import org.apache.http.params.HttpParams; import org.xml.sax.SAXException; import org.xmlpull.v1.XmlSerializer; +import android.content.Context; import android.util.Xml; +import android.view.View; import android.widget.Toast; public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil { @@ -69,7 +71,8 @@ public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil { private static final long NO_CHANGESET_ID = -1; - private final MapActivity ctx; + private final Context ctx; + private final View view; private EntityInfo entityInfo; // reuse changeset @@ -78,8 +81,9 @@ public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil { public final static Log log = LogUtil.getLog(OpenstreetmapRemoteUtil.class); - public OpenstreetmapRemoteUtil(MapActivity uiContext){ + public OpenstreetmapRemoteUtil(Context uiContext, View view){ this.ctx = uiContext; + this.view = view; } public EntityInfo getEntityInfo() { @@ -367,6 +371,29 @@ public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil { } } + public EntityInfo loadNode(Node n) { + long nodeId = n.getId() >> 1; + try { + String res = sendRequest(SITE_API + "api/0.6/node/"+nodeId, "GET", null, ctx.getString(R.string.loading_poi_obj) + nodeId, false); //$NON-NLS-1$ //$NON-NLS-2$ + if(res != null){ + OsmBaseStorage st = new OsmBaseStorage(); + st.parseOSM(new ByteArrayInputStream(res.getBytes("UTF-8")), null, null, true); //$NON-NLS-1$ + EntityId id = new Entity.EntityId(EntityType.NODE, nodeId); + Node entity = (Node) st.getRegisteredEntities().get(id); + entityInfo = st.getRegisteredEntityInfo().get(id); + return entityInfo; + } + + } catch (IOException e) { + log.error("Loading node failed " + nodeId, e); //$NON-NLS-1$ + Toast.makeText(ctx, ctx.getResources().getString(R.string.error_io_error), Toast.LENGTH_LONG).show(); + } catch (SAXException e) { + log.error("Loading node failed " + nodeId, e); //$NON-NLS-1$ + Toast.makeText(ctx, ctx.getResources().getString(R.string.error_io_error), Toast.LENGTH_LONG).show(); + } + return null; + } + public Node loadNode(Amenity n) { if(n.getId() % 2 == 1){ // that's way id @@ -399,7 +426,7 @@ public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil { } private void showWarning(final String msg){ - ctx.getMapView().post(new Runnable(){ + view.post(new Runnable(){ @Override public void run() { Toast.makeText(ctx, msg, Toast.LENGTH_LONG).show(); diff --git a/OsmAnd/src/net/osmand/plus/OpenstreetmapsDbHelper.java b/OsmAnd/src/net/osmand/plus/OpenstreetmapsDbHelper.java index 1085e0cb76..1f7f0645cb 100644 --- a/OsmAnd/src/net/osmand/plus/OpenstreetmapsDbHelper.java +++ b/OsmAnd/src/net/osmand/plus/OpenstreetmapsDbHelper.java @@ -70,6 +70,28 @@ public class OpenstreetmapsDbHelper extends SQLiteOpenHelper { return false; } + public boolean deleteOpenstreetmap(OpenstreetmapPoint p) { + checkOpenstreetmapPoints(); + SQLiteDatabase db = getWritableDatabase(); + if (db != null) { + db.execSQL("DELETE FROM " + OPENSTREETMAP_TABLE_NAME + + " WHERE " + OPENSTREETMAP_COL_ID + " = ? AND " + + OPENSTREETMAP_COL_NAME + " = ? AND " + + OPENSTREETMAP_COL_TYPE + " = ? AND " + + OPENSTREETMAP_COL_SUBTYPE + " = ? AND " + + OPENSTREETMAP_COL_LAT + " = ? AND " + + OPENSTREETMAP_COL_LON + " = ? AND " + + OPENSTREETMAP_COL_ACTION + " = ? AND " + + OPENSTREETMAP_COL_COMMENT + " = ? AND " + + OPENSTREETMAP_COL_OPENINGHOURS + " = ?", + new Object[] { p.getId(), p.getName(), p.getType(), p.getSubtype(), p.getLatitude(), p.getLongitude(), OpenstreetmapRemoteUtil.stringAction.get(p.getAction()), p.getComment(), p.getOpeninghours() }); //$NON-NLS-1$ //$NON-NLS-2$ + cachedOpenstreetmapPoints.remove(p); + p.setStored(false); + return true; + } + return false; + } + private void checkOpenstreetmapPoints(){ SQLiteDatabase db = getWritableDatabase(); if (db != null) { @@ -86,11 +108,14 @@ public class OpenstreetmapsDbHelper extends SQLiteOpenHelper { entity.putTag(query.getString(2), query.getString(3)); entity.putTag(OSMTagKey.NAME.getValue(), name); - entity.putTag(OSMTagKey.OPENING_HOURS.getValue(), query.getString(8)); + String openingHours = query.getString(8); + if (openingHours != null && openingHours.length() > 0) + entity.putTag(OSMTagKey.OPENING_HOURS.getValue(), openingHours); p.setEntity(entity); p.setStored(true); p.setAction(query.getString(6)); p.setComment(query.getString(7)); + cachedOpenstreetmapPoints.add(p); } while (query.moveToNext()); } query.close(); diff --git a/OsmAnd/src/net/osmand/plus/activities/EditingPOIActivity.java b/OsmAnd/src/net/osmand/plus/activities/EditingPOIActivity.java index d51ea6127a..ef9db21d99 100644 --- a/OsmAnd/src/net/osmand/plus/activities/EditingPOIActivity.java +++ b/OsmAnd/src/net/osmand/plus/activities/EditingPOIActivity.java @@ -75,7 +75,7 @@ public class EditingPOIActivity implements DialogProvider { if(!settings.isInternetConnectionAvailable(true)){ this.openstreetmapUtil = new OpenstreetmapLocalUtil(ctx); } else { - this.openstreetmapUtil = new OpenstreetmapRemoteUtil(ctx); + this.openstreetmapUtil = new OpenstreetmapRemoteUtil(ctx, ctx.getMapView()); } } diff --git a/OsmAnd/src/net/osmand/plus/activities/LocalOpenstreetmapActivity.java b/OsmAnd/src/net/osmand/plus/activities/LocalOpenstreetmapActivity.java index 903576d60e..d19f6b4cac 100644 --- a/OsmAnd/src/net/osmand/plus/activities/LocalOpenstreetmapActivity.java +++ b/OsmAnd/src/net/osmand/plus/activities/LocalOpenstreetmapActivity.java @@ -1,15 +1,44 @@ package net.osmand.plus.activities; +import android.app.ExpandableListActivity; +import android.app.AlertDialog; +import android.app.AlertDialog.Builder; +import android.content.DialogInterface; +import android.graphics.Color; +import android.os.Bundle; +import android.view.ContextMenu; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.ContextMenu.ContextMenuInfo; +import android.widget.BaseExpandableListAdapter; +import android.widget.ExpandableListView; +import android.widget.TextView; +import android.widget.ExpandableListView.ExpandableListContextMenuInfo; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import net.osmand.OpenstreetmapPoint; +import net.osmand.OpenstreetmapUtil; +import net.osmand.OpenstreetmapRemoteUtil; +import net.osmand.LogUtil; +import net.osmand.osm.EntityInfo; +import net.osmand.plus.AmenityIndexRepositoryOdb; +import net.osmand.plus.OpenstreetmapsDbHelper; import net.osmand.plus.OsmandSettings; import net.osmand.plus.R; -import android.app.ExpandableListActivity; -import android.os.Bundle; - public class LocalOpenstreetmapActivity extends ExpandableListActivity { + private LocalOpenstreetmapAdapter listAdapter; + private OsmandSettings settings; + private OpenstreetmapsDbHelper db; + @SuppressWarnings("unchecked") @Override protected void onCreate(Bundle savedInstanceState) { @@ -17,6 +46,229 @@ public class LocalOpenstreetmapActivity extends ExpandableListActivity { setContentView(R.layout.local_openstreetmap); settings = OsmandSettings.getOsmandSettings(this); + listAdapter = new LocalOpenstreetmapAdapter(); + + getExpandableListView().setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() { + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { + long packedPos = ((ExpandableListContextMenuInfo)menuInfo).packedPosition; + int group = ExpandableListView.getPackedPositionGroup(packedPos); + int child = ExpandableListView.getPackedPositionChild(packedPos); + if (child >= 0 && group >= 0) { + final OpenstreetmapPoint point = (OpenstreetmapPoint) listAdapter.getChild(group, child); + showContextMenu(point); + } + } + }); + + setListAdapter(listAdapter); + + db = new OpenstreetmapsDbHelper(this); + List l = db.getOpenstreetmapPoints(); + android.util.Log.d(LogUtil.TAG, "List of POI " + l.size() + " length"); + for (OpenstreetmapPoint p : l) { + listAdapter.addOpenstreetmapPoint(p); + } + listAdapter.notifyDataSetChanged(); + } + + private void showContextMenu(final OpenstreetmapPoint info) { + Builder builder = new AlertDialog.Builder(this); + final List menu = new ArrayList(); + + menu.add(R.string.local_openstreetmap_show_poi); + menu.add(R.string.local_openstreetmap_upload); + menu.add(R.string.local_openstreetmap_delete); + + String[] values = new String[menu.size()]; + for (int i = 0; i < values.length; i++) { + values[i] = getString(menu.get(i)); + } + builder.setItems(values, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + int resId = menu.get(which); + if (info != null) { + if (resId == R.string.local_openstreetmap_show_poi) { + OsmandSettings settings = OsmandSettings.getOsmandSettings(LocalOpenstreetmapActivity.this); + settings.setMapLocationToShow(info.getLatitude(), info.getLongitude(), settings.getLastKnownMapZoom()); + MapActivity.launchMapActivityMoveToTop(LocalOpenstreetmapActivity.this); + } else if (resId == R.string.local_openstreetmap_delete) { + listAdapter.delete(info); + } else if (resId == R.string.local_openstreetmap_upload) { + OpenstreetmapRemoteUtil remote = new OpenstreetmapRemoteUtil(LocalOpenstreetmapActivity.this, + LocalOpenstreetmapActivity.this.getWindow().getDecorView()); + EntityInfo entityInfo = null; + if (OpenstreetmapUtil.Action.CREATE != info.getAction()) { + entityInfo = remote.loadNode(info.getEntity()); + } + if (remote.commitNodeImpl(info.getAction(), info.getEntity(), entityInfo, info.getComment())) { + listAdapter.delete(info); + } + } + } + } + }); + + builder.show(); } + + protected class LocalOpenstreetmapAdapter extends BaseExpandableListAdapter { + Map> data = new LinkedHashMap>(); + List category = new ArrayList(); + List filterCategory = null; + + + public LocalOpenstreetmapAdapter() { + } + + public void clear() { + data.clear(); + category.clear(); + filterCategory = null; + notifyDataSetChanged(); + } + + public void delete(OpenstreetmapPoint i) { + final AmenityIndexRepositoryOdb repo = ((OsmandApplication) getApplication()).getResourceManager().getUpdatablePoiDb(); + android.util.Log.d(LogUtil.TAG, "Delete " + i); + db.deleteOpenstreetmap(i); + String c = i.getType(); + if(c != null){ + data.get(c).remove(i); + // We need to re-insert the POI if it is a delete or modify + repo.deleteAmenities(i.getId() << 1); + repo.clearCache(); + } + listAdapter.notifyDataSetChanged(); + } + + public void cancelFilter(){ + filterCategory = null; + notifyDataSetChanged(); + } + + public void filterCategories(String... types) { + List filter = new ArrayList(); + List source = filterCategory == null ? category : filterCategory; + for (String info : source) { + for (String ts : types) { + if (info.compareTo(ts) == 0) { + filter.add(info); + } + } + } + filterCategory = filter; + notifyDataSetChanged(); + } + + public void addOpenstreetmapPoint(OpenstreetmapPoint info) { + int found = -1; + // search from end + for (int i = category.size() - 1; i >= 0; i--) { + String cat = category.get(i); + if (cat.compareTo(info.getType()) == 0) { + found = i; + break; + } + } + if (found == -1) { + found = category.size(); + category.add(info.getType()); + } + if (!data.containsKey(category.get(found))) { + data.put(category.get(found), new ArrayList()); + } + data.get(category.get(found)).add(info); + } + + @Override + public OpenstreetmapPoint getChild(int groupPosition, int childPosition) { + String cat = filterCategory != null ? filterCategory.get(groupPosition) : category.get(groupPosition); + return data.get(cat).get(childPosition); + } + + @Override + public long getChildId(int groupPosition, int childPosition) { + // it would be unusable to have 10000 local indexes + return groupPosition * 10000 + childPosition; + } + + @Override + public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { + View v = convertView; + final OpenstreetmapPoint child = (OpenstreetmapPoint) getChild(groupPosition, childPosition); + if (v == null ) { + LayoutInflater inflater = getLayoutInflater(); + v = inflater.inflate(net.osmand.plus.R.layout.local_openstreetmap_list_item, parent, false); + } + TextView viewName = ((TextView) v.findViewById(R.id.local_openstreetmap_name)); + viewName.setText("(" + child.getSubtype() + ") " + child.getName()); + if (child.getAction() == OpenstreetmapUtil.Action.CREATE) { + viewName.setTextColor(Color.GREEN); + } else if (child.getAction() == OpenstreetmapUtil.Action.MODIFY) { + viewName.setTextColor(Color.MAGENTA); + } else if (child.getAction() == OpenstreetmapUtil.Action.DELETE) { + viewName.setTextColor(Color.RED); + } + + return v; + } + + @Override + public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { + View v = convertView; + String group = getGroup(groupPosition); + if (v == null) { + LayoutInflater inflater = getLayoutInflater(); + v = inflater.inflate(net.osmand.plus.R.layout.local_openstreetmap_list_item_category, parent, false); + } + StringBuilder t = new StringBuilder(group); + TextView nameView = ((TextView) v.findViewById(R.id.local_openstreetmap_category_name)); + t.append(" [").append(getChildrenCount(groupPosition)); + if(getString(R.string.local_openstreetmap_items).length() > 0){ + t.append(" ").append(getString(R.string.local_openstreetmap_items)); + } + if(getString(R.string.local_openstreetmap_items).length() > 0){ + t.append(" ").append(getString(R.string.local_openstreetmap_items)); + } + List list = data.get(group); + t.append("]"); + nameView.setText(t.toString()); + + return v; + } + + @Override + public int getChildrenCount(int groupPosition) { + String cat = filterCategory != null ? filterCategory.get(groupPosition) : category.get(groupPosition); + return data.get(cat).size(); + } + + @Override + public String getGroup(int groupPosition) { + return filterCategory == null ? category.get(groupPosition) : filterCategory.get(groupPosition); + } + + @Override + public int getGroupCount() { + return filterCategory == null ? category.size() : filterCategory.size(); + } + + @Override + public long getGroupId(int groupPosition) { + return groupPosition; + } + + @Override + public boolean hasStableIds() { + return false; + } + + @Override + public boolean isChildSelectable(int groupPosition, int childPosition) { + return true; + } + } }