Commit db2e8799 authored by Mudar Noufal's avatar Mudar Noufal

HelloApi, to check dataset updates timestamps

related to #26
parent f7118065
......@@ -58,6 +58,7 @@ public class Const {
*/
public interface ApiPaths {
// String BASE_URL = BuildConfig.API_BASE_URL; // "http://www.montrealaucasou.com/api/"
String GET_HELLO = "hello.json";
String GET_FIRE_HALLS = "fire_halls.json";
String GET_SPVM_STATIONS = "spvm_stations.json";
String GET_WATER_SUPPLIES = "water_supplies.json";
......@@ -66,6 +67,11 @@ public class Const {
String GET_HOSPITALS = "hospitals.json";
}
public interface ApiValues {
String TYPE_PLACEMARKS = "placemarks";
String TYPE_SHAPES = "shapes";
}
public interface BundleKeys {
String NAME = "name";
String DESCRIPTION = "desc";
......@@ -110,10 +116,11 @@ public class Const {
String UNITS_SYSTEM = "prefs_units_system";
// String LIST_SORT = "prefs_list_sort_by";
// String FOLLOW_LOCATION_CHANGES = "prefs_follow_location_changes";
String LAST_UPDATE_TIME = "prefs_last_update_time";
String LAST_UPDATE_LAT = "prefs_last_update_lat";
String LAST_UPDATE_LNG = "prefs_last_update_lng";
// String LAST_UPDATE_TIME = "prefs_last_update_time";
// String LAST_UPDATE_LAT = "prefs_last_update_lat";
// String LAST_UPDATE_LNG = "prefs_last_update_lng";
String PERMISSION_DENIED_FOR_EVER = "prefs_permission_denied";
String ITEM_UPDATED_AT = "prefs_updated_%s";
}
public interface PrefsValues {
......
......@@ -33,6 +33,7 @@ import java.util.concurrent.TimeUnit;
import ca.mudar.mtlaucasou.BuildConfig;
import ca.mudar.mtlaucasou.model.geojson.PointsFeatureCollection;
import ca.mudar.mtlaucasou.model.jsonapi.HelloApi;
import ca.mudar.mtlaucasou.util.LogUtils;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
......@@ -80,54 +81,10 @@ public class ApiClient {
return retrofit.create(GeoApiService.class);
}
public static void getFireHalls(GeoApiService service, Callback<PointsFeatureCollection> cb) {
service.getFireHalls()
.enqueue(cb);
}
public static void getSpvmStations(GeoApiService service, Callback<PointsFeatureCollection> cb) {
service.getSpvmStations()
.enqueue(cb);
}
public static void getWaterSupplies(GeoApiService service, Callback<PointsFeatureCollection> cb) {
service.getWaterSupplies()
.enqueue(cb);
}
public static void getEmergencyHostels(GeoApiService service, Callback<PointsFeatureCollection> cb) {
service.getEmergencyHostels()
.enqueue(cb);
}
@Nullable
public static Response<PointsFeatureCollection> getFireHalls(GeoApiService service) {
try {
return service.getFireHalls()
.execute();
} catch (IOException e) {
LogUtils.REMOTE_LOG(e);
}
return null;
}
@Nullable
public static Response<PointsFeatureCollection> getSpvmStations(GeoApiService service) {
try {
return service.getSpvmStations()
.execute();
} catch (IOException e) {
LogUtils.REMOTE_LOG(e);
}
return null;
}
@Nullable
public static Response<PointsFeatureCollection> getWaterSupplies(GeoApiService service) {
public static Response<HelloApi> hello(GeoApiService service) {
try {
return service.getWaterSupplies()
return service.hello()
.execute();
} catch (IOException e) {
LogUtils.REMOTE_LOG(e);
......@@ -136,22 +93,15 @@ public class ApiClient {
return null;
}
@Nullable
public static Response<PointsFeatureCollection> getAirConditioning(GeoApiService service) {
try {
return service.getAirConditioning()
.execute();
} catch (IOException e) {
LogUtils.REMOTE_LOG(e);
}
return null;
public static void hello(GeoApiService service, Callback<HelloApi> cb) {
service.hello()
.enqueue(cb);
}
@Nullable
public static Response<PointsFeatureCollection> getEmergencyHostels(GeoApiService service) {
public static Response<PointsFeatureCollection> getPlacemarks(GeoApiService service, String url) {
try {
return service.getEmergencyHostels()
return service.getPlacemarks(url)
.execute();
} catch (IOException e) {
LogUtils.REMOTE_LOG(e);
......@@ -160,15 +110,8 @@ public class ApiClient {
return null;
}
@Nullable
public static Response<PointsFeatureCollection> getHospitals(GeoApiService service) {
try {
return service.getHospitals()
.execute();
} catch (IOException e) {
LogUtils.REMOTE_LOG(e);
}
return null;
public static void getPlacemarks(GeoApiService service, String url, Callback<PointsFeatureCollection> cb) {
service.getPlacemarks(url)
.enqueue(cb);
}
}
......@@ -25,34 +25,21 @@ package ca.mudar.mtlaucasou.api;
import ca.mudar.mtlaucasou.Const;
import ca.mudar.mtlaucasou.model.geojson.PointsFeatureCollection;
import ca.mudar.mtlaucasou.model.jsonapi.HelloApi;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Headers;
import retrofit2.http.Url;
public interface GeoApiService {
String CONTENT_TYPE = "Content-type: application/json";
@Headers({CONTENT_TYPE})
@GET(Const.ApiPaths.GET_FIRE_HALLS)
Call<PointsFeatureCollection> getFireHalls();
@GET(Const.ApiPaths.GET_HELLO)
Call<HelloApi> hello();
@Headers({CONTENT_TYPE})
@GET(Const.ApiPaths.GET_SPVM_STATIONS)
Call<PointsFeatureCollection> getSpvmStations();
@Headers({CONTENT_TYPE})
@GET(Const.ApiPaths.GET_WATER_SUPPLIES)
Call<PointsFeatureCollection> getWaterSupplies();
@Headers({CONTENT_TYPE})
@GET(Const.ApiPaths.GET_AIR_CONDITIONING)
Call<PointsFeatureCollection> getAirConditioning();
@Headers({CONTENT_TYPE})
@GET(Const.ApiPaths.GET_EMERGENCY_HOSTELS)
Call<PointsFeatureCollection> getEmergencyHostels();
@Headers({CONTENT_TYPE})
@GET(Const.ApiPaths.GET_HOSPITALS)
Call<PointsFeatureCollection> getHospitals();
@GET
Call<PointsFeatureCollection> getPlacemarks(@Url String url);
}
......@@ -28,6 +28,7 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import java.util.Date;
import java.util.Locale;
import ca.mudar.mtlaucasou.Const;
......@@ -133,4 +134,20 @@ public class UserPrefs implements
edit().putBoolean(PERMISSION_DENIED_FOR_EVER, denied)
.apply();
}
/**
* Check if the API dataset has updates for the requested dataset item
*
* @param key The local dataset key
* @param updatedAt The remote dataset date to compare to
* @return true if updates are needed
*/
public boolean isApiDataNewer(String key, Date updatedAt) {
return Long.compare(mPrefs.getLong(key, Const.UNKNOWN_VALUE), updatedAt.getTime()) < 0;
}
public void setDataUpdatedAt(String key, Date updatedAt) {
edit().putLong(key, updatedAt.getTime())
.apply();
}
}
......@@ -33,15 +33,19 @@ import com.google.gson.Gson;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Date;
import ca.mudar.mtlaucasou.Const;
import ca.mudar.mtlaucasou.R;
import ca.mudar.mtlaucasou.api.ApiClient;
import ca.mudar.mtlaucasou.api.GeoApiService;
import ca.mudar.mtlaucasou.data.RealmQueries;
import ca.mudar.mtlaucasou.data.UserPrefs;
import ca.mudar.mtlaucasou.model.MapType;
import ca.mudar.mtlaucasou.model.geojson.PointsFeatureCollection;
import ca.mudar.mtlaucasou.model.jsonapi.DataItem;
import ca.mudar.mtlaucasou.model.jsonapi.HelloApi;
import ca.mudar.mtlaucasou.util.ApiUtils;
import ca.mudar.mtlaucasou.util.LogUtils;
import io.realm.Realm;
import retrofit2.Response;
......@@ -65,11 +69,12 @@ public class SyncService extends IntentService {
mRealm = Realm.getDefaultInstance();
final long startTime = System.currentTimeMillis();
if (!UserPrefs.getInstance(this).hasLoadedData()) {
final UserPrefs userPrefs = UserPrefs.getInstance(this);
if (!userPrefs.hasLoadedData()) {
loadInitialLocalData();
} else {
// TODO handle updates frequency and redundancy
// downloadRemoteUpdatesIfAvailable();
downloadRemoteUpdatesIfAvailable(userPrefs);
}
Log.v(TAG, String.format("Data sync duration: %dms", System.currentTimeMillis() - startTime));
......@@ -81,7 +86,7 @@ public class SyncService extends IntentService {
mRealm.beginTransaction();
importLocalData(R.raw.fire_halls, Const.MapTypes.FIRE_HALLS);
importLocalData(R.raw.spvm_stations, Const.MapTypes.SVPM_STATIONS);
importLocalData(R.raw.spvm_stations, Const.MapTypes.SPVM_STATIONS);
importLocalData(R.raw.water_supplies, Const.MapTypes.WATER_SUPPLIES);
importLocalData(R.raw.air_conditioning, Const.MapTypes.WATER_SUPPLIES);
importLocalData(R.raw.emergency_hostels, Const.MapTypes.EMERGENCY_HOSTELS);
......@@ -90,12 +95,33 @@ public class SyncService extends IntentService {
mRealm.commitTransaction();
}
private void downloadRemoteUpdatesIfAvailable() {
importRemoteData(Const.MapTypes.FIRE_HALLS);
importRemoteData(Const.MapTypes.SVPM_STATIONS);
importRemoteData(Const.MapTypes.WATER_SUPPLIES);
importRemoteData(Const.MapTypes.EMERGENCY_HOSTELS);
importRemoteData(Const.MapTypes.HOSPITALS);
private void downloadRemoteUpdatesIfAvailable(UserPrefs prefs) {
try {
Response<HelloApi> helloResponse = ApiClient.hello(ApiClient.getService());
if (helloResponse != null && helloResponse.body() != null) {
final HelloApi api = helloResponse.body();
for (DataItem dataset : api.getData()) {
if (!Const.ApiValues.TYPE_PLACEMARKS.equals(dataset.getType())) {
continue;
}
final String key = ApiUtils.getSharedPrefsKey(dataset.getId());
final Date updatedAt = dataset.getAttributes().getUpdated();
if (prefs.isApiDataNewer(key, updatedAt)) {
final boolean result = importRemoteData(dataset.getLinks().getSelf(),
dataset.getAttributes().getType());
if (result) {
prefs.setDataUpdatedAt(key, updatedAt);
}
}
}
}
} catch (Exception e) {
LogUtils.REMOTE_LOG(e);
}
}
private void importLocalData(@RawRes int resource, @MapType String mapType) {
......@@ -111,49 +137,24 @@ public class SyncService extends IntentService {
/**
* Request the GeoJSON data from the API
*
* @param mapType
* @param url The remote dataset URL
* @param mapType The MapType
* @return
*/
private void importRemoteData(@MapType String mapType) {
final GeoApiService apiService = ApiClient.getService();
Response<PointsFeatureCollection> response;
switch (mapType) {
case Const.MapTypes.FIRE_HALLS:
response = ApiClient.getFireHalls(apiService);
break;
case Const.MapTypes.SVPM_STATIONS:
response = ApiClient.getSpvmStations(apiService);
break;
case Const.MapTypes.WATER_SUPPLIES:
response = ApiClient.getWaterSupplies(apiService);
break;
case Const.MapTypes.EMERGENCY_HOSTELS:
response = ApiClient.getEmergencyHostels(apiService);
break;
case Const.MapTypes.HOSPITALS:
response = ApiClient.getHospitals(apiService);
break;
default:
response = null;
break;
}
private boolean importRemoteData(String url, @MapType String mapType) {
final Response<PointsFeatureCollection> response = ApiClient
.getPlacemarks(ApiClient.getService(), url);
if (response != null) {
PointsFeatureCollection collection = response.body();
if (collection != null && collection.getFeatures() != null) {
RealmQueries.clearMapData(mRealm, mapType);
RealmQueries.cacheMapData(mRealm, collection.getFeatures(), mapType, true);
}
}
if (Const.MapTypes.WATER_SUPPLIES.equals(mapType)) {
// WATER_SUPPLIES supplies has an extra source: air conditioning
response = ApiClient.getWaterSupplies(apiService);
if (response != null) {
PointsFeatureCollection collection = response.body();
if (collection != null && collection.getFeatures() != null) {
RealmQueries.cacheMapData(mRealm, collection.getFeatures(), mapType, true);
}
}
return true;
}
return false;
}
}
/*
Montréal Just in Case
Copyright (C) 2011 Mudar Noufal <mn@mudar.ca>
Geographic locations of public safety services. A Montréal Open Data
project.
This file is part of Montréal Just in Case.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ca.mudar.mtlaucasou.util;
import java.util.Locale;
import static ca.mudar.mtlaucasou.Const.PrefsNames.ITEM_UPDATED_AT;
public class ApiUtils {
public static String getSharedPrefsKey(String id) {
return String.format(Locale.ROOT, ITEM_UPDATED_AT, id);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment