Skip to content

Commit

Permalink
Merge branch 'master' into maxspeed-redesign
Browse files Browse the repository at this point in the history
# Conflicts:
#	res/country_metadata/isSlowZoneKnown.yml
  • Loading branch information
westnordost committed Aug 1, 2018
2 parents 70c4d27 + 26c28e1 commit ceb599d
Show file tree
Hide file tree
Showing 79 changed files with 2,078 additions and 811 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ android {
applicationId "de.westnordost.streetcomplete"
minSdkVersion 17
targetSdkVersion 27
versionCode 600
versionName "6.0-beta1"
versionCode 700
versionName "7.0-beta1"
testInstrumentationRunner "android.test.InstrumentationTestRunner"
buildConfigField "String", "MAPZEN_API_KEY", MAPZEN_API_KEY
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.util.Map;

import de.westnordost.osmapi.map.data.BoundingBox;
import de.westnordost.osmapi.map.data.OsmLatLon;

import static de.westnordost.streetcomplete.data.OsmModule.ONEWAY_API_URL;
import static org.assertj.core.api.Assertions.*;
Expand All @@ -27,26 +28,33 @@ public void testParseTwoOfDifferentWay() throws JSONException
{
Map<Long, List<TrafficFlowSegment>> result = TrafficFlowSegmentsDao.parse(
"{\"segments\":[" +
"{\"wayId\":1,\"fromNodeId\":7,\"toNodeId\":8}," +
"{\"wayId\":2,\"fromNodeId\":5,\"toNodeId\":6}," +
"]}"
"{\"wayId\":1,\"fromPosition\":{\"lon\":1, \"lat\":2},\"toPosition\":{\"lon\":5, \"lat\":6}}," +
"{\"wayId\":2,\"fromPosition\":{\"lon\":3, \"lat\":4},\"toPosition\":{\"lon\":7, \"lat\":8}}," +
"]}"
);
Map<Long, List<TrafficFlowSegment>> expected = new HashMap<>();
expected.put(1L, Collections.singletonList(new TrafficFlowSegment(7, 8)));
expected.put(2L, Collections.singletonList(new TrafficFlowSegment(5, 6)));
expected.put(1L, Collections.singletonList(
new TrafficFlowSegment(new OsmLatLon(2,1), new OsmLatLon(6,5))
));
expected.put(2L, Collections.singletonList(new TrafficFlowSegment(
new OsmLatLon(4,3), new OsmLatLon(8,7))
));
assertThat(result).containsAllEntriesOf(expected);
}

public void testParseTwoOfSameWay() throws JSONException
{
Map<Long, List<TrafficFlowSegment>> result = TrafficFlowSegmentsDao.parse(
"{\"segments\":[" +
"{\"wayId\":1,\"fromNodeId\":7,\"toNodeId\":8}," +
"{\"wayId\":1,\"fromNodeId\":5,\"toNodeId\":6}," +
"{\"wayId\":1,\"fromPosition\":{\"lon\":1, \"lat\":2},\"toPosition\":{\"lon\":5, \"lat\":6}}," +
"{\"wayId\":1,\"fromPosition\":{\"lon\":3, \"lat\":4},\"toPosition\":{\"lon\":7, \"lat\":8}}," +
"]}"
);
Map<Long, List<TrafficFlowSegment>> expected = new HashMap<>();
expected.put(1L, Arrays.asList(new TrafficFlowSegment(7,8), new TrafficFlowSegment(5,6)));
expected.put(1L, Arrays.asList(
new TrafficFlowSegment(new OsmLatLon(2,1), new OsmLatLon(6,5)),
new TrafficFlowSegment(new OsmLatLon(4,3), new OsmLatLon(8,7))
));
assertThat(result).containsAllEntriesOf(expected);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import de.westnordost.streetcomplete.oauth.OsmOAuthDialogFragment;
import de.westnordost.streetcomplete.quests.AbstractQuestAnswerFragment;
import de.westnordost.streetcomplete.quests.QuestModule;
import de.westnordost.streetcomplete.quests.localized_name.AddLocalizedNameForm;
import de.westnordost.streetcomplete.quests.oneway.AddOnewayForm;
import de.westnordost.streetcomplete.quests.opening_hours.AddOpeningHoursForm;
import de.westnordost.streetcomplete.quests.localized_name.AddRoadNameForm;
import de.westnordost.streetcomplete.quests.parking_fee.AddParkingFeeForm;
Expand Down Expand Up @@ -47,8 +49,10 @@ public interface ApplicationComponent
void inject(UnsyncedChangesCounter unsyncedChangesCounter);

void inject(AddOpeningHoursForm addOpeningHoursForm);
void inject(AddLocalizedNameForm addLocalizedNameForm);
void inject(AddRoadNameForm addRoadNameForm);
void inject(AddParkingFeeForm parkingFeeForm);
void inject(AddOnewayForm addOnewayForm);
void inject(AddCollectionTimesForm addCollectionTimesForm);

void inject(OsmOAuthDialogFragment osmOAuthDialogFragment);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ public class ApplicationConstants

public final static int NOTE_MIN_ZOOM = 15;

/** How many quests to download when pressing manually on "download quests" */
public final static int MANUAL_DOWNLOAD_QUEST_TYPE_COUNT = 10;

/** a "best before" duration for quests. Quests will not be downloaded again for any tile
* before the time expired */
public static final int REFRESH_QUESTS_AFTER = 7*24*60*60*1000; // one week in ms
Expand All @@ -33,4 +36,6 @@ public class ApplicationConstants

public static final int ATTACH_PHOTO_QUALITY = 60;
public static final int ATTACH_PHOTO_MAXWIDTH = 1280; // WXGA

public static final String NOTIFICATIONS_CHANNEL_DOWNLOAD = "downloading";
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@
import de.westnordost.streetcomplete.util.SphericalEarthMath;
import de.westnordost.streetcomplete.view.dialogs.AlertDialogBuilder;

import static de.westnordost.streetcomplete.ApplicationConstants.MANUAL_DOWNLOAD_QUEST_TYPE_COUNT;

public class MainActivity extends AppCompatActivity implements
OsmQuestAnswerListener, CreateNoteListener, VisibleQuestListener,
QuestsMapFragment.Listener, MapFragment.Listener, MapControlsFragment.Listener
Expand Down Expand Up @@ -452,7 +454,7 @@ private void downloadAreaConfirmed(BoundingBox bbox)
ApplicationConstants.MIN_DOWNLOADABLE_RADIUS_IN_METERS);
}
}
questController.download(bbox, 5, true);
questController.download(bbox, MANUAL_DOWNLOAD_QUEST_TYPE_COUNT, true);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@
import de.westnordost.streetcomplete.data.visiblequests.QuestVisibilityTable;
import de.westnordost.streetcomplete.data.statistics.QuestStatisticsTable;
import de.westnordost.streetcomplete.data.tiles.DownloadedTilesTable;
import de.westnordost.streetcomplete.quests.oneway.AddOneway;

@Singleton
public class StreetCompleteOpenHelper extends SQLiteOpenHelper
{
public static final String DB_NAME = "streetcomplete.db";
public static final int DB_VERSION = 10;
public static final int DB_VERSION = 11;

private static final String OSM_QUESTS_CREATE_PARAMS = " (" +
OsmQuestTable.Columns.QUEST_ID + " INTEGER PRIMARY KEY, " +
Expand Down Expand Up @@ -327,6 +328,14 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
db.execSQL(QUEST_VISIBILITY_TABLE_CREATE);
}

// all oneway quest data was invalidated on version 11
if(oldVersion < 11 && newVersion >= 11)
{
String where = OsmQuestTable.Columns.QUEST_TYPE + " = ?";
String[] args = {AddOneway.class.getSimpleName()};
db.delete(OsmQuestTable.NAME, where, args);
db.delete(OsmQuestTable.NAME_UNDO, where, args);
}

// for later changes to the DB
// ...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class MobileDataAutoDownloadStrategy extends AActiveRadiusStrategy

@Override public int getQuestTypeDownloadCount()
{
return 3;
return 4;
}

@Override protected int getMinQuestsInActiveRadiusPerKm2()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class QuestDownloadProgressRelay implements QuestDownloadProgressListener
private boolean isDownloading;
private Float progress;

public QuestDownloadProgressRelay(Service service, int notificationId)
public QuestDownloadProgressRelay(Service service, String notificationChannelId, int notificationId)
{
this.service = service;
this.id = notificationId;
Expand All @@ -37,7 +37,16 @@ public QuestDownloadProgressRelay(Service service, int notificationId)
PendingIntent pendingIntent = PendingIntent.getActivity(
service, 0, new Intent(service, MainActivity.class), 0);

notificationBuilder = new Notification.Builder(service)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
notificationBuilder = new Notification.Builder(service, notificationChannelId);
}
else
{
notificationBuilder = new Notification.Builder(service);
}

notificationBuilder
.setSmallIcon(R.mipmap.ic_dl_notification)
.setContentTitle(ApplicationConstants.NAME)
.setContentText(service.getResources().getString(R.string.notification_downloading))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
package de.westnordost.streetcomplete.data.download;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.Log;

import java.util.concurrent.atomic.AtomicBoolean;
Expand All @@ -18,9 +23,12 @@
import javax.inject.Provider;

import de.westnordost.streetcomplete.Injector;
import de.westnordost.streetcomplete.R;
import de.westnordost.streetcomplete.data.VisibleQuestListener;
import de.westnordost.streetcomplete.data.VisibleQuestRelay;

import static de.westnordost.streetcomplete.ApplicationConstants.NOTIFICATIONS_CHANNEL_DOWNLOAD;

/** Downloads all quests in a given area asynchronously. To use, start the service with the
* appropriate parameters. (see #onStartCommand)
*
Expand Down Expand Up @@ -80,10 +88,24 @@ public QuestDownloadService()
thread.start();
serviceLooper = thread.getLooper();
serviceHandler = new ServiceHandler(serviceLooper);
progressListenerRelay = new QuestDownloadProgressRelay(this, 1);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
createNotificationChannel();
}
progressListenerRelay = new QuestDownloadProgressRelay(this, NOTIFICATIONS_CHANNEL_DOWNLOAD, 1);
visibleQuestRelay = new VisibleQuestRelay();
}

@RequiresApi(api = Build.VERSION_CODES.O)
private void createNotificationChannel()
{
NotificationManager service = (NotificationManager) getApplication().getSystemService(Context.NOTIFICATION_SERVICE);
assert service != null;
service.createNotificationChannel(new NotificationChannel(
NOTIFICATIONS_CHANNEL_DOWNLOAD, getString(R.string.notification_channel_download), NotificationManager.IMPORTANCE_LOW));
}

@Override public int onStartCommand(@Nullable Intent intent, int flags, int startId)
{
cancel();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class WifiAutoDownloadStrategy extends AActiveRadiusStrategy

@Override public int getQuestTypeDownloadCount()
{
return 3;
return 8;
}

@Override protected int getMinQuestsInActiveRadiusPerKm2()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package de.westnordost.streetcomplete.data.osm;

import android.text.TextUtils;
import android.util.Log;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;
import javax.inject.Provider;

import de.westnordost.osmapi.map.data.BoundingBox;
import de.westnordost.osmapi.map.data.Element;
import de.westnordost.osmapi.map.data.LatLon;
import de.westnordost.streetcomplete.data.QuestStatus;
import de.westnordost.streetcomplete.data.QuestType;
import de.westnordost.streetcomplete.data.osm.persist.ElementGeometryDao;
import de.westnordost.streetcomplete.data.osm.persist.OsmQuestDao;
import de.westnordost.streetcomplete.data.osmnotes.OsmNoteQuestDao;

/** Manages creating new quests and removing quests that are no longer applicable for an OSM
* element locally */
public class OsmQuestGiver
{
private static final String TAG = "OsmQuestGiver";

private final OsmNoteQuestDao osmNoteQuestDb;
private final OsmQuestDao questDB;
private final ElementGeometryDao elementGeometryDB;
private final Provider<List<QuestType>> questTypesProvider;

@Inject public OsmQuestGiver(
OsmNoteQuestDao osmNoteQuestDb, OsmQuestDao questDB,
ElementGeometryDao elementGeometryDB, Provider<List<QuestType>> questTypesProvider)
{
this.osmNoteQuestDb = osmNoteQuestDb;
this.questDB = questDB;
this.elementGeometryDB = elementGeometryDB;
this.questTypesProvider = questTypesProvider;
}

public class QuestUpdates
{
public List<OsmQuest> createdQuests = new ArrayList<>();
public List<Long> removedQuestIds = new ArrayList<>();
}

public QuestUpdates updateQuests(Element element)
{
ElementGeometry geometry = elementGeometryDB.get(element.getType(), element.getId());
boolean hasNote = hasNoteAt(geometry.center);

QuestUpdates result = new QuestUpdates();

Map<QuestType, OsmQuest> currentQuests = getCurrentQuests(element);
List<String> createdQuestsLog = new ArrayList<>();
List<String> removedQuestsLog = new ArrayList<>();

for(QuestType questType : questTypesProvider.get())
{
if(!(questType instanceof OsmElementQuestType)) continue;
OsmElementQuestType osmQuestType = (OsmElementQuestType)questType;

Boolean appliesToElement = osmQuestType.isApplicableTo(element);
if(appliesToElement == null) continue;

boolean hasQuest = currentQuests.containsKey(osmQuestType);
if(appliesToElement && !hasQuest && !hasNote)
{
OsmQuest quest = new OsmQuest(osmQuestType, element.getType(), element.getId(), geometry);
result.createdQuests.add(quest);
createdQuestsLog.add(osmQuestType.getClass().getSimpleName());
}
if(!appliesToElement && hasQuest)
{
OsmQuest quest = currentQuests.get(osmQuestType);
// only remove "fresh" unanswered quests because answered/closed quests by definition
// do not apply to the element anymore. E.g. after adding the name to the street,
// there shan't be any AddRoadName quest for that street anymore
if(quest.getStatus() == QuestStatus.NEW)
{
result.removedQuestIds.add(quest.getId());
removedQuestsLog.add(osmQuestType.getClass().getSimpleName());
}
}
}

if(!result.createdQuests.isEmpty())
{
// Before new quests are unlocked, all reverted quests need to be removed for
// this element so that they can be created anew as the case may be
questDB.deleteAllReverted(element.getType(), element.getId());

questDB.addAll(result.createdQuests);

Log.d(TAG, "Created new quests for " + element.getType().name() + "#" + element.getId() + ": " +
TextUtils.join(", ", createdQuestsLog)
);
}
if(!result.removedQuestIds.isEmpty())
{
questDB.deleteAll(result.removedQuestIds);

Log.d(TAG, "Removed quests no longer applicable for " + element.getType().name() + "#" + element.getId() + ": " +
TextUtils.join(", ", removedQuestsLog)
);
}

return result;
}

private boolean hasNoteAt(LatLon pos)
{
BoundingBox bbox = new BoundingBox(pos, pos);
return !osmNoteQuestDb.getAllPositions(bbox).isEmpty();
}

private Map<QuestType, OsmQuest> getCurrentQuests(Element element)
{
List<OsmQuest> quests = questDB.getAll(null, null, null, element.getType(), element.getId());
Map<QuestType, OsmQuest> result = new HashMap<>(quests.size());
for (OsmQuest quest : quests)
{
if(quest.getStatus() == QuestStatus.REVERT) continue;
result.put(quest.getType(), quest);
}
return result;
}
}
Loading

0 comments on commit ceb599d

Please sign in to comment.