diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index e64efc4b02..153633ae05 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -9,6 +9,10 @@ 3. 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 --> + User %1$s joined group %2$s + User %1$s left group %2$s + Show group notifications + Show toast messages when user joins or leavs the group Follow Sign in In order to create groups you need to be a registered user of OsMo. diff --git a/OsmAnd/src/net/osmand/plus/OsmandSettings.java b/OsmAnd/src/net/osmand/plus/OsmandSettings.java index afc859fa90..0089b68116 100644 --- a/OsmAnd/src/net/osmand/plus/OsmandSettings.java +++ b/OsmAnd/src/net/osmand/plus/OsmandSettings.java @@ -834,6 +834,8 @@ public class OsmandSettings { public final OsmandPreference OSMO_AUTO_SEND_LOCATIONS = new BooleanPreference("osmo_automatically_send_locations", false).makeGlobal(); + public final OsmandPreference OSMO_SHOW_GROUP_NOTIFICATIONS = new BooleanPreference("osmo_show_toast_notifications", true).makeGlobal(); + public final CommonPreference OSMO_SAVE_TRACK_INTERVAL = new IntPreference("osmo_save_track_interval", 5000).makeGlobal().cache(); public final OsmandPreference OSMO_GROUPS = new StringPreference("osmo_groups", "{}").makeGlobal(); diff --git a/OsmAnd/src/net/osmand/plus/osmo/OsMoGroups.java b/OsmAnd/src/net/osmand/plus/osmo/OsMoGroups.java index 50883c174a..82d92048cf 100644 --- a/OsmAnd/src/net/osmand/plus/osmo/OsMoGroups.java +++ b/OsmAnd/src/net/osmand/plus/osmo/OsMoGroups.java @@ -7,8 +7,10 @@ import java.util.List; import java.util.Map; import net.osmand.Location; +import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandSettings; import net.osmand.plus.GPXUtilities.GPXFile; +import net.osmand.plus.R; import net.osmand.plus.osmo.OsMoGroupsStorage.OsMoDevice; import net.osmand.plus.osmo.OsMoGroupsStorage.OsMoGroup; import net.osmand.plus.osmo.OsMoTracker.OsmoTrackerListener; @@ -39,6 +41,8 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener { private OsMoGroupsStorage storage; private OsMoGroupsUIListener uiListener; private OsMoPlugin plugin; + private OsmandSettings settings; + private OsmandApplication app; public interface OsMoGroupsUIListener { @@ -47,13 +51,14 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener { public void deviceLocationChanged(OsMoDevice device); } - public OsMoGroups(OsMoPlugin plugin, OsMoService service, OsMoTracker tracker, OsmandSettings settings) { + public OsMoGroups(OsMoPlugin plugin, OsMoService service, OsMoTracker tracker, OsmandApplication app) { this.plugin = plugin; this.service = service; this.tracker = tracker; + this.app = app; service.registerReactor(this); tracker.setTrackerListener(this); - storage = new OsMoGroupsStorage(this, settings.OSMO_GROUPS); + storage = new OsMoGroupsStorage(this, app.getSettings().OSMO_GROUPS); storage.load(); } @@ -158,13 +163,19 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener { group = storage.getGroup(gid); if(group != null) { List delta = mergeGroup(group, obj, false); + StringBuilder b = new StringBuilder(); for(OsMoDevice d : delta) { if(d.getDeletedTimestamp() != 0 && d.isEnabled()) { + b.append(app.getString(R.string.osmo_user_joined, d.getVisibleName(), group.getVisibleName(app))).append("\n"); disconnectImpl(d); } else if(!d.isActive()) { + b.append(app.getString(R.string.osmo_user_left, d.getVisibleName(), group.getVisibleName(app))).append("\n"); connectDeviceImpl(d); } } + if(b.length() > 0 && settings.OSMO_SHOW_GROUP_NOTIFICATIONS.get()){ + app.showToastMessage(b.toString().trim()); + } storage.save(); } processed = true; diff --git a/OsmAnd/src/net/osmand/plus/osmo/OsMoGroupsStorage.java b/OsmAnd/src/net/osmand/plus/osmo/OsMoGroupsStorage.java index ab41e03a00..7da0bb4a56 100644 --- a/OsmAnd/src/net/osmand/plus/osmo/OsMoGroupsStorage.java +++ b/OsmAnd/src/net/osmand/plus/osmo/OsMoGroupsStorage.java @@ -6,6 +6,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; import net.osmand.Location; import net.osmand.data.LatLon; @@ -26,6 +27,7 @@ public class OsMoGroupsStorage { private static final String TRACKER_ID = "trackerId"; private static final String USER_NAME = "userName"; private static final String USER_COLOR = "userSetColor"; + private static final String GEN_COLOR = "genColor"; private static final String SERVER_COLOR = "serverColor"; private static final String DESCRIPTION = "description"; private static final String POLICY = "policy"; @@ -146,6 +148,9 @@ public class OsMoGroupsStorage { if (u.userColor != 0) { obj.put(USER_COLOR, u.userColor); } + if (u.genColor != 0) { + obj.put(GEN_COLOR, u.genColor); + } if (u.serverColor != 0) { obj.put(SERVER_COLOR, u.serverColor); } @@ -183,6 +188,9 @@ public class OsMoGroupsStorage { if(o.has(USER_COLOR)) { user.userColor = o.getInt(USER_COLOR); } + if(o.has(GEN_COLOR)) { + user.genColor = o.getInt(GEN_COLOR); + } if(o.has(DELETED)) { user.deleted = o.getLong(DELETED); } @@ -274,9 +282,6 @@ public class OsMoGroupsStorage { OsMoDevice d = users.get(trackerId); if(d != null) { d.setLastLocation(location); - if(location != null) { - d.setLastOnline(location.getTime()); - } } return d; } @@ -317,6 +322,7 @@ public class OsMoGroupsStorage { protected long deleted; protected OsMoGroup group ; + protected ConcurrentLinkedQueue previousLocations = new java.util.concurrent.ConcurrentLinkedQueue(); protected List messages = new ArrayList(); protected long lastOnline; protected Location lastLocation; @@ -326,8 +332,21 @@ public class OsMoGroupsStorage { return messages; } + public ConcurrentLinkedQueue getPreviousLocations(long threshold) { + while(!previousLocations.isEmpty() && previousLocations.peek().getTime() < threshold) { + previousLocations.poll(); + } + return previousLocations; + } + public void setLastLocation(Location lastLocation) { + if(this.lastLocation != null) { + previousLocations.add(this.lastLocation); + } this.lastLocation = lastLocation; + if (lastLocation != null) { + setLastOnline(lastLocation.getTime()); + } } public Location getLastLocation() { diff --git a/OsmAnd/src/net/osmand/plus/osmo/OsMoPlugin.java b/OsmAnd/src/net/osmand/plus/osmo/OsMoPlugin.java index 1b7cf95a8c..20ee58dacc 100644 --- a/OsmAnd/src/net/osmand/plus/osmo/OsMoPlugin.java +++ b/OsmAnd/src/net/osmand/plus/osmo/OsMoPlugin.java @@ -64,7 +64,7 @@ public class OsMoPlugin extends OsmandPlugin implements MonitoringInfoControlSer tracker = new OsMoTracker(service, app.getSettings().OSMO_SAVE_TRACK_INTERVAL, app.getSettings().OSMO_AUTO_SEND_LOCATIONS); new OsMoControlDevice(app, this, service, tracker); - groups = new OsMoGroups(this, service, tracker, app.getSettings()); + groups = new OsMoGroups(this, service, tracker, app); this.app = app; ApplicationMode.regWidget("osmo_control", (ApplicationMode[])null); } diff --git a/OsmAnd/src/net/osmand/plus/osmo/OsMoPositionLayer.java b/OsmAnd/src/net/osmand/plus/osmo/OsMoPositionLayer.java index 1abe50404a..246c661cd4 100644 --- a/OsmAnd/src/net/osmand/plus/osmo/OsMoPositionLayer.java +++ b/OsmAnd/src/net/osmand/plus/osmo/OsMoPositionLayer.java @@ -36,7 +36,8 @@ import android.widget.Toast; * Class represents a layer for osmo positions * */ -public class OsMoPositionLayer extends OsmandMapLayer implements ContextMenuLayer.IContextMenuProvider, OsMoGroupsUIListener { +public class OsMoPositionLayer extends OsmandMapLayer implements ContextMenuLayer.IContextMenuProvider, OsMoGroupsUIListener, + ContextMenuLayer.IContextMenuProviderSelection{ private DisplayMetrics dm; private final MapActivity map; @@ -163,10 +164,10 @@ public class OsMoPositionLayer extends OsmandMapLayer implements ContextMenuLaye @Override public String getObjectName(Object o) { - if(o instanceof OsMoDevice) { - return map.getString(R.string.osmo_user_name) + " " + ((OsMoDevice) o).getVisibleName(); - } - return null; +// if(o instanceof OsMoDevice) { +// return map.getString(R.string.osmo_user_name) + " " + ((OsMoDevice) o).getVisibleName(); +// } + return getObjectDescription(o); } public void refresh() { @@ -297,6 +298,22 @@ public class OsMoPositionLayer extends OsmandMapLayer implements ContextMenuLaye } } } + + @Override + public void setSelectedObject(Object o) { + if(o instanceof OsMoDevice) { + followTrackerId = ((OsMoDevice) o).getTrackerId(); + } + } + + @Override + public void clearSelectedObjects() { + LatLon mapLoc = new LatLon(map.getMapView().getLatitude(), map.getMapView().getLongitude()); + final boolean centered = Algorithms.objectEquals(followMapLocation, mapLoc); + if(!centered && followTrackerId != null) { + followTrackerId = null; + } + } } diff --git a/OsmAnd/src/net/osmand/plus/osmo/OsMoService.java b/OsmAnd/src/net/osmand/plus/osmo/OsMoService.java index dd0466e708..db86275b5b 100644 --- a/OsmAnd/src/net/osmand/plus/osmo/OsMoService.java +++ b/OsmAnd/src/net/osmand/plus/osmo/OsMoService.java @@ -74,7 +74,7 @@ public class OsMoService implements OsMoReactor { if(thread == null) { return Collections.emptyList(); } - return new ArrayList(thread.getLast100Commands()); + return new ArrayList(thread.getLastCommands()); } @@ -246,6 +246,7 @@ public class OsMoService implements OsMoReactor { app.showToastMessage(app.getString(R.string.osmo_io_error) + string); } + public void pushCommand(String cmd) { commands.add(cmd); } diff --git a/OsmAnd/src/net/osmand/plus/osmo/OsMoThread.java b/OsmAnd/src/net/osmand/plus/osmo/OsMoThread.java index a7b2eeb2ca..e10da8cfc2 100644 --- a/OsmAnd/src/net/osmand/plus/osmo/OsMoThread.java +++ b/OsmAnd/src/net/osmand/plus/osmo/OsMoThread.java @@ -66,7 +66,8 @@ public class OsMoThread { private SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss"); - private ConcurrentLinkedQueue last100Commands = new ConcurrentLinkedQueue(); + private ConcurrentLinkedQueue lastCommands = new ConcurrentLinkedQueue(); + private final static int STACK_CMD = 30; @@ -91,6 +92,7 @@ public class OsMoThread { this.activeChannel = null; authorized = 0; reconnect = false; + pingSent = 0; failures = 0; lastSendCommand = 0; selector = Selector.open(); @@ -382,25 +384,29 @@ public class OsMoThread { return ByteBuffer.wrap(prepareCommand(l).toString().getBytes("UTF-8")); } } - if(System.currentTimeMillis() - lastSendCommand > TIMEOUT_TO_PING) { - if(pingSent == 0) { + final long interval = System.currentTimeMillis() - lastSendCommand; + if(interval > TIMEOUT_TO_PING) { + final long pingInterval = System.currentTimeMillis() - pingSent; + if(pingSent == 0 || pingInterval > TIMEOUT_TO_PING) { pingSent = System.currentTimeMillis(); cmd(PING_CMD, true); return ByteBuffer.wrap(prepareCommand(PING_CMD).toString().getBytes("UTF-8")); } + } else if(pingSent != 0) { + pingSent = 0; } return null; } - public ConcurrentLinkedQueue getLast100Commands() { - return last100Commands; + public ConcurrentLinkedQueue getLastCommands() { + return lastCommands; } private void cmd(String cmd, boolean send) { log.info("OsMO" + (send ? "> " : ">> ") + cmd); - last100Commands.add((send ? "> " : ">> ") + df.format(new Date()) + " " + cmd); - while(last100Commands.size() > 100) { - last100Commands.poll(); + lastCommands.add((send ? "> " : ">> ") + df.format(new Date()) + " " + cmd); + while(lastCommands.size() > STACK_CMD) { + lastCommands.poll(); } } diff --git a/OsmAnd/src/net/osmand/plus/osmo/SettingsOsMoActivity.java b/OsmAnd/src/net/osmand/plus/osmo/SettingsOsMoActivity.java index f74fc35198..bdd000db44 100644 --- a/OsmAnd/src/net/osmand/plus/osmo/SettingsOsMoActivity.java +++ b/OsmAnd/src/net/osmand/plus/osmo/SettingsOsMoActivity.java @@ -28,7 +28,6 @@ public class SettingsOsMoActivity extends SettingsBaseActivity { private Preference debugPref; private Preference trackerId; - private CheckBoxPreference sendLocationsref; public static final int[] SECONDS = new int[] {0, 1, 2, 3, 5, 10, 15, 30, 60, 90}; public static final int[] MINUTES = new int[] {2, 3, 5}; @@ -48,7 +47,7 @@ public class SettingsOsMoActivity extends SettingsBaseActivity { trackerId.setOnPreferenceClickListener(this); grp.addPreference(trackerId); - sendLocationsref = createCheckBoxPreference(settings.OSMO_AUTO_SEND_LOCATIONS); + CheckBoxPreference sendLocationsref = createCheckBoxPreference(settings.OSMO_AUTO_SEND_LOCATIONS); sendLocationsref.setTitle(R.string.osmo_auto_send_locations); sendLocationsref.setSummary(R.string.osmo_auto_send_locations_descr); grp.addPreference(sendLocationsref); @@ -56,6 +55,11 @@ public class SettingsOsMoActivity extends SettingsBaseActivity { grp.addPreference(createTimeListPreference(settings.OSMO_SAVE_TRACK_INTERVAL, SECONDS, MINUTES, 1000, R.string.osmo_track_interval, R.string.osmo_track_interval_descr)); + CheckBoxPreference showGroupNotifiations = createCheckBoxPreference(settings.OSMO_SHOW_GROUP_NOTIFICATIONS); + sendLocationsref.setTitle(R.string.osmo_show_group_notifications); + sendLocationsref.setSummary(R.string.osmo_show_group_notifications_descr); + grp.addPreference(sendLocationsref); + debugPref = new Preference(this); debugPref.setTitle(R.string.osmo_settings_debug); debugPref.setOnPreferenceClickListener(this); diff --git a/OsmAnd/src/net/osmand/plus/views/ContextMenuLayer.java b/OsmAnd/src/net/osmand/plus/views/ContextMenuLayer.java index 73dd4ecba6..1ff0324c5b 100644 --- a/OsmAnd/src/net/osmand/plus/views/ContextMenuLayer.java +++ b/OsmAnd/src/net/osmand/plus/views/ContextMenuLayer.java @@ -40,7 +40,17 @@ public class ContextMenuLayer extends OsmandMapLayer { public String getObjectName(Object o); + } + + public interface IContextMenuProviderSelection { + + public void setSelectedObject(Object o); + + public void clearSelectedObjects(); + + } + private static final String KEY_LAT_LAN = "context_menu_lat_lon"; private static final String KEY_DESCRIPTION = "context_menu_description"; private static final String KEY_SELECTED_OBJECTS = "context_menu_selected_objects"; @@ -189,17 +199,29 @@ public class ContextMenuLayer extends OsmandMapLayer { public void setSelections(Map selections) { + clearSelectedObjects(); + if (selections != null) { selectedObjects = selections; - } else { - selectedObjects.clear(); } if (!selectedObjects.isEmpty()) { Entry e = selectedObjects.entrySet().iterator().next(); latLon = e.getValue().getObjectLocation(e.getKey()); + if(e.getValue() instanceof IContextMenuProviderSelection){ + ((IContextMenuProviderSelection) e.getValue()).setSelectedObject(e.getKey()); + } } } + private void clearSelectedObjects() { + for(IContextMenuProvider p : this.selectedObjects.values()) { + if(p instanceof IContextMenuProviderSelection){ + ((IContextMenuProviderSelection) p).clearSelectedObjects(); + } + } + selectedObjects.clear(); + } + @Override public boolean onLongPressEvent(PointF point, RotatedTileBox tileBox) { if ((Build.VERSION.SDK_INT < 14) && !view.getSettings().SCROLL_MAP_BY_GESTURES.get()) { @@ -223,15 +245,19 @@ public class ContextMenuLayer extends OsmandMapLayer { public LatLon selectObjectsForContextMenu(RotatedTileBox tileBox, PointF point) { final double lat = tileBox.getLatFromPixel((int) point.x, (int) point.y); final double lon = tileBox.getLonFromPixel((int) point.x, (int) point.y); - selectedObjects.clear(); + clearSelectedObjects(); List s = new ArrayList(); LatLon latLon = null; - for(OsmandMapLayer l : view.getLayers()){ - if(l instanceof ContextMenuLayer.IContextMenuProvider){ + for(OsmandMapLayer lt : view.getLayers()){ + if(lt instanceof ContextMenuLayer.IContextMenuProvider){ s.clear(); - ((ContextMenuLayer.IContextMenuProvider) l).collectObjectsFromPoint(point, tileBox, s); + final IContextMenuProvider l = (ContextMenuLayer.IContextMenuProvider) lt; + l.collectObjectsFromPoint(point, tileBox, s); for(Object o : s) { - selectedObjects.put(o, ((ContextMenuLayer.IContextMenuProvider) l)); + selectedObjects.put(o, l); + if(l instanceof IContextMenuProviderSelection){ + ((IContextMenuProviderSelection) l).setSelectedObject(o); + } if(latLon == null) { latLon = ((ContextMenuLayer.IContextMenuProvider) l).getObjectLocation(o); } @@ -382,13 +408,16 @@ public class ContextMenuLayer extends OsmandMapLayer { } public void setSelectedObject(Object toShow) { - selectedObjects.clear(); + clearSelectedObjects(); if(toShow != null){ for(OsmandMapLayer l : view.getLayers()){ if(l instanceof ContextMenuLayer.IContextMenuProvider){ String des = ((ContextMenuLayer.IContextMenuProvider) l).getObjectDescription(toShow); if(des != null) { selectedObjects.put(toShow, (IContextMenuProvider) l); + if(l instanceof IContextMenuProviderSelection){ + ((IContextMenuProviderSelection) l).setSelectedObject(toShow); + } } } }