1
0
Fork 0
mirror of https://github.com/MatomoCamp/matomocamp-companion-android.git synced 2024-09-19 16:13:46 +02:00

Added Http cache awareness

to skip updating the database when the remote file has not changed.
This commit is contained in:
Christophe Beyls 2015-02-05 23:49:31 +01:00
parent 6f48640a13
commit 90d73831c6
5 changed files with 85 additions and 32 deletions

View file

@ -150,6 +150,9 @@ public class MainActivity extends ActionBarActivity implements ListView.OnItemCl
case FosdemApi.RESULT_ERROR: case FosdemApi.RESULT_ERROR:
message = getString(R.string.schedule_loading_error); message = getString(R.string.schedule_loading_error);
break; break;
case FosdemApi.RESULT_UP_TO_DATE:
message = getString(R.string.events_download_up_to_date);
break;
case 0: case 0:
message = getString(R.string.events_download_empty); message = getString(R.string.events_download_empty);
break; break;

View file

@ -1,12 +1,12 @@
package be.digitalia.fosdem.api; package be.digitalia.fosdem.api;
import java.io.InputStream;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import be.digitalia.fosdem.db.DatabaseManager; import be.digitalia.fosdem.db.DatabaseManager;
import be.digitalia.fosdem.model.Event; import be.digitalia.fosdem.model.Event;
import be.digitalia.fosdem.parsers.EventsParser; import be.digitalia.fosdem.parsers.EventsParser;
@ -27,6 +27,7 @@ public class FosdemApi {
public static final String EXTRA_RESULT = "RESULT"; public static final String EXTRA_RESULT = "RESULT";
public static final int RESULT_ERROR = -1; public static final int RESULT_ERROR = -1;
public static final int RESULT_UP_TO_DATE = -2;
private static final Lock scheduleLock = new ReentrantLock(); private static final Lock scheduleLock = new ReentrantLock();
@ -43,16 +44,29 @@ public class FosdemApi {
int result = RESULT_ERROR; int result = RESULT_ERROR;
try { try {
InputStream is = HttpUtils.get(context, FosdemUrls.getSchedule(), ACTION_DOWNLOAD_SCHEDULE_PROGRESS, EXTRA_PROGRESS); DatabaseManager dbManager = DatabaseManager.getInstance();
HttpUtils.HttpResult httpResult = HttpUtils.get(
context,
FosdemUrls.getSchedule(),
dbManager.getLastModifiedTag(),
ACTION_DOWNLOAD_SCHEDULE_PROGRESS,
EXTRA_PROGRESS);
if (httpResult.inputStream == null) {
// Nothing to parse, the result is up-to-date.
result = RESULT_UP_TO_DATE;
return;
}
try { try {
Iterable<Event> events = new EventsParser().parse(is); Iterable<Event> events = new EventsParser().parse(httpResult.inputStream);
result = DatabaseManager.getInstance().storeSchedule(events); result = dbManager.storeSchedule(events, httpResult.lastModified);
} finally { } finally {
try { try {
is.close(); httpResult.inputStream.close();
} catch (Exception ignored) { } catch (Exception ignored) {
} }
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} finally { } finally {

View file

@ -50,6 +50,7 @@ public class DatabaseManager {
private static final String DB_PREFS_FILE = "database"; private static final String DB_PREFS_FILE = "database";
private static final String LAST_UPDATE_TIME_PREF = "last_update_time"; private static final String LAST_UPDATE_TIME_PREF = "last_update_time";
private static final String LAST_MODIFIED_TAG_PREF = "last_modified_tag";
private static DatabaseManager instance; private static DatabaseManager instance;
@ -117,13 +118,21 @@ public class DatabaseManager {
return getSharedPreferences().getLong(LAST_UPDATE_TIME_PREF, -1L); return getSharedPreferences().getLong(LAST_UPDATE_TIME_PREF, -1L);
} }
/**
*
* @return The time identifier of the current version of the database.
*/
public String getLastModifiedTag() {
return getSharedPreferences().getString(LAST_MODIFIED_TAG_PREF, null);
}
/** /**
* Stores the schedule to the database. * Stores the schedule to the database.
* *
* @param events * @param events
* @return The number of events processed. * @return The number of events processed.
*/ */
public int storeSchedule(Iterable<Event> events) { public int storeSchedule(Iterable<Event> events, String lastModifiedTag) {
boolean isComplete = false; boolean isComplete = false;
SQLiteDatabase db = helper.getWritableDatabase(); SQLiteDatabase db = helper.getWritableDatabase();
@ -260,8 +269,11 @@ public class DatabaseManager {
// Clear cache // Clear cache
cachedDays = null; cachedDays = null;
year = -1; year = -1;
// Set last update time // Set last update time and server's last modified tag
getSharedPreferences().edit().putLong(LAST_UPDATE_TIME_PREF, System.currentTimeMillis()).commit(); getSharedPreferences().edit()
.putLong(LAST_UPDATE_TIME_PREF, System.currentTimeMillis())
.putString(LAST_MODIFIED_TAG_PREF, lastModifiedTag)
.commit();
context.getContentResolver().notifyChange(URI_TRACKS, null); context.getContentResolver().notifyChange(URI_TRACKS, null);
context.getContentResolver().notifyChange(URI_EVENTS, null); context.getContentResolver().notifyChange(URI_EVENTS, null);

View file

@ -22,7 +22,7 @@ import android.support.v4.content.LocalBroadcastManager;
/** /**
* Utility class to perform HTTP requests. * Utility class to perform HTTP requests.
* *
* @author Christophe Beyls * @author Christophe Beyls
*/ */
public class HttpUtils { public class HttpUtils {
@ -43,9 +43,9 @@ public class HttpUtils {
}); });
// Trust all HTTPS certificates // Trust all HTTPS certificates
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() { public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[] {}; return new java.security.cert.X509Certificate[]{};
} }
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
@ -53,7 +53,7 @@ public class HttpUtils {
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
} }
} }; }};
try { try {
SSLContext sc = SSLContext.getInstance("TLS"); SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom()); sc.init(null, trustAllCerts, new java.security.SecureRandom());
@ -63,44 +63,67 @@ public class HttpUtils {
} }
} }
public static class HttpResult {
// Will be null when the local content is up-to-date
public InputStream inputStream;
public String lastModified;
}
public static InputStream get(Context context, String path) throws IOException { public static InputStream get(Context context, String path) throws IOException {
return get(context, new URL(path), null, null); return get(context, new URL(path), null, null, null).inputStream;
} }
public static InputStream get(Context context, String path, String progressAction, String progressExtra) throws IOException { public static HttpResult get(Context context, String path, String lastModified,
return get(context, new URL(path), progressAction, progressExtra); String progressAction, String progressExtra) throws IOException {
return get(context, new URL(path), lastModified, progressAction, progressExtra);
} }
public static InputStream get(final Context context, URL url, final String progressAction, final String progressExtra) throws IOException { public static HttpResult get(final Context context, URL url, String lastModified,
final String progressAction, final String progressExtra) throws IOException {
HttpResult result = new HttpResult();
HttpURLConnection connection = (HttpURLConnection) url.openConnection(); HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setReadTimeout(DEFAULT_TIMEOUT); connection.setReadTimeout(DEFAULT_TIMEOUT);
connection.setConnectTimeout(DEFAULT_TIMEOUT); connection.setConnectTimeout(DEFAULT_TIMEOUT);
if (lastModified != null) {
connection.addRequestProperty("If-Modified-Since", lastModified);
}
connection.connect(); connection.connect();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) { result.lastModified = connection.getHeaderField("Last-Modified");
int responseCode = connection.getResponseCode();
if (responseCode != HttpURLConnection.HTTP_OK) {
connection.disconnect(); connection.disconnect();
throw new IOException("Server returned response code: " + connection.getResponseCode()); if ((responseCode == HttpURLConnection.HTTP_NOT_MODIFIED) && (lastModified != null)) {
// Cached result is still valid; return an empty response
return result;
}
throw new IOException("Server returned response code: " + responseCode);
} }
final int length = connection.getContentLength(); final int length = connection.getContentLength();
InputStream is = new BufferedInputStream(connection.getInputStream()); result.inputStream = new BufferedInputStream(connection.getInputStream());
if ((progressAction == null) || (length == -1)) { if ((progressAction == null) || (length == -1)) {
// No progress support // No progress support
return is; return result;
} }
// Broadcast the progression in percents, with a precision of 1/10 of the total file size // Broadcast the progression in percents, with a precision of 1/10 of the total file size
return new ByteCountInputStream(is, new ByteCountInputStream.ByteCountListener() { result.inputStream = new ByteCountInputStream(result.inputStream,
new ByteCountInputStream.ByteCountListener() {
private LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context); private LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
@Override @Override
public void onNewCount(int byteCount) { public void onNewCount(int byteCount) {
// Cap percent to 100 // Cap percent to 100
int percent = (byteCount >= length) ? 100 : byteCount * 100 / length; int percent = (byteCount >= length) ? 100 : byteCount * 100 / length;
lbm.sendBroadcast(new Intent(progressAction).putExtra(progressExtra, percent)); lbm.sendBroadcast(new Intent(progressAction).putExtra(progressExtra, percent));
} }
}, length / 10); }, length / 10);
return result;
} }
} }

View file

@ -10,6 +10,7 @@
<string name="download_reminder_message">This will update the schedule database to the latest version. Make sure you are connected to the internet.</string> <string name="download_reminder_message">This will update the schedule database to the latest version. Make sure you are connected to the internet.</string>
<string name="never">Never</string> <string name="never">Never</string>
<string name="update_events_db">Update events database</string> <string name="update_events_db">Update events database</string>
<string name="events_download_up_to_date">Database is already up-to-date</string>
<string name="events_download_empty">No new events found</string> <string name="events_download_empty">No new events found</string>
<plurals name="events_download_completed"> <plurals name="events_download_completed">