mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-30 15:57:11 +00:00
# working towards migration of Event Sending Services
This commit is contained in:
1 parent
42223b63f5
commit
fdfc27278c
22 files changed
+849
-127
No files matched your search
@@ -13,6 +13,8 @@
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
|
||||
|
||||
<application
|
||||
android:icon="@drawable/sap_sailing_app_icon"
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.sap.sailing.racecommittee.app.domain.state;
|
||||
package com.sap.sailing.racecommittee.app.domain.racelog;
|
||||
|
||||
import com.sap.sailing.domain.racelog.RaceLogEvent;
|
||||
|
||||
+58
-58
@@ -10,77 +10,77 @@ import com.sap.sailing.racecommittee.app.domain.racelog.PassAwareRaceLog;
|
||||
import com.sap.sailing.racecommittee.app.logging.ExLog;
|
||||
|
||||
public class PassAwareRaceLogImpl extends RaceLogImpl implements PassAwareRaceLog {
|
||||
private static final String TAG = PassAwareRaceLogImpl.class.getName();
|
||||
private static final long serialVersionUID = -1252381252528365834L;
|
||||
private static final String ReadWriteLockName = PassAwareRaceLogImpl.class.getName() + ".lock";
|
||||
|
||||
public static final int DefaultPassId = 0;
|
||||
|
||||
private int currentPassId;
|
||||
|
||||
public PassAwareRaceLogImpl(RaceLog raceLog) {
|
||||
this();
|
||||
for (RaceLogEvent event : raceLog.getRawFixes()) {
|
||||
this.add(event);
|
||||
}
|
||||
}
|
||||
|
||||
public PassAwareRaceLogImpl() {
|
||||
this(DefaultPassId);
|
||||
}
|
||||
private static final String TAG = PassAwareRaceLogImpl.class.getName();
|
||||
private static final long serialVersionUID = -1252381252528365834L;
|
||||
private static final String ReadWriteLockName = PassAwareRaceLogImpl.class.getName() + ".lock";
|
||||
|
||||
public PassAwareRaceLogImpl(int currentPassId) {
|
||||
super(ReadWriteLockName);
|
||||
this.currentPassId = currentPassId;
|
||||
}
|
||||
|
||||
public int getCurrentPassId() {
|
||||
return currentPassId;
|
||||
}
|
||||
|
||||
public void setCurrentPassId(int newPassId) {
|
||||
if (newPassId != this.currentPassId) {
|
||||
ExLog.i(TAG, String.format("Changing pass id to %d", newPassId));
|
||||
this.currentPassId = newPassId;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableSet<RaceLogEvent> getFixes() {
|
||||
lockForRead();
|
||||
try {
|
||||
return super.getFixes();
|
||||
} finally {
|
||||
unlockAfterRead();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NavigableSet<RaceLogEvent> getInternalFixes() {
|
||||
public static final int DefaultPassId = 0;
|
||||
|
||||
private int currentPassId;
|
||||
|
||||
public PassAwareRaceLogImpl(RaceLog raceLog) {
|
||||
this();
|
||||
for (RaceLogEvent event : raceLog.getRawFixes()) {
|
||||
this.add(event);
|
||||
}
|
||||
}
|
||||
|
||||
public PassAwareRaceLogImpl() {
|
||||
this(DefaultPassId);
|
||||
}
|
||||
|
||||
public PassAwareRaceLogImpl(int currentPassId) {
|
||||
super(ReadWriteLockName);
|
||||
this.currentPassId = currentPassId;
|
||||
}
|
||||
|
||||
public int getCurrentPassId() {
|
||||
return currentPassId;
|
||||
}
|
||||
|
||||
public void setCurrentPassId(int newPassId) {
|
||||
if (newPassId != this.currentPassId) {
|
||||
ExLog.i(TAG, String.format("Changing pass id to %d", newPassId));
|
||||
this.currentPassId = newPassId;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableSet<RaceLogEvent> getFixes() {
|
||||
lockForRead();
|
||||
try {
|
||||
return super.getFixes();
|
||||
} finally {
|
||||
unlockAfterRead();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NavigableSet<RaceLogEvent> getInternalFixes() {
|
||||
return new PartialNavigableSetView<RaceLogEvent>(super.getInternalFixes()) {
|
||||
@Override
|
||||
protected boolean isValid(RaceLogEvent e) {
|
||||
return e.getPassId() == getCurrentPassId();
|
||||
return e.getPassId() == getCurrentPassId();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(RaceLogEvent event) {
|
||||
boolean isAdded = false;
|
||||
lockForWrite();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(RaceLogEvent event) {
|
||||
boolean isAdded = false;
|
||||
lockForWrite();
|
||||
try {
|
||||
isAdded = getInternalRawFixes().add(event);
|
||||
} finally {
|
||||
unlockAfterWrite();
|
||||
}
|
||||
if (isAdded) {
|
||||
ExLog.i(TAG, String.format("%s (%s) was added to log.", event, event.getClass().getName()));
|
||||
setCurrentPassId(Math.max(event.getPassId(), this.currentPassId));
|
||||
notifyListenersAboutReceive(event);
|
||||
ExLog.i(TAG, String.format("%s (%s) was added to log.", event, event.getClass().getName()));
|
||||
setCurrentPassId(Math.max(event.getPassId(), this.currentPassId));
|
||||
notifyListenersAboutReceive(event);
|
||||
} else {
|
||||
ExLog.w(TAG, String.format("%s (%s) was not added to log. Ignoring", event, event.getClass().getName()));
|
||||
ExLog.w(TAG, String.format("%s (%s) was not added to log. Ignoring", event, event.getClass().getName()));
|
||||
}
|
||||
return isAdded;
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package com.sap.sailing.racecommittee.app.domain.state.impl;
|
||||
package com.sap.sailing.racecommittee.app.domain.racelog.impl;
|
||||
|
||||
import com.sap.sailing.domain.racelog.RaceLogCourseAreaChangedEvent;
|
||||
import com.sap.sailing.domain.racelog.RaceLogEventVisitor;
|
||||
@@ -6,7 +6,7 @@ import com.sap.sailing.domain.racelog.RaceLogFlagEvent;
|
||||
import com.sap.sailing.domain.racelog.RaceLogPassChangeEvent;
|
||||
import com.sap.sailing.domain.racelog.RaceLogRaceStatusEvent;
|
||||
import com.sap.sailing.domain.racelog.RaceLogStartTimeEvent;
|
||||
import com.sap.sailing.racecommittee.app.domain.state.RaceLogChangedListener;
|
||||
import com.sap.sailing.racecommittee.app.domain.racelog.RaceLogChangedListener;
|
||||
|
||||
public class RaceLogChangedVisitor implements RaceLogEventVisitor {
|
||||
|
||||
-2
@@ -1,7 +1,5 @@
|
||||
package com.sap.sailing.racecommittee.app.domain.state;
|
||||
|
||||
public interface RaceStateChangedListener {
|
||||
|
||||
void onRaceStateChanged(RaceState state);
|
||||
|
||||
}
|
||||
+2
-1
@@ -14,7 +14,8 @@ import com.sap.sailing.domain.racelog.impl.RaceLogPassChangeEventImpl;
|
||||
import com.sap.sailing.domain.racelog.impl.RaceLogRaceStatusEventImpl;
|
||||
import com.sap.sailing.domain.racelog.impl.RaceLogStartTimeEventImpl;
|
||||
import com.sap.sailing.racecommittee.app.domain.racelog.PassAwareRaceLog;
|
||||
import com.sap.sailing.racecommittee.app.domain.state.RaceLogChangedListener;
|
||||
import com.sap.sailing.racecommittee.app.domain.racelog.RaceLogChangedListener;
|
||||
import com.sap.sailing.racecommittee.app.domain.racelog.impl.RaceLogChangedVisitor;
|
||||
import com.sap.sailing.racecommittee.app.domain.state.RaceState;
|
||||
import com.sap.sailing.racecommittee.app.domain.state.RaceStateChangedListener;
|
||||
import com.sap.sailing.racecommittee.app.domain.state.impl.analyzers.RaceStatusAnalyzer;
|
||||
|
||||
+13
-13
@@ -5,17 +5,17 @@ import com.sap.sailing.domain.racelog.RaceLogEvent;
|
||||
|
||||
public abstract class RaceLogAnalyzer {
|
||||
|
||||
private RaceLog raceLog;
|
||||
|
||||
public RaceLogAnalyzer(RaceLog raceLog) {
|
||||
this.raceLog = raceLog;
|
||||
}
|
||||
|
||||
protected Iterable<RaceLogEvent> getPassEvents() {
|
||||
return raceLog.getFixes();
|
||||
}
|
||||
|
||||
protected Iterable<RaceLogEvent> getAllEvents() {
|
||||
return raceLog.getRawFixes();
|
||||
}
|
||||
private RaceLog raceLog;
|
||||
|
||||
public RaceLogAnalyzer(RaceLog raceLog) {
|
||||
this.raceLog = raceLog;
|
||||
}
|
||||
|
||||
protected Iterable<RaceLogEvent> getPassEvents() {
|
||||
return raceLog.getFixes();
|
||||
}
|
||||
|
||||
protected Iterable<RaceLogEvent> getAllEvents() {
|
||||
return raceLog.getRawFixes();
|
||||
}
|
||||
}
|
||||
+21
-23
@@ -7,29 +7,27 @@ import com.sap.sailing.domain.racelog.RaceLogRaceStatusEvent;
|
||||
import com.sap.sailing.racecommittee.app.logging.ExLog;
|
||||
|
||||
public class RaceStatusAnalyzer extends RaceLogAnalyzer {
|
||||
private static final String TAG = RaceStatusAnalyzer.class.getName();
|
||||
private static final String TAG = RaceStatusAnalyzer.class.getName();
|
||||
|
||||
public RaceStatusAnalyzer(RaceLog raceLog) {
|
||||
super(raceLog);
|
||||
}
|
||||
|
||||
public RaceLogRaceStatus getStatus() {
|
||||
ExLog.i(TAG, String.format("Updating status..."));
|
||||
|
||||
RaceLogRaceStatus newStatus = RaceLogRaceStatus.UNSCHEDULED;
|
||||
for (RaceLogEvent event : getPassEvents()) {
|
||||
ExLog.i(TAG, String.format("Deciding on event of type %s.", event.getClass().getSimpleName()));
|
||||
if (event instanceof RaceLogRaceStatusEvent) {
|
||||
RaceLogRaceStatusEvent statusEvent = (RaceLogRaceStatusEvent) event;
|
||||
ExLog.i(TAG, String.format("Decision to %s.", statusEvent.getNextStatus()));
|
||||
newStatus = statusEvent.getNextStatus();
|
||||
}
|
||||
}
|
||||
|
||||
ExLog.i(TAG, String.format("Status will be set to %s.", newStatus));
|
||||
return newStatus;
|
||||
}
|
||||
public RaceStatusAnalyzer(RaceLog raceLog) {
|
||||
super(raceLog);
|
||||
}
|
||||
|
||||
public RaceLogRaceStatus getStatus() {
|
||||
ExLog.i(TAG, String.format("Updating status..."));
|
||||
|
||||
RaceLogRaceStatus newStatus = RaceLogRaceStatus.UNSCHEDULED;
|
||||
for (RaceLogEvent event : getPassEvents()) {
|
||||
ExLog.i(TAG, String.format("Deciding on event of type %s.", event.getClass().getSimpleName()));
|
||||
if (event instanceof RaceLogRaceStatusEvent) {
|
||||
RaceLogRaceStatusEvent statusEvent = (RaceLogRaceStatusEvent) event;
|
||||
ExLog.i(TAG, String.format("Decision to %s.", statusEvent.getNextStatus()));
|
||||
newStatus = statusEvent.getNextStatus();
|
||||
}
|
||||
}
|
||||
|
||||
ExLog.i(TAG, String.format("Status will be set to %s.", newStatus));
|
||||
return newStatus;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+14
-14
@@ -7,18 +7,18 @@ import com.sap.sailing.domain.racelog.RaceLogStartTimeEvent;
|
||||
|
||||
public class StartTimeFinder extends RaceLogAnalyzer {
|
||||
|
||||
public StartTimeFinder(RaceLog raceLog) {
|
||||
super(raceLog);
|
||||
}
|
||||
|
||||
public TimePoint getStartTime() {
|
||||
TimePoint startTime = null;
|
||||
for (RaceLogEvent event : getPassEvents()) {
|
||||
if (event instanceof RaceLogStartTimeEvent) {
|
||||
startTime = ((RaceLogStartTimeEvent) event).getStartTime();
|
||||
}
|
||||
}
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public StartTimeFinder(RaceLog raceLog) {
|
||||
super(raceLog);
|
||||
}
|
||||
|
||||
public TimePoint getStartTime() {
|
||||
TimePoint startTime = null;
|
||||
for (RaceLogEvent event : getPassEvents()) {
|
||||
if (event instanceof RaceLogStartTimeEvent) {
|
||||
startTime = ((RaceLogStartTimeEvent) event).getStartTime();
|
||||
}
|
||||
}
|
||||
return startTime;
|
||||
}
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.sap.sailing.racecommittee.app.services;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
|
||||
import com.sap.sailing.racecommittee.app.domain.state.RaceState;
|
||||
import com.sap.sailing.racecommittee.app.domain.state.RaceStateChangedListener;
|
||||
import com.sap.sailing.racecommittee.app.logging.ExLog;
|
||||
|
||||
public class RaceStateListener implements RaceStateChangedListener {
|
||||
private final static String TAG = RaceStateListener.class.getName();
|
||||
|
||||
private final ManagedRace race;
|
||||
|
||||
public RaceStateListener(ManagedRace race) {
|
||||
this.race = race;
|
||||
}
|
||||
|
||||
public void onRaceStateChanged(RaceState state) {
|
||||
ExLog.i(TAG, "Race state changed but service is ignoring it...");
|
||||
}
|
||||
|
||||
}
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
package com.sap.sailing.racecommittee.app.services;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
|
||||
import com.sap.sailing.domain.racelog.RaceLogEvent;
|
||||
import com.sap.sailing.domain.racelog.RaceLogEventVisitor;
|
||||
import com.sap.sailing.racecommittee.app.AppConstants;
|
||||
import com.sap.sailing.racecommittee.app.R;
|
||||
import com.sap.sailing.racecommittee.app.data.DataManager;
|
||||
import com.sap.sailing.racecommittee.app.data.ReadonlyDataManager;
|
||||
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
|
||||
import com.sap.sailing.racecommittee.app.domain.racelog.impl.RaceLogChangedVisitor;
|
||||
import com.sap.sailing.racecommittee.app.domain.state.RaceState;
|
||||
import com.sap.sailing.racecommittee.app.domain.state.RaceStateChangedListener;
|
||||
import com.sap.sailing.racecommittee.app.logging.ExLog;
|
||||
import com.sap.sailing.racecommittee.app.services.sending.RaceEventSender;
|
||||
import com.sap.sailing.racecommittee.app.ui.activities.LoginActivity;
|
||||
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.impl.CompetitorIdJsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.impl.racelog.RaceLogEventSerializer;
|
||||
|
||||
public class RaceStateService extends Service {
|
||||
private final static String TAG = RaceStateService.class.getName();
|
||||
|
||||
/**
|
||||
* Binder for this {@link RaceStateService}.
|
||||
*/
|
||||
public class RaceStateServiceBinder extends Binder {
|
||||
public RaceStateService getService() {
|
||||
return RaceStateService.this;
|
||||
}
|
||||
}
|
||||
|
||||
private final IBinder mBinder = new RaceStateServiceBinder();
|
||||
|
||||
private UUID serviceId;
|
||||
|
||||
private AlarmManager alarmManager;
|
||||
|
||||
private ReadonlyDataManager dataManager;
|
||||
|
||||
private Map<ManagedRace, RaceLogEventVisitor> registeredLogListeners;
|
||||
private Map<ManagedRace, RaceStateChangedListener> registeredStateListeners;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
this.serviceId = UUID.randomUUID();
|
||||
this.alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
|
||||
this.dataManager = DataManager.create(this);
|
||||
|
||||
this.registeredLogListeners = new HashMap<ManagedRace, RaceLogEventVisitor>();
|
||||
this.registeredStateListeners = new HashMap<ManagedRace, RaceStateChangedListener>();
|
||||
|
||||
startForeground();
|
||||
ExLog.i(TAG, "Started.");
|
||||
super.onCreate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent arg0) {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
if (intent == null) {
|
||||
ExLog.i(TAG, "Restarted.");
|
||||
} else {
|
||||
handleStartCommand(intent);
|
||||
}
|
||||
|
||||
// We want this service to continue running until it is explicitly
|
||||
// stopped, therefore return sticky.
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
// Unregister all race listener...
|
||||
for (Entry<ManagedRace, RaceLogEventVisitor> entry : registeredLogListeners.entrySet()) {
|
||||
entry.getKey().getState().getRaceLog().removeListener(entry.getValue());
|
||||
}
|
||||
for (Entry<ManagedRace, RaceStateChangedListener> entry : registeredStateListeners.entrySet()) {
|
||||
entry.getKey().getState().unregisterListener(entry.getValue());
|
||||
}
|
||||
|
||||
// ... and remove from status bar!
|
||||
stopForeground(true);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
private void startForeground() {
|
||||
CharSequence text = getText(R.string.service_title);
|
||||
|
||||
// Set the icon, scrolling text and timestamp
|
||||
Notification notification = new Notification(R.drawable.sap_sailing_app_icon, text, System.currentTimeMillis());
|
||||
|
||||
Intent intent = new Intent(this, LoginActivity.class);
|
||||
// clear all activities above started and reuse if already existing!
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
// The PendingIntent to launch our activity if the user selects this
|
||||
// notification
|
||||
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, 0);
|
||||
|
||||
// Set the info for the views that show in the notification panel.
|
||||
notification.setLatestEventInfo(this, getText(R.string.service_info), text, contentIntent);
|
||||
notification.flags |= Notification.FLAG_NO_CLEAR;
|
||||
|
||||
// Send the notification.
|
||||
this.startForeground(42, notification);
|
||||
}
|
||||
|
||||
private void handleStartCommand(Intent intent) {
|
||||
String action = intent.getAction();
|
||||
ExLog.i(TAG, String.format("Command action '%s' received.", action));
|
||||
|
||||
if (AppConstants.REGISTER_RACE_ACTION.equals(action)) {
|
||||
handleRegisterRace(intent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleRegisterRace(Intent intent) {
|
||||
ExLog.i(TAG, "Registering race.");
|
||||
ManagedRace race = getRaceFromIntent(intent);
|
||||
if (race == null) {
|
||||
ExLog.i(TAG, "Intent did not carry valid race information.");
|
||||
return;
|
||||
}
|
||||
registerRace(race);
|
||||
}
|
||||
|
||||
private ManagedRace getRaceFromIntent(Intent intent) {
|
||||
if (intent.getExtras() == null || !intent.getExtras().containsKey(AppConstants.RACE_ID_KEY)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Serializable raceId = intent.getExtras().getSerializable(AppConstants.RACE_ID_KEY);
|
||||
return dataManager.getDataStore().getRace(raceId);
|
||||
}
|
||||
|
||||
private void registerRace(ManagedRace race) {
|
||||
RaceState state = race.getState();
|
||||
|
||||
// Register on event additions...
|
||||
JsonSerializer<RaceLogEvent> eventSerializer = RaceLogEventSerializer.create(new CompetitorIdJsonSerializer());
|
||||
RaceEventSender sender = new RaceEventSender(this, eventSerializer, race);
|
||||
RaceLogChangedVisitor logListener = new RaceLogChangedVisitor(sender);
|
||||
state.getRaceLog().addListener(logListener);
|
||||
|
||||
// ... register on state changes!
|
||||
RaceStateChangedListener stateListener = new RaceStateListener(race);
|
||||
state.registerListener(stateListener);
|
||||
|
||||
this.registeredLogListeners.put(race, logListener);
|
||||
this.registeredStateListeners.put(race, stateListener);
|
||||
}
|
||||
|
||||
}
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
package com.sap.sailing.racecommittee.app.services.sending;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.AppConstants;
|
||||
import com.sap.sailing.racecommittee.app.logging.ExLog;
|
||||
import com.sap.sailing.racecommittee.app.utils.FileHandlerUtils;
|
||||
|
||||
public class EventPersistenceManager {
|
||||
|
||||
private final static String delayedEventFileName = "delayedEvents.txt";
|
||||
private final static String TAG = "EventPersistanceManager";
|
||||
|
||||
private Context context;
|
||||
private String fileContent;
|
||||
|
||||
public EventPersistenceManager(Context context) {
|
||||
this.context = context;
|
||||
fileContent = "";
|
||||
initializeFile();
|
||||
}
|
||||
|
||||
public boolean areIntentsDelayed() {
|
||||
return !fileContent.isEmpty();
|
||||
}
|
||||
|
||||
public void persistIntent(Intent intent) {
|
||||
Bundle extras = intent.getExtras();
|
||||
|
||||
String serializedEvent = extras.getString(AppConstants.EXTRAS_JSON_KEY);
|
||||
String raceUuid = extras.getSerializable(AppConstants.RACE_ID_KEY).toString();
|
||||
|
||||
persistEvent(raceUuid, serializedEvent);
|
||||
}
|
||||
|
||||
private void persistEvent(String raceUuid, String serializedEvent) {
|
||||
String eventLine = String.format("%s;%s\n", raceUuid, serializedEvent);
|
||||
ExLog.i(TAG, "Called to persist following event " + eventLine);
|
||||
|
||||
if (!fileContent.isEmpty()) {
|
||||
if (fileContent.contains(eventLine)) {
|
||||
ExLog.i(TAG, "The event to persist exists already in file");
|
||||
return;
|
||||
}
|
||||
}
|
||||
writeEventToFile(eventLine);
|
||||
}
|
||||
|
||||
public void removeIntent(Intent intent) {
|
||||
Bundle extras = intent.getExtras();
|
||||
|
||||
String serializedEvent = extras.getString(AppConstants.EXTRAS_JSON_KEY);
|
||||
String raceUuid = extras.getString(AppConstants.RACE_ID_KEY);
|
||||
|
||||
removeEvent(raceUuid, serializedEvent);
|
||||
}
|
||||
|
||||
private void removeEvent(String raceUuid, String serializedEvent) {
|
||||
if (fileContent.isEmpty())
|
||||
return;
|
||||
|
||||
ExLog.i(TAG, "removeEvent is called for " + raceUuid + ", serializedEvent " + serializedEvent);
|
||||
String eventLine = String.format("%s;%s\n", raceUuid, serializedEvent);
|
||||
|
||||
removeEntryInFileContent(eventLine);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param eventLine
|
||||
*/
|
||||
private void removeEntryInFileContent(String eventLine) {
|
||||
if (fileContent.contains(eventLine)) {
|
||||
fileContent = fileContent.replace(eventLine, "");
|
||||
writeFileContentToFile();
|
||||
ExLog.i(TAG, "Entry " + eventLine + " is removed from fileContent");
|
||||
}
|
||||
}
|
||||
|
||||
public int getEventCount() {
|
||||
if (fileContent.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
return fileContent.split("\n").length;
|
||||
}
|
||||
|
||||
public List<Intent> restoreEvents() {
|
||||
List<Intent> delayedIntents = new ArrayList<Intent>();
|
||||
|
||||
if (!fileContent.isEmpty()) {
|
||||
String[] eventLines = fileContent.split("\n");
|
||||
for (String line : eventLines) {
|
||||
String[] lineParts = line.split(";");
|
||||
|
||||
Intent eventIntent = EventSendingService.createEventIntent(context, lineParts[0], lineParts[1]);
|
||||
delayedIntents.add(eventIntent);
|
||||
}
|
||||
}
|
||||
|
||||
ExLog.i(TAG, "Restored " + delayedIntents.size() + " events");
|
||||
return delayedIntents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
private String getFileContent() throws FileNotFoundException {
|
||||
String fileContent = "";
|
||||
FileInputStream inputStream;
|
||||
try {
|
||||
inputStream = context.openFileInput(delayedEventFileName);
|
||||
|
||||
fileContent = FileHandlerUtils.convertStreamToString(inputStream);
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
ExLog.e(TAG, "In Method getFileContent(): " + e.getMessage() + " fileContent is empty");
|
||||
}
|
||||
return fileContent;
|
||||
}
|
||||
|
||||
private void writeEventToFile(String eventLine) {
|
||||
fileContent += eventLine;
|
||||
writeFileContentToFile();
|
||||
ExLog.i(TAG, "Wrote event to file: " + eventLine);
|
||||
}
|
||||
|
||||
private void writeFileContentToFile() {
|
||||
writeToFile(fileContent, Context.MODE_PRIVATE);
|
||||
ExLog.i(TAG, "Wrote file content to file: " + fileContent);
|
||||
}
|
||||
|
||||
private void initializeFile() {
|
||||
try {
|
||||
fileContent = getFileContent();
|
||||
} catch (FileNotFoundException e) {
|
||||
ExLog.w(TAG, "persistence file not found in internal storage. The file will be created.");
|
||||
clearFileContent();
|
||||
}
|
||||
ExLog.i(TAG, "Initialized file");
|
||||
}
|
||||
|
||||
private void clearFileContent() {
|
||||
fileContent = "";
|
||||
writeFileContentToFile();
|
||||
}
|
||||
|
||||
private void writeToFile(String content, int mode) {
|
||||
try {
|
||||
FileOutputStream outputStream = context.openFileOutput(delayedEventFileName, mode);
|
||||
outputStream.write(content.getBytes());
|
||||
outputStream.close();
|
||||
} catch (IOException e) {
|
||||
ExLog.e(TAG, "In Method writeToFile: " + e.getMessage() + " with content " + content + " and mode " + mode);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.sap.sailing.racecommittee.app.services.sending;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.URI;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.AppConstants;
|
||||
import com.sap.sailing.racecommittee.app.data.http.HttpJsonPostRequest;
|
||||
import com.sap.sailing.racecommittee.app.data.http.HttpRequest;
|
||||
import com.sap.sailing.racecommittee.app.logging.ExLog;
|
||||
|
||||
public class EventSenderTask extends AsyncTask<Intent, Void, Pair<Intent, Integer>> {
|
||||
|
||||
public interface EventSendingListener {
|
||||
public void onResult(Intent intent, boolean success);
|
||||
}
|
||||
|
||||
private EventSendingListener listener;
|
||||
|
||||
public EventSenderTask(EventSendingListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Pair<Intent, Integer> doInBackground(Intent... params) {
|
||||
|
||||
Intent intent = params[0];
|
||||
|
||||
Bundle extras = intent.getExtras();
|
||||
Serializable serializedEvent = extras.getSerializable(AppConstants.EXTRAS_JSON_KEY);
|
||||
String url = extras.getString(AppConstants.EXTRAS_URL);
|
||||
if (serializedEvent == null || url == null) {
|
||||
return Pair.create(intent, -1);
|
||||
}
|
||||
|
||||
try {
|
||||
HttpRequest post = new HttpJsonPostRequest(URI.create(url), serializedEvent.toString());
|
||||
try {
|
||||
post.execute().close();
|
||||
} finally {
|
||||
post.disconnect();
|
||||
}
|
||||
ExLog.i(getClass().getName(), "Post request issued for the following Event: " + serializedEvent);
|
||||
} catch (Exception e) {
|
||||
ExLog.e(getClass().getName(), e.toString());
|
||||
return Pair.create(intent, -1);
|
||||
}
|
||||
return Pair.create(intent, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Pair<Intent, Integer> resultPair) {
|
||||
super.onPostExecute(resultPair);
|
||||
listener.onResult(resultPair.first, resultPair.second == 0);
|
||||
}
|
||||
|
||||
}
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
package com.sap.sailing.racecommittee.app.services.sending;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.AppConstants;
|
||||
import com.sap.sailing.racecommittee.app.data.DataManager;
|
||||
import com.sap.sailing.racecommittee.app.data.ReadonlyDataManager;
|
||||
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
|
||||
import com.sap.sailing.racecommittee.app.logging.ExLog;
|
||||
import com.sap.sailing.racecommittee.app.services.sending.EventSenderTask.EventSendingListener;
|
||||
|
||||
/*
|
||||
* Sending an event to the webservice
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* Intent i = new Intent(AppConstants.SEND_EVENT_ACTION);
|
||||
* i.putExtra(AppConstants.EXTRAS_JSON_KEY, JsonUtils.getObjectAsString('someEventObject'));
|
||||
* i.putExtra(AppConstants.RACE_UUID_KEY, 'raceuuid');
|
||||
* context.startService(i);
|
||||
*/
|
||||
public class EventSendingService extends Service implements EventSendingListener {
|
||||
|
||||
protected final static String TAG = "EventSendingService";
|
||||
|
||||
private ConnectivityManager connectivityManager;
|
||||
private Handler handler;
|
||||
private final IBinder mBinder = new EventSendingBinder();
|
||||
private EventPersistenceManager persistenceManager;
|
||||
private boolean isHandlerSet;
|
||||
|
||||
public class EventSendingBinder extends Binder {
|
||||
public EventSendingService getService() {
|
||||
return EventSendingService.this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent arg0) {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
private Date lastSuccessfulSend;
|
||||
|
||||
public int getDelayedIntentsCount() {
|
||||
return persistenceManager.getEventCount();
|
||||
}
|
||||
|
||||
public Date getLastSuccessfulSend() {
|
||||
return lastSuccessfulSend;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates an intent that contains the event to be sent and the race id which shall be sent to the backend
|
||||
*
|
||||
* @param context
|
||||
* the context of the app
|
||||
* @param race
|
||||
* the race for which the event was created
|
||||
* @param serializedEvent
|
||||
* the event serizalized to JSON
|
||||
* @return the intent that shall be sent to the EventSendingService
|
||||
*/
|
||||
public static Intent createEventIntent(Context context, ManagedRace race, Serializable serializedEvent) {
|
||||
String url = String.format(
|
||||
"%s/rc/racelog?leaderboard=%s&raceColumn=%s&fleet=%s",
|
||||
AppConstants.getServerBaseURL(context),
|
||||
race.getRaceGroup().getName(),
|
||||
race.getName(),
|
||||
race.getFleet().getName());
|
||||
|
||||
Intent eventIntent = new Intent(AppConstants.SEND_EVENT_ACTION);
|
||||
eventIntent.putExtra(AppConstants.RACE_ID_KEY, race.getId());
|
||||
eventIntent.putExtra(AppConstants.EXTRAS_JSON_KEY, serializedEvent);
|
||||
eventIntent.putExtra(AppConstants.EXTRAS_URL, url);
|
||||
ExLog.i(TAG, "Created event " + eventIntent + " for sending to backend");
|
||||
return eventIntent;
|
||||
}
|
||||
|
||||
public static Intent createEventIntent(Context context, Serializable raceId, Serializable serializedEvent) {
|
||||
ReadonlyDataManager data = DataManager.create(context);
|
||||
ManagedRace race = data.getDataStore().getRace(raceId);
|
||||
if (race == null) {
|
||||
ExLog.e(TAG, "There is no race with id " + raceId);
|
||||
return null;
|
||||
}
|
||||
return createEventIntent(context, race, serializedEvent);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see android.app.Service#onCreate()
|
||||
*/
|
||||
@Override
|
||||
public void onCreate() {
|
||||
connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
persistenceManager = new EventPersistenceManager(this);
|
||||
|
||||
handler = new Handler();
|
||||
isHandlerSet = false;
|
||||
|
||||
if (persistenceManager.areIntentsDelayed()) {
|
||||
handleDelayedEvents();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
if (intent == null) {
|
||||
ExLog.i(TAG, "Service is restarted.");
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
ExLog.i(TAG, "Service is called by following intent: " + intent.getAction());
|
||||
handleCommand(intent, startId);
|
||||
// We want this service to continue running until it is explicitly
|
||||
// stopped, so return sticky.
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
private void handleCommand(Intent intent, int startId) {
|
||||
String action = intent.getAction();
|
||||
if (action.equals(AppConstants.SEND_SAVED_INTENTS_ACTION)) {
|
||||
handleDelayedEvents();
|
||||
} else if (action.equals(AppConstants.SEND_EVENT_ACTION)) {
|
||||
handleSendEvents(intent);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSendEvents(Intent intent) {
|
||||
if (!isConnected()) {
|
||||
persistenceManager.persistIntent(intent);
|
||||
//ConnectivityChangedReceiver.enable(this);
|
||||
} else {
|
||||
sendEvent(intent);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDelayedEvents() {
|
||||
isHandlerSet = false;
|
||||
if (!isConnected())
|
||||
return;
|
||||
|
||||
sendDelayedEvents();
|
||||
}
|
||||
|
||||
private void sendDelayedEvents() {
|
||||
List<Intent> delayedIntents = persistenceManager.restoreEvents();
|
||||
ExLog.i(TAG, String.format("Trying to resend %d waiting events", delayedIntents.size()));
|
||||
for (Intent intent : delayedIntents)
|
||||
sendEvent(intent);
|
||||
}
|
||||
|
||||
private void sendEvent(Intent intent) {
|
||||
if (!AppConstants.isSendingActive(this)) {
|
||||
ExLog.i(TAG, "Sending deactivated. Event will not be sent to server.");
|
||||
} else {
|
||||
EventSenderTask task = new EventSenderTask(this);
|
||||
task.execute(intent);
|
||||
}
|
||||
}
|
||||
|
||||
public void onResult(Intent intent, boolean success) {
|
||||
if (!success) {
|
||||
ExLog.w(TAG, "Could not POST intent to server.");
|
||||
persistenceManager.persistIntent(intent);
|
||||
if (!isHandlerSet) {
|
||||
SendDelayedEventsCaller delayedCaller = new SendDelayedEventsCaller(this);
|
||||
handler.postDelayed(delayedCaller, 1000 * 60 * 1);
|
||||
isHandlerSet = true;
|
||||
}
|
||||
} else {
|
||||
ExLog.i(TAG, "Event successfully send. " + intent.getStringExtra(AppConstants.EXTRAS_JSON_KEY));
|
||||
persistenceManager.removeIntent(intent);
|
||||
lastSuccessfulSend = Calendar.getInstance().getTime();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if there is network connectivity
|
||||
*
|
||||
* @return connectivity check value
|
||||
*/
|
||||
private boolean isConnected() {
|
||||
NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
|
||||
if (activeNetwork == null)
|
||||
return false;
|
||||
boolean isConnected = activeNetwork.isConnected();
|
||||
return isConnected;
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.sap.sailing.racecommittee.app.services.sending;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import android.app.Service;
|
||||
|
||||
import com.sap.sailing.domain.racelog.RaceLogEvent;
|
||||
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
|
||||
import com.sap.sailing.racecommittee.app.domain.racelog.RaceLogChangedListener;
|
||||
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
|
||||
|
||||
public class RaceEventSender implements RaceLogChangedListener {
|
||||
|
||||
private final Service service;
|
||||
private final JsonSerializer<RaceLogEvent> serializer;
|
||||
private final ManagedRace race;
|
||||
|
||||
public RaceEventSender(Service context, JsonSerializer<RaceLogEvent> serializer, ManagedRace race) {
|
||||
this.service = context;
|
||||
this.serializer = serializer;
|
||||
this.race = race;
|
||||
}
|
||||
|
||||
public void eventAdded(RaceLogEvent event) {
|
||||
Serializable serializedEvent = serializer.serialize(event);
|
||||
|
||||
service.startService(EventSendingService.createEventIntent(service, race, serializedEvent));
|
||||
}
|
||||
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.sap.sailing.racecommittee.app.services.sending;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.AppConstants;
|
||||
import com.sap.sailing.racecommittee.app.logging.ExLog;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
public class SendDelayedEventsCaller implements Runnable {
|
||||
|
||||
private final static String TAG = "SendDelayedEventsCaller";
|
||||
private Context context;
|
||||
|
||||
public SendDelayedEventsCaller(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
ExLog.i(TAG, "The Event Sending Service is called to send possibly delayed intents");
|
||||
Intent sendSavedIntent = new Intent(AppConstants.SEND_SAVED_INTENTS_ACTION);
|
||||
context.startService(sendSavedIntent);
|
||||
}
|
||||
}
|
||||
-1
@@ -128,7 +128,6 @@ public class RacingActivity extends TwoPaneActivity implements RaceInfoListener
|
||||
dataManager.loadRaces(courseArea.getId(), new LoadClient<Collection<ManagedRace>>() {
|
||||
public void onLoadSucceded(Collection<ManagedRace> data) {
|
||||
onLoadRacesSucceded(courseArea, data);
|
||||
|
||||
}
|
||||
|
||||
public void onLoadFailed(Exception reason) {
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.sap.sailing.racecommittee.app.utils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.logging.ExLog;
|
||||
|
||||
public class FileHandlerUtils {
|
||||
|
||||
private final static String TAG = FileHandlerUtils.class.getName();
|
||||
|
||||
public static String convertStreamToString(InputStream inputStream) {
|
||||
/*
|
||||
* To convert the InputStream to String we use the BufferedReader.readLine() method. We iterate until the
|
||||
* BufferedReader return null which means there's no more data to read. Each line will appended to a
|
||||
* StringBuilder and returned as String.
|
||||
*/
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
String line = null;
|
||||
try {
|
||||
while ((line = reader.readLine()) != null) {
|
||||
stringBuilder.append(line + "\n");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
ExLog.e(TAG, "In Method convertStreamToString while converting stream to string: " + e.getMessage());
|
||||
} finally {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
ExLog.e(TAG, "In Method convertStreamToString while closing the input stream: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user