diff --git a/mobile/com.sap.sailing.android.tracking.app.test-test/src/com/sap/sailing/android/tracking/app/test/CheckinDataTest.java b/mobile/com.sap.sailing.android.tracking.app.test-test/src/com/sap/sailing/android/tracking/app/test/CheckinDataTest.java
new file mode 100644
index 00000000000..0351eb3216d
--- /dev/null
+++ b/mobile/com.sap.sailing.android.tracking.app.test-test/src/com/sap/sailing/android/tracking/app/test/CheckinDataTest.java
@@ -0,0 +1,67 @@
+package com.sap.sailing.android.tracking.app.test;
+
+import com.sap.sailing.android.tracking.app.valueobjects.CheckinData;
+import com.sap.sailing.android.tracking.app.valueobjects.CompetitorInfo;
+import com.sap.sailing.android.tracking.app.valueobjects.EventInfo;
+import com.sap.sailing.android.tracking.app.valueobjects.LeaderboardInfo;
+
+import junit.framework.TestCase;
+
+public class CheckinDataTest extends TestCase {
+
+ private CheckinData checkinData;
+
+ @Override
+ protected void setUp() throws Exception {
+ checkinData = new CheckinData();
+
+ checkinData.leaderboardName = "lt";
+ checkinData.eventId = "et";
+ checkinData.eventName = "ent";
+ checkinData.eventStartDateStr = "123";
+ checkinData.eventEndDateStr = "456";
+ checkinData.eventFirstImageUrl = "http://1.2.3.4/test.png";
+ checkinData.eventServerUrl = "http://5.6.7.8";
+ checkinData.checkinURL = "http://9.1.2.3/checkin";
+ checkinData.competitorCountryCode = "DE";
+ checkinData.competitorName = "cn";
+ checkinData.competitorNationality = "GER";
+ checkinData.competitorSailId = "SAIL 1";
+ checkinData.competitorId = "1-2-3-4";
+ checkinData.deviceUid = "0011223344";
+
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testGetEvent()
+ {
+ EventInfo event = checkinData.getEvent();
+ assertEquals("et", event.id);
+ assertEquals("ent", event.name);
+ assertEquals(123, event.startMillis);
+ assertEquals(456, event.endMillis);
+ assertEquals("http://1.2.3.4/test.png", event.imageUrl);
+ assertEquals("http://5.6.7.8", event.server);
+ }
+
+ public void testGetCompetitor()
+ {
+ CompetitorInfo competitor = checkinData.getCompetitor();
+ assertEquals("DE", competitor.countryCode);
+ assertEquals("cn", competitor.name);
+ assertEquals("GER", competitor.nationality);
+ assertEquals("SAIL 1", competitor.sailId);
+ assertEquals("1-2-3-4", competitor.id);
+ }
+
+ public void testGetLeaderboard()
+ {
+ LeaderboardInfo leaderboard = checkinData.getLeaderboard();
+ assertEquals("lt", leaderboard.name);
+ }
+}
diff --git a/mobile/com.sap.sailing.android.tracking.app/AndroidManifest.xml b/mobile/com.sap.sailing.android.tracking.app/AndroidManifest.xml
index b2e509b56cb..07376d02587 100644
--- a/mobile/com.sap.sailing.android.tracking.app/AndroidManifest.xml
+++ b/mobile/com.sap.sailing.android.tracking.app/AndroidManifest.xml
@@ -52,6 +52,14 @@
+
+
+
@@ -302,18 +302,40 @@
android:layout_alignParentTop="true"
android:background="@color/white_transparent" />
-
+ android:layout_below="@id/white_bar"
+ android:orientation="horizontal" >
+
+
+
+
+
+
+
+
+
+
diff --git a/mobile/com.sap.sailing.android.tracking.app/res/layout/fragment_regatta.xml b/mobile/com.sap.sailing.android.tracking.app/res/layout/fragment_regatta.xml
index 7e9c65c14c2..c3b27fee7d1 100644
--- a/mobile/com.sap.sailing.android.tracking.app/res/layout/fragment_regatta.xml
+++ b/mobile/com.sap.sailing.android.tracking.app/res/layout/fragment_regatta.xml
@@ -287,19 +287,41 @@
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:background="@color/white_transparent" />
-
-
+ android:layout_below="@id/white_bar"
+ android:orientation="horizontal" >
+
+
+
+
+
Scan Race Barcode
GPS Fix Interval
Regatta
+ Leaderboard
GPS Tracker einstellen
Tracking
Hello wörld!
@@ -81,4 +82,5 @@
Kurs
SOG
Keine
+ Leaderboard
\ No newline at end of file
diff --git a/mobile/com.sap.sailing.android.tracking.app/res/values/strings.xml b/mobile/com.sap.sailing.android.tracking.app/res/values/strings.xml
index d5e1be940b4..de6248ca714 100644
--- a/mobile/com.sap.sailing.android.tracking.app/res/values/strings.xml
+++ b/mobile/com.sap.sailing.android.tracking.app/res/values/strings.xml
@@ -21,6 +21,7 @@
Scan Race Barcode
GPS fix interval
Regatta
+ Leader board
Setup GPS-Tracker
Tracking
Hello world!
@@ -68,5 +69,6 @@
Heading
SOG
None
+ Leader board
diff --git a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/services/TrackingService.java b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/services/TrackingService.java
index 2f2db356da6..8fd7fb07987 100644
--- a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/services/TrackingService.java
+++ b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/services/TrackingService.java
@@ -151,11 +151,11 @@ public class TrackingService extends Service implements ConnectionCallbacks,
GPSQuality quality = GPSQuality.noSignal;
if (gpsQualityListener != null) {
- if (gpsAccurracy > 163) {
+ if (gpsAccurracy > 48) {
quality = GPSQuality.poor;
- } else if (gpsAccurracy > 48) {
+ } else if (gpsAccurracy > 10) {
quality = GPSQuality.good;
- } else if (gpsAccurracy < 48) {
+ } else if (gpsAccurracy <= 10) {
quality = GPSQuality.great;
}
diff --git a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/services/TransmittingService.java b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/services/TransmittingService.java
index 8eed352498a..914b3b9a137 100644
--- a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/services/TransmittingService.java
+++ b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/services/TransmittingService.java
@@ -34,87 +34,92 @@ import com.sap.sailing.android.tracking.app.valueobjects.GpsFix;
/**
* Service that handles sending of GPS-fixes (fixes) to the Sailing-API.
*
- * It checks, after a certain time-interval has passed, if any fixes are available in the database
- * and attempts to send them batch-wise.
+ * It checks, after a certain time-interval has passed, if any fixes are
+ * available in the database and attempts to send them batch-wise.
*
- * (There are two strategies for sending, depending on whether tracking is running. If it's running,
- * only fixes for the current event are being sent. If not, it tries to send fixes for previous events,
- * as well. Assuming there are older unsent fixes that for some reason have not been sent.)
+ * (There are two strategies for sending, depending on whether tracking is
+ * running. If it's running, only fixes for the current event are being sent. If
+ * not, it tries to send fixes for previous events, as well. Assuming there are
+ * older unsent fixes that for some reason have not been sent.)
*
- * It keeps track of when the last successful sending occurred and, if no new data is available
- * (i.e., if tracking is disabled), ends itself after a certain period. It relies on being restarted
- * by the {@link TrackingService}.
+ * It keeps track of when the last successful sending occurred and, if no new
+ * data is available (i.e., if tracking is disabled), ends itself after a
+ * certain period. It relies on being restarted by the {@link TrackingService}.
*
- * It also ends itself when connectivity is lost. In that case it relies on being restarted by
- * the {@link ConnectivityChangedReceiver}.
+ * It also ends itself when connectivity is lost. In that case it relies on
+ * being restarted by the {@link ConnectivityChangedReceiver}.
*
- * It switches into a power saving mode, if a certain battery discharge is reached. It does, however,
- * not do so, if the device is plugged in (= when it is charging). The power saving mode causes the
- * time-interval between check- and transmit-cycles to be increased to conserve power.
+ * It switches into a power saving mode, if a certain battery discharge is
+ * reached. It does, however, not do so, if the device is plugged in (= when it
+ * is charging). The power saving mode causes the time-interval between check-
+ * and transmit-cycles to be increased to conserve power.
*
* @author Lukas Zielinski
*
*/
public class TransmittingService extends Service {
-
+
private static final String TAG = TransmittingService.class.getName();
-
+
private final int UPDATE_BATCH_SIZE = 1000;
private final int UPDATE_INTERVAL_DEFAULT = 3000;
private final int UPDATE_INTERVAL_POWERSAVE_MODE = 30000;
- private final long AUTO_END_SERVICE_AFTER_NANO_PASSED = 10000000000L; // 10 sec
+ private final long AUTO_END_SERVICE_AFTER_NANO_PASSED = 10000000000L; // 10
+ // sec
private final float BATTERY_POWER_SAVE_TRESHOLD = 0.2f;
-
+
private int currentUpdateInterval = UPDATE_INTERVAL_DEFAULT;
-
+
private boolean sendingAttempted = false;
private boolean lastTransmissionFailed = false;
private long lastTransmissionTimestamp = 0;
-
+
private AppPreferences prefs;
private Timer timer;
private boolean timerRunning;
-
- private APIConnectivityListener apiConnectivityListener;
- private final IBinder transmittingBinder = new TransmittingBinder();
-
+
+ private APIConnectivityListener apiConnectivityListener;
+ private final IBinder transmittingBinder = new TransmittingBinder();
+
+ /**
+ * True if sending, because if sending takes longer a new attempt should not
+ * be made.
+ */
+ private static boolean currentlySending = false;
+
@Override
public IBinder onBind(Intent intent) {
prefs = new AppPreferences(this);
-
- if (!timerRunning)
- {
+
+ if (!timerRunning) {
startTimer();
}
-
+
return transmittingBinder;
}
-
+
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
-
+
prefs = new AppPreferences(this);
-
+
if (intent != null) {
if (intent.getAction() != null) {
if (intent.getAction().equals(getString(R.string.transmitting_service_start))) {
- if (!timerRunning)
- {
- startTimer();
+ if (!timerRunning) {
+ startTimer();
}
} else {
stopTimer();
}
- }
- else
- {
+ } else {
stopTimer();
}
}
-
+
return Service.START_STICKY;
}
-
+
private void startTimer() {
timer = new Timer();
timer.start();
@@ -122,168 +127,151 @@ public class TransmittingService extends Service {
if (BuildConfig.DEBUG) {
ExLog.i(this, "TIMER", "Background update-timer start");
}
-
+
}
private void stopTimer() {
- if (timer != null)
- {
- timer.stop();
+ if (timer != null) {
+ timer.stop();
timerRunning = false;
if (BuildConfig.DEBUG) {
ExLog.i(this, "TIMER", "Background update-timer stop");
}
-
}
}
-
- private void markSuccessfulTransmission()
- {
+
+ private void markSuccessfulTransmission() {
+ currentlySending = false;
+
if (BuildConfig.DEBUG) {
ExLog.i(this, "TRANSMISSION", "markSuccessfulTransmission");
}
-
+
lastTransmissionFailed = false;
lastTransmissionTimestamp = System.nanoTime();
-
+
reportApiConnectivity(APIConnectivity.reachableTransmissionSuccess);
}
-
- private void markFailedTransmission()
- {
+
+ private void markFailedTransmission() {
+ currentlySending = false;
+
if (BuildConfig.DEBUG) {
ExLog.i(this, "TRANSMISSION", "markFailedTransmission");
}
-
+
lastTransmissionFailed = true;
lastTransmissionTimestamp = 0;
-
- if (isConnected())
- {
+
+ if (isConnected()) {
reportApiConnectivity(APIConnectivity.reachableTransmissionError);
+ } else {
+ reportApiConnectivity(APIConnectivity.notReachable);
}
- else
- {
- reportApiConnectivity(APIConnectivity.notReachable);
- }
-
+
}
-
+
/**
- * If time interval has passed without any transmission, the service can turn
- * itself off. Same for
+ * If time interval has passed without any transmission, the service can
+ * turn itself off. Same for
+ *
* @return
*/
- private boolean serviceCanShutItselfDown()
- {
+ private boolean serviceCanShutItselfDown() {
long currentNanoTime = System.nanoTime();
-
- if (BuildConfig.DEBUG)
- {
+
+ if (BuildConfig.DEBUG) {
ExLog.i(this, "TRANSMISSION", "serviceCanShutItselfDown?");
ExLog.i(this, "TRANSMISSION", "DELTA:" + (currentNanoTime - lastTransmissionTimestamp));
}
-
- // if network is not connected, shutdown. ConnevtivityChangedReceiver should restart us.
- if (!isConnected())
- {
- enabledConnectivityReceiver(); // make sure ConnectivityReceiver is running
+
+ // if network is not connected, shutdown. ConnevtivityChangedReceiver
+ // should restart us.
+ if (!isConnected()) {
+ enabledConnectivityReceiver(); // make sure ConnectivityReceiver is
+ // running
return true;
}
-
- // if we had a failure, never go to sleep until data is sent successfully.
- if (lastTransmissionFailed)
- {
- if (BuildConfig.DEBUG)
- {
- ExLog.i(this, "TRANSMISSION", "returning false, have failed transmission");
+
+ // if we had a failure, never go to sleep until data is sent
+ // successfully.
+ if (lastTransmissionFailed) {
+ if (BuildConfig.DEBUG) {
+ ExLog.i(this, "TRANSMISSION", "returning false, have failed transmission");
}
-
+
return false;
}
-
- if (!sendingAttempted)
- {
- if (BuildConfig.DEBUG)
- {
- ExLog.i(this, "TRANSMISSION", "returning true, no sending attempt");
+
+ if (!sendingAttempted) {
+ if (BuildConfig.DEBUG) {
+ ExLog.i(this, "TRANSMISSION", "returning true, no sending attempt");
}
-
+
return true;
}
-
- if (currentNanoTime - lastTransmissionTimestamp > AUTO_END_SERVICE_AFTER_NANO_PASSED)
- {
- if (BuildConfig.DEBUG)
- {
- ExLog.i(this, "TRANSMISSION", "returning true, timeout");
+
+ if (currentNanoTime - lastTransmissionTimestamp > AUTO_END_SERVICE_AFTER_NANO_PASSED) {
+ if (BuildConfig.DEBUG) {
+ ExLog.i(this, "TRANSMISSION", "returning true, timeout");
}
-
+
return true;
}
-
- if (BuildConfig.DEBUG)
- {
- ExLog.i(this, "TRANSMISSION", "returning false, don't terminate");
+
+ if (BuildConfig.DEBUG) {
+ ExLog.i(this, "TRANSMISSION", "returning false, don't terminate");
}
-
+
return false;
}
-
- private void timerFired()
- {
+
+ private void timerFired() {
float batteryPct = getBatteryPercentage();
- boolean batteryIsCharging = prefs.getBatteryIsCharging();
-
- if ( prefs.getEnergySavingEnabledByUser() ||
- (batteryPct < BATTERY_POWER_SAVE_TRESHOLD && !batteryIsCharging))
- {
- if (BuildConfig.DEBUG)
- {
- ExLog.i(this, "POWER-LEVELS", "in power saving mode");
+ boolean batteryIsCharging = prefs.getBatteryIsCharging();
+
+ if (prefs.getEnergySavingEnabledByUser()
+ || (batteryPct < BATTERY_POWER_SAVE_TRESHOLD && !batteryIsCharging)) {
+ if (BuildConfig.DEBUG) {
+ ExLog.i(this, "POWER-LEVELS", "in power saving mode");
}
-
+
currentUpdateInterval = UPDATE_INTERVAL_POWERSAVE_MODE;
- }
- else
- {
- if (BuildConfig.DEBUG)
- {
- ExLog.i(this, "POWER-LEVELS", "in default power mode");
+ } else {
+ if (BuildConfig.DEBUG) {
+ ExLog.i(this, "POWER-LEVELS", "in default power mode");
}
-
+
currentUpdateInterval = UPDATE_INTERVAL_DEFAULT;
}
-
+
sendFixesToAPI(null);
- reportUnsentGPSFixesCount(DatabaseHelper.getInstance().getNumberOfUnsentGPSFixes(getBaseContext()));
+ reportUnsentGPSFixesCount(DatabaseHelper.getInstance().getNumberOfUnsentGPSFixes(
+ getBaseContext()));
}
-
- private boolean getTrackingServiceIsCurrentlyTracking()
- {
+
+ private boolean getTrackingServiceIsCurrentlyTracking() {
return prefs.getTrackerIsTracking();
}
-
+
private void sendFixesToAPI(List failedHosts) {
-
// first, lets fetch all unsent fixes
- List fixes = DatabaseHelper.getInstance().getUnsentFixes(getBaseContext(), failedHosts, UPDATE_BATCH_SIZE);
+ List fixes = DatabaseHelper.getInstance().getUnsentFixes(getBaseContext(),
+ failedHosts, UPDATE_BATCH_SIZE);
// store ids so we can delete the rows later
ArrayList ids = new ArrayList();
-
+
// create JSON
- JSONArray jsonArray = new JSONArray();
- String currentEventId = null;
- String host = null;
-
- for (GpsFix fix : fixes)
- {
- if (currentEventId == null)
- {
+ JSONArray jsonArray = new JSONArray();
+ String currentEventId = null;
+ String host = null;
+
+ for (GpsFix fix : fixes) {
+ if (currentEventId == null) {
currentEventId = fix.eventId;
host = fix.host;
}
-
+
if (currentEventId.equals(fix.eventId)) {
// still have more unsent Gps-Fixes for this event.
ids.add(String.valueOf(fix.id));
@@ -296,8 +284,7 @@ public class TransmittingService extends Service {
json.put("longitude", fix.longitude);
json.put("latitude", fix.latitude);
} catch (JSONException ex) {
- ExLog.i(this, TAG, "Error while building geolocation json "
- + ex.getMessage());
+ ExLog.i(this, TAG, "Error while building geolocation json " + ex.getMessage());
}
jsonArray.put(json);
@@ -306,197 +293,198 @@ public class TransmittingService extends Service {
// collection, proceed with sending.
break;
}
-
+
}
if (jsonArray.length() > 0) {
// send
-
String[] idsArr = new String[ids.size()];
JSONObject requestObject = new JSONObject();
-
+
try {
requestObject.put("deviceUuid", UniqueDeviceUuid.getUniqueId(this));
requestObject.put("fixes", jsonArray);
} catch (JSONException e) {
e.printStackTrace();
}
-
+
if (BuildConfig.DEBUG) {
ExLog.i(this, TAG, "sending gps fix json: " + requestObject.toString());
- ExLog.i(this, TAG, "url: " + prefs.getServerURL() + prefs.getServerGpsFixesPostPath());
+ ExLog.i(this, TAG,
+ "url: " + prefs.getServerURL() + prefs.getServerGpsFixesPostPath());
}
-
- if (host != null)
- {
- sendingAttempted = true;
-
- JsonObjectOrStatusOnlyRequest request = new JsonObjectOrStatusOnlyRequest(host
- + prefs.getServerGpsFixesPostPath(), requestObject, new FixSubmitListener(
- ids.toArray(idsArr)), new FixSubmitErrorListener(host,
- getTrackingServiceIsCurrentlyTracking(), failedHosts));
-
- VolleyHelper.getInstance(this).addRequest(request);
- }
- else
- {
+
+ if (host != null) {
+ if (currentlySending == true)
+ {
+ ExLog.w(this, TAG, "Warning, can't send fixes, currentlySending flag is set!");
+ }
+ else
+ {
+ currentlySending = true;
+ sendingAttempted = true; // will be set to false in the
+ // listeners
+ JsonObjectOrStatusOnlyRequest request = new JsonObjectOrStatusOnlyRequest(host
+ + prefs.getServerGpsFixesPostPath(), requestObject,
+ new FixSubmitListener(ids.toArray(idsArr)), new FixSubmitErrorListener(
+ host, getTrackingServiceIsCurrentlyTracking(), failedHosts));
+
+ VolleyHelper.getInstance(this).addRequest(request);
+ }
+ } else {
ExLog.w(this, TAG, "Warning, can't send fixes, host is null!");
}
-
+
} else {
-
- if (serviceCanShutItselfDown())
- {
+
+ if (serviceCanShutItselfDown()) {
if (BuildConfig.DEBUG) {
- ExLog.i(this, TAG, "Nothing to send or timeout occurred, Transmitting Service is stopping timer and terminating itself.");
+ ExLog.i(this,
+ TAG,
+ "Nothing to send or timeout occurred, Transmitting Service is stopping timer and terminating itself.");
}
-
+
stopTimer();
stopSelf();
}
}
}
-
+
/**
* Get a count of ALL unsent GPS-fixes.
*
- * This method is only interested in the GPS-fixes for the currently tracked event,
- * and needs to find out the id of that event first.
+ * This method is only interested in the GPS-fixes for the currently tracked
+ * event, and needs to find out the id of that event first.
+ *
* @return
*/
-
- private float getBatteryPercentage()
- {
+
+ private float getBatteryPercentage() {
IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus = this.registerReceiver(null, ifilter);
-
+
int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
- float batteryPct = level / (float)scale;
-
+ float batteryPct = level / (float) scale;
+
if (BuildConfig.DEBUG) {
ExLog.i(this, TAG, "Battery: " + (batteryPct * 100) + "%");
}
-
+
return batteryPct;
}
-
- private void deleteSynced(String[] fixIdStrings)
- {
+
+ private void deleteSynced(String[] fixIdStrings) {
DatabaseHelper.getInstance().deleteGpsFixes(getBaseContext(), fixIdStrings);
}
-
+
/**
- * checks if there is network connectivity
- *
- * @return connectivity check value
- */
- private boolean isConnected() {
- ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
- if (activeNetwork == null) {
- return false;
- }
- return activeNetwork.isConnected();
- }
-
- private void enabledConnectivityReceiver()
- {
- ConnectivityChangedReceiver.enable(this);
- }
-
- /**
- * Report API connectivity to listening activity
- * @param apiConnectivity
- */
- private void reportApiConnectivity( APIConnectivity apiConnectivity )
- {
- if (apiConnectivityListener != null)
- {
- apiConnectivityListener.apiConnectivityUpdated( apiConnectivity );
- }
- }
-
- /**
- * Report the number of currently unsent GPS-fixes
- * @param unsentGPSFixesCount
- */
- private void reportUnsentGPSFixesCount( int unsentGPSFixesCount )
- {
- if (apiConnectivityListener != null)
- {
- apiConnectivityListener.setUnsentGPSFixesCount(unsentGPSFixesCount);
- }
- }
-
-// might need this class in the future:
-//
-// private void markAsSynced(String[] fixIdStrings)
-// {
-// for (String idStr: fixIdStrings)
-// {
-// ContentValues updateValues = new ContentValues();
-// updateValues.put(SensorGps.GPS_SYNCED, 1);
-// Uri uri = ContentUris.withAppendedId(SensorGps.CONTENT_URI, Long.parseLong(idStr));
-// getContentResolver().update(uri, updateValues, null, null);
-// }
-// }
-
-
-
+ * checks if there is network connectivity
+ *
+ * @return connectivity check value
+ */
+ private boolean isConnected() {
+ ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
+ if (activeNetwork == null) {
+ return false;
+ }
+ return activeNetwork.isConnected();
+ }
+
+ private void enabledConnectivityReceiver() {
+ ConnectivityChangedReceiver.enable(this);
+ }
+
+ /**
+ * Report API connectivity to listening activity
+ *
+ * @param apiConnectivity
+ */
+ private void reportApiConnectivity(APIConnectivity apiConnectivity) {
+ if (apiConnectivityListener != null) {
+ apiConnectivityListener.apiConnectivityUpdated(apiConnectivity);
+ }
+ }
+
+ /**
+ * Report the number of currently unsent GPS-fixes
+ *
+ * @param unsentGPSFixesCount
+ */
+ private void reportUnsentGPSFixesCount(int unsentGPSFixesCount) {
+ if (apiConnectivityListener != null) {
+ apiConnectivityListener.setUnsentGPSFixesCount(unsentGPSFixesCount);
+ }
+ }
+
+ // might need this class in the future:
+ //
+ // private void markAsSynced(String[] fixIdStrings)
+ // {
+ // for (String idStr: fixIdStrings)
+ // {
+ // ContentValues updateValues = new ContentValues();
+ // updateValues.put(SensorGps.GPS_SYNCED, 1);
+ // Uri uri = ContentUris.withAppendedId(SensorGps.CONTENT_URI,
+ // Long.parseLong(idStr));
+ // getContentResolver().update(uri, updateValues, null, null);
+ // }
+ // }
+
private class FixSubmitListener implements Listener {
- private String[] ids;
+ private String[] ids;
- public FixSubmitListener(String[] ids) {
- this.ids = ids;
- }
-
- @Override
- public void onResponse(JSONObject response) {
- deleteSynced(ids);
- markSuccessfulTransmission();
- //markAsSynced(ids);
- }
- }
-
- private class FixSubmitErrorListener implements ErrorListener {
-
- private String host;
- private List failedHosts;
- private boolean currentlyTracking = false;
-
- public FixSubmitErrorListener(String host, boolean currentlyTracking, List failedHosts) {
- this.failedHosts = failedHosts;
- this.host = host;
- this.currentlyTracking = true;
+ public FixSubmitListener(String[] ids) {
+ this.ids = ids;
}
-
- @Override
- public void onErrorResponse(VolleyError error) {
- markFailedTransmission();
- ExLog.e(TransmittingService.this, TAG, "Error while sending GPS fix " + error.getMessage());
-
- if (!currentlyTracking)
- {
- if (failedHosts == null)
- {
- failedHosts = new ArrayList();
- failedHosts.add(host);
- }
-
- sendFixesToAPI(this.failedHosts);
- ExLog.i(TransmittingService.this, TAG, "Retrying resend step with this failed hosts list: " + failedHosts);
- }
- }
- }
-
+
+ @Override
+ public void onResponse(JSONObject response) {
+ deleteSynced(ids);
+ markSuccessfulTransmission();
+ // markAsSynced(ids);
+ }
+ }
+
+ private class FixSubmitErrorListener implements ErrorListener {
+ private String host;
+ private List failedHosts;
+ private boolean currentlyTracking = false;
+
+ public FixSubmitErrorListener(String host, boolean currentlyTracking,
+ List failedHosts) {
+ this.failedHosts = failedHosts;
+ this.host = host;
+ this.currentlyTracking = true;
+ }
+
+ @Override
+ public void onErrorResponse(VolleyError error) {
+ markFailedTransmission();
+ ExLog.e(TransmittingService.this, TAG,
+ "Error while sending GPS fix " + error.getMessage());
+
+ if (!currentlyTracking) {
+ if (failedHosts == null) {
+ failedHosts = new ArrayList();
+ failedHosts.add(host);
+ }
+
+ sendFixesToAPI(this.failedHosts);
+ ExLog.i(TransmittingService.this, TAG,
+ "Retrying resend step with this failed hosts list: " + failedHosts);
+ }
+ }
+ }
+
class Timer implements Runnable {
public Thread t;
public volatile boolean endExecution;
-
+
@Override
public void run() {
while (!endExecution) {
@@ -505,7 +493,7 @@ public class TransmittingService extends Service {
} catch (InterruptedException e) {
e.printStackTrace();
}
-
+
timerFired();
}
reportApiConnectivity(APIConnectivity.noAttempt);
@@ -518,50 +506,45 @@ public class TransmittingService extends Service {
t.start();
}
}
-
+
public void stop() {
endExecution = true;
}
}
-
- public void registerAPIConnectivityListener( APIConnectivityListener listener )
- {
+
+ public void registerAPIConnectivityListener(APIConnectivityListener listener) {
apiConnectivityListener = listener;
}
-
- public void unregisterAPIConnectivityListener()
- {
+
+ public void unregisterAPIConnectivityListener() {
apiConnectivityListener = null;
}
-
+
public class TransmittingBinder extends Binder {
public TransmittingService getService() {
return TransmittingService.this;
}
}
-
+
public enum APIConnectivity {
- notReachable (0),
- reachableTransmissionSuccess (1),
- reachableTransmissionError (2),
- noAttempt (4);
-
+ notReachable(0), reachableTransmissionSuccess(1), reachableTransmissionError(2), noAttempt(
+ 4);
+
private final int apiConnectivity;
-
- APIConnectivity(int connectivity)
- {
+
+ APIConnectivity(int connectivity) {
this.apiConnectivity = connectivity;
}
-
- public int toInt()
- {
+
+ public int toInt() {
return this.apiConnectivity;
}
}
-
+
public interface APIConnectivityListener {
- public void apiConnectivityUpdated( APIConnectivity apiConnectivity );
- public void setUnsentGPSFixesCount( int count );
+ public void apiConnectivityUpdated(APIConnectivity apiConnectivity);
+
+ public void setUnsentGPSFixesCount(int count);
}
-
+
}
diff --git a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/LeaderboardWebViewActivity.java b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/LeaderboardWebViewActivity.java
new file mode 100644
index 00000000000..64d7e43c64c
--- /dev/null
+++ b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/LeaderboardWebViewActivity.java
@@ -0,0 +1,45 @@
+package com.sap.sailing.android.tracking.app.ui.activities;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v7.widget.Toolbar;
+
+import com.sap.sailing.android.tracking.app.R;
+import com.sap.sailing.android.tracking.app.ui.fragments.LeaderboardFragment;
+
+public class LeaderboardWebViewActivity extends BaseActivity {
+
+ public final static String LEADERBOARD_EXTRA_SERVER_URL = "leaderboardExtraServerUrl";
+ public final static String LEADERBOARD_EXTRA_EVENT_ID = "leaderboardExtraEventId";
+ public final static String LEADERBOARD_EXTRA_LEADERBOARD_NAME = "leaderboardExtraLeaderboardName";
+
+ public String serverUrl;
+ public String eventId;
+ public String leaderboardName;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Intent intent = getIntent();
+ serverUrl = intent.getStringExtra(LEADERBOARD_EXTRA_SERVER_URL);
+ eventId = intent.getStringExtra(LEADERBOARD_EXTRA_EVENT_ID);
+ leaderboardName = intent.getStringExtra(LEADERBOARD_EXTRA_LEADERBOARD_NAME);
+
+ setContentView(R.layout.fragment_container);
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ if (toolbar != null) {
+ setSupportActionBar(toolbar);
+ toolbar.setBackgroundColor(getResources().getColor(R.color.colorPrimary));
+ }
+ if (getSupportActionBar() != null) {
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setHomeButtonEnabled(true);
+ toolbar.setNavigationIcon(R.drawable.sap_logo_64_sq);
+ toolbar.setPadding(20, 0, 0, 0);
+ getSupportActionBar().setTitle(getString(R.string.title_activity_webview));
+ }
+
+ replaceFragment(R.id.content_frame, new LeaderboardFragment());
+ }
+}
diff --git a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/RegattaActivity.java b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/RegattaActivity.java
index 4ebbeca3c54..19113f174a4 100644
--- a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/RegattaActivity.java
+++ b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/RegattaActivity.java
@@ -45,10 +45,11 @@ import com.sap.sailing.android.tracking.app.valueobjects.LeaderboardInfo;
public class RegattaActivity extends BaseActivity {
private final static String TAG = RegattaActivity.class.getName();
+ private final static String LEADERBOARD_IMAGE_FILENAME_PREFIX = "leaderboardImage_";
- private EventInfo event;
- private CompetitorInfo competitor;
- private LeaderboardInfo leaderboard;
+ public EventInfo event;
+ public CompetitorInfo competitor;
+ public LeaderboardInfo leaderboard;
@Override
@@ -85,7 +86,6 @@ public class RegattaActivity extends BaseActivity {
}
replaceFragment(R.id.content_frame, new RegattaFragment());
-
}
@Override
@@ -102,10 +102,6 @@ public class RegattaActivity extends BaseActivity {
ExLog.i(this, TAG, "Clicked SETTINGS.");
startActivity(new Intent(this, SettingsActivity.class));
return true;
-// case R.id.options_menu_info:
-// ExLog.i(this, TAG, "Clicked INFO.");
-// startActivity(new Intent(this, SystemInformationActivity.class));
-// return true;
case R.id.options_menu_checkout:
ExLog.i(this, TAG, "Clicked CHECKOUT.");
checkout();
@@ -153,21 +149,22 @@ public class RegattaActivity extends BaseActivity {
}
getRegattaFragment().setChangePhotoButtonHidden(true);
+ ExLog.w(this, TAG, "Event Image URL: " + event.imageUrl);
- if (event.imageUrl != null)
+ ImageView imageView = (ImageView) findViewById(R.id.userImage);
+ Bitmap storedImage = getStoredImage(getLeaderboardImageFileName(leaderboard.name));
+
+ if (storedImage == null)
{
- ImageView imageView = (ImageView) findViewById(R.id.userImage);
- Bitmap storedImage = getStoredImage();
- if (storedImage != null)
- {
- imageView.setImageBitmap(storedImage);
- userImageUpdated();
- }
- else
- {
- new DownloadImageTask(imageView).execute(event.imageUrl);
- }
-
+ if (event.imageUrl != null)
+ {
+ new DownloadImageTask(imageView).execute(event.imageUrl);
+ }
+ }
+ else
+ {
+ imageView.setImageBitmap(storedImage);
+ userImageUpdated();
}
super.onResume();
@@ -177,9 +174,9 @@ public class RegattaActivity extends BaseActivity {
*
* @param bitmap
*/
- public void updatePictureChosenByUser(final Bitmap bitmap)
+ public void updateLeaderboardPictureChosenByUser(final Bitmap bitmap)
{
- storeImage(bitmap);
+ storeImage(bitmap, getLeaderboardImageFileName(leaderboard.name));
runOnUiThread(new Runnable() {
@Override
@@ -196,8 +193,8 @@ public class RegattaActivity extends BaseActivity {
* Store image for quicker retrieval later.
* @param images
*/
- private void storeImage(Bitmap image) {
- File pictureFile = getMediaFile();
+ private void storeImage(Bitmap image, String fileName) {
+ File pictureFile = getImageFile(fileName);
if (pictureFile == null) {
Log.d(TAG,
"Error creating media file, check storage permissions: ");// e.getMessage());
@@ -215,12 +212,12 @@ public class RegattaActivity extends BaseActivity {
}
/**
- * Get leaderboard image if there's one saved.
+ * Get stored image if there's one saved.
* @return
*/
- private Bitmap getStoredImage()
+ private Bitmap getStoredImage(String fileName)
{
- File pictureFile = getMediaFile();
+ File pictureFile = getImageFile(fileName);
if (pictureFile == null)
{
return null;
@@ -228,21 +225,44 @@ public class RegattaActivity extends BaseActivity {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
- Bitmap image = BitmapFactory.decodeFile(pictureFile.getAbsolutePath(),
- options);
+ Bitmap image = BitmapFactory.decodeFile(pictureFile.getAbsolutePath(), options);
return image;
}
+
+// private File getMediaFile(){
+//
+//
+// }
+
/**
* Get Path for cached leaderbaord image.
* @return
*/
- private File getMediaFile(){
+ public File getImageFile(String fileName) {
- File mediaStorageDir;
+ File mediaStorageDir = getMediaStorageDir();
- if (Environment.MEDIA_MOUNTED.equals(Environment
- .getExternalStorageState())) {
+ File mediaFile;
+ String mImageName="MI_"+ fileName +".png";
+ mediaFile = new File(mediaStorageDir.getPath() + File.separator + mImageName);
+ return mediaFile;
+ }
+
+ public void deleteImageFile(String fileName) {
+ File mediaStorageDir = getMediaStorageDir();
+
+ File mediaFile;
+ String mImageName = "MI_" + fileName + ".png";
+ mediaFile = new File(mediaStorageDir.getPath() + File.separator + mImageName);
+
+ mediaFile.delete();
+ }
+
+ public File getMediaStorageDir() {
+ File mediaStorageDir;
+
+ if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
mediaStorageDir = new File(
Environment.getExternalStorageDirectory()
+ "/Android/data/"
@@ -257,12 +277,9 @@ public class RegattaActivity extends BaseActivity {
return null;
}
}
-
- File mediaFile;
- String mImageName="MI_"+ leaderboard.name +".png";
- mediaFile = new File(mediaStorageDir.getPath() + File.separator + mImageName);
- return mediaFile;
- }
+
+ return mediaStorageDir;
+ }
private class DownloadImageTask extends AsyncTask {
ImageView bmImage;
@@ -274,6 +291,7 @@ public class RegattaActivity extends BaseActivity {
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap mIcon11 = null;
+
try {
InputStream in = new java.net.URL(urldisplay).openStream();
mIcon11 = BitmapFactory.decodeStream(in);
@@ -285,11 +303,15 @@ public class RegattaActivity extends BaseActivity {
protected void onPostExecute(Bitmap result) {
bmImage.setImageBitmap(result);
- storeImage(result);
+ storeImage(result, getLeaderboardImageFileName(leaderboard.name));
userImageUpdated();
}
}
+ private String getLeaderboardImageFileName(String leaderboardName) {
+ return LEADERBOARD_IMAGE_FILENAME_PREFIX + leaderboardName;
+ }
+
/**
* Check out from regatta;
*/
@@ -320,6 +342,7 @@ public class RegattaActivity extends BaseActivity {
public void onResponse(JSONObject response) {
DatabaseHelper.getInstance().deleteRegattaFromDatabase(
RegattaActivity.this, event, competitor, leaderboard);
+ deleteImageFile(getLeaderboardImageFileName(leaderboard.name));
dismissProgressDialog();
finish();
}
@@ -331,15 +354,23 @@ public class RegattaActivity extends BaseActivity {
showErrorPopup(
R.string.error,
R.string.error_could_not_complete_operation_on_server_try_again);
-
}
});
VolleyHelper.getInstance(this).addRequest(checkoutRequest);
}
- public EventInfo getEvent()
- {
- return event;
+ @Override
+ public void onBackPressed() {
+ RegattaFragment fragment = (RegattaFragment) getSupportFragmentManager().findFragmentById(R.id.content_frame);
+
+ if (fragment.isShowingBigCheckoutButton())
+ {
+ //do nothing, user must checkout himself at this point.
+ }
+ else
+ {
+ super.onBackPressed();
+ }
}
}
diff --git a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/TrackingActivity.java b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/TrackingActivity.java
index 2535c94e10f..08dfa5f8eaf 100644
--- a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/TrackingActivity.java
+++ b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/activities/TrackingActivity.java
@@ -14,9 +14,7 @@ import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.support.v7.widget.Toolbar;
-import android.view.MotionEvent;
import android.widget.TextView;
-import android.widget.Toast;
import com.sap.sailing.android.shared.logging.ExLog;
import com.sap.sailing.android.tracking.app.BuildConfig;
@@ -52,6 +50,9 @@ public class TrackingActivity extends BaseActivity implements GPSQualityListener
private final static String TAG = TrackingActivity.class.getName();
private final static String SIS_TRACKING_FRAGMENT = "savedInstanceTrackingFragment";
+ private final static String SIS_LAST_VIEWPAGER_ITEM = "instanceStateLastViewPagerItem";
+ private final static String SIS_LAST_SPEED_TEXT = "instanceStateLastSpeedText";
+ private final static String SIS_LAST_COMPASS_TEXT = "instanceStateLastCompassText";
private ViewPager mPager;
private ScreenSlidePagerAdapter mPagerAdapter;
@@ -59,9 +60,20 @@ public class TrackingActivity extends BaseActivity implements GPSQualityListener
private String eventId;
private AppPreferences prefs;
- private TrackingFragment trackingFragment;
-
+ private TrackingFragment trackingFragment;
private TimerRunnable timer;
+
+ private int lastViewPagerItem;
+
+ /**
+ * This isn't nice. The callbacks for fragments inside a
+ * view pager are unreliable, but I want the values
+ * to be displayed immediately after device rotation.
+ * Thus they are cached here and the fragments can pick
+ * them up.
+ */
+ public String lastSpeedIndicatorText = "";
+ public String lastCompassIndicatorText = "";
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -101,12 +113,8 @@ public class TrackingActivity extends BaseActivity implements GPSQualityListener
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
}
mPager.setAdapter(mPagerAdapter);
- mPager.setOffscreenPageLimit(3);
+ mPager.setOffscreenPageLimit(0);
- // ok, here be dragons.
- // however, I haven't found out how the ViewPager retains and dismisses fragments, so I check for every case.
- // The easy way (if savedInstanceState != null) takeFromBundle(); doesn't work, since only some fragments are
- // saved to the bundle it seems.
if (savedInstanceState != null) {
Fragment tFragment = getSupportFragmentManager().getFragment(savedInstanceState, SIS_TRACKING_FRAGMENT);
if (tFragment != null) {
@@ -114,6 +122,10 @@ public class TrackingActivity extends BaseActivity implements GPSQualityListener
} else {
trackingFragment = new TrackingFragment();
}
+
+ lastViewPagerItem = savedInstanceState.getInt(SIS_LAST_VIEWPAGER_ITEM);
+ lastSpeedIndicatorText = savedInstanceState.getString(SIS_LAST_SPEED_TEXT);
+ lastCompassIndicatorText = savedInstanceState.getString(SIS_LAST_COMPASS_TEXT);
} else {
trackingFragment = new TrackingFragment();
}
@@ -125,6 +137,7 @@ public class TrackingActivity extends BaseActivity implements GPSQualityListener
@Override
public void onPageSelected(int arg0) {
+ lastViewPagerItem = arg0;
}
@Override
@@ -140,23 +153,17 @@ public class TrackingActivity extends BaseActivity implements GPSQualityListener
ServiceHelper.getInstance().startTrackingService(this, eventId);
}
- @Override
- public void onWindowFocusChanged(boolean hasFocus) {
- super.onWindowFocusChanged(hasFocus);
- // HudFragment hudFragment = (HudFragment)
- // getSupportFragmentManager().findFragmentById(R.id.hud_content_frame);
- // hudFragment.layoutOverlay();
- //
- // hudFragment.setSpeedOverGround(0);
- // hudFragment.setHeading(0);
- }
-
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
+
+ outState.putInt(SIS_LAST_VIEWPAGER_ITEM, lastViewPagerItem);
+ outState.putString(SIS_LAST_SPEED_TEXT, lastSpeedIndicatorText);
+ outState.putString(SIS_LAST_COMPASS_TEXT, lastCompassIndicatorText);
+
if (trackingFragment.isAdded()) {
getSupportFragmentManager().putFragment(outState, SIS_TRACKING_FRAGMENT, trackingFragment);
- }
+ }
}
@Override
@@ -219,7 +226,9 @@ public class TrackingActivity extends BaseActivity implements GPSQualityListener
{
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
}
+
mPager.setAdapter(mPagerAdapter);
+ mPager.setCurrentItem(lastViewPagerItem);
}
@Override
@@ -367,14 +376,6 @@ public class TrackingActivity extends BaseActivity implements GPSQualityListener
return 3;
}
-// public StopTrackingButtonFragment getStopTrackingButtonFragment() {
-// if (stbFragment != null && stbFragment.isAdded())
-// {
-// return stbFragment;
-// }
-// else return null;
-// }
-
public CompassFragment getCompassFragment() {
if (cFragment != null && cFragment.isAdded())
{
diff --git a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/CompassFragment.java b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/CompassFragment.java
index 32f20886dd7..b69432b3203 100644
--- a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/CompassFragment.java
+++ b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/CompassFragment.java
@@ -7,11 +7,11 @@ import android.view.ViewGroup;
import android.widget.TextView;
import com.sap.sailing.android.tracking.app.R;
+import com.sap.sailing.android.tracking.app.ui.activities.TrackingActivity;
public class CompassFragment extends BaseFragment {
- private String TAG = CompassFragment.class.getName();
- private final String SIS_HEADING_TEXTIVEW = "CompassFragmentHeadingTextView";
+ //private String TAG = CompassFragment.class.getName();
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
@@ -25,6 +25,12 @@ public class CompassFragment extends BaseFragment {
{
TextView headingText = (TextView) getActivity().findViewById(R.id.compass_bearing_text_view);
headingText.setText(String.valueOf(Math.round(heading)) + "°");
+
+ TrackingActivity activity = (TrackingActivity) getActivity();
+
+ if (activity != null) {
+ activity.lastCompassIndicatorText = headingText.getText().toString();
+ }
}
}
@@ -32,20 +38,12 @@ public class CompassFragment extends BaseFragment {
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
TextView headingText = (TextView)getActivity().findViewById(R.id.compass_bearing_text_view);
- if (savedInstanceState != null)
- {
- headingText.setText(savedInstanceState.getString(SIS_HEADING_TEXTIVEW));
+
+ TrackingActivity activity = (TrackingActivity) getActivity();
+ if (activity != null) {
+ headingText.setText(activity.lastCompassIndicatorText);
+ } else {
+ headingText.setText("");
}
- else
- {
- headingText.setText("---°");
- }
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- TextView headingText = (TextView)getActivity().findViewById(R.id.compass_bearing_text_view);
- outState.putString(SIS_HEADING_TEXTIVEW, headingText.getText().toString());
- }
+ }
}
diff --git a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/HomeFragment.java b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/HomeFragment.java
index 98223ffb57f..8abef5d0fbe 100644
--- a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/HomeFragment.java
+++ b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/HomeFragment.java
@@ -2,7 +2,6 @@ package com.sap.sailing.android.tracking.app.ui.fragments;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
-import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
@@ -14,19 +13,13 @@ import org.json.JSONObject;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
-import android.content.ContentProviderOperation;
-import android.content.ContentResolver;
-import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.OperationApplicationException;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
-import android.os.RemoteException;
-import android.provider.BaseColumns;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
@@ -49,17 +42,17 @@ import com.sap.sailing.android.tracking.app.BuildConfig;
import com.sap.sailing.android.tracking.app.R;
import com.sap.sailing.android.tracking.app.adapter.RegattaAdapter;
import com.sap.sailing.android.tracking.app.provider.AnalyticsContract;
-import com.sap.sailing.android.tracking.app.provider.AnalyticsContract.Competitor;
import com.sap.sailing.android.tracking.app.provider.AnalyticsContract.Event;
-import com.sap.sailing.android.tracking.app.provider.AnalyticsContract.Leaderboard;
import com.sap.sailing.android.tracking.app.ui.activities.RegattaActivity;
import com.sap.sailing.android.tracking.app.ui.activities.StartActivity;
import com.sap.sailing.android.tracking.app.utils.AppPreferences;
import com.sap.sailing.android.tracking.app.utils.CheckinHelper;
import com.sap.sailing.android.tracking.app.utils.DatabaseHelper;
+import com.sap.sailing.android.tracking.app.utils.DatabaseHelper.GeneralDatabaseHelperException;
import com.sap.sailing.android.tracking.app.utils.JsonObjectOrStatusOnlyRequest;
import com.sap.sailing.android.tracking.app.utils.UniqueDeviceUuid;
import com.sap.sailing.android.tracking.app.utils.VolleyHelper;
+import com.sap.sailing.android.tracking.app.valueobjects.CheckinData;
import com.sap.sailing.domain.racelog.tracking.DeviceIdentifier;
import com.sap.sailing.domain.racelog.tracking.impl.SmartphoneUUIDIdentifierImpl;
@@ -83,8 +76,6 @@ public class HomeFragment extends BaseFragment implements
prefs = new AppPreferences(getActivity());
- getActivity().getContentResolver();
-
View view = inflater.inflate(R.layout.fragment_home, container, false);
Button scanButton = (Button) view.findViewById(R.id.scanQr);
@@ -103,8 +94,7 @@ public class HomeFragment extends BaseFragment implements
listView.addHeaderView(inflater.inflate(
R.layout.regatta_listview_header, null));
- adapter = new RegattaAdapter(getActivity(),
- R.layout.ragatta_listview_row, null, 0);
+ adapter = new RegattaAdapter(getActivity(), R.layout.ragatta_listview_row, null, 0);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new ItemClickListener());
}
@@ -184,17 +174,13 @@ public class HomeFragment extends BaseFragment implements
String leaderboardNameFromQR;
try {
- leaderboardNameFromQR = URLEncoder.encode(
- uri.getQueryParameter(CheckinHelper.LEADERBOARD_NAME),
- "UTF-8").replace("+", "%20");
+ leaderboardNameFromQR = URLEncoder.encode(uri.getQueryParameter(CheckinHelper.LEADERBOARD_NAME),"UTF-8").replace("+", "%20");
} catch (UnsupportedEncodingException e) {
- ExLog.e(getActivity(), TAG, "Failed to encode leaderboard name: "
- + e.getMessage());
+ ExLog.e(getActivity(), TAG, "Failed to encode leaderboard name: " + e.getMessage());
leaderboardNameFromQR = "";
}
- final String competitorId = uri
- .getQueryParameter(CheckinHelper.COMPETITOR_ID);
+ final String competitorId = uri.getQueryParameter(CheckinHelper.COMPETITOR_ID);
final String checkinURLStr = prefs.getServerURL()
+ prefs.getServerCheckinPath().replace("{leaderboard-name}",
leaderboardNameFromQR);
@@ -435,30 +421,6 @@ public class HomeFragment extends BaseFragment implements
alert.show();
}
- /**
- * Return true if the combination of eventId, leaderboardName and
- * competitorId does not exist in the DB.
- *
- * @param eventId
- * @param leaderboardName
- * @param competitorId
- * @return
- */
- private boolean eventLeaderboardCompetitorCombnationAvailable(
- String eventId, String leaderboardName, String competitorId) {
-
- ContentResolver cr = getActivity().getContentResolver();
- String sel = "leaderboards.leaderboard_name = \"" + leaderboardName
- + "\" AND competitors.competitor_id = \"" + competitorId
- + "\" AND events.event_id = \"" + eventId + "\"";
-
- int count = cr.query(
- AnalyticsContract.EventLeaderboardCompetitorJoined.CONTENT_URI,
- null, sel, null, null).getCount();
-
- return count == 0;
- }
-
/**
* Perform a checkin request and launch RegattaAcitivity afterwards
*
@@ -468,74 +430,21 @@ public class HomeFragment extends BaseFragment implements
*/
private void checkInWithAPIAndDisplayTrackingActivity(
CheckinData checkinData) {
- if (eventLeaderboardCompetitorCombnationAvailable(checkinData.eventId,
- checkinData.leaderboardName, checkinData.competitorId)) {
-
- // inserting leaderboard first in order to get the ID.
- // This should be atomic, but couldn't get withValueBackReference to
- // work yet.
-
- ContentResolver cr = getActivity().getContentResolver();
-
- ContentValues clv = new ContentValues();
- clv.put(Leaderboard.LEADERBOARD_NAME, checkinData.leaderboardName);
- cr.insert(Leaderboard.CONTENT_URI, clv);
-
- Cursor cur = cr.query(Leaderboard.CONTENT_URI, null, null, null, null);
- long lastLeaderboardId = 0;
-
- if (cur.moveToLast()) {
- lastLeaderboardId = cur.getLong(cur
- .getColumnIndex(BaseColumns._ID));
- }
-
- cur.close();
-
- // now, with the leaderboard id, insert event and competitor
- // todo: fix this so its atomic.
-
- ArrayList opList = new ArrayList();
-
- ContentValues cev = new ContentValues();
- cev.put(Event.EVENT_ID, checkinData.eventId);
- cev.put(Event.EVENT_NAME, checkinData.eventName);
- cev.put(Event.EVENT_DATE_START, Long.parseLong(checkinData.eventStartDateStr));
- cev.put(Event.EVENT_DATE_END, Long.parseLong(checkinData.eventEndDateStr));
- cev.put(Event.EVENT_SERVER, checkinData.eventServerUrl);
- cev.put(Event.EVENT_IMAGE_URL, checkinData.eventFirstImageUrl);
- cev.put(Event.EVENT_LEADERBOARD_FK, lastLeaderboardId);
-
- opList.add(ContentProviderOperation.newInsert(Event.CONTENT_URI)
- .withValues(cev).build());
-
- ContentValues ccv = new ContentValues();
-
- ccv.put(Competitor.COMPETITOR_COUNTRY_CODE,checkinData.competitorCountryCode);
- ccv.put(Competitor.COMPETITOR_DISPLAY_NAME,checkinData.competitorName);
- ccv.put(Competitor.COMPETITOR_ID, checkinData.competitorId);
- ccv.put(Competitor.COMPETITOR_NATIONALITY,checkinData.competitorNationality);
- ccv.put(Competitor.COMPETITOR_SAIL_ID, checkinData.competitorSailId);
- ccv.put(Competitor.COMPETITOR_LEADERBOARD_FK, lastLeaderboardId);
-
- opList.add(ContentProviderOperation
- .newInsert(Competitor.CONTENT_URI).withValues(ccv).build());
+ if (DatabaseHelper.getInstance().eventLeaderboardCompetitorCombnationAvailable(
+ getActivity(), checkinData.eventId, checkinData.leaderboardName, checkinData.competitorId)) {
try {
- cr.applyBatch(AnalyticsContract.CONTENT_AUTHORITY, opList);
+ DatabaseHelper.getInstance().storeCheckinRow(getActivity(), checkinData.getEvent(),
+ checkinData.getCompetitor(), checkinData.getLeaderboard());
adapter.notifyDataSetChanged();
- } catch (RemoteException e1) {
- ExLog.e(getActivity(), TAG, "Batch insert failed: " + e1.getMessage());
- displayDatabaseError();
- return;
- } catch (OperationApplicationException e1) {
- ExLog.e(getActivity(), TAG, "Batch insert failed: " + e1.getMessage());
+ } catch (GeneralDatabaseHelperException e) {
+ ExLog.e(getActivity(), TAG, "Batch insert failed: " + e.getMessage());
displayDatabaseError();
return;
}
if (BuildConfig.DEBUG) {
- ExLog.i(getActivity(), TAG,
- "Batch-insert of checkinData completed.");
+ ExLog.i(getActivity(), TAG, "Batch-insert of checkinData completed.");
}
} else {
ExLog.w(getActivity(), TAG,
@@ -554,7 +463,6 @@ public class HomeFragment extends BaseFragment implements
Date date = new Date();
StartActivity startActivity = (StartActivity)getActivity();
-
startActivity.showProgressDialog(R.string.please_wait, R.string.checking_in);
try {
@@ -625,8 +533,7 @@ public class HomeFragment extends BaseFragment implements
* @param regattaName
* @param eventName
*/
- private void startRegatta(String leaderboardName, String eventId,
- String competitorId) {
+ private void startRegatta(String leaderboardName, String eventId, String competitorId) {
Intent intent = new Intent(getActivity(), RegattaActivity.class);
intent.putExtra(getString(R.string.leaderboard_name), leaderboardName);
intent.putExtra(getString(R.string.event_id), eventId);
@@ -638,7 +545,8 @@ public class HomeFragment extends BaseFragment implements
public Loader onCreateLoader(int loaderId, Bundle bundle) {
switch (loaderId) {
case REGATTA_LOADER:
- String[] projection = new String[] { "events.event_id",
+ String[] projection = new String[] {
+ "events.event_id",
"events._id", "events.event_name", "events.event_server",
"competitors.competitor_display_name",
"competitors.competitor_id",
@@ -678,25 +586,7 @@ public class HomeFragment extends BaseFragment implements
break;
}
}
-
- private class CheckinData {
- // public String gcmId;
- public String leaderboardName;
- public String eventId;
- public String eventName;
- public String eventStartDateStr;
- public String eventEndDateStr;
- public String eventFirstImageUrl;
- public String eventServerUrl;
- public String checkinURL;
- public String competitorName;
- public String competitorId;
- public String competitorSailId;
- public String competitorNationality;
- public String competitorCountryCode;
- public String deviceUid;
- }
-
+
private class ClickListener implements OnClickListener {
@Override
@@ -757,6 +647,7 @@ public class HomeFragment extends BaseFragment implements
public void onResponse(JSONObject response) {
StartActivity startActivity = (StartActivity)getActivity();
startActivity.dismissProgressDialog();
+
startRegatta(leaderboardName, eventId, competitorId);
}
}
diff --git a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/LeaderboardFragment.java b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/LeaderboardFragment.java
new file mode 100644
index 00000000000..6c3abce3e4d
--- /dev/null
+++ b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/LeaderboardFragment.java
@@ -0,0 +1,67 @@
+package com.sap.sailing.android.tracking.app.ui.fragments;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import android.annotation.SuppressLint;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.Toast;
+import com.sap.sailing.android.shared.logging.ExLog;
+import com.sap.sailing.android.tracking.app.R;
+import com.sap.sailing.android.tracking.app.ui.activities.LeaderboardWebViewActivity;
+
+public class LeaderboardFragment extends BaseFragment {
+
+ private static final String TAG = LeaderboardFragment.class.getName();
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ super.onCreateView(inflater, container, savedInstanceState);
+
+ View view = inflater.inflate(R.layout.fragment_leaderboard, container, false);
+ return view;
+ }
+
+ @SuppressLint("SetJavaScriptEnabled")
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ WebView webview = (WebView)getActivity().findViewById(R.id.web_view);
+
+ WebSettings webSettings = webview.getSettings();
+ webSettings.setJavaScriptEnabled(true);
+
+ webview.setWebViewClient(new WebViewClient() {
+ public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
+ Toast.makeText(getActivity(), description, Toast.LENGTH_SHORT).show();
+ }
+ });
+
+ try {
+ String url = getLeaderboardURL();
+ webview.loadUrl(url);
+ } catch (UnsupportedEncodingException e) {
+ LeaderboardWebViewActivity activity = (LeaderboardWebViewActivity)getActivity();
+ activity.showErrorPopup(R.string.error, R.string.error_could_not_complete_operation_on_server_try_again);
+ ExLog.e(getActivity(), TAG, "UnsupportedEncodingException when creating leaderboard-url: " + e);
+ }
+ }
+
+ private String getLeaderboardURL() throws UnsupportedEncodingException
+ {
+ LeaderboardWebViewActivity activity = (LeaderboardWebViewActivity)getActivity();
+ String eventId = URLEncoder.encode(activity.eventId, "UTF-8");
+ String leaderboardName = URLEncoder.encode(activity.leaderboardName, "UTF-8");
+ String serverUrl = activity.serverUrl;
+
+ String formatString = "%s/gwt/Home.html#LeaderboardPlace:eventId=%s" +
+ "&leaderboardName=%s&showRaceDetails=true&showSettings=true";
+ return String.format(formatString, serverUrl, eventId, leaderboardName);
+ }
+}
diff --git a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/RegattaFragment.java b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/RegattaFragment.java
index 39de24932eb..a1b93f740a2 100644
--- a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/RegattaFragment.java
+++ b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/RegattaFragment.java
@@ -1,6 +1,8 @@
package com.sap.sailing.android.tracking.app.ui.fragments;
+import java.io.File;
import java.io.FileNotFoundException;
+import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;
@@ -24,7 +26,10 @@ import android.widget.RelativeLayout;
import android.widget.TextView;
import com.sap.sailing.android.shared.logging.ExLog;
+import com.sap.sailing.android.tracking.app.BuildConfig;
import com.sap.sailing.android.tracking.app.R;
+import com.sap.sailing.android.tracking.app.provider.AnalyticsContract.Event;
+import com.sap.sailing.android.tracking.app.ui.activities.LeaderboardWebViewActivity;
import com.sap.sailing.android.tracking.app.ui.activities.RegattaActivity;
import com.sap.sailing.android.tracking.app.ui.activities.TrackingActivity;
@@ -34,7 +39,11 @@ public class RegattaFragment extends BaseFragment implements OnClickListener {
private final int CAMERA_REQUEST_CODE = 3118;
private final int SELECT_PHOTO_REQUEST_CODE = 1693;
-
+ private final int IMAGE_MAX_SIZE = 2000;
+
+ private final String CAMERA_TEMP_FILE = "cameraTempFile";
+
+
private boolean showingThankYouNote;
private TimerRunnable timer;
@@ -48,6 +57,9 @@ public class RegattaFragment extends BaseFragment implements OnClickListener {
Button startTrackingButton = (Button) view.findViewById(R.id.start_tracking);
startTrackingButton.setOnClickListener(this);
+
+ Button showLeaderboardButton = (Button) view.findViewById(R.id.show_leaderboards_button);
+ showLeaderboardButton.setOnClickListener(this);
Button changePhotoButton = (Button) view.findViewById(R.id.change_photo_button);
changePhotoButton.setOnClickListener(this);
@@ -63,7 +75,7 @@ public class RegattaFragment extends BaseFragment implements OnClickListener {
private void checkAndSwitchToThankYouScreenIfRegattaOver() {
RegattaActivity regattaActivity = (RegattaActivity) getActivity();
- long regattaEnd = regattaActivity.getEvent().endMillis;
+ long regattaEnd = regattaActivity.event.endMillis;
if (System.currentTimeMillis() > regattaEnd) {
switchToThankYouScreen();
@@ -77,7 +89,7 @@ public class RegattaFragment extends BaseFragment implements OnClickListener {
TextView textView = (TextView)getActivity().findViewById(R.id.regatta_starts_in);
RegattaActivity regattaActivity = (RegattaActivity) getActivity();
- long regattaStart = regattaActivity.getEvent().startMillis;
+ long regattaStart = regattaActivity.event.startMillis;
LinearLayout threeBoxesLayout = (LinearLayout) getActivity()
.findViewById(R.id.three_boxes_regatta_starts);
@@ -94,6 +106,10 @@ public class RegattaFragment extends BaseFragment implements OnClickListener {
}
}
+ public boolean isShowingBigCheckoutButton() {
+ return showingThankYouNote;
+ }
+
private void switchToThankYouScreen() {
showingThankYouNote = true;
@@ -130,6 +146,9 @@ public class RegattaFragment extends BaseFragment implements OnClickListener {
@Override
public void onClick(View view) {
switch (view.getId()) {
+ case R.id.show_leaderboards_button:
+ startLeaderboardActivity();
+ break;
case R.id.start_tracking:
if (showingThankYouNote) {
RegattaActivity regattaActivity = (RegattaActivity) getActivity();
@@ -198,6 +217,8 @@ public class RegattaFragment extends BaseFragment implements OnClickListener {
private void showTakePhotoActivity() {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+ File photoFile = ((RegattaActivity)getActivity()).getImageFile(CAMERA_TEMP_FILE);
+ cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
startActivityForResult(cameraIntent, CAMERA_REQUEST_CODE);
}
@@ -207,39 +228,99 @@ public class RegattaFragment extends BaseFragment implements OnClickListener {
RegattaActivity activity = (RegattaActivity) getActivity();
if (requestCode == CAMERA_REQUEST_CODE) {
- Bitmap photo = (Bitmap) data.getExtras().get("data");
- activity.updatePictureChosenByUser(photo);
+ File photoFile = ((RegattaActivity)getActivity()).getImageFile(CAMERA_TEMP_FILE);
+ Bitmap photo;
+ try {
+ photo = decodeUri(Uri.fromFile(photoFile));
+ activity.updateLeaderboardPictureChosenByUser(photo);
+ } catch (FileNotFoundException e) {
+ if (BuildConfig.DEBUG)
+ {
+ ExLog.i(getActivity(), TAG, "update photo, file not found: " + photoFile);
+ }
+ } catch (IOException e) {
+ if (BuildConfig.DEBUG)
+ {
+ ExLog.i(getActivity(), TAG, "update photo, io exception: " + e.getMessage());
+ }
+ } finally {
+ ((RegattaActivity)getActivity()).deleteFile(CAMERA_TEMP_FILE);
+ }
} else if (requestCode == SELECT_PHOTO_REQUEST_CODE) {
Uri selectedImage = data.getData();
- InputStream imageStream;
+
try {
- imageStream = getActivity().getContentResolver()
- .openInputStream(selectedImage);
- Bitmap photo = BitmapFactory.decodeStream(imageStream);
- activity.updatePictureChosenByUser(photo);
+ Bitmap photo = decodeUri(selectedImage);
+ activity.updateLeaderboardPictureChosenByUser(photo);
} catch (FileNotFoundException e) {
ExLog.e(getActivity(), TAG,
"File not found exception after picking image from gallery");
- return;
+ } catch (IOException e) {
+ if (BuildConfig.DEBUG)
+ {
+ ExLog.i(getActivity(), TAG, "update photo, io exception: " + e.getMessage());
+ }
}
}
}
super.onActivityResult(requestCode, resultCode, data);
}
+
+ /**
+ * Decode image with maximum size
+ * @param uri
+ * @return
+ * @throws IOException
+ */
+ private Bitmap decodeUri(Uri uri) throws IOException{
+ Bitmap bitmap = null;
+
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+
+ InputStream fis = getActivity().getContentResolver().openInputStream(uri);
+ BitmapFactory.decodeStream(fis, null, options);
+ fis.close();
+
+ int scale = 1;
+ if (options.outHeight > IMAGE_MAX_SIZE || options.outWidth > IMAGE_MAX_SIZE) {
+ scale = (int)Math.pow(2, (int) Math.ceil(Math.log(IMAGE_MAX_SIZE /
+ (double) Math.max(options.outHeight, options.outWidth)) / Math.log(0.5)));
+ }
+
+ BitmapFactory.Options options2 = new BitmapFactory.Options();
+ options2.inSampleSize = scale;
+ fis = getActivity().getContentResolver().openInputStream(uri);
+ bitmap = BitmapFactory.decodeStream(fis, null, options2);
+ fis.close();
+
+ return bitmap;
+ }
+
+ private void startLeaderboardActivity() {
+ RegattaActivity activity = (RegattaActivity)getActivity();
+
+ Intent intent = new Intent(getActivity(), LeaderboardWebViewActivity.class);
+ intent.putExtra(LeaderboardWebViewActivity.LEADERBOARD_EXTRA_SERVER_URL, activity.event.server);
+ intent.putExtra(LeaderboardWebViewActivity.LEADERBOARD_EXTRA_EVENT_ID, activity.event.id);
+ intent.putExtra(LeaderboardWebViewActivity.LEADERBOARD_EXTRA_LEADERBOARD_NAME, activity.leaderboard.name);
+
+ getActivity().startActivity(intent);
+ }
private void startTrackingActivity() {
RegattaActivity regattaActivity = (RegattaActivity) getActivity();
Intent intent = new Intent(getActivity(), TrackingActivity.class);
intent.putExtra(
getString(R.string.tracking_activity_event_id_parameter),
- regattaActivity.getEvent().id);
+ regattaActivity.event.id);
getActivity().startActivity(intent);
}
private void timerFired() {
RegattaActivity regattaActivity = (RegattaActivity) getActivity();
- updateCountdownTimer(regattaActivity.getEvent().startMillis);
+ updateCountdownTimer(regattaActivity.event.startMillis);
}
private void updateCountdownTimer(long startTime) {
@@ -258,19 +339,13 @@ public class RegattaFragment extends BaseFragment implements OnClickListener {
}
private void setCountdownTime(int days, int hours, int minutes) {
- TextView daysTextView = (TextView) getActivity().findViewById(
- R.id.starts_in_days);
- TextView hoursTextView = (TextView) getActivity().findViewById(
- R.id.starts_in_hours);
- TextView minutesTextView = (TextView) getActivity().findViewById(
- R.id.starts_in_minutes);
+ TextView daysTextView = (TextView) getActivity().findViewById(R.id.starts_in_days);
+ TextView hoursTextView = (TextView) getActivity().findViewById(R.id.starts_in_hours);
+ TextView minutesTextView = (TextView) getActivity().findViewById(R.id.starts_in_minutes);
- TextView daysTextViewLabel = (TextView) getActivity().findViewById(
- R.id.starts_in_days_label);
- TextView hoursTextViewLabel = (TextView) getActivity().findViewById(
- R.id.starts_in_hours_label);
- TextView minutesTextViewLabel = (TextView) getActivity().findViewById(
- R.id.starts_in_minutes_label);
+ TextView daysTextViewLabel = (TextView) getActivity().findViewById(R.id.starts_in_days_label);
+ TextView hoursTextViewLabel = (TextView) getActivity().findViewById(R.id.starts_in_hours_label);
+ TextView minutesTextViewLabel = (TextView) getActivity().findViewById(R.id.starts_in_minutes_label);
daysTextView.setText(String.format("%02d", days));
hoursTextView.setText(String.format("%02d", hours));
diff --git a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/SpeedFragment.java b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/SpeedFragment.java
index ad548d7345a..1b690336b14 100644
--- a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/SpeedFragment.java
+++ b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/SpeedFragment.java
@@ -11,22 +11,20 @@ import android.view.ViewGroup;
import android.widget.TextView;
import com.sap.sailing.android.tracking.app.R;
+import com.sap.sailing.android.tracking.app.ui.activities.TrackingActivity;
public class SpeedFragment extends BaseFragment {
- private String TAG = SpeedFragment.class.getName();
- private final String SIS_SPEED_TEXTIVEW = "SpeedFragmentSpeedTextView";
+ //private String TAG = SpeedFragment.class.getName();
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
- ViewGroup view = (ViewGroup) inflater.inflate(R.layout.fragment_speed, container, false);
+ ViewGroup view = (ViewGroup) inflater.inflate(R.layout.fragment_speed, container, false);
return view;
}
- public void setSpeed(float speedInMetersPerSecond)
- {
- if (isAdded())
- {
+ public void setSpeed(float speedInMetersPerSecond) {
+ if (isAdded()) {
float speedInKnots = speedInMetersPerSecond * 1.9438444924574f;
NumberFormat df = DecimalFormat.getInstance();
@@ -34,30 +32,29 @@ public class SpeedFragment extends BaseFragment {
df.setMaximumFractionDigits(2);
df.setRoundingMode(RoundingMode.HALF_UP);
String formattedSpeed = df.format(speedInKnots);
-
+
TextView speedText = (TextView) getActivity().findViewById(R.id.speed_text_view);
speedText.setText(formattedSpeed + "kn");
+ TrackingActivity activity = (TrackingActivity) getActivity();
+
+ if (activity != null) {
+ activity.lastSpeedIndicatorText = speedText.getText().toString();
+ }
}
}
-
+
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- TextView speedText = (TextView)getActivity().findViewById(R.id.speed_text_view);
- if (savedInstanceState != null)
- {
- speedText.setText(savedInstanceState.getString(SIS_SPEED_TEXTIVEW));
- }
- else
- {
- speedText.setText("--kn");
+
+ TextView speedText = (TextView) getActivity().findViewById(R.id.speed_text_view);
+
+ TrackingActivity activity = (TrackingActivity) getActivity();
+ if (activity != null) {
+ speedText.setText(activity.lastSpeedIndicatorText);
+ } else {
+ speedText.setText("");
}
+
}
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- TextView speedText = (TextView)getActivity().findViewById(R.id.speed_text_view);
- outState.putString(SIS_SPEED_TEXTIVEW, speedText.getText().toString());
- }
-}
+}
\ No newline at end of file
diff --git a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/TrackingFragment.java b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/TrackingFragment.java
index 6591c258642..8669ed34e85 100644
--- a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/TrackingFragment.java
+++ b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/ui/fragments/TrackingFragment.java
@@ -31,7 +31,6 @@ public class TrackingFragment extends BaseFragment {
static final String SIS_GPS_ACCURACY = "instanceStateGpsAccuracy";
static final String SIS_GPS_UNSENT_FIXES = "instanceStateGpsUnsentFixes";
-
private AppPreferences prefs;
private long lastGPSQualityUpdate;
@@ -247,11 +246,8 @@ public class TrackingFragment extends BaseFragment {
{
unsentGpsFixesTextView.setText(String.valueOf(count));
}
-
}
});
}
}
-
-
}
diff --git a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/utils/DatabaseHelper.java b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/utils/DatabaseHelper.java
index 546fee4981e..388085368dd 100644
--- a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/utils/DatabaseHelper.java
+++ b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/utils/DatabaseHelper.java
@@ -3,16 +3,20 @@ package com.sap.sailing.android.tracking.app.utils;
import java.util.ArrayList;
import java.util.List;
+import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
+import android.content.OperationApplicationException;
import android.database.Cursor;
import android.net.Uri;
+import android.os.RemoteException;
import android.provider.BaseColumns;
import com.sap.sailing.android.shared.logging.ExLog;
import com.sap.sailing.android.tracking.app.BuildConfig;
+import com.sap.sailing.android.tracking.app.provider.AnalyticsContract;
import com.sap.sailing.android.tracking.app.provider.AnalyticsContract.Competitor;
import com.sap.sailing.android.tracking.app.provider.AnalyticsContract.Event;
import com.sap.sailing.android.tracking.app.provider.AnalyticsContract.EventGpsFixesJoined;
@@ -195,18 +199,19 @@ public class DatabaseHelper {
return result;
}
- public EventInfo getEventInfo(Context context, String eventId) {
+ public EventInfo getEventInfo(Context context, String eventId) {
EventInfo event = new EventInfo();
event.id = eventId;
Cursor cursor = context.getContentResolver().query(Event.CONTENT_URI,
- null, "event_id = \"" + eventId + "\"", null, null);
+ null, "event_id = \"" + eventId + "\"", null, null);
if (cursor.moveToFirst()) {
event.name = cursor.getString(cursor.getColumnIndex(Event.EVENT_NAME));
event.imageUrl = cursor.getString(cursor.getColumnIndex(Event.EVENT_IMAGE_URL));
event.startMillis = cursor.getLong(cursor.getColumnIndex(Event.EVENT_DATE_START));
event.endMillis = cursor.getLong(cursor.getColumnIndex(Event.EVENT_DATE_END));
+ event.server = cursor.getString(cursor.getColumnIndex(Event.EVENT_SERVER));
event.rowId = cursor.getInt(cursor.getColumnIndex(BaseColumns._ID));
}
@@ -277,4 +282,107 @@ public class DatabaseHelper {
ExLog.i(context, TAG, "Checkout, number of leaderbards deleted: " + d3);
}
}
+
+ /**
+ * Attempt to check in to a race.
+ *
+ * @param context
+ * @param event
+ * @param competitor
+ * @param leaderboard
+ * @return success or failure
+ * @throws GeneralDatabaseHelperException
+ * @throws OperationApplicationException
+ * @throws RemoteException
+ */
+ public void storeCheckinRow(Context context, EventInfo event, CompetitorInfo competitor,
+ LeaderboardInfo leaderboard) throws GeneralDatabaseHelperException {
+
+ // inserting leaderboard first in order to get the ID.
+ // This should be atomic, but couldn't get withValueBackReference to
+ // work yet.
+
+ ContentResolver cr = context.getContentResolver();
+
+ ContentValues clv = new ContentValues();
+ clv.put(Leaderboard.LEADERBOARD_NAME, leaderboard.name);
+ cr.insert(Leaderboard.CONTENT_URI, clv);
+
+ Cursor cur = cr.query(Leaderboard.CONTENT_URI, null, null, null, null);
+ long lastLeaderboardId = 0;
+
+ if (cur.moveToLast()) {
+ lastLeaderboardId = cur.getLong(cur.getColumnIndex(BaseColumns._ID));
+ }
+
+ cur.close();
+
+ // now, with the leaderboard id, insert event and competitor
+ // todo: fix this so its atomic.
+
+ ArrayList opList = new ArrayList();
+
+ ContentValues cev = new ContentValues();
+ cev.put(Event.EVENT_ID, event.id);
+ cev.put(Event.EVENT_NAME, event.name);
+ cev.put(Event.EVENT_DATE_START, event.startMillis);
+ cev.put(Event.EVENT_DATE_END, event.endMillis);
+ cev.put(Event.EVENT_SERVER, event.server);
+ cev.put(Event.EVENT_IMAGE_URL, event.imageUrl);
+ cev.put(Event.EVENT_LEADERBOARD_FK, lastLeaderboardId);
+
+ opList.add(ContentProviderOperation.newInsert(Event.CONTENT_URI).withValues(cev).build());
+
+ ContentValues ccv = new ContentValues();
+
+ ccv.put(Competitor.COMPETITOR_COUNTRY_CODE, competitor.countryCode);
+ ccv.put(Competitor.COMPETITOR_DISPLAY_NAME, competitor.name);
+ ccv.put(Competitor.COMPETITOR_ID, competitor.id);
+ ccv.put(Competitor.COMPETITOR_NATIONALITY, competitor.nationality);
+ ccv.put(Competitor.COMPETITOR_SAIL_ID, competitor.sailId);
+ ccv.put(Competitor.COMPETITOR_LEADERBOARD_FK, lastLeaderboardId);
+
+ opList.add(ContentProviderOperation.newInsert(Competitor.CONTENT_URI).withValues(ccv).build());
+
+ try {
+ cr.applyBatch(AnalyticsContract.CONTENT_AUTHORITY, opList);
+ } catch (RemoteException e) {
+ throw new GeneralDatabaseHelperException(e.getMessage());
+ } catch (OperationApplicationException e) {
+ throw new GeneralDatabaseHelperException(e.getMessage());
+ }
+ }
+
+ /**
+ * Return true if the combination of eventId, leaderboardName and
+ * competitorId does not exist in the DB.
+ *
+ * @param eventId
+ * @param leaderboardName
+ * @param competitorId
+ * @return
+ */
+ public boolean eventLeaderboardCompetitorCombnationAvailable(Context context,
+ String eventId, String leaderboardName, String competitorId) {
+
+ ContentResolver cr = context.getContentResolver();
+ String sel = "leaderboards.leaderboard_name = \"" + leaderboardName
+ + "\" AND competitors.competitor_id = \"" + competitorId
+ + "\" AND events.event_id = \"" + eventId + "\"";
+
+ int count = cr.query(
+ AnalyticsContract.EventLeaderboardCompetitorJoined.CONTENT_URI,
+ null, sel, null, null).getCount();
+
+ return count == 0;
+ }
+
+ public class GeneralDatabaseHelperException extends Exception {
+ private static final long serialVersionUID = 4333494334720305541L;
+
+ public GeneralDatabaseHelperException(String message) {
+ super(message);
+ }
+ }
+
}
diff --git a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/utils/ImageController.java b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/utils/ImageController.java
new file mode 100644
index 00000000000..b4e41f7e717
--- /dev/null
+++ b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/utils/ImageController.java
@@ -0,0 +1,495 @@
+package com.sap.sailing.android.tracking.app.utils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.media.ExifInterface;
+import android.net.Uri;
+import android.provider.MediaStore;
+import android.util.Base64;
+
+/**
+ * Todo: Use this class?
+ *
+ */
+public class ImageController {
+
+ public static String getRealPathFromURI(ContentResolver contentResolver,
+ Uri contentUri) {
+ String res = null;
+ String[] proj = { MediaStore.Images.Media.DATA };
+ Cursor cursor = contentResolver.query(contentUri, proj, null, null,
+ null);
+ if (cursor.moveToFirst()) {
+ int column_index = cursor
+ .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
+ res = cursor.getString(column_index);
+ }
+ cursor.close();
+ return res;
+ }
+
+ // -----------------------------------------------------------------------
+
+ public static Bitmap scaleCenterCrop(Bitmap source, int newWidth,
+ int newHeight) {
+ int sourceWidth = source.getWidth();
+ int sourceHeight = source.getHeight();
+
+ // Compute the scaling factors to fit the new height and width,
+ // respectively.
+ // To cover the final image, the final scaling will be the bigger
+ // of these two.
+ float xScale = (float) newWidth / sourceWidth;
+ float yScale = (float) newHeight / sourceHeight;
+ float scale = Math.max(xScale, yScale);
+
+ // Now get the size of the source bitmap when scaled
+ float scaledWidth = scale * sourceWidth;
+ float scaledHeight = scale * sourceHeight;
+
+ // Let's find out the upper left coordinates if the scaled bitmap
+ // should be centered in the new size give by the parameters
+ float left = (newWidth - scaledWidth) / 2;
+ float top = (newHeight - scaledHeight) / 2;
+
+ // The target rectangle for the new, scaled version of the source bitmap
+ // will now
+ // be
+ RectF targetRect = new RectF(left, top, left + scaledWidth, top
+ + scaledHeight);
+
+ // Finally, we create a new bitmap of the specified size and draw our
+ // new,
+ // scaled bitmap onto it.
+ Bitmap dest = Bitmap.createBitmap(newWidth, newHeight,
+ source.getConfig());
+ Canvas canvas = new Canvas(dest);
+ canvas.drawBitmap(source, null, targetRect, null);
+
+ return dest;
+ }
+
+ public static Bitmap scaleBitmap(Bitmap bitmap, int newWidth, int newHeight) {
+ Bitmap scaledBitmap = Bitmap.createBitmap(newWidth, newHeight,
+ Config.ARGB_8888);
+
+ float ratioX = newWidth / (float) bitmap.getWidth();
+ float ratioY = newHeight / (float) bitmap.getHeight();
+ float middleX = newWidth / 2.0f;
+ float middleY = newHeight / 2.0f;
+
+ Matrix scaleMatrix = new Matrix();
+ scaleMatrix.setScale(ratioX, ratioY, middleX, middleY);
+
+ Canvas canvas = new Canvas(scaledBitmap);
+ canvas.setMatrix(scaleMatrix);
+ float left = middleX - (float) bitmap.getWidth() / 2;
+ float top = middleY - (float) bitmap.getHeight() / 2;
+ canvas.drawBitmap(bitmap, left, top,
+ new Paint(Paint.FILTER_BITMAP_FLAG));
+ return scaledBitmap;
+ }
+
+ public static Bitmap scaleBitmapAspectRatio(Bitmap bitmap, int targetWidth,
+ int targetHeight) {
+ float ratioX = targetWidth / (float) bitmap.getWidth();
+ float ratioY = targetHeight / (float) bitmap.getHeight();
+ float aspectRatio = (float) bitmap.getWidth() / bitmap.getHeight();
+ if (ratioX < ratioY) {
+ aspectRatio = ratioX;
+ } else {
+ aspectRatio = ratioY;
+ }
+ int newWidth = Math.round(bitmap.getWidth() * aspectRatio);
+ if (newWidth < 1) {
+ newWidth = 1;
+ }
+ int newHeight = Math.round(bitmap.getHeight() * aspectRatio);
+ if (newHeight < 1) {
+ newHeight = 1;
+ }
+ return scaleBitmap(bitmap, newWidth, newHeight);
+ }
+
+ // -----------------------------------------------------------------------
+
+ // http://stackoverflow.com/a/10028267
+ public static Bitmap fastblur(Bitmap sentBitmap, int radius) {
+
+ // Stack Blur v1.0 from
+ // http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
+ //
+ // Java Author: Mario Klingemann
+ // http://incubator.quasimondo.com
+ // created Feburary 29, 2004
+ // Android port : Yahel Bouaziz
+ // http://www.kayenko.com
+ // ported april 5th, 2012
+
+ // This is a compromise between Gaussian Blur and Box blur
+ // It creates much better looking blurs than Box Blur, but is
+ // 7x faster than my Gaussian Blur implementation.
+ //
+ // I called it Stack Blur because this describes best how this
+ // filter works internally: it creates a kind of moving stack
+ // of colors whilst scanning through the image. Thereby it
+ // just has to add one new block of color to the right side
+ // of the stack and remove the leftmost color. The remaining
+ // colors on the topmost layer of the stack are either added on
+ // or reduced by one, depending on if they are on the right or
+ // on the left side of the stack.
+ //
+ // If you are using this algorithm in your code please add
+ // the following line:
+ //
+ // Stack Blur Algorithm by Mario Klingemann
+
+ Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
+
+ if (radius < 1) {
+ return (null);
+ }
+
+ int w = bitmap.getWidth();
+ int h = bitmap.getHeight();
+
+ int[] pix = new int[w * h];
+ bitmap.getPixels(pix, 0, w, 0, 0, w, h);
+
+ int wm = w - 1;
+ int hm = h - 1;
+ int wh = w * h;
+ int div = radius + radius + 1;
+
+ int r[] = new int[wh];
+ int g[] = new int[wh];
+ int b[] = new int[wh];
+ int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
+ int vmin[] = new int[Math.max(w, h)];
+
+ int divsum = (div + 1) >> 1;
+ divsum *= divsum;
+ int dv[] = new int[256 * divsum];
+ for (i = 0; i < 256 * divsum; i++) {
+ dv[i] = (i / divsum);
+ }
+
+ yw = yi = 0;
+
+ int[][] stack = new int[div][3];
+ int stackpointer;
+ int stackstart;
+ int[] sir;
+ int rbs;
+ int r1 = radius + 1;
+ int routsum, goutsum, boutsum;
+ int rinsum, ginsum, binsum;
+
+ for (y = 0; y < h; y++) {
+ rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
+ for (i = -radius; i <= radius; i++) {
+ p = pix[yi + Math.min(wm, Math.max(i, 0))];
+ sir = stack[i + radius];
+ sir[0] = (p & 0xff0000) >> 16;
+ sir[1] = (p & 0x00ff00) >> 8;
+ sir[2] = (p & 0x0000ff);
+ rbs = r1 - Math.abs(i);
+ rsum += sir[0] * rbs;
+ gsum += sir[1] * rbs;
+ bsum += sir[2] * rbs;
+ if (i > 0) {
+ rinsum += sir[0];
+ ginsum += sir[1];
+ binsum += sir[2];
+ } else {
+ routsum += sir[0];
+ goutsum += sir[1];
+ boutsum += sir[2];
+ }
+ }
+ stackpointer = radius;
+
+ for (x = 0; x < w; x++) {
+
+ r[yi] = dv[rsum];
+ g[yi] = dv[gsum];
+ b[yi] = dv[bsum];
+
+ rsum -= routsum;
+ gsum -= goutsum;
+ bsum -= boutsum;
+
+ stackstart = stackpointer - radius + div;
+ sir = stack[stackstart % div];
+
+ routsum -= sir[0];
+ goutsum -= sir[1];
+ boutsum -= sir[2];
+
+ if (y == 0) {
+ vmin[x] = Math.min(x + radius + 1, wm);
+ }
+ p = pix[yw + vmin[x]];
+
+ sir[0] = (p & 0xff0000) >> 16;
+ sir[1] = (p & 0x00ff00) >> 8;
+ sir[2] = (p & 0x0000ff);
+
+ rinsum += sir[0];
+ ginsum += sir[1];
+ binsum += sir[2];
+
+ rsum += rinsum;
+ gsum += ginsum;
+ bsum += binsum;
+
+ stackpointer = (stackpointer + 1) % div;
+ sir = stack[(stackpointer) % div];
+
+ routsum += sir[0];
+ goutsum += sir[1];
+ boutsum += sir[2];
+
+ rinsum -= sir[0];
+ ginsum -= sir[1];
+ binsum -= sir[2];
+
+ yi++;
+ }
+ yw += w;
+ }
+ for (x = 0; x < w; x++) {
+ rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
+ yp = -radius * w;
+ for (i = -radius; i <= radius; i++) {
+ yi = Math.max(0, yp) + x;
+
+ sir = stack[i + radius];
+
+ sir[0] = r[yi];
+ sir[1] = g[yi];
+ sir[2] = b[yi];
+
+ rbs = r1 - Math.abs(i);
+
+ rsum += r[yi] * rbs;
+ gsum += g[yi] * rbs;
+ bsum += b[yi] * rbs;
+
+ if (i > 0) {
+ rinsum += sir[0];
+ ginsum += sir[1];
+ binsum += sir[2];
+ } else {
+ routsum += sir[0];
+ goutsum += sir[1];
+ boutsum += sir[2];
+ }
+
+ if (i < hm) {
+ yp += w;
+ }
+ }
+ yi = x;
+ stackpointer = radius;
+ for (y = 0; y < h; y++) {
+ // Preserve alpha channel: ( 0xff000000 & pix[yi] )
+ pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16)
+ | (dv[gsum] << 8) | dv[bsum];
+
+ rsum -= routsum;
+ gsum -= goutsum;
+ bsum -= boutsum;
+
+ stackstart = stackpointer - radius + div;
+ sir = stack[stackstart % div];
+
+ routsum -= sir[0];
+ goutsum -= sir[1];
+ boutsum -= sir[2];
+
+ if (x == 0) {
+ vmin[y] = Math.min(y + r1, hm) * w;
+ }
+ p = x + vmin[y];
+
+ sir[0] = r[p];
+ sir[1] = g[p];
+ sir[2] = b[p];
+
+ rinsum += sir[0];
+ ginsum += sir[1];
+ binsum += sir[2];
+
+ rsum += rinsum;
+ gsum += ginsum;
+ bsum += binsum;
+
+ stackpointer = (stackpointer + 1) % div;
+ sir = stack[stackpointer];
+
+ routsum += sir[0];
+ goutsum += sir[1];
+ boutsum += sir[2];
+
+ rinsum -= sir[0];
+ ginsum -= sir[1];
+ binsum -= sir[2];
+
+ yi += w;
+ }
+ }
+
+ bitmap.setPixels(pix, 0, w, 0, 0, w, h);
+
+ return (bitmap);
+ }
+
+ // -----------------------------------------------------------------------
+
+ // http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
+ public static int calculateInSampleSize(BitmapFactory.Options options,
+ int reqWidth, int reqHeight) {
+ // Raw height and width of image
+ final int height = options.outHeight;
+ final int width = options.outWidth;
+ int inSampleSize = 1;
+
+ if (height > reqHeight || width > reqWidth) {
+
+ final int halfHeight = height / 2;
+ final int halfWidth = width / 2;
+
+ // Calculate the largest inSampleSize value that is a power of 2 and
+ // keeps both
+ // height and width larger than the requested height and width.
+ while ((halfHeight / inSampleSize) > reqHeight
+ && (halfWidth / inSampleSize) > reqWidth) {
+ inSampleSize *= 2;
+ }
+ }
+ return inSampleSize;
+ }
+
+ public static Bitmap decodeSampledBitmapFromFile(
+ ContentResolver contentResolver, Uri uri, String filename,
+ int reqWidth, int reqHeight) {
+
+ // First decode with inJustDecodeBounds=true to check dimensions
+ final BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+ if (filename == null) {
+ try {
+ InputStream inputStream = contentResolver.openInputStream(uri);
+ BitmapFactory.decodeStream(inputStream, null, options);
+ } catch (IOException e) {
+
+ }
+ } else {
+ BitmapFactory.decodeFile(filename, options);
+
+ }
+ // Calculate inSampleSize
+ options.inSampleSize = calculateInSampleSize(options, reqWidth,
+ reqHeight);
+
+ // Decode bitmap with inSampleSize set
+ options.inJustDecodeBounds = false;
+ Bitmap bitmap = null;
+ if (filename == null) {
+ try {
+ InputStream inputStream = contentResolver.openInputStream(uri);
+ bitmap = BitmapFactory.decodeStream(inputStream, null, options);
+ } catch (IOException e) {
+
+ }
+ } else {
+ bitmap = BitmapFactory.decodeFile(filename, options);
+ }
+
+ // check orientation
+ if (bitmap != null && filename != null) {
+ try {
+ ExifInterface exif = new ExifInterface(filename);
+ int orientation = exif.getAttributeInt(
+ ExifInterface.TAG_ORIENTATION, 1);
+ int angle = 0;
+
+ switch (orientation) {
+ case ExifInterface.ORIENTATION_ROTATE_90:
+ angle = -90;
+ break;
+ case ExifInterface.ORIENTATION_ROTATE_180:
+ angle = -180;
+ break;
+ case ExifInterface.ORIENTATION_ROTATE_270:
+ angle = -270;
+ break;
+
+ default:
+ break;
+ }
+ if (angle != 0) {
+ Matrix matrix = new Matrix();
+ matrix.postRotate(90);
+ Bitmap rotatedBitmap = Bitmap
+ .createBitmap(bitmap, 0, 0, bitmap.getWidth(),
+ bitmap.getHeight(), matrix, true);
+ bitmap.recycle();
+ bitmap = rotatedBitmap;
+ }
+ } catch (IOException e) {
+
+ }
+ }
+ return bitmap;
+ }
+
+ // -----------------------------------------------------------------------
+
+ // http://stackoverflow.com/a/8557147
+ private final static String[] projection = new String[] {
+ MediaStore.Images.ImageColumns._ID,
+ MediaStore.Images.ImageColumns.DATA,
+ MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
+ MediaStore.Images.ImageColumns.DATE_TAKEN,
+ MediaStore.Images.ImageColumns.MIME_TYPE };
+
+ public static File latestImage(Context context) {
+ final Cursor cursor = context.getContentResolver().query(
+ MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null,
+ null, MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC");
+
+ // Put it in the image view
+ if (cursor.moveToFirst()) {
+ String imageLocation = cursor.getString(1);
+ File imageFile = new File(imageLocation);
+ return imageFile;
+ }
+ return null;
+ }
+
+ // -----------------------------------------------------------------------
+
+ public static String encodeTobase64(Bitmap image) {
+ Bitmap immagex = image;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ immagex.compress(Bitmap.CompressFormat.JPEG, 60, baos);
+ byte[] b = baos.toByteArray();
+ String imageEncoded = Base64.encodeToString(b, Base64.NO_WRAP);
+ return "data:image/jpeg;base64," + imageEncoded;
+ }
+}
diff --git a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/valueobjects/CheckinData.java b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/valueobjects/CheckinData.java
new file mode 100644
index 00000000000..151851840c6
--- /dev/null
+++ b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/valueobjects/CheckinData.java
@@ -0,0 +1,49 @@
+package com.sap.sailing.android.tracking.app.valueobjects;
+
+public class CheckinData {
+ // public String gcmId;
+ public String leaderboardName;
+ public String eventId;
+ public String eventName;
+ public String eventStartDateStr;
+ public String eventEndDateStr;
+ public String eventFirstImageUrl;
+ public String eventServerUrl;
+ public String checkinURL;
+ public String competitorName;
+ public String competitorId;
+ public String competitorSailId;
+ public String competitorNationality;
+ public String competitorCountryCode;
+ public String deviceUid;
+
+ public EventInfo getEvent()
+ {
+ EventInfo event = new EventInfo();
+ event.name = eventName;
+ event.id = eventId;
+ event.startMillis = Long.parseLong(eventStartDateStr);
+ event.endMillis = Long.parseLong(eventEndDateStr);
+ event.imageUrl = eventFirstImageUrl;
+ event.server = eventServerUrl;
+ return event;
+ }
+
+ public LeaderboardInfo getLeaderboard()
+ {
+ LeaderboardInfo leaderboard = new LeaderboardInfo();
+ leaderboard.name = leaderboardName;
+ return leaderboard;
+ }
+
+ public CompetitorInfo getCompetitor()
+ {
+ CompetitorInfo competitor = new CompetitorInfo();
+ competitor.name = competitorName;
+ competitor.id = competitorId;
+ competitor.sailId = competitorSailId;
+ competitor.nationality = competitorNationality;
+ competitor.countryCode = competitorCountryCode;
+ return competitor;
+ }
+}
\ No newline at end of file
diff --git a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/valueobjects/CompetitorInfo.java b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/valueobjects/CompetitorInfo.java
index 709ccaf365f..f821bc2d9f4 100644
--- a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/valueobjects/CompetitorInfo.java
+++ b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/valueobjects/CompetitorInfo.java
@@ -5,6 +5,7 @@ public class CompetitorInfo {
public String id;
public String name;
public String countryCode;
+ public String nationality;
public String sailId;
public int rowId;
diff --git a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/valueobjects/EventInfo.java b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/valueobjects/EventInfo.java
index 4cad3d70505..e5dd9242f09 100644
--- a/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/valueobjects/EventInfo.java
+++ b/mobile/com.sap.sailing.android.tracking.app/src/com/sap/sailing/android/tracking/app/valueobjects/EventInfo.java
@@ -9,6 +9,7 @@ public class EventInfo {
public long startMillis;
public long endMillis;
public int rowId;
+ public String server;
@Override
public String toString() {
@@ -16,6 +17,6 @@ public class EventInfo {
+ leaderboardName + ", eventImageUrl: " + imageUrl
+ ", eventStartMillis: " + startMillis
+ ", eventEndMillis: " + endMillis + ", eventRowId: "
- + rowId;
+ + rowId + ", server: " + server;
}
}