Merge branch 'master' into competitor_filtering

This commit is contained in:
Axel Uhl committed 2013-05-01 15:35:23 +02:00
commit d270e7ff81
50 files changed
+803 -464

No files matched your search

+16 -13
View File
@@ -53,6 +53,7 @@ MAVEN_SETTINGS_PROXY=$PROJECT_HOME/configuration/maven-settings-proxy.xml
p2PluginRepository=$PROJECT_HOME/java/com.sap.sailing.feature.p2build/bin/products/raceanalysis.product.id/linux/gtk/$ARCH p2PluginRepository=$PROJECT_HOME/java/com.sap.sailing.feature.p2build/bin/products/raceanalysis.product.id/linux/gtk/$ARCH
HAS_OVERWRITTEN_TARGET=0
TARGET_SERVER_NAME=$active_branch TARGET_SERVER_NAME=$active_branch
gwtcompile=1 gwtcompile=1
@@ -104,7 +105,8 @@ do
m) MAVEN_SETTINGS=$OPTARG;; m) MAVEN_SETTINGS=$OPTARG;;
n) OSGI_BUNDLE_NAME=$OPTARG;; n) OSGI_BUNDLE_NAME=$OPTARG;;
l) OSGI_TELNET_PORT=$OPTARG;; l) OSGI_TELNET_PORT=$OPTARG;;
s) TARGET_SERVER_NAME=$OPTARG;; s) TARGET_SERVER_NAME=$OPTARG
HAS_OVERWRITTEN_TARGET=1;;
\?) echo "Invalid option" \?) echo "Invalid option"
exit 2;; exit 2;;
esac esac
@@ -331,27 +333,28 @@ if [[ "$@" == "install" ]] || [[ "$@" == "all" ]]; then
rm -rf $ACDIR/org.eclipse.* rm -rf $ACDIR/org.eclipse.*
rm -rf $ACDIR/configuration/org.eclipse.* rm -rf $ACDIR/configuration/org.eclipse.*
rm -rf $ACDIR/start if [[ i$HAS_OVERWRITTEN_TARGET -eq 0 ]]; then
rm -rf $ACDIR/stop rm -rf $ACDIR/start
rm -rf $ACDIR/stop
cp -v $p2PluginRepository/configuration/config.ini configuration/
mkdir -p configuration/jetty/etc
cp -v $PROJECT_HOME/java/target/configuration/jetty/etc/jetty.xml configuration/jetty/etc
cp -v $PROJECT_HOME/java/target/configuration/jetty/etc/realm.properties configuration/jetty/etc
cp -v $PROJECT_HOME/java/target/configuration/monitoring.properties configuration/
cp -v $PROJECT_HOME/configuration/mongodb.cfg $ACDIR/
cp -v $PROJECT_HOME/java/target/start $ACDIR/
cp -v $PROJECT_HOME/java/target/stop $ACDIR/
fi
cp -v $p2PluginRepository/configuration/config.ini configuration/
cp -r -v $p2PluginRepository/configuration/org.eclipse.equinox.simpleconfigurator configuration/ cp -r -v $p2PluginRepository/configuration/org.eclipse.equinox.simpleconfigurator configuration/
cp -v $p2PluginRepository/plugins/*.jar plugins/ cp -v $p2PluginRepository/plugins/*.jar plugins/
mkdir -p configuration/jetty/etc
cp -v $PROJECT_HOME/java/target/configuration/jetty/etc/jetty.xml configuration/jetty/etc
cp -v $PROJECT_HOME/java/target/configuration/jetty/etc/realm.properties configuration/jetty/etc
cp -v $PROJECT_HOME/java/target/configuration/monitoring.properties configuration/
# Make sure mongodb configuration is active
cp -v $PROJECT_HOME/configuration/mongodb.cfg $ACDIR/
cp -rv $PROJECT_HOME/configuration/native-libraries $ACDIR/ cp -rv $PROJECT_HOME/configuration/native-libraries $ACDIR/
# Make sure this script is up2date at least for the next run # Make sure this script is up2date at least for the next run
cp -v $PROJECT_HOME/configuration/buildAndUpdateProduct.sh $ACDIR/ cp -v $PROJECT_HOME/configuration/buildAndUpdateProduct.sh $ACDIR/
cp -v $PROJECT_HOME/java/target/start $ACDIR/
cp -v $PROJECT_HOME/java/target/stop $ACDIR/
cp -v $PROJECT_HOME/java/target/udpmirror $ACDIR/ cp -v $PROJECT_HOME/java/target/udpmirror $ACDIR/
echo "Installation complete. You may now start the server using ./start" echo "Installation complete. You may now start the server using ./start"
@@ -1,8 +1,18 @@
package com.sap.sailing.domain.common.racelog; package com.sap.sailing.domain.common.racelog;
public enum StartProcedureType { public enum StartProcedureType {
UNKNOWN, //RRS26("Fix-Line-Start (RRS26)"),
RRS26, GateStart("Gate-Line-Start"),
GateStart, ESS("\"Extreme Sailing Series\"-Start");
ESS
private String displayName;
private StartProcedureType(String displayName){
this.displayName = displayName;
}
@Override
public String toString(){
return displayName;
}
} }
@@ -30,22 +30,38 @@ public class RaceLogEventComparatorTest {
@Test @Test
public void testEqualsOnSame() { public void testEqualsOnSame() {
when(eventOne.getTimePoint()).thenReturn(new MillisecondsTimePoint(1)); when(eventOne.getTimePoint()).thenReturn(new MillisecondsTimePoint(1));
when(eventOne.getId()).thenReturn("a");
int result = comparator.compare(eventOne, eventOne); int result = comparator.compare(eventOne, eventOne);
assertEquals(0, result); assertEquals(0, result);
} }
@Test @Test
public void testSamePassAndSameTime() { public void testSamePassAndSameTimeSameId() {
when(eventOne.getPassId()).thenReturn(0); when(eventOne.getPassId()).thenReturn(0);
when(eventOne.getTimePoint()).thenReturn(new MillisecondsTimePoint(0)); when(eventOne.getTimePoint()).thenReturn(new MillisecondsTimePoint(0));
when(eventOne.getId()).thenReturn("a");
when(eventTwo.getPassId()).thenReturn(0); when(eventTwo.getPassId()).thenReturn(0);
when(eventTwo.getTimePoint()).thenReturn(new MillisecondsTimePoint(0)); when(eventTwo.getTimePoint()).thenReturn(new MillisecondsTimePoint(0));
when(eventTwo.getId()).thenReturn("a");
int result = comparator.compare(eventOne, eventTwo); int result = comparator.compare(eventOne, eventTwo);
assertEquals(0, result); assertEquals(0, result);
} }
@Test
public void testSamePassAndSameTimeDifferentId() {
when(eventOne.getPassId()).thenReturn(0);
when(eventOne.getTimePoint()).thenReturn(new MillisecondsTimePoint(0));
when(eventOne.getId()).thenReturn("a");
when(eventTwo.getPassId()).thenReturn(0);
when(eventTwo.getTimePoint()).thenReturn(new MillisecondsTimePoint(0));
when(eventTwo.getId()).thenReturn("b");
int result = comparator.compare(eventOne, eventTwo);
assertTrue(result < 0);
}
@Test @Test
public void testSamePassLowerHigherTime() { public void testSamePassLowerHigherTime() {
when(eventOne.getPassId()).thenReturn(0); when(eventOne.getPassId()).thenReturn(0);
@@ -61,8 +61,10 @@ public class RaceLogTest {
when(eventOne.getPassId()).thenReturn(0); when(eventOne.getPassId()).thenReturn(0);
when(eventOne.getTimePoint()).thenReturn(new MillisecondsTimePoint(0)); when(eventOne.getTimePoint()).thenReturn(new MillisecondsTimePoint(0));
when(eventOne.getId()).thenReturn("a");
when(eventTwo.getPassId()).thenReturn(1); when(eventTwo.getPassId()).thenReturn(1);
when(eventTwo.getTimePoint()).thenReturn(new MillisecondsTimePoint(0)); when(eventTwo.getTimePoint()).thenReturn(new MillisecondsTimePoint(0));
when(eventTwo.getId()).thenReturn("b");
assertTrue(raceLog.add(eventOne)); assertTrue(raceLog.add(eventOne));
assertTrue(raceLog.add(eventTwo)); assertTrue(raceLog.add(eventTwo));
@@ -74,14 +76,37 @@ public class RaceLogTest {
} }
@Test @Test
public void testWontAddEventSamePassSameTimePoint() { public void testAddEventSamePassSameTimePointDifferentId() {
RaceLogEvent eventOne = mock(RaceLogEvent.class); RaceLogEvent eventOne = mock(RaceLogEvent.class);
RaceLogEvent eventTwo = mock(RaceLogEvent.class); RaceLogEvent eventTwo = mock(RaceLogEvent.class);
when(eventOne.getPassId()).thenReturn(0); when(eventOne.getPassId()).thenReturn(0);
when(eventOne.getTimePoint()).thenReturn(new MillisecondsTimePoint(0)); when(eventOne.getTimePoint()).thenReturn(new MillisecondsTimePoint(0));
when(eventOne.getId()).thenReturn("a");
when(eventTwo.getPassId()).thenReturn(0); when(eventTwo.getPassId()).thenReturn(0);
when(eventTwo.getTimePoint()).thenReturn(new MillisecondsTimePoint(0)); when(eventTwo.getTimePoint()).thenReturn(new MillisecondsTimePoint(0));
when(eventTwo.getId()).thenReturn("b");
assertTrue(raceLog.add(eventOne));
assertTrue(raceLog.add(eventTwo));
raceLog.lockForRead();
assertTrue(Util.contains(raceLog.getRawFixes(), eventOne));
assertTrue(Util.contains(raceLog.getRawFixes(), eventTwo));
raceLog.unlockAfterRead();
}
@Test
public void testWontAddEventSamePassSameTimePointSameId() {
RaceLogEvent eventOne = mock(RaceLogEvent.class);
RaceLogEvent eventTwo = mock(RaceLogEvent.class);
when(eventOne.getPassId()).thenReturn(0);
when(eventOne.getTimePoint()).thenReturn(new MillisecondsTimePoint(0));
when(eventOne.getId()).thenReturn("a");
when(eventTwo.getPassId()).thenReturn(0);
when(eventTwo.getTimePoint()).thenReturn(new MillisecondsTimePoint(0));
when(eventTwo.getId()).thenReturn("a");
assertTrue(raceLog.add(eventOne)); assertTrue(raceLog.add(eventOne));
assertFalse(raceLog.add(eventTwo)); assertFalse(raceLog.add(eventTwo));
@@ -0,0 +1,36 @@
package com.sap.sailing.domain.racelog.analyzing.impl;
import com.sap.sailing.domain.common.racelog.StartProcedureType;
import com.sap.sailing.domain.racelog.RaceLog;
import com.sap.sailing.domain.racelog.RaceLogEvent;
import com.sap.sailing.domain.racelog.RaceLogStartProcedureChangedEvent;
public class StartProcedureTypeAnalyzer extends RaceLogAnalyzer {
public StartProcedureTypeAnalyzer(RaceLog raceLog) {
super(raceLog);
}
public StartProcedureType getActiveStartProcedureType() {
StartProcedureType result = null;
raceLog.lockForRead();
try {
result = searchLog();
} finally {
raceLog.unlockAfterRead();
}
return result;
}
private StartProcedureType searchLog() {
StartProcedureType result = null;
for (RaceLogEvent event : getAllEvents()) {
if (event instanceof RaceLogStartProcedureChangedEvent) {
RaceLogStartProcedureChangedEvent startProcedureEvent = (RaceLogStartProcedureChangedEvent) event;
result = startProcedureEvent.getStartProcedureType();
}
}
return result;
}
}
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.racelog.impl; package com.sap.sailing.domain.racelog.impl;
import java.util.NavigableSet; import java.util.NavigableSet;
import java.util.logging.Logger;
import com.sap.sailing.domain.racelog.PassAwareRaceLog; import com.sap.sailing.domain.racelog.PassAwareRaceLog;
import com.sap.sailing.domain.racelog.RaceLog; import com.sap.sailing.domain.racelog.RaceLog;
@@ -8,27 +9,27 @@ import com.sap.sailing.domain.racelog.RaceLogEvent;
import com.sap.sailing.domain.tracking.impl.PartialNavigableSetView; import com.sap.sailing.domain.tracking.impl.PartialNavigableSetView;
public class PassAwareRaceLogImpl extends RaceLogImpl implements PassAwareRaceLog { public class PassAwareRaceLogImpl extends RaceLogImpl implements PassAwareRaceLog {
// private static final String TAG = PassAwareRaceLogImpl.class.getName(); private static final Logger logger = Logger.getLogger(PassAwareRaceLogImpl.class.getName());
private static final long serialVersionUID = -1252381252528365834L; private static final long serialVersionUID = -1252381252528365834L;
private static final String ReadWriteLockName = PassAwareRaceLogImpl.class.getName() + ".lock"; private static final String ReadWriteLockName = PassAwareRaceLogImpl.class.getName() + ".lock";
public static final int DefaultPassId = 0; public static final int DefaultPassId = 0;
private int currentPassId; public static PassAwareRaceLog copy(RaceLog raceLog) {
PassAwareRaceLog newRaceLog = new PassAwareRaceLogImpl();
public PassAwareRaceLogImpl(RaceLog raceLog) {
this();
raceLog.lockForRead(); raceLog.lockForRead();
try { try {
for (RaceLogEvent event : raceLog.getRawFixes()) { for (RaceLogEvent event : raceLog.getRawFixes()) {
this.add(event); newRaceLog.add(event);
} }
} finally { } finally {
raceLog.unlockAfterRead(); raceLog.unlockAfterRead();
} }
return newRaceLog;
} }
private int currentPassId;
public PassAwareRaceLogImpl() { public PassAwareRaceLogImpl() {
this(DefaultPassId); this(DefaultPassId);
} }
@@ -44,7 +45,7 @@ public class PassAwareRaceLogImpl extends RaceLogImpl implements PassAwareRaceLo
public void setCurrentPassId(int newPassId) { public void setCurrentPassId(int newPassId) {
if (newPassId != this.currentPassId) { if (newPassId != this.currentPassId) {
// ExLog.i(TAG, String.format("Changing pass id to %d", newPassId)); logger.info(String.format("Changing pass id to %d", newPassId));
this.currentPassId = newPassId; this.currentPassId = newPassId;
} }
} }
@@ -79,11 +80,11 @@ public class PassAwareRaceLogImpl extends RaceLogImpl implements PassAwareRaceLo
unlockAfterWrite(); unlockAfterWrite();
} }
if (isAdded) { if (isAdded) {
// ExLog.i(TAG, String.format("%s (%s) was added to log.", event, event.getClass().getName())); logger.finer(String.format("%s (%s) was added to log.", event, event.getClass().getName()));
setCurrentPassId(Math.max(event.getPassId(), this.currentPassId)); setCurrentPassId(Math.max(event.getPassId(), this.currentPassId));
notifyListenersAboutReceive(event); notifyListenersAboutReceive(event);
} else { } else {
// ExLog.w(TAG, String.format("%s (%s) was not added to log. Ignoring", event, event.getClass().getName())); logger.warning(String.format("%s (%s) was not added to log. Ignoring", event, event.getClass().getName()));
} }
return isAdded; return isAdded;
} }
@@ -28,11 +28,20 @@ public enum RaceLogEventComparator implements Comparator<Timed>, Serializable {
private int compareEvents(RaceLogEvent e1, RaceLogEvent e2) { private int compareEvents(RaceLogEvent e1, RaceLogEvent e2) {
int result = comparePasses(e1, e2); int result = comparePasses(e1, e2);
return result == 0 ? timedComparator.compare(e1, e2) : result; return result == 0 ? compareTimes(e1, e2) : result;
} }
private int comparePasses(RaceLogEvent e1, RaceLogEvent e2) { private int comparePasses(RaceLogEvent e1, RaceLogEvent e2) {
return e1.getPassId() - e2.getPassId(); return e1.getPassId() - e2.getPassId();
} }
private int compareTimes(RaceLogEvent e1, RaceLogEvent e2) {
int result = timedComparator.compare(e1, e2);
return result == 0 ? compareIds(e1, e2) : result;
}
private int compareIds(RaceLogEvent e1, RaceLogEvent e2) {
return e1.getId().toString().compareTo(e2.getId().toString());
}
} }
@@ -15,12 +15,10 @@ import com.sap.sailing.domain.tracking.impl.TrackImpl;
import com.sap.sailing.util.impl.ArrayListNavigableSet; import com.sap.sailing.util.impl.ArrayListNavigableSet;
public class RaceLogImpl extends TrackImpl<RaceLogEvent> implements RaceLog { public class RaceLogImpl extends TrackImpl<RaceLogEvent> implements RaceLog {
private static final long serialVersionUID = -176745401321893502L; private static final long serialVersionUID = -176745401321893502L;
private transient Set<RaceLogEventVisitor> listeners;
private final static Logger logger = Logger.getLogger(RaceLogImpl.class.getName()); private final static Logger logger = Logger.getLogger(RaceLogImpl.class.getName());
private transient Set<RaceLogEventVisitor> listeners;
public RaceLogImpl(String nameForReadWriteLock) { public RaceLogImpl(String nameForReadWriteLock) {
super(new ArrayListNavigableSet<Timed>(RaceLogEventComparator.INSTANCE), nameForReadWriteLock); super(new ArrayListNavigableSet<Timed>(RaceLogEventComparator.INSTANCE), nameForReadWriteLock);
@@ -45,7 +43,10 @@ public class RaceLogImpl extends TrackImpl<RaceLogEvent> implements RaceLog {
unlockAfterWrite(); unlockAfterWrite();
} }
if (isAdded) { if (isAdded) {
logger.finer(String.format("%s (%s) was added to log.", event, event.getClass().getName()));
notifyListenersAboutReceive(event); notifyListenersAboutReceive(event);
} else {
logger.warning(String.format("%s (%s) was not added to log. Ignoring", event, event.getClass().getName()));
} }
return isAdded; return isAdded;
} }
@@ -29,7 +29,7 @@ public class PassawareRaceLogTest {
RaceLogFlagEvent rcEvent1 = RaceLogEventFactory.INSTANCE.createFlagEvent(t1, UUID.randomUUID(), new ArrayList<Competitor>(), passId, Flags.CLASS, Flags.NONE, false); RaceLogFlagEvent rcEvent1 = RaceLogEventFactory.INSTANCE.createFlagEvent(t1, UUID.randomUUID(), new ArrayList<Competitor>(), passId, Flags.CLASS, Flags.NONE, false);
RaceLogFlagEvent rcEvent2 = RaceLogEventFactory.INSTANCE.createFlagEvent(t1, UUID.randomUUID(), new ArrayList<Competitor>(), ++passId, Flags.CLASS, Flags.NONE, false); RaceLogFlagEvent rcEvent2 = RaceLogEventFactory.INSTANCE.createFlagEvent(t1, UUID.randomUUID(), new ArrayList<Competitor>(), ++passId, Flags.CLASS, Flags.NONE, false);
RaceLog passAwareRaceLog = new PassAwareRaceLogImpl(raceLog); RaceLog passAwareRaceLog = PassAwareRaceLogImpl.copy(raceLog);
passAwareRaceLog.add(rcEvent1); passAwareRaceLog.add(rcEvent1);
passAwareRaceLog.add(rcEvent2); passAwareRaceLog.add(rcEvent2);
@@ -125,6 +125,7 @@ import com.sap.sailing.domain.persistence.MongoRaceLogStoreFactory;
import com.sap.sailing.domain.persistence.MongoWindStoreFactory; import com.sap.sailing.domain.persistence.MongoWindStoreFactory;
import com.sap.sailing.domain.polarsheets.BoatAndWindSpeed; import com.sap.sailing.domain.polarsheets.BoatAndWindSpeed;
import com.sap.sailing.domain.polarsheets.PolarSheetGenerationWorker; import com.sap.sailing.domain.polarsheets.PolarSheetGenerationWorker;
import com.sap.sailing.domain.racelog.PassAwareRaceLog;
import com.sap.sailing.domain.racelog.RaceLog; import com.sap.sailing.domain.racelog.RaceLog;
import com.sap.sailing.domain.racelog.RaceLogFlagEvent; import com.sap.sailing.domain.racelog.RaceLogFlagEvent;
import com.sap.sailing.domain.racelog.analyzing.impl.GateLineOpeningTimeFinder; import com.sap.sailing.domain.racelog.analyzing.impl.GateLineOpeningTimeFinder;
@@ -1159,7 +1160,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
RaceLog raceLog = raceColumn.getRaceLog(fleet); RaceLog raceLog = raceColumn.getRaceLog(fleet);
if (raceLog != null) { if (raceLog != null) {
PassAwareRaceLogImpl passAwareRaceLog = new PassAwareRaceLogImpl(raceLog); PassAwareRaceLog passAwareRaceLog = PassAwareRaceLogImpl.copy(raceLog);
StartTimeFinder startTimeFinder = new StartTimeFinder(passAwareRaceLog); StartTimeFinder startTimeFinder = new StartTimeFinder(passAwareRaceLog);
if(startTimeFinder.getStartTime()!=null){ if(startTimeFinder.getStartTime()!=null){
raceInfoDTO.startTime = startTimeFinder.getStartTime().asDate(); raceInfoDTO.startTime = startTimeFinder.getStartTime().asDate();
@@ -122,7 +122,7 @@ public class TestStoringAndRetrievingRaceLogInRegatta extends RaceLogMongoDBTest
@Test @Test
public void testStoreAndRetrieveSimpleLeaderboardWithRaceLogStartProcedureChangedEvent() { public void testStoreAndRetrieveSimpleLeaderboardWithRaceLogStartProcedureChangedEvent() {
RaceLogStartProcedureChangedEvent expectedEvent = RaceLogEventFactory.INSTANCE.createStartProcedureChangedEvent(now, 0, StartProcedureType.RRS26); RaceLogStartProcedureChangedEvent expectedEvent = RaceLogEventFactory.INSTANCE.createStartProcedureChangedEvent(now, 0, StartProcedureType.ESS);
addAndStoreRaceLogEvent(regatta, raceColumnName, expectedEvent); addAndStoreRaceLogEvent(regatta, raceColumnName, expectedEvent);
@@ -25,7 +25,7 @@ public class RaceLogStartProcedureChangedEventSerializer extends BaseRaceLogEven
public JSONObject serialize(RaceLogEvent object) { public JSONObject serialize(RaceLogEvent object) {
RaceLogStartProcedureChangedEvent event = (RaceLogStartProcedureChangedEvent) object; RaceLogStartProcedureChangedEvent event = (RaceLogStartProcedureChangedEvent) object;
JSONObject result = super.serialize(event); JSONObject result = super.serialize(event);
result.put(FIELD_START_PROCEDURE_TYPE, event.getStartProcedureType().toString()); result.put(FIELD_START_PROCEDURE_TYPE, event.getStartProcedureType().name());
return result; return result;
} }
Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

+1 -1
View File
@@ -16,7 +16,7 @@
</div> </div>
<div id='contentWrapper'> <div id='contentWrapper'>
<div id='keyVisual'> <div id='keyVisual'>
<img alt='Sailer' src='images/key-visual.png' /> <img alt='Sailer' src='images/key-visual.jpg' />
<div id='infoBox'> <div id='infoBox'>
<h1 id='pageHeadline'>SAP Sailing Analytics</h1> <h1 id='pageHeadline'>SAP Sailing Analytics</h1>
<p> <p>
@@ -217,7 +217,7 @@ public class RegattaDataPerLegAction extends HttpAction {
int posGL = 0; int posGL = 0;
if (previousLeg != null) { if (previousLeg != null) {
posGL = rankAtWaypoint.get(competitor).get(trackedLeg.getLeg().getTo()) - posGL = rankAtWaypoint.get(competitor).get(trackedLeg.getLeg().getTo()) -
- rankAtWaypoint.get(competitor).get(trackedLeg.getLeg().getFrom()); rankAtWaypoint.get(competitor).get(trackedLeg.getLeg().getFrom());
} }
final Element competitor_node = addNamedElement(competitor_data_node, "competitor"); final Element competitor_node = addNamedElement(competitor_data_node, "competitor");
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 505 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

@@ -2,129 +2,135 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:baselineAligned="false" android:gravity="center_horizontal"
android:orientation="vertical" > android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="left"
android:scaleY="1"
android:text="@string/please_pick_a_time"
android:textAppearance="@style/TextAppearance.Welter.AppDescriptionText" />
<ImageView
android:layout_width="500dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:paddingBottom="2dp"
android:scaleType="fitXY"
android:contentDescription="@string/empty"
android:src="@android:drawable/divider_horizontal_textfield" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="30dp" >
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="200dp"
android:layout_gravity="center_vertical|center_horizontal" >
<LinearLayout
android:layout_width="400dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:scaleY="1.55" >
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="2dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:scaleType="fitXY"
android:contentDescription="@string/empty"
android:src="@android:drawable/divider_horizontal_textfield" />
<TimePicker
android:id="@+id/timePicker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center_horizontal"
android:scaleX="1.55" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="30dp" >
</LinearLayout>
<TextView
android:id="@+id/time_below_picker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="left"
android:scaleY="1"
android:text="@string/time_until_start"
android:textAppearance="@style/TextAppearance.Welter.AppDescriptionText" />
<ImageView
android:layout_width="500dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:paddingBottom="2dp"
android:scaleType="fitXY"
android:contentDescription="@string/empty"
android:src="@android:drawable/divider_horizontal_textfield" />
<LinearLayout <LinearLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="30dp" > android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
android:layout_marginBottom="18dp">
<TextView
android:id="@+id/race_reset_time_txt_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Welter.ExtraBigTitleLabel"
android:text="Schedule race" />
<TextView
android:id="@+id/race_reset_time_text_subheader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Welter.BigTitleLabel"
android:text="Select start mode and start time" />
<ImageView
android:layout_width="500dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:paddingBottom="2dp"
android:scaleType="fitXY"
android:contentDescription="@string/app_name"
android:src="@android:drawable/divider_horizontal_textfield" />
</LinearLayout> </LinearLayout>
<RelativeLayout <LinearLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="200dp" android:layout_height="wrap_content"
android:orientation="horizontal"> android:gravity="center_horizontal"
android:orientation="horizontal"
<Button android:layout_marginBottom="18dp">
android:id="@+id/btnRescheduleTime"
android:layout_width="400dp" <LinearLayout
android:layout_height="200dp"
android:layout_gravity="center_vertical|center_horizontal"
android:text="@string/reset_time"
android:layout_centerHorizontal="true" />
<LinearLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentRight="true" android:orientation="vertical" >
android:layout_alignParentTop="true"
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_horizontal"
android:layout_margin="18dp">
<Spinner
android:id="@+id/race_reset_time_spinner_procedure"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal" />
</LinearLayout>
<LinearLayout
android:layout_width="400dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_margin="18dp">
<Button
android:id="@+id/race_reset_time_btn_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="Today" />
<TimePicker
android:id="@+id/race_reset_time_picker_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="75dp"
android:scaleX="1.55"
android:scaleY="1.55" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:orientation="vertical" android:orientation="vertical"
android:layout_marginRight="30dp"> android:paddingLeft="18dp" >
<ImageButton
android:id="@+id/resetTimeAPButton" <Button
android:layout_width="200dp" android:id="@+id/race_reset_time_btn_time"
android:layout_height="110dp" android:layout_width="180dp"
android:scaleType="fitCenter" android:layout_height="0dp"
android:contentDescription="@string/flag_ap" android:layout_weight="1"
android:src="@drawable/ap_flag" /> android:layout_gravity="center_vertical"
<TextView android:layout_marginTop="18dp"
android:id="@+id/abortingFlagButtonLabel" android:drawableLeft="@drawable/ic_menu_recent_history"
android:layout_width="wrap_content" android:text="Start" />
android:layout_height="wrap_content"
android:layout_marginBottom="20dp" <Button
android:layout_marginTop="2dp" android:id="@+id/race_reset_time_btn_postpone"
android:text="@string/postpone_race" android:layout_width="180dp"
android:layout_gravity="center_horizontal" android:layout_height="0dp"
android:textAppearance="@style/TextAppearance.Welter.AppDescriptionText" /> android:layout_weight="0.2"
</LinearLayout> android:drawableLeft="@drawable/ic_menu_block"
android:text="Postpone" />
</RelativeLayout> </LinearLayout>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal">
<TextView
android:id="@+id/race_reset_time_text_infotext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Welter.LargeFontLabel"
android:text="calculating..." />
</LinearLayout>
</LinearLayout> </LinearLayout>
@@ -4,9 +4,9 @@
<PreferenceCategory android:title="@string/settings_category_general" > <PreferenceCategory android:title="@string/settings_category_general" >
<EditTextPreference <EditTextPreference
android:key="courseAreasPref"
android:name="@string/settings_general_manageareas_header" android:name="@string/settings_general_manageareas_header"
android:defaultValue="@string/settings_general_manageareas_default" android:defaultValue="@string/settings_general_manageareas_default"
android:key="courseAreasPref"
android:summary="@string/settings_general_manageareas_description" android:summary="@string/settings_general_manageareas_description"
android:title="@string/settings_general_manageareas_header" /> android:title="@string/settings_general_manageareas_header" />
</PreferenceCategory> </PreferenceCategory>
@@ -19,6 +19,19 @@
android:summary="Check the box if the Golf flag should be automatically removed in a gate start race" android:summary="Check the box if the Golf flag should be automatically removed in a gate start race"
android:title="Remove Golf Automatically" /> android:title="Remove Golf Automatically" />
--> -->
<CheckBoxPreference
android:key="overrideDefaultStartProcedureType"
android:defaultValue="false"
android:summary="Check the box if races should use the start procedure type defined below as a default"
android:title="Override default start procedure type" />
<ListPreference
android:key="defaultStartProcedureType"
android:title="Default start procedure type"
android:summary="Races will use selected start procedure type as a default. For this option to be active override checkbox has to be enabled."
/>
<EditTextPreference <EditTextPreference
android:defaultValue="30" android:defaultValue="30"
android:inputType="numberDecimal" android:inputType="numberDecimal"
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="settings_advanced_service_default">http://localhost:8888</string> <string name="settings_advanced_service_default">http://192.168.56.1:8888</string>
<string name="intentActionRegisterRace">com.sap.sailing.racecommittee.app.action.registerRace</string> <string name="intentActionRegisterRace">com.sap.sailing.racecommittee.app.action.registerRace</string>
<!-- <string name="intentActionSaveIntent">com.sap.sailing.racecommittee.app.action.saveIntent</string> --> <!-- <string name="intentActionSaveIntent">com.sap.sailing.racecommittee.app.action.saveIntent</string> -->
@@ -18,8 +18,8 @@
<string name="service_info">SAP Race Committee Service</string> <string name="service_info">SAP Race Committee Service</string>
<string name="service_title">Monitoring all races on selected event course.</string> <string name="service_title">Monitoring all races on selected event course.</string>
<string name="app_name">SAP Race Committee Cockpit</string> <string name="app_name">SAP Race Committee Cockpit</string>
<string name="set_time">Set start time</string> <string name="set_time">Start</string>
<string name="reset_time">Reset start time</string> <string name="reset_time">Restart</string>
<string name="choose">Choose</string> <string name="choose">Choose</string>
<string name="current_time">Current time</string> <string name="current_time">Current time</string>
<string name="race_finished_template">%s is finished</string> <string name="race_finished_template">%s is finished</string>
@@ -17,7 +17,7 @@ public class AppConstants {
public final static String RACE_ID_KEY = "raceUuid"; public final static String RACE_ID_KEY = "raceUuid";
public final static String SERVICE_UNIQUE_ID = "serviceUID"; public final static String SERVICE_UNIQUE_ID = "serviceUID";
public final static String RACING_EVENT_TIME = "racingEventTime"; public final static String RACING_EVENT_TIME = "racingEventTime";
public final static String EXTRAS_JSON_KEY = "json"; public final static String EXTRAS_SERIALIZED_EVENT = "json";
public final static String EXTRAS_URL = "url"; public final static String EXTRAS_URL = "url";
public final static String FLAG_KEY = "raceFlag"; public final static String FLAG_KEY = "raceFlag";
@@ -25,6 +25,7 @@ import com.sap.sailing.domain.base.racegroup.SeriesWithRows;
import com.sap.sailing.domain.base.racegroup.impl.RaceGroupImpl; import com.sap.sailing.domain.base.racegroup.impl.RaceGroupImpl;
import com.sap.sailing.domain.base.racegroup.impl.SeriesWithRowsImpl; import com.sap.sailing.domain.base.racegroup.impl.SeriesWithRowsImpl;
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
import com.sap.sailing.domain.common.racelog.StartProcedureType;
import com.sap.sailing.domain.racelog.PassAwareRaceLog; import com.sap.sailing.domain.racelog.PassAwareRaceLog;
import com.sap.sailing.domain.racelog.RaceLogEventFactory; import com.sap.sailing.domain.racelog.RaceLogEventFactory;
import com.sap.sailing.domain.racelog.impl.PassAwareRaceLogImpl; import com.sap.sailing.domain.racelog.impl.PassAwareRaceLogImpl;
@@ -88,7 +89,8 @@ public class OfflineDataManager extends DataManager {
"Q1", "Q1",
new FleetImpl("Default"), new FleetImpl("Default"),
qualifying, qualifying,
raceGroup), raceGroup),
StartProcedureType.ESS,
log); log);
log = new PassAwareRaceLogImpl(); log = new PassAwareRaceLogImpl();
@@ -105,6 +107,7 @@ public class OfflineDataManager extends DataManager {
new FleetImpl("Default"), new FleetImpl("Default"),
qualifying, qualifying,
raceGroup), raceGroup),
StartProcedureType.ESS,
log); log);
log = new PassAwareRaceLogImpl(); log = new PassAwareRaceLogImpl();
@@ -118,6 +121,7 @@ public class OfflineDataManager extends DataManager {
new FleetImpl("Default"), new FleetImpl("Default"),
qualifying, qualifying,
raceGroup), raceGroup),
StartProcedureType.ESS,
log); log);
/*ManagedRace m1 = new ManagedRaceImpl( /*ManagedRace m1 = new ManagedRaceImpl(
new ManagedRaceIdentifierImpl( new ManagedRaceIdentifierImpl(
@@ -13,6 +13,7 @@ import com.sap.sailing.domain.base.racegroup.RaceCell;
import com.sap.sailing.domain.base.racegroup.RaceGroup; import com.sap.sailing.domain.base.racegroup.RaceGroup;
import com.sap.sailing.domain.base.racegroup.RaceRow; import com.sap.sailing.domain.base.racegroup.RaceRow;
import com.sap.sailing.domain.base.racegroup.SeriesWithRows; import com.sap.sailing.domain.base.racegroup.SeriesWithRows;
import com.sap.sailing.domain.common.racelog.StartProcedureType;
import com.sap.sailing.domain.racelog.PassAwareRaceLog; import com.sap.sailing.domain.racelog.PassAwareRaceLog;
import com.sap.sailing.domain.racelog.impl.PassAwareRaceLogImpl; import com.sap.sailing.domain.racelog.impl.PassAwareRaceLogImpl;
import com.sap.sailing.racecommittee.app.domain.ManagedRace; import com.sap.sailing.racecommittee.app.domain.ManagedRace;
@@ -53,7 +54,7 @@ public class ManagedRacesDataParser implements DataParser<Collection<ManagedRace
for (RaceCell cell : raceRow.getCells()) { for (RaceCell cell : raceRow.getCells()) {
PassAwareRaceLog log = cell.getRaceLog() instanceof PassAwareRaceLog ? PassAwareRaceLog log = cell.getRaceLog() instanceof PassAwareRaceLog ?
(PassAwareRaceLog) cell.getRaceLog() : (PassAwareRaceLog) cell.getRaceLog() :
new PassAwareRaceLogImpl(cell.getRaceLog()); PassAwareRaceLogImpl.copy(cell.getRaceLog());
ManagedRace race = createManagedRace( ManagedRace race = createManagedRace(
raceGroup, raceGroup,
series, series,
@@ -71,6 +72,7 @@ public class ManagedRacesDataParser implements DataParser<Collection<ManagedRace
return new ManagedRaceImpl( return new ManagedRaceImpl(
new ManagedRaceIdentifierImpl(name, new ManagedRaceIdentifierImpl(name,
new FleetIdentifierImpl(fleet, series, raceGroup)), new FleetIdentifierImpl(fleet, series, raceGroup)),
StartProcedureType.ESS,
raceLog); raceLog);
} }
@@ -41,7 +41,6 @@ public interface ManagedRace extends ManagedRaceIdentifier, Named, WithID {
*/ */
public CourseBase getCourseDesign(); public CourseBase getCourseDesign();
/** /**
* returns the list of competitors for this race * returns the list of competitors for this race
* @return list of competitors * @return list of competitors
@@ -10,32 +10,30 @@ import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.SeriesBase; import com.sap.sailing.domain.base.SeriesBase;
import com.sap.sailing.domain.base.racegroup.RaceGroup; import com.sap.sailing.domain.base.racegroup.RaceGroup;
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
import com.sap.sailing.domain.common.racelog.StartProcedureType;
import com.sap.sailing.domain.racelog.PassAwareRaceLog; import com.sap.sailing.domain.racelog.PassAwareRaceLog;
import com.sap.sailing.domain.racelog.RaceLog; import com.sap.sailing.domain.racelog.RaceLog;
import com.sap.sailing.racecommittee.app.domain.ManagedRace; import com.sap.sailing.racecommittee.app.domain.ManagedRace;
import com.sap.sailing.racecommittee.app.domain.ManagedRaceIdentifier; import com.sap.sailing.racecommittee.app.domain.ManagedRaceIdentifier;
import com.sap.sailing.racecommittee.app.domain.startprocedure.impl.GateStartProcedure;
import com.sap.sailing.racecommittee.app.domain.state.RaceState; import com.sap.sailing.racecommittee.app.domain.state.RaceState;
import com.sap.sailing.racecommittee.app.domain.state.impl.RaceStateImpl; import com.sap.sailing.racecommittee.app.domain.state.impl.RaceStateImpl;
public class ManagedRaceImpl implements ManagedRace { public class ManagedRaceImpl implements ManagedRace {
private static final long serialVersionUID = -4936566684992524001L; private static final long serialVersionUID = -4936566684992524001L;
//private static final String TAG = ManagedRace.class.getName(); // private static final String TAG = ManagedRace.class.getName();
private ManagedRaceIdentifier identifier; private ManagedRaceIdentifier identifier;
private RaceState state; private RaceState state;
private Collection<Competitor> competitors; private Collection<Competitor> competitors;
private CourseBase courseOnServer; private CourseBase courseOnServer;
public ManagedRaceImpl(ManagedRaceIdentifier identifier, PassAwareRaceLog raceLog) { public ManagedRaceImpl(ManagedRaceIdentifier identifier, StartProcedureType defaultStartProcedureType,
//TODO To be changed when the start procedure for a regatta/leaderboard can be selected in the GWT Admin Console on backend side PassAwareRaceLog raceLog) {
this(identifier, new RaceStateImpl(raceLog, new GateStartProcedure(raceLog))); this(identifier, new RaceStateImpl(defaultStartProcedureType, raceLog));
} }
public ManagedRaceImpl( public ManagedRaceImpl(ManagedRaceIdentifier identifier, RaceState state) {
ManagedRaceIdentifier identifier,
RaceState state) {
this.identifier = identifier; this.identifier = identifier;
this.state = state; this.state = state;
this.competitors = new ArrayList<Competitor>(); this.competitors = new ArrayList<Competitor>();
@@ -86,7 +84,7 @@ public class ManagedRaceImpl implements ManagedRace {
public CourseBase getCourseDesign() { public CourseBase getCourseDesign() {
return state.getCourseDesign(); return state.getCourseDesign();
} }
@Override @Override
public Collection<Competitor> getCompetitors() { public Collection<Competitor> getCompetitors() {
return competitors; return competitors;
@@ -26,7 +26,7 @@ public interface StartProcedure {
void dispatchFiredEventTimePoint(TimePoint startTime, TimePoint eventTime); void dispatchFiredEventTimePoint(TimePoint startTime, TimePoint eventTime);
void setRaceStateChangedListener(StartProcedureRaceStateChangedListener raceStateChangedListener); void setChangeListener(StartProcedureListener listener);
void setFinishing(TimePoint eventTime); void setFinishing(TimePoint eventTime);
@@ -1,21 +1,21 @@
package com.sap.sailing.racecommittee.app.domain.startprocedure; package com.sap.sailing.racecommittee.app.domain.startprocedure;
import com.sap.sailing.domain.common.TimePoint; import com.sap.sailing.domain.common.TimePoint;
public interface StartProcedureRaceStateChangedListener { public interface StartProcedureListener {
void onRaceAborted(TimePoint eventTime); void onRaceAborted(TimePoint eventTime);
void onRaceStartphaseEntered(TimePoint eventTime); void onRaceStartphaseEntered(TimePoint eventTime);
void onRaceStarted(TimePoint eventTime); void onRaceStarted(TimePoint eventTime);
void onRaceFinishing(TimePoint now); void onRaceFinishing(TimePoint now);
void onRaceFinishing(TimePoint now, TimePoint automaticRaceEnd); void onRaceFinishing(TimePoint now, TimePoint automaticRaceEnd);
void onRaceFinished(TimePoint now); void onRaceFinished(TimePoint now);
void onIndividualRecall(TimePoint eventTime); void onIndividualRecall(TimePoint eventTime);
void onIndividualRecallRemoval(); void onIndividualRecallRemoval();
} }
@@ -22,7 +22,7 @@ import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.domain.startprocedure.RunningRaceEventListener; import com.sap.sailing.racecommittee.app.domain.startprocedure.RunningRaceEventListener;
import com.sap.sailing.racecommittee.app.domain.startprocedure.StartPhaseEventListener; import com.sap.sailing.racecommittee.app.domain.startprocedure.StartPhaseEventListener;
import com.sap.sailing.racecommittee.app.domain.startprocedure.StartProcedure; import com.sap.sailing.racecommittee.app.domain.startprocedure.StartProcedure;
import com.sap.sailing.racecommittee.app.domain.startprocedure.StartProcedureRaceStateChangedListener; import com.sap.sailing.racecommittee.app.domain.startprocedure.StartProcedureListener;
import com.sap.sailing.racecommittee.app.ui.fragments.RaceFragment; import com.sap.sailing.racecommittee.app.ui.fragments.RaceFragment;
import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.RunningRaceFragment; import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.RunningRaceFragment;
import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.startphase.EssStartPhaseFragment; import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.startphase.EssStartPhaseFragment;
@@ -41,7 +41,7 @@ public class ExtremeSailingSeriesStartProcedure implements StartProcedure {
private List<Long> startProcedureEventIntervals; private List<Long> startProcedureEventIntervals;
private PassAwareRaceLog raceLog; private PassAwareRaceLog raceLog;
private StartProcedureRaceStateChangedListener raceStateChangedListener; private StartProcedureListener raceStateChangedListener;
private EssStartPhaseEventListener startPhaseEventListener; private EssStartPhaseEventListener startPhaseEventListener;
public ExtremeSailingSeriesStartProcedure(PassAwareRaceLog raceLog) { public ExtremeSailingSeriesStartProcedure(PassAwareRaceLog raceLog) {
@@ -90,10 +90,9 @@ public class ExtremeSailingSeriesStartProcedure implements StartProcedure {
} }
private void handleAPDown(TimePoint eventTime) { private void handleAPDown(TimePoint eventTime) {
TimePoint startPhaseTimePoint = eventTime.minus(1);
if (raceStateChangedListener != null) { if (raceStateChangedListener != null) {
raceStateChangedListener.onRaceStartphaseEntered(startPhaseTimePoint); raceStateChangedListener.onRaceStartphaseEntered(eventTime);
} }
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(eventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(), RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(eventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
@@ -116,9 +115,8 @@ public class ExtremeSailingSeriesStartProcedure implements StartProcedure {
} }
private void handleEssTwoUpAndEssThreeDown(TimePoint eventTime) { private void handleEssTwoUpAndEssThreeDown(TimePoint eventTime) {
TimePoint essThreeDownTimePoint = eventTime.minus(1);
RaceLogEvent essThreeDownEvent = RaceLogEventFactory.INSTANCE.createFlagEvent(essThreeDownTimePoint, UUID.randomUUID(), Collections.<Competitor>emptyList(), RaceLogEvent essThreeDownEvent = RaceLogEventFactory.INSTANCE.createFlagEvent(eventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
raceLog.getCurrentPassId(), Flags.ESSTHREE, Flags.NONE, /*isDisplayed*/false); raceLog.getCurrentPassId(), Flags.ESSTHREE, Flags.NONE, /*isDisplayed*/false);
raceLog.add(essThreeDownEvent); raceLog.add(essThreeDownEvent);
@@ -132,9 +130,8 @@ public class ExtremeSailingSeriesStartProcedure implements StartProcedure {
} }
private void handleEssOneUpAndEssTwoDown(TimePoint eventTime) { private void handleEssOneUpAndEssTwoDown(TimePoint eventTime) {
TimePoint essTwoDownTimePoint = eventTime.minus(1);
RaceLogEvent essTwoDownEvent = RaceLogEventFactory.INSTANCE.createFlagEvent(essTwoDownTimePoint, UUID.randomUUID(), Collections.<Competitor>emptyList(), RaceLogEvent essTwoDownEvent = RaceLogEventFactory.INSTANCE.createFlagEvent(eventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
raceLog.getCurrentPassId(), Flags.ESSTWO, Flags.NONE, /*isDisplayed*/false); raceLog.getCurrentPassId(), Flags.ESSTWO, Flags.NONE, /*isDisplayed*/false);
raceLog.add(essTwoDownEvent); raceLog.add(essTwoDownEvent);
@@ -148,8 +145,7 @@ public class ExtremeSailingSeriesStartProcedure implements StartProcedure {
} }
private void handleEssOneDown(TimePoint eventTime) { private void handleEssOneDown(TimePoint eventTime) {
TimePoint essOneDownTimePoint = eventTime.minus(1); RaceLogEvent essOneDownEvent = RaceLogEventFactory.INSTANCE.createFlagEvent(eventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
RaceLogEvent essOneDownEvent = RaceLogEventFactory.INSTANCE.createFlagEvent(essOneDownTimePoint, UUID.randomUUID(), Collections.<Competitor>emptyList(),
raceLog.getCurrentPassId(), Flags.ESSONE, Flags.NONE, /*isDisplayed*/false); raceLog.getCurrentPassId(), Flags.ESSONE, Flags.NONE, /*isDisplayed*/false);
raceLog.add(essOneDownEvent); raceLog.add(essOneDownEvent);
@@ -159,7 +155,7 @@ public class ExtremeSailingSeriesStartProcedure implements StartProcedure {
} }
@Override @Override
public void setRaceStateChangedListener(StartProcedureRaceStateChangedListener raceStateChangedListener) { public void setChangeListener(StartProcedureListener raceStateChangedListener) {
this.raceStateChangedListener = raceStateChangedListener; this.raceStateChangedListener = raceStateChangedListener;
} }
@@ -169,6 +165,8 @@ public class ExtremeSailingSeriesStartProcedure implements StartProcedure {
TimePoint startPhaseStartTime = getStartPhaseStartTime(newEnteredStartTime); TimePoint startPhaseStartTime = getStartPhaseStartTime(newEnteredStartTime);
TimePoint resultTime; TimePoint resultTime;
if (now.after(startPhaseStartTime)) { if (now.after(startPhaseStartTime)) {
// We do not want RaceStatusEvents with the same timestamp to ensure a reasonable ordering
// Therefore we guarantee that SCHEDULDED happens before STARTPHASE
resultTime = startPhaseStartTime.minus(1); resultTime = startPhaseStartTime.minus(1);
} else { } else {
resultTime = now; resultTime = now;
@@ -179,8 +177,7 @@ public class ExtremeSailingSeriesStartProcedure implements StartProcedure {
@Override @Override
public void setFinishing(TimePoint eventTime) { public void setFinishing(TimePoint eventTime) {
TimePoint blueFlagDisplayEventTime = eventTime.minus(1); RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(eventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(blueFlagDisplayEventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
raceLog.getCurrentPassId(), Flags.BLUE, Flags.NONE, /*isDisplayed*/true); raceLog.getCurrentPassId(), Flags.BLUE, Flags.NONE, /*isDisplayed*/true);
raceLog.add(event); raceLog.add(event);
@@ -204,8 +201,7 @@ public class ExtremeSailingSeriesStartProcedure implements StartProcedure {
@Override @Override
public void setFinished(TimePoint eventTime) { public void setFinished(TimePoint eventTime) {
TimePoint blueFlagRemoveEventTime = eventTime.minus(1); RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(eventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(blueFlagRemoveEventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
raceLog.getCurrentPassId(), Flags.BLUE, Flags.NONE, /*isDisplayed*/false); raceLog.getCurrentPassId(), Flags.BLUE, Flags.NONE, /*isDisplayed*/false);
raceLog.add(event); raceLog.add(event);
@@ -228,8 +224,7 @@ public class ExtremeSailingSeriesStartProcedure implements StartProcedure {
} }
private void handleAPUp(TimePoint eventTime, Flags lowerFlag) { private void handleAPUp(TimePoint eventTime, Flags lowerFlag) {
TimePoint apFlagDisplayEventTime = eventTime.minus(1); RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(eventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(apFlagDisplayEventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
raceLog.getCurrentPassId(), Flags.AP, lowerFlag, /*isDisplayed*/true); raceLog.getCurrentPassId(), Flags.AP, lowerFlag, /*isDisplayed*/true);
raceLog.add(event); raceLog.add(event);
@@ -252,8 +247,7 @@ public class ExtremeSailingSeriesStartProcedure implements StartProcedure {
} }
private void handleNovemberUp(TimePoint eventTime, Flags lowerFlag) { private void handleNovemberUp(TimePoint eventTime, Flags lowerFlag) {
TimePoint novemberFlagDisplayEventTime = eventTime.minus(1); RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(eventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(novemberFlagDisplayEventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
raceLog.getCurrentPassId(), Flags.NOVEMBER, lowerFlag, /*isDisplayed*/true); raceLog.getCurrentPassId(), Flags.NOVEMBER, lowerFlag, /*isDisplayed*/true);
raceLog.add(event); raceLog.add(event);
@@ -264,8 +258,7 @@ public class ExtremeSailingSeriesStartProcedure implements StartProcedure {
@Override @Override
public void setGeneralRecall(TimePoint eventTime) { public void setGeneralRecall(TimePoint eventTime) {
TimePoint recallDisplayEventTime = eventTime.minus(1); RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(eventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(recallDisplayEventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
raceLog.getCurrentPassId(), Flags.FIRSTSUBSTITUTE, Flags.NONE, /*isDisplayed*/true); raceLog.getCurrentPassId(), Flags.FIRSTSUBSTITUTE, Flags.NONE, /*isDisplayed*/true);
raceLog.add(event); raceLog.add(event);
@@ -19,7 +19,7 @@ import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.domain.startprocedure.RunningRaceEventListener; import com.sap.sailing.racecommittee.app.domain.startprocedure.RunningRaceEventListener;
import com.sap.sailing.racecommittee.app.domain.startprocedure.StartPhaseEventListener; import com.sap.sailing.racecommittee.app.domain.startprocedure.StartPhaseEventListener;
import com.sap.sailing.racecommittee.app.domain.startprocedure.StartProcedure; import com.sap.sailing.racecommittee.app.domain.startprocedure.StartProcedure;
import com.sap.sailing.racecommittee.app.domain.startprocedure.StartProcedureRaceStateChangedListener; import com.sap.sailing.racecommittee.app.domain.startprocedure.StartProcedureListener;
import com.sap.sailing.racecommittee.app.ui.fragments.RaceFragment; import com.sap.sailing.racecommittee.app.ui.fragments.RaceFragment;
import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.GateStartRunningRaceFragment; import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.GateStartRunningRaceFragment;
import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.startphase.GateStartPhaseFragment; import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.startphase.GateStartPhaseFragment;
@@ -35,7 +35,7 @@ public class GateStartProcedure implements StartProcedure {
private List<Long> startProcedureEventIntervals; private List<Long> startProcedureEventIntervals;
private PassAwareRaceLog raceLog; private PassAwareRaceLog raceLog;
private StartProcedureRaceStateChangedListener raceStateChangedListener; private StartProcedureListener raceStateChangedListener;
private GateStartPhaseEventListener startPhaseEventListener; private GateStartPhaseEventListener startPhaseEventListener;
private GateStartRunningRaceEventListener runningRaceEventListener; private GateStartRunningRaceEventListener runningRaceEventListener;
@@ -83,13 +83,13 @@ public class GateStartProcedure implements StartProcedure {
} }
private void handleClassOverGolfUp(TimePoint eventTime) { private void handleClassOverGolfUp(TimePoint eventTime) {
TimePoint startPhaseTimePoint = eventTime.minus(1); TimePoint startPhaseTimePoint = eventTime;
if (raceStateChangedListener != null) { if (raceStateChangedListener != null) {
raceStateChangedListener.onRaceStartphaseEntered(startPhaseTimePoint); raceStateChangedListener.onRaceStartphaseEntered(startPhaseTimePoint);
} }
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(eventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(), RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(startPhaseTimePoint, UUID.randomUUID(), Collections.<Competitor>emptyList(),
raceLog.getCurrentPassId(), Flags.CLASS, Flags.GOLF, /*isDisplayed*/true); raceLog.getCurrentPassId(), Flags.CLASS, Flags.GOLF, /*isDisplayed*/true);
raceLog.add(event); raceLog.add(event);
@@ -109,7 +109,7 @@ public class GateStartProcedure implements StartProcedure {
} }
private void handlePapaDown(TimePoint eventTime) { private void handlePapaDown(TimePoint eventTime) {
TimePoint papaDownTimepoint = eventTime.minus(1); TimePoint papaDownTimepoint = eventTime;
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(papaDownTimepoint, UUID.randomUUID(), Collections.<Competitor>emptyList(), RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(papaDownTimepoint, UUID.randomUUID(), Collections.<Competitor>emptyList(),
raceLog.getCurrentPassId(), Flags.PAPA, Flags.NONE, /*isDisplayed*/false); raceLog.getCurrentPassId(), Flags.PAPA, Flags.NONE, /*isDisplayed*/false);
@@ -121,7 +121,8 @@ public class GateStartProcedure implements StartProcedure {
} }
private void handleClassOverGolfDown(TimePoint eventTime) { private void handleClassOverGolfDown(TimePoint eventTime) {
TimePoint essOneDownTimePoint = eventTime.minus(1); TimePoint essOneDownTimePoint = eventTime;
RaceLogEvent essOneDownEvent = RaceLogEventFactory.INSTANCE.createFlagEvent(essOneDownTimePoint, UUID.randomUUID(), Collections.<Competitor>emptyList(), RaceLogEvent essOneDownEvent = RaceLogEventFactory.INSTANCE.createFlagEvent(essOneDownTimePoint, UUID.randomUUID(), Collections.<Competitor>emptyList(),
raceLog.getCurrentPassId(), Flags.CLASS, Flags.GOLF, /*isDisplayed*/false); raceLog.getCurrentPassId(), Flags.CLASS, Flags.GOLF, /*isDisplayed*/false);
raceLog.add(essOneDownEvent); raceLog.add(essOneDownEvent);
@@ -132,7 +133,7 @@ public class GateStartProcedure implements StartProcedure {
} }
@Override @Override
public void setRaceStateChangedListener(StartProcedureRaceStateChangedListener raceStateChangedListener) { public void setChangeListener(StartProcedureListener raceStateChangedListener) {
this.raceStateChangedListener = raceStateChangedListener; this.raceStateChangedListener = raceStateChangedListener;
} }
@@ -142,6 +143,8 @@ public class GateStartProcedure implements StartProcedure {
TimePoint startPhaseStartTime = getStartPhaseStartTime(newEnteredStartTime); TimePoint startPhaseStartTime = getStartPhaseStartTime(newEnteredStartTime);
TimePoint resultTime; TimePoint resultTime;
if (now.after(startPhaseStartTime)) { if (now.after(startPhaseStartTime)) {
// We do not want RaceStatusEvents with the same timestamp to ensure a reasonable ordering
// Therefore we guarantee that SCHEDULDED happens before STARTPHASE
resultTime = startPhaseStartTime.minus(1); resultTime = startPhaseStartTime.minus(1);
} else { } else {
resultTime = now; resultTime = now;
@@ -152,8 +155,7 @@ public class GateStartProcedure implements StartProcedure {
@Override @Override
public void setFinishing(TimePoint eventTime) { public void setFinishing(TimePoint eventTime) {
TimePoint blueFlagDisplayEventTime = eventTime.minus(1); RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(eventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(blueFlagDisplayEventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
raceLog.getCurrentPassId(), Flags.BLUE, Flags.NONE, /*isDisplayed*/true); raceLog.getCurrentPassId(), Flags.BLUE, Flags.NONE, /*isDisplayed*/true);
raceLog.add(event); raceLog.add(event);
@@ -169,8 +171,7 @@ public class GateStartProcedure implements StartProcedure {
@Override @Override
public void setFinished(TimePoint eventTime) { public void setFinished(TimePoint eventTime) {
TimePoint blueFlagRemoveEventTime = eventTime.minus(1); RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(eventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(blueFlagRemoveEventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
raceLog.getCurrentPassId(), Flags.BLUE, Flags.NONE, /*isDisplayed*/false); raceLog.getCurrentPassId(), Flags.BLUE, Flags.NONE, /*isDisplayed*/false);
raceLog.add(event); raceLog.add(event);
@@ -192,9 +193,8 @@ public class GateStartProcedure implements StartProcedure {
} }
} }
private void handleAPUp(TimePoint eventTime, Flags lowerFlag) { private void handleAPUp(TimePoint eventTime, Flags lowerFlag) {
TimePoint apFlagDisplayEventTime = eventTime.minus(1); RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(eventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(apFlagDisplayEventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
raceLog.getCurrentPassId(), Flags.AP, lowerFlag, /*isDisplayed*/true); raceLog.getCurrentPassId(), Flags.AP, lowerFlag, /*isDisplayed*/true);
raceLog.add(event); raceLog.add(event);
@@ -217,8 +217,7 @@ public class GateStartProcedure implements StartProcedure {
} }
private void handleNovemberUp(TimePoint eventTime, Flags lowerFlag) { private void handleNovemberUp(TimePoint eventTime, Flags lowerFlag) {
TimePoint novemberFlagDisplayEventTime = eventTime.minus(1); RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(eventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(novemberFlagDisplayEventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
raceLog.getCurrentPassId(), Flags.NOVEMBER, lowerFlag, /*isDisplayed*/true); raceLog.getCurrentPassId(), Flags.NOVEMBER, lowerFlag, /*isDisplayed*/true);
raceLog.add(event); raceLog.add(event);
@@ -229,8 +228,7 @@ public class GateStartProcedure implements StartProcedure {
@Override @Override
public void setGeneralRecall(TimePoint eventTime) { public void setGeneralRecall(TimePoint eventTime) {
TimePoint recallDisplayEventTime = eventTime.minus(1); RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(eventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(recallDisplayEventTime, UUID.randomUUID(), Collections.<Competitor>emptyList(),
raceLog.getCurrentPassId(), Flags.FIRSTSUBSTITUTE, Flags.NONE, /*isDisplayed*/true); raceLog.getCurrentPassId(), Flags.FIRSTSUBSTITUTE, Flags.NONE, /*isDisplayed*/true);
raceLog.add(event); raceLog.add(event);
@@ -0,0 +1,19 @@
package com.sap.sailing.racecommittee.app.domain.startprocedure.impl;
import com.sap.sailing.domain.common.racelog.StartProcedureType;
import com.sap.sailing.domain.racelog.PassAwareRaceLog;
import com.sap.sailing.racecommittee.app.domain.startprocedure.StartProcedure;
public class StartProcedureFactory {
public static StartProcedure create(StartProcedureType type, PassAwareRaceLog raceLog) {
switch (type) {
case ESS:
return new ExtremeSailingSeriesStartProcedure(raceLog);
case GateStart:
return new GateStartProcedure(raceLog);
default:
throw new UnsupportedOperationException("Not yet implemented start procedure.");
}
}
}
@@ -8,11 +8,12 @@ import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.TimePoint; import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.Util.Triple; import com.sap.sailing.domain.common.impl.Util.Triple;
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
import com.sap.sailing.domain.common.racelog.StartProcedureType;
import com.sap.sailing.domain.racelog.RaceLog; import com.sap.sailing.domain.racelog.RaceLog;
import com.sap.sailing.racecommittee.app.domain.startprocedure.StartProcedure; import com.sap.sailing.racecommittee.app.domain.startprocedure.StartProcedure;
import com.sap.sailing.racecommittee.app.domain.startprocedure.StartProcedureRaceStateChangedListener; import com.sap.sailing.racecommittee.app.domain.startprocedure.StartProcedureListener;
public interface RaceState extends StartProcedureRaceStateChangedListener { public interface RaceState extends StartProcedureListener {
/** /**
* Register a new listener on state changes. * Register a new listener on state changes.
@@ -34,6 +35,16 @@ public interface RaceState extends StartProcedureRaceStateChangedListener {
* @return the log of the race. * @return the log of the race.
*/ */
RaceLog getRaceLog(); RaceLog getRaceLog();
/**
* @return the active or default start procedure type.
*/
StartProcedureType getStartProcedureType();
/**
* @return the start procedure of the race
*/
StartProcedure getStartProcedure();
/** /**
* Gets the current race's start time. * Gets the current race's start time.
@@ -76,7 +87,7 @@ public interface RaceState extends StartProcedureRaceStateChangedListener {
* @param newStartTime * @param newStartTime
* to be set. * to be set.
*/ */
void setStartTime(TimePoint newStartTime); void setStartTime(TimePoint newStartTime, StartProcedureType startProcedureType);
/** /**
* Sets the current race's course design * Sets the current race's course design
@@ -109,11 +120,6 @@ public interface RaceState extends StartProcedureRaceStateChangedListener {
* @return the status of the race. * @return the status of the race.
*/ */
RaceLogRaceStatus getStatus(); RaceLogRaceStatus getStatus();
/**
* @return the start procedure of the race
*/
StartProcedure getStartProcedure();
/** /**
* @return the timepoint at which the individual recall was displayed or null when the individual recall is already removed * @return the timepoint at which the individual recall was displayed or null when the individual recall is already removed
@@ -14,6 +14,7 @@ import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.TimePoint; import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.Util.Triple; import com.sap.sailing.domain.common.impl.Util.Triple;
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
import com.sap.sailing.domain.common.racelog.StartProcedureType;
import com.sap.sailing.domain.racelog.PassAwareRaceLog; import com.sap.sailing.domain.racelog.PassAwareRaceLog;
import com.sap.sailing.domain.racelog.RaceLog; import com.sap.sailing.domain.racelog.RaceLog;
import com.sap.sailing.domain.racelog.RaceLogEvent; import com.sap.sailing.domain.racelog.RaceLogEvent;
@@ -26,17 +27,21 @@ import com.sap.sailing.domain.racelog.analyzing.impl.IndividualRecallFinder;
import com.sap.sailing.domain.racelog.analyzing.impl.LastPublishedCourseDesignFinder; import com.sap.sailing.domain.racelog.analyzing.impl.LastPublishedCourseDesignFinder;
import com.sap.sailing.domain.racelog.analyzing.impl.PathfinderFinder; import com.sap.sailing.domain.racelog.analyzing.impl.PathfinderFinder;
import com.sap.sailing.domain.racelog.analyzing.impl.RaceStatusAnalyzer; import com.sap.sailing.domain.racelog.analyzing.impl.RaceStatusAnalyzer;
import com.sap.sailing.domain.racelog.analyzing.impl.StartProcedureTypeAnalyzer;
import com.sap.sailing.domain.racelog.analyzing.impl.StartTimeFinder; import com.sap.sailing.domain.racelog.analyzing.impl.StartTimeFinder;
import com.sap.sailing.racecommittee.app.domain.racelog.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.racelog.impl.RaceLogChangedVisitor;
import com.sap.sailing.racecommittee.app.domain.startprocedure.StartProcedure; import com.sap.sailing.racecommittee.app.domain.startprocedure.StartProcedure;
import com.sap.sailing.racecommittee.app.domain.startprocedure.impl.GateStartProcedure; import com.sap.sailing.racecommittee.app.domain.startprocedure.impl.GateStartProcedure;
import com.sap.sailing.racecommittee.app.domain.startprocedure.impl.StartProcedureFactory;
import com.sap.sailing.racecommittee.app.domain.state.RaceState; 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.RaceStateChangedListener;
import com.sap.sailing.racecommittee.app.logging.ExLog;
public class RaceStateImpl implements RaceState, RaceLogChangedListener { public class RaceStateImpl implements RaceState, RaceLogChangedListener {
// private static final String TAG = RaceStateImpl.class.getName(); private static final String TAG = RaceStateImpl.class.getSimpleName();
protected StartProcedureType defaultStartProcedureType;
protected PassAwareRaceLog raceLog; protected PassAwareRaceLog raceLog;
protected StartProcedure startProcedure; protected StartProcedure startProcedure;
@@ -44,6 +49,7 @@ public class RaceStateImpl implements RaceState, RaceLogChangedListener {
protected Set<RaceStateChangedListener> stateChangedListeners; protected Set<RaceStateChangedListener> stateChangedListeners;
private RaceLogChangedVisitor raceLogListener; private RaceLogChangedVisitor raceLogListener;
private RaceStatusAnalyzer statusAnalyzer; private RaceStatusAnalyzer statusAnalyzer;
private StartTimeFinder startTimeFinder; private StartTimeFinder startTimeFinder;
private FinishedTimeFinder finishedTimeFinder; private FinishedTimeFinder finishedTimeFinder;
@@ -53,11 +59,11 @@ public class RaceStateImpl implements RaceState, RaceLogChangedListener {
private IndividualRecallFinder individualRecallFinder; private IndividualRecallFinder individualRecallFinder;
private PathfinderFinder pathfinderFinder; private PathfinderFinder pathfinderFinder;
private GateLineOpeningTimeFinder gateLineOpeningTimeFinder; private GateLineOpeningTimeFinder gateLineOpeningTimeFinder;
private StartProcedureTypeAnalyzer startProcedureTypeAnalyzer;
public RaceStateImpl(PassAwareRaceLog raceLog, StartProcedure procedure) { public RaceStateImpl(StartProcedureType defaultStartProcedureType, PassAwareRaceLog raceLog) {
this.defaultStartProcedureType = defaultStartProcedureType;
this.raceLog = raceLog; this.raceLog = raceLog;
this.startProcedure = procedure;
this.startProcedure.setRaceStateChangedListener(this);
this.status = RaceLogRaceStatus.UNKNOWN; this.status = RaceLogRaceStatus.UNKNOWN;
this.stateChangedListeners = new HashSet<RaceStateChangedListener>(); this.stateChangedListeners = new HashSet<RaceStateChangedListener>();
@@ -74,13 +80,18 @@ public class RaceStateImpl implements RaceState, RaceLogChangedListener {
this.individualRecallFinder = new IndividualRecallFinder(raceLog); this.individualRecallFinder = new IndividualRecallFinder(raceLog);
this.pathfinderFinder = new PathfinderFinder(raceLog); this.pathfinderFinder = new PathfinderFinder(raceLog);
this.gateLineOpeningTimeFinder = new GateLineOpeningTimeFinder(raceLog); this.gateLineOpeningTimeFinder = new GateLineOpeningTimeFinder(raceLog);
this.startProcedureTypeAnalyzer = new StartProcedureTypeAnalyzer(raceLog);
registerStartProcedure();
updateStatus(); updateStatus();
} }
@Override
public RaceLog getRaceLog() { public RaceLog getRaceLog() {
return raceLog; return raceLog;
} }
@Override
public RaceLogRaceStatus getStatus() { public RaceLogRaceStatus getStatus() {
return status; return status;
} }
@@ -90,6 +101,21 @@ public class RaceStateImpl implements RaceState, RaceLogChangedListener {
return startProcedure; return startProcedure;
} }
@Override
public StartProcedureType getStartProcedureType() {
StartProcedureType type = startProcedureTypeAnalyzer.getActiveStartProcedureType();
return type == null ? defaultStartProcedureType : type;
}
private void registerStartProcedure() {
if (startProcedure != null) {
startProcedure.setChangeListener(null);
}
StartProcedureType type = getStartProcedureType();
startProcedure = StartProcedureFactory.create(type, raceLog);
startProcedure.setChangeListener(this);
}
private void setStatus(RaceLogRaceStatus newStatus) { private void setStatus(RaceLogRaceStatus newStatus) {
RaceLogRaceStatus oldStatus = this.status; RaceLogRaceStatus oldStatus = this.status;
this.status = newStatus; this.status = newStatus;
@@ -128,15 +154,16 @@ public class RaceStateImpl implements RaceState, RaceLogChangedListener {
return startTimeFinder.getStartTime(); return startTimeFinder.getStartTime();
} }
public void setStartTime(TimePoint newStartTime) { public void setStartTime(TimePoint newStartTime, StartProcedureType type) {
TimePoint eventTime = startProcedure.getLogicalStartTimeEventTime(newStartTime);
RaceLogRaceStatus status = getStatus(); RaceLogRaceStatus status = getStatus();
if (status != RaceLogRaceStatus.UNSCHEDULED) { if (status != RaceLogRaceStatus.UNSCHEDULED) {
//substract minus 2, because a PassChangeEvent (minus 2) AND a RaceStatusEvent (minus 1) will be written to log onRaceAborted(MillisecondsTimePoint.now());
onRaceAborted(eventTime.minus(2));
} }
switchStartProcedure(type);
TimePoint eventTime = startProcedure.getLogicalStartTimeEventTime(newStartTime);
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createStartTimeEvent(eventTime, UUID.randomUUID(), RaceLogEvent event = RaceLogEventFactory.INSTANCE.createStartTimeEvent(eventTime, UUID.randomUUID(),
Collections.<Competitor> emptyList(), raceLog.getCurrentPassId(), newStartTime); Collections.<Competitor> emptyList(), raceLog.getCurrentPassId(), newStartTime);
this.raceLog.add(event); this.raceLog.add(event);
@@ -144,6 +171,18 @@ public class RaceStateImpl implements RaceState, RaceLogChangedListener {
notifyListenersAboutStartTimeChange(newStartTime); notifyListenersAboutStartTimeChange(newStartTime);
} }
private void switchStartProcedure(StartProcedureType type) {
if (!type.equals(startProcedureTypeAnalyzer.getActiveStartProcedureType())) {
RaceLogEvent event = RaceLogEventFactory.INSTANCE.createStartProcedureChangedEvent(MillisecondsTimePoint.now(), raceLog.getCurrentPassId(), type);
this.raceLog.add(event);
registerStartProcedure();
ExLog.i(TAG, String.format("Switch start procedure to %s", this.startProcedure.getClass().getSimpleName()));
}
}
public TimePoint getFinishedTime() { public TimePoint getFinishedTime() {
return finishedTimeFinder.getFinishedTime(); return finishedTimeFinder.getFinishedTime();
} }
@@ -152,8 +191,7 @@ public class RaceStateImpl implements RaceState, RaceLogChangedListener {
public CourseBase getCourseDesign() { public CourseBase getCourseDesign() {
return lastCourseDesignFinder.getLastCourseDesign(); return lastCourseDesignFinder.getLastCourseDesign();
} }
public void setCourseDesign(CourseBase newCourseData) { public void setCourseDesign(CourseBase newCourseData) {
TimePoint eventTime = MillisecondsTimePoint.now(); TimePoint eventTime = MillisecondsTimePoint.now();
@@ -164,6 +202,9 @@ public class RaceStateImpl implements RaceState, RaceLogChangedListener {
@Override @Override
public void onRaceAborted(TimePoint eventTime) { public void onRaceAborted(TimePoint eventTime) {
/*RaceLogEvent abortEvent = RaceLogEventFactory.INSTANCE.createRaceStatusEvent(eventTime, raceLog.getCurrentPassId(), RaceLogRaceStatus.UNSCHEDULED);
this.raceLog.add(abortEvent);*/
RaceLogEvent passChangeEvent = RaceLogEventFactory.INSTANCE.createPassChangeEvent(eventTime, raceLog.getCurrentPassId() + 1); RaceLogEvent passChangeEvent = RaceLogEventFactory.INSTANCE.createPassChangeEvent(eventTime, raceLog.getCurrentPassId() + 1);
this.raceLog.add(passChangeEvent); this.raceLog.add(passChangeEvent);
@@ -23,101 +23,95 @@ public class EventPersistenceManager {
private final static String delayedEventFileName = "delayedEvents.txt"; private final static String delayedEventFileName = "delayedEvents.txt";
private Context context; private Context context;
private String fileContent; private List<String> persistedEvents;
public EventPersistenceManager(Context context) { public EventPersistenceManager(Context context) {
this.context = context; this.context = context;
fileContent = ""; persistedEvents = new ArrayList<String>();
initializeFile(); initializeFileAndPersistedEvents();
} }
public boolean areIntentsDelayed() { public boolean areIntentsDelayed() {
return !fileContent.isEmpty(); return !persistedEvents.isEmpty();
} }
public void persistIntent(Intent intent) { public void persistIntent(Intent intent) {
Bundle extras = intent.getExtras(); Bundle extras = intent.getExtras();
Serializable serializedEvent = extras.getSerializable(AppConstants.EXTRAS_JSON_KEY); String raceId = extras.getString(AppConstants.RACE_ID_KEY);
String raceUuid = extras.getSerializable(AppConstants.RACE_ID_KEY).toString(); String url = extras.getString(AppConstants.EXTRAS_URL);
Serializable serializedEvent = extras.getSerializable(AppConstants.EXTRAS_SERIALIZED_EVENT);
persistEvent(raceUuid, serializedEvent);
persistEvent(url, raceId, serializedEvent);
} }
private void persistEvent(String raceUuid, Serializable serializedEvent) { private void persistEvent(String url, String raceId, Serializable serializedEvent) {
String eventLine = String.format("%s;%s\n", raceUuid, serializedEvent); String eventLine = getSerializedIntentForPersistence(url, raceId, serializedEvent);
ExLog.i(TAG, "Called to persist following event " + eventLine); ExLog.i(TAG, String.format("Persisting event \"%s\" for race %s.", eventLine, raceId));
if (!fileContent.isEmpty()) { if (persistedEvents.contains(eventLine)) {
if (fileContent.contains(eventLine)) { ExLog.i(TAG, "The event already exists. Ignoring.");
ExLog.i(TAG, "The event to persist exists already in file"); return;
return;
}
} }
writeEventToFile(eventLine); saveEvent(eventLine);
}
private String getSerializedIntentForPersistence(String url, String raceId, Serializable serializedEvent) {
String eventLine = String.format("%s;%s;%s", raceId, serializedEvent, url);
return eventLine;
} }
public void removeIntent(Intent intent) { public void removeIntent(Intent intent) {
Bundle extras = intent.getExtras(); Bundle extras = intent.getExtras();
String serializedEvent = extras.getString(AppConstants.EXTRAS_JSON_KEY); String url = extras.getString(AppConstants.EXTRAS_URL);
String raceUuid = extras.getString(AppConstants.RACE_ID_KEY); String raceId = extras.getString(AppConstants.RACE_ID_KEY);
String serializedEvent = extras.getString(AppConstants.EXTRAS_SERIALIZED_EVENT);
removeEvent(raceUuid, serializedEvent); removeEvent(url, raceId, serializedEvent);
} }
private void removeEvent(String raceUuid, String serializedEvent) { private void removeEvent(String url, String raceId, String serializedEvent) {
if (fileContent.isEmpty()) if (persistedEvents.isEmpty())
return; return;
ExLog.i(TAG, "removeEvent is called for " + raceUuid + ", serializedEvent " + serializedEvent); ExLog.i(TAG, String.format("Removing event \"%s\" for race %s.", serializedEvent, raceId));
String eventLine = String.format("%s;%s\n", raceUuid, serializedEvent); String eventLine = getSerializedIntentForPersistence(url, raceId, serializedEvent);
removeEntryInFileContent(eventLine);
removePersistedEvent(eventLine);
} }
/** /**
* @param eventLine * @param eventLine
*/ */
private void removeEntryInFileContent(String eventLine) { private void removePersistedEvent(String eventLine) {
if (fileContent.contains(eventLine)) { if (persistedEvents.contains(eventLine)) {
fileContent = fileContent.replace(eventLine, ""); persistedEvents.remove(eventLine);
writeFileContentToFile(); writePersistedEventsToFile();
ExLog.i(TAG, "Entry " + eventLine + " is removed from fileContent"); ExLog.i(TAG, "Event removed.");
} }
} }
public int getEventCount() { public int getEventCount() {
if (fileContent.isEmpty()) { return persistedEvents.size();
return 0;
}
return fileContent.split("\n").length;
} }
public List<Intent> restoreEvents() { public List<Intent> restoreEvents() {
List<Intent> delayedIntents = new ArrayList<Intent>(); List<Intent> delayedIntents = new ArrayList<Intent>();
List<String> fileEntriesToBeRemoved = new ArrayList<String>(); //These file entries may be too old. No appropriate race id has been found for this event.
if (!fileContent.isEmpty()) { for (String persistedEvent : persistedEvents) {
String[] eventLines = fileContent.split("\n");
for (String line : eventLines) {
if (!line.isEmpty()) {
String[] lineParts = line.split(";");
Intent eventIntent = EventSendingService.createEventIntent(context, lineParts[0], lineParts[1]); String[] lineParts = persistedEvent.split(";");
if (eventIntent != null) { String url = lineParts[2];
delayedIntents.add(eventIntent); String raceId = lineParts[0];
} else { String serializedEvent = lineParts[1];
fileEntriesToBeRemoved.add(line);
} Intent eventIntent = EventSendingService.createEventIntent(context, url, raceId, serializedEvent);
} if (eventIntent != null) {
delayedIntents.add(eventIntent);
} }
} }
for (String lineToBeRemoved : fileEntriesToBeRemoved) {
removeEntryInFileContent(lineToBeRemoved);
}
ExLog.i(TAG, "Restored " + delayedIntents.size() + " events"); ExLog.i(TAG, "Restored " + delayedIntents.size() + " events");
return delayedIntents; return delayedIntents;
@@ -141,30 +135,40 @@ public class EventPersistenceManager {
return fileContent; return fileContent;
} }
private void writeEventToFile(String eventLine) { private void saveEvent(String eventLine) {
fileContent += eventLine; persistedEvents.add(eventLine);
writeFileContentToFile(); writePersistedEventsToFile();
ExLog.i(TAG, "Wrote event to file: " + eventLine); ExLog.i(TAG, "Wrote event to file: " + eventLine);
} }
private void writeFileContentToFile() { private void writePersistedEventsToFile() {
writeToFile(fileContent, Context.MODE_PRIVATE); String newFileContent = "";
ExLog.i(TAG, "Wrote file content to file: " + fileContent); for (String persistedEvent : persistedEvents) {
newFileContent += persistedEvent + "\n";
}
writeToFile(newFileContent, Context.MODE_PRIVATE);
ExLog.i(TAG, "Wrote file content to file: " + newFileContent);
} }
private void initializeFile() { private void initializeFileAndPersistedEvents() {
try { try {
fileContent = getFileContent(); String fileContent = getFileContent();
String[] eventLines = fileContent.split("\n");
for (String eventLine : eventLines) {
if (!eventLine.isEmpty()) {
persistedEvents.add(eventLine);
}
}
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
ExLog.w(TAG, "persistence file not found in internal storage. The file will be created."); ExLog.w(TAG, "persistence file not found in internal storage. The file will be created.");
clearFileContent(); clearPersistedEvents();
} }
ExLog.i(TAG, "Initialized file"); ExLog.i(TAG, "Initialized file");
} }
private void clearFileContent() { private void clearPersistedEvents() {
fileContent = ""; persistedEvents.clear();
writeFileContentToFile(); writePersistedEventsToFile();
} }
private void writeToFile(String content, int mode) { private void writeToFile(String content, int mode) {
@@ -34,7 +34,7 @@ public class EventSenderTask extends AsyncTask<Intent, Void, Pair<Intent, Intege
} }
Bundle extras = intent.getExtras(); Bundle extras = intent.getExtras();
Serializable serializedEvent = extras.getSerializable(AppConstants.EXTRAS_JSON_KEY); Serializable serializedEvent = extras.getSerializable(AppConstants.EXTRAS_SERIALIZED_EVENT);
String url = extras.getString(AppConstants.EXTRAS_URL); String url = extras.getString(AppConstants.EXTRAS_URL);
if (serializedEvent == null || url == null) { if (serializedEvent == null || url == null) {
return Pair.create(intent, -1); return Pair.create(intent, -1);
@@ -47,7 +47,7 @@ public class EventSenderTask extends AsyncTask<Intent, Void, Pair<Intent, Intege
} finally { } finally {
post.disconnect(); post.disconnect();
} }
ExLog.i(getClass().getName(), "Post request issued for the following Event: " + serializedEvent); ExLog.i(getClass().getName(), "Post successful for the following event: " + serializedEvent);
} catch (Exception e) { } catch (Exception e) {
ExLog.e(getClass().getName(), e.toString()); ExLog.e(getClass().getName(), e.toString());
return Pair.create(intent, -1); return Pair.create(intent, -1);
@@ -17,8 +17,6 @@ import android.os.IBinder;
import com.sap.sailing.racecommittee.app.AppConstants; import com.sap.sailing.racecommittee.app.AppConstants;
import com.sap.sailing.racecommittee.app.R; 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.ManagedRace;
import com.sap.sailing.racecommittee.app.logging.ExLog; import com.sap.sailing.racecommittee.app.logging.ExLog;
import com.sap.sailing.racecommittee.app.receiver.ConnectivityChangedReceiver; import com.sap.sailing.racecommittee.app.receiver.ConnectivityChangedReceiver;
@@ -43,6 +41,17 @@ public class EventSendingService extends Service implements EventSendingListener
private final IBinder mBinder = new EventSendingBinder(); private final IBinder mBinder = new EventSendingBinder();
private EventPersistenceManager persistenceManager; private EventPersistenceManager persistenceManager;
private boolean isHandlerSet; private boolean isHandlerSet;
private EventSendingServiceLogger serviceLogger;
public interface EventSendingServiceLogger {
public void onEventSentSuccessful();
public void onEventSentFailed();
}
public void setEventSendingServiceLogger(EventSendingServiceLogger logger) {
serviceLogger = logger;
}
public class EventSendingBinder extends Binder { public class EventSendingBinder extends Binder {
public EventSendingService getService() { public EventSendingService getService() {
@@ -84,23 +93,17 @@ public class EventSendingService extends Service implements EventSendingListener
URLEncoder.encode(race.getName()), URLEncoder.encode(race.getName()),
URLEncoder.encode(race.getFleet().getName())); URLEncoder.encode(race.getFleet().getName()));
return createEventIntent(context, url, race.getId(), serializedEvent);
}
public static Intent createEventIntent(Context context, String url, Serializable raceId, Serializable serializedEvent) {
Intent eventIntent = new Intent(context.getString(R.string.intentActionSendEvent)); Intent eventIntent = new Intent(context.getString(R.string.intentActionSendEvent));
eventIntent.putExtra(AppConstants.RACE_ID_KEY, race.getId()); eventIntent.putExtra(AppConstants.RACE_ID_KEY, raceId);
eventIntent.putExtra(AppConstants.EXTRAS_JSON_KEY, serializedEvent); eventIntent.putExtra(AppConstants.EXTRAS_SERIALIZED_EVENT, serializedEvent);
eventIntent.putExtra(AppConstants.EXTRAS_URL, url); eventIntent.putExtra(AppConstants.EXTRAS_URL, url);
ExLog.i(TAG, "Created event " + eventIntent + " for sending to backend"); ExLog.i(TAG, "Created event " + eventIntent + " for sending to backend");
return eventIntent; 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) * (non-Javadoc)
@@ -144,7 +147,9 @@ public class EventSendingService extends Service implements EventSendingListener
} }
private void handleSendEvents(Intent intent) { private void handleSendEvents(Intent intent) {
ExLog.i(TAG, String.format("Trying to send an event..."));
if (!isConnected()) { if (!isConnected()) {
ExLog.i(TAG, String.format("Send aborted because there is no connection."));
persistenceManager.persistIntent(intent); persistenceManager.persistIntent(intent);
ConnectivityChangedReceiver.enable(this); ConnectivityChangedReceiver.enable(this);
} else { } else {
@@ -153,16 +158,21 @@ public class EventSendingService extends Service implements EventSendingListener
} }
private void handleDelayedEvents() { private void handleDelayedEvents() {
ExLog.i(TAG, String.format("Trying to resend stored events..."));
isHandlerSet = false; isHandlerSet = false;
if (!isConnected()) if (!isConnected()) {
ExLog.i(TAG, String.format("Resend aborted because there is no connection."));
return; return;
}
sendDelayedEvents(); sendDelayedEvents();
} }
private void sendDelayedEvents() { private void sendDelayedEvents() {
List<Intent> delayedIntents = persistenceManager.restoreEvents(); List<Intent> delayedIntents = persistenceManager.restoreEvents();
ExLog.i(TAG, String.format("Trying to resend %d waiting events", delayedIntents.size())); ExLog.i(TAG, String.format("Resending %d events...", delayedIntents.size()));
for (Intent intent : delayedIntents) for (Intent intent : delayedIntents)
sendEvent(intent); sendEvent(intent);
} }
@@ -178,17 +188,23 @@ public class EventSendingService extends Service implements EventSendingListener
public void onResult(Intent intent, boolean success) { public void onResult(Intent intent, boolean success) {
if (!success) { if (!success) {
ExLog.w(TAG, "Could not POST intent to server."); ExLog.w(TAG, "Error while posting intent to server. Will persist intent...");
persistenceManager.persistIntent(intent); persistenceManager.persistIntent(intent);
if (!isHandlerSet) { if (!isHandlerSet) {
SendDelayedEventsCaller delayedCaller = new SendDelayedEventsCaller(this); SendDelayedEventsCaller delayedCaller = new SendDelayedEventsCaller(this);
handler.postDelayed(delayedCaller, 1000 * 30); //after 30 sec, try the sending again handler.postDelayed(delayedCaller, 1000 * 30); //after 30 sec, try the sending again
isHandlerSet = true; isHandlerSet = true;
} }
serviceLogger.onEventSentFailed();
} else { } else {
ExLog.i(TAG, "Event successfully send. " + intent.getStringExtra(AppConstants.EXTRAS_JSON_KEY)); ExLog.i(TAG, "Event successfully send.");
persistenceManager.removeIntent(intent); if (persistenceManager.areIntentsDelayed()) {
persistenceManager.removeIntent(intent);
}
lastSuccessfulSend = Calendar.getInstance().getTime(); lastSuccessfulSend = Calendar.getInstance().getTime();
serviceLogger.onEventSentSuccessful();
} }
} }
@@ -1,30 +1,75 @@
package com.sap.sailing.racecommittee.app.ui.activities; package com.sap.sailing.racecommittee.app.ui.activities;
import com.sap.sailing.racecommittee.app.AppConstants; import java.util.Date;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.logging.ExLog;
import android.app.Activity; import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.os.IBinder;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.widget.Toast; import android.widget.Toast;
import com.sap.sailing.racecommittee.app.AppConstants;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.services.sending.EventSendingService;
import com.sap.sailing.racecommittee.app.services.sending.EventSendingService.EventSendingBinder;
import com.sap.sailing.racecommittee.app.services.sending.EventSendingService.EventSendingServiceLogger;
/** /**
* Base activity for all race committee cockpit activities enabling basic menu functionality. * Base activity for all race committee cockpit activities enabling basic menu functionality.
*/ */
public abstract class BaseActivity extends Activity { public abstract class BaseActivity extends Activity {
private class EventSendingServiceConnection implements ServiceConnection, EventSendingServiceLogger {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
EventSendingBinder binder = (EventSendingBinder) service;
sendingService = binder.getService();
boundSendingService = true;
sendingService.setEventSendingServiceLogger(this);
updateLiveIcon();
}
@Override
public void onServiceDisconnected(ComponentName arg) {
boundSendingService = false;
}
@Override
public void onEventSentSuccessful() {
updateLiveIcon();
}
@Override
public void onEventSentFailed() {
updateLiveIcon();
}
}
protected MenuItem menuItemLive; protected MenuItem menuItemLive;
boolean boundSendingService = false;
EventSendingService sendingService;
EventSendingServiceConnection sendingServiceConnection;
String sendingServiceStatus = "";
public BaseActivity() {
this.sendingServiceConnection = new EventSendingServiceConnection();
}
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater(); MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.options_menu, menu); inflater.inflate(R.menu.options_menu, menu);
menuItemLive = menu.findItem(R.id.LiveIcon); menuItemLive = menu.findItem(R.id.LiveIcon);
setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
return true; return true;
} }
@@ -39,7 +84,7 @@ public abstract class BaseActivity extends Activity {
fadeActivity(SettingsActivity.class); fadeActivity(SettingsActivity.class);
return true; return true;
case R.id.LiveIcon: case R.id.LiveIcon:
Toast.makeText(this, AppConstants.getServerBaseURL(this), Toast.LENGTH_SHORT).show(); Toast.makeText(this, getLiveIconText(), Toast.LENGTH_LONG).show();
return true; return true;
case R.id.WindLog: // fadeActivity(WindActivity.class); return false; case R.id.WindLog: // fadeActivity(WindActivity.class); return false;
case android.R.id.home: case android.R.id.home:
@@ -48,37 +93,58 @@ public abstract class BaseActivity extends Activity {
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
} }
protected boolean onHomeClicked() {
return false;
}
@Override @Override
public boolean onPrepareOptionsMenu(Menu menu) { public boolean onPrepareOptionsMenu(Menu menu) {
updateLiveIcon(); updateLiveIcon();
return super.onPrepareOptionsMenu(menu); return super.onPrepareOptionsMenu(menu);
} }
protected boolean onHomeClicked() {
return false;
}
@Override @Override
protected void onResume() { protected void onStart() {
super.onResume(); super.onStart();
updateLiveIcon();
Intent intent = new Intent(this, EventSendingService.class);
bindService(intent, sendingServiceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
if (boundSendingService) {
unbindService(sendingServiceConnection);
boundSendingService = false;
}
} }
private void updateLiveIcon() { private void updateLiveIcon() {
if (menuItemLive == null) if (menuItemLive == null)
return; return;
ExLog.i("OptionsMenu", "Querying remote status."); if (!boundSendingService)
if (AppConstants.getServerBaseURL(this).indexOf("sapsailing.com") != -1) { return;
ExLog.i("OptionsMenu", "It's remote.");
menuItemLive.setIcon(R.drawable.ic_menu_share_sapsailing); int errorCount = this.sendingService.getDelayedIntentsCount();
if (errorCount > 0) {
menuItemLive.setIcon(R.drawable.ic_menu_share_red);
Date lastSuccessfulSend = this.sendingService.getLastSuccessfulSend();
sendingServiceStatus = String.format("Currently %d events waiting to be sent.\nLast successful sent was at %s",
errorCount, lastSuccessfulSend == null ? "never" : lastSuccessfulSend);
} else { } else {
ExLog.i("OptionsMenu", "It's local."); menuItemLive.setIcon(R.drawable.ic_menu_share_holo_light);
menuItemLive.setIcon(R.drawable.ic_menu_share_local); sendingServiceStatus = String.format("Currently no event waiting to be sent.", errorCount);
} }
} }
private String getLiveIconText() {
return String.format("Connected to: %s\n%s", AppConstants.getServerBaseURL(this), sendingServiceStatus);
}
protected void fadeActivity(Class<?> activity) { protected void fadeActivity(Class<?> activity) {
Intent intent = new Intent(getBaseContext(), activity); Intent intent = new Intent(getBaseContext(), activity);
fadeActivity(intent); fadeActivity(intent);
@@ -177,8 +177,10 @@ public class RacingActivity extends TwoPaneActivity implements RaceInfoListener,
dialog.cancel(); dialog.cancel();
} }
}); });
AlertDialog alert = builder.create(); if (!isFinishing()) {
alert.show(); AlertDialog alert = builder.create();
alert.show();
}
} }
public void onRaceItemClicked(ManagedRace managedRace) { public void onRaceItemClicked(ManagedRace managedRace) {
@@ -1,8 +1,13 @@
package com.sap.sailing.racecommittee.app.ui.activities; package com.sap.sailing.racecommittee.app.ui.activities;
import java.util.ArrayList;
import java.util.List;
import android.os.Bundle; import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.PreferenceActivity; import android.preference.PreferenceActivity;
import com.sap.sailing.domain.common.racelog.StartProcedureType;
import com.sap.sailing.racecommittee.app.R; import com.sap.sailing.racecommittee.app.R;
/** /**
@@ -15,5 +20,18 @@ public class SettingsActivity extends PreferenceActivity {
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
addPreferencesFromResource(R.layout.settings_view); addPreferencesFromResource(R.layout.settings_view);
ListPreference startProcedurePreference = (ListPreference) findPreference("defaultStartProcedureType");
List<CharSequence> entries = new ArrayList<CharSequence>();
List<CharSequence> entryValues = new ArrayList<CharSequence>();
for (StartProcedureType type : StartProcedureType.values()) {
entries.add(type.toString());
entryValues.add(type.name());
}
startProcedurePreference.setEntries(entries.toArray(new CharSequence[0]));
startProcedurePreference.setEntryValues(entryValues.toArray(new CharSequence[0]));
} }
} }
@@ -19,6 +19,17 @@ public abstract class RaceFragment extends Fragment implements TickListener {
return arguments; return arguments;
} }
/**
* Creates a bundle that contains the race id as parameter for the next fragment
*
* @return a bundle containing the race id
*/
protected Bundle getRecentArguments() {
Bundle args = new Bundle();
args.putSerializable(AppConstants.RACE_ID_KEY, managedRace.getId());
return args;
}
private ManagedRace managedRace; private ManagedRace managedRace;
@Override @Override
@@ -49,16 +60,10 @@ public abstract class RaceFragment extends Fragment implements TickListener {
public ManagedRace getRace() { public ManagedRace getRace() {
return managedRace; return managedRace;
} }
/** @Override
* Creates a bundle that contains the race id as parameter for the next fragment public void notifyTick() {
* // may be overriden in subclasses.
* @return a bundle containing the race id
*/
protected Bundle getParameterBundle() {
Bundle args = new Bundle();
args.putSerializable(AppConstants.RACE_ID_KEY, managedRace.getId());
return args;
} }
} }
@@ -147,7 +147,7 @@ public class RaceInfoFragment extends RaceFragment implements RaceStateChangedLi
RaceDialogFragment fragment = new CourseDesignDialogFragment(); RaceDialogFragment fragment = new CourseDesignDialogFragment();
Bundle args = getParameterBundle(); Bundle args = getRecentArguments();
fragment.setArguments(args); fragment.setArguments(args);
fragment.show(fragmentManager, "courseDesignDialogFragment"); fragment.show(fragmentManager, "courseDesignDialogFragment");
@@ -119,7 +119,7 @@ public class FinishingRaceFragment extends RaceFragment {
RaceDialogFragment fragment = new AbortModeSelectionDialog(); RaceDialogFragment fragment = new AbortModeSelectionDialog();
Bundle args = getParameterBundle(); Bundle args = getRecentArguments();
args.putString(AppConstants.FLAG_KEY, Flags.NOVEMBER.name()); args.putString(AppConstants.FLAG_KEY, Flags.NOVEMBER.name());
fragment.setArguments(args); fragment.setArguments(args);
@@ -171,7 +171,7 @@ public class GateStartRunningRaceFragment extends RaceFragment implements GateSt
RaceDialogFragment fragment = new AbortTypeSelectionDialog(); RaceDialogFragment fragment = new AbortTypeSelectionDialog();
Bundle args = getParameterBundle(); Bundle args = getRecentArguments();
fragment.setArguments(args); fragment.setArguments(args);
fragment.show(fragmentManager, "dialogAPNovemberMode"); fragment.show(fragmentManager, "dialogAPNovemberMode");
@@ -185,7 +185,7 @@ public class GateStartRunningRaceFragment extends RaceFragment implements GateSt
private void showPathFinderDialog() { private void showPathFinderDialog() {
FragmentManager fragmentManager = getFragmentManager(); FragmentManager fragmentManager = getFragmentManager();
RaceDialogFragment fragment = new RaceChoosePathFinderDialog(); RaceDialogFragment fragment = new RaceChoosePathFinderDialog();
Bundle args = getParameterBundle(); Bundle args = getRecentArguments();
fragment.setArguments(args); fragment.setArguments(args);
fragment.show(fragmentManager, null); fragment.show(fragmentManager, null);
} }
@@ -193,7 +193,7 @@ public class GateStartRunningRaceFragment extends RaceFragment implements GateSt
private void showLineOpeningTimeDialog() { private void showLineOpeningTimeDialog() {
FragmentManager fragmentManager = getFragmentManager(); FragmentManager fragmentManager = getFragmentManager();
RaceDialogFragment fragment = new RaceChooseLineOpeningTimeDialog(); RaceDialogFragment fragment = new RaceChooseLineOpeningTimeDialog();
Bundle args = getParameterBundle(); Bundle args = getRecentArguments();
fragment.setArguments(args); fragment.setArguments(args);
fragment.show(fragmentManager, null); fragment.show(fragmentManager, null);
} }
@@ -156,7 +156,7 @@ public class RunningRaceFragment extends RaceFragment implements IndividualRecal
RaceDialogFragment fragment = new AbortTypeSelectionDialog(); RaceDialogFragment fragment = new AbortTypeSelectionDialog();
Bundle args = getParameterBundle(); Bundle args = getRecentArguments();
fragment.setArguments(args); fragment.setArguments(args);
fragment.show(fragmentManager, "dialogAPNovemberMode"); fragment.show(fragmentManager, "dialogAPNovemberMode");
@@ -5,17 +5,23 @@ import java.util.Date;
import android.app.FragmentManager; import android.app.FragmentManager;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageButton; import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import android.widget.TimePicker; import android.widget.TimePicker;
import android.widget.Toast;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint; import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.common.racelog.Flags; import com.sap.sailing.domain.common.racelog.Flags;
import com.sap.sailing.domain.common.racelog.StartProcedureType;
import com.sap.sailing.racecommittee.app.AppConstants; import com.sap.sailing.racecommittee.app.AppConstants;
import com.sap.sailing.racecommittee.app.R; import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.domain.ManagedRace; import com.sap.sailing.racecommittee.app.domain.ManagedRace;
@@ -33,13 +39,14 @@ public class SetStartTimeRaceFragment extends RaceFragment {
} }
protected boolean isReset; protected boolean isReset;
private StartProcedureType selectedStartProcedureType;
protected TimePicker startTimePicker; protected Spinner spinnerStartProcedure;
protected Button setStartTimeButton; protected TimePicker pickerTime;
protected TextView countdownView; protected Button btSetDate;
protected ImageButton abortRaceButton; protected Button btSetTime;
protected Button btPostpone;
protected Date scheduledTime; protected TextView textInfoText;
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@@ -49,100 +56,144 @@ public class SetStartTimeRaceFragment extends RaceFragment {
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
isReset = getArguments().getBoolean(AppConstants.RESET_TIME_FRAGMENT_IS_RESET); isReset = getArguments().getBoolean(AppConstants.RESET_TIME_FRAGMENT_IS_RESET);
startTimePicker = (TimePicker) getView().findViewById(R.id.timePicker); spinnerStartProcedure = (Spinner) getView().findViewById(R.id.race_reset_time_spinner_procedure);
setStartTimeButton = (Button) getView().findViewById(R.id.btnRescheduleTime); setupStartProcedureSpinner();
countdownView = (TextView) getView().findViewById(R.id.time_below_picker); pickerTime = (TimePicker) getView().findViewById(R.id.race_reset_time_picker_time);
abortRaceButton = (ImageButton) getView().findViewById(R.id.resetTimeAPButton); setupTimePicker();
btSetDate = (Button) getView().findViewById(R.id.race_reset_time_btn_date);
btSetTime = (Button) getView().findViewById(R.id.race_reset_time_btn_time);
btPostpone = (Button) getView().findViewById(R.id.race_reset_time_btn_postpone);
startTimePicker.setIs24HourView(true); btSetDate.setOnClickListener(new OnClickListener() {
startTimePicker.setOnClickListener(new OnClickListener() { @Override
public void onClick(View view) { public void onClick(View view) {
refreshDifferenceTime(); Toast.makeText(getActivity(), "Not implemented yet.", Toast.LENGTH_SHORT).show();
} }
}); });
setStartTimeButton.setText(isReset ? R.string.reset_time : R.string.set_time);
setStartTimeButton.setOnClickListener(new OnClickListener() { btSetTime.setText(isReset ? R.string.reset_time : R.string.set_time);
btSetTime.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) { public void onClick(View view) {
setStartTime(); setStartTime();
} }
}); });
abortRaceButton.setOnClickListener(new OnClickListener() {
btPostpone.setOnClickListener(new OnClickListener() {
@Override @Override
public void onClick(View arg0) { public void onClick(View arg0) {
ExLog.i(ExLog.RACE_SET_TIME_BUTTON_AP, getRace().getId().toString(), getActivity()); ExLog.i(ExLog.RACE_SET_TIME_BUTTON_AP, getRace().getId().toString(), getActivity());
showAPModeDialog(); showAPModeDialog();
} }
}); });
// / TODO: click-listener for abort button textInfoText = (TextView) getView().findViewById(R.id.race_reset_time_text_infotext);
refreshTimePickerTime();
} }
private void setupTimePicker() {
pickerTime.setIs24HourView(true);
// In 10 minutes from now, but always a 5-minute-mark.
Calendar now = Calendar.getInstance();
now.add(Calendar.MINUTE, 10);
int hours = now.get(Calendar.HOUR_OF_DAY);
int minutes = now.get(Calendar.MINUTE);
minutes = (int) (Math.ceil((minutes / 5.0)) * 5.0);
if (minutes >= 60) {
hours++;
}
pickerTime.setCurrentHour(hours);
pickerTime.setCurrentMinute(minutes);
}
private void setupStartProcedureSpinner() {
ArrayAdapter<StartProcedureType> adapter = new ArrayAdapter<StartProcedureType>(getActivity(),
android.R.layout.simple_spinner_dropdown_item, StartProcedureType.values());
spinnerStartProcedure.setAdapter(adapter);
spinnerStartProcedure.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
selectedStartProcedureType = (StartProcedureType) adapterView.getItemAtPosition(position);
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
StartProcedureType type = StartProcedureType.ESS;
boolean overrideStartProcedureType = PreferenceManager.getDefaultSharedPreferences(getActivity()).getBoolean(
"overrideDefaultStartProcedureType", false);
if (overrideStartProcedureType) {
type = StartProcedureType.valueOf(PreferenceManager.getDefaultSharedPreferences(getActivity()).getString(
"defaultStartProcedureType", StartProcedureType.ESS.name()));
} else {
type = getRace().getState().getStartProcedureType();
}
spinnerStartProcedure.setSelection(adapter.getPosition(type));
}
@Override @Override
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
ExLog.w(SetStartTimeRaceFragment.class.getName(), String.format("Fragment %s is now shown", SetStartTimeRaceFragment.class.getName())); ExLog.i(SetStartTimeRaceFragment.class.getName(),
String.format("Fragment %s is now shown", SetStartTimeRaceFragment.class.getName()));
} }
@Override
public void notifyTick() { public void notifyTick() {
refreshDifferenceTime(); super.notifyTick();
textInfoText.setText(String.format("Start %s", getTimeStringToStart()));
} }
private void refreshTimePickerTime() { private Date getStartTime() {
Calendar calendar = Calendar.getInstance(); Calendar newStartTimeCal = Calendar.getInstance();
calendar.add(Calendar.MINUTE, AppConstants.DefaultStartTimeMinuteOffset); // newStartTimeCal.set(Calendar.YEAR, 0);
int hour = calendar.get(Calendar.HOUR_OF_DAY); // newStartTimeCal.set(Calendar.MONTH, 0);
int minute = calendar.get(Calendar.MINUTE); // newStartTimeCal.set(Calendar.DAY_OF_MONTH, 0);
startTimePicker.setCurrentHour(hour); newStartTimeCal.set(Calendar.HOUR_OF_DAY, pickerTime.getCurrentHour());
startTimePicker.setCurrentMinute(minute); newStartTimeCal.set(Calendar.MINUTE, pickerTime.getCurrentMinute());
refreshDifferenceTime(); newStartTimeCal.set(Calendar.SECOND, 0);
newStartTimeCal.set(Calendar.MILLISECOND, 0);
Date newStartTime = newStartTimeCal.getTime();
return newStartTime;
} }
private void refreshDifferenceTime() { private String getTimeStringToStart() {
// This method might be called by the ticker before initialization happens... Date startTime = getStartTime();
if (startTimePicker == null || countdownView == null) { Date now = new Date();
return;
long differenceInSeconds = (startTime.getTime() - now.getTime()) / 1000;
boolean isInPast = Math.signum(differenceInSeconds) < 0;
if (isInPast) {
differenceInSeconds = Math.abs(differenceInSeconds);
} }
// / TODO: Why is this method synchronized? long diff[] = new long[] { 0, 0, 0, 0 };
synchronized (this) { /* sec */diff[3] = (differenceInSeconds >= 60 ? differenceInSeconds % 60 : differenceInSeconds);
int hourOfDay = startTimePicker.getCurrentHour(); /* min */diff[2] = (differenceInSeconds = (differenceInSeconds / 60)) >= 60 ? differenceInSeconds % 60
int minute = startTimePicker.getCurrentMinute(); : differenceInSeconds;
/* hours */diff[1] = (differenceInSeconds = (differenceInSeconds / 60)) >= 24 ? differenceInSeconds % 24
: differenceInSeconds;
/* days */diff[0] = (differenceInSeconds = (differenceInSeconds / 24));
Calendar calendar = Calendar.getInstance(); String timeText = "";
calendar.setTimeInMillis(System.currentTimeMillis()); if (diff[0] > 0) {
Date nowDate = calendar.getTime(); timeText += String.format("%d day%s, ", diff[0], diff[0] > 1 ? "s" : "");
Date pickedDate = (Date) nowDate.clone();
pickedDate.setHours(hourOfDay);
pickedDate.setMinutes(minute);
pickedDate.setSeconds(0);
long nowTime = nowDate.getTime();
long pickedTime = pickedDate.getTime();
long diffTime = pickedTime - nowTime;
if (diffTime >= 0 && diffTime > 12 * 60 * 60 * 1000) {
diffTime -= (24 * 60 * 60 * 1000);
} else if (diffTime < 0 && diffTime < -(12 * 60 * 60 * 1000)) {
diffTime += (24 * 60 * 60 * 1000);
}
long diffHours = diffTime / 1000 / 60 / 60;
long diffMins = (diffTime / 1000 / 60) % 60;
long diffSecs = (diffTime / 1000) % 60;
String minusInd = (diffHours < 0 || diffMins < 0 || diffSecs < 0 ? "-" : "");
countdownView.setText(getString(R.string.time_until_start) + ": " + minusInd + Math.abs(diffHours) + "h "
+ Math.abs(diffMins) + "min " + Math.abs(diffSecs) + "sec");
} }
if (diff[1] > 0) {
timeText += String.format("%d hours%s, ", diff[1], diff[1] > 1 ? "s" : "");
}
if (diff[2] > 0) {
timeText += String.format("%d minute%s, ", diff[2], diff[2] > 1 ? "s" : "");
}
timeText += String.format("%d second%s", diff[3], diff[3] > 1 ? "s" : "");
return isInPast ? String.format("%s %s", timeText, "ago") : String.format("%s %s", "in", timeText);
} }
protected void setStartTime() { protected void setStartTime() {
@@ -151,20 +202,13 @@ public class SetStartTimeRaceFragment extends RaceFragment {
} else { } else {
ExLog.i(ExLog.RACE_SET_TIME, getRace().getId().toString(), getActivity()); ExLog.i(ExLog.RACE_SET_TIME, getRace().getId().toString(), getActivity());
} }
setStartTime(getStartTime());
Calendar newStartTime = Calendar.getInstance();
newStartTime.set(Calendar.HOUR_OF_DAY, startTimePicker.getCurrentHour());
newStartTime.set(Calendar.MINUTE, startTimePicker.getCurrentMinute());
newStartTime.set(Calendar.SECOND, 0);
newStartTime.set(Calendar.MILLISECOND, 0);
setStartTime(newStartTime.getTime());
// TODO: start course designer activity! // TODO: start course designer activity!
} }
private void setStartTime(Date newStartTime) { private void setStartTime(Date newStartTime) {
getRace().getState().setStartTime(new MillisecondsTimePoint(newStartTime)); getRace().getState().setStartTime(new MillisecondsTimePoint(newStartTime), selectedStartProcedureType);
} }
protected void showAPModeDialog() { protected void showAPModeDialog() {
@@ -172,7 +216,7 @@ public class SetStartTimeRaceFragment extends RaceFragment {
RaceDialogFragment fragment = new AbortModeSelectionDialog(); RaceDialogFragment fragment = new AbortModeSelectionDialog();
Bundle args = getParameterBundle(); Bundle args = getRecentArguments();
args.putString(AppConstants.FLAG_KEY, Flags.AP.name()); args.putString(AppConstants.FLAG_KEY, Flags.AP.name());
fragment.setArguments(args); fragment.setArguments(args);
@@ -94,6 +94,7 @@ public class EssStartPhaseFragment extends RaceFragment implements EssStartPhase
log.lockForRead(); log.lockForRead();
try { try {
RaceLogEvent lastEvent = log.getLastFixAtOrBefore(MillisecondsTimePoint.now()); RaceLogEvent lastEvent = log.getLastFixAtOrBefore(MillisecondsTimePoint.now());
// TODO: better analysis of state. only flagevents... sort by timestamp...
if (lastEvent instanceof RaceLogFlagEvent) { if (lastEvent instanceof RaceLogFlagEvent) {
RaceLogFlagEvent flagEvent = (RaceLogFlagEvent) lastEvent; RaceLogFlagEvent flagEvent = (RaceLogFlagEvent) lastEvent;
Flags flag = flagEvent.getUpperFlag(); Flags flag = flagEvent.getUpperFlag();
@@ -102,9 +103,11 @@ public class EssStartPhaseFragment extends RaceFragment implements EssStartPhase
onAPDown(); onAPDown();
} else if (flagEvent.isDisplayed() && flag.equals(Flags.ESSTHREE)) { } else if (flagEvent.isDisplayed() && flag.equals(Flags.ESSTHREE)) {
onEssThreeUp(); onEssThreeUp();
} else if (flagEvent.isDisplayed() && flag.equals(Flags.ESSTWO)) { } else if ((!flagEvent.isDisplayed() && flag.equals(Flags.ESSTHREE)) ||
(flagEvent.isDisplayed() && flag.equals(Flags.ESSTWO))) {
onEssTwoUp(); onEssTwoUp();
} else if (flagEvent.isDisplayed() && flag.equals(Flags.ESSONE)) { } else if ((!flagEvent.isDisplayed() && flag.equals(Flags.ESSTWO)) ||
(flagEvent.isDisplayed() && flag.equals(Flags.ESSONE))) {
onEssOneUp(); onEssOneUp();
} }
} }
@@ -159,7 +162,7 @@ public class EssStartPhaseFragment extends RaceFragment implements EssStartPhase
RaceDialogFragment fragment = new AbortModeSelectionDialog(); RaceDialogFragment fragment = new AbortModeSelectionDialog();
Bundle args = getParameterBundle(); Bundle args = getRecentArguments();
args.putString(AppConstants.FLAG_KEY, Flags.AP.name()); args.putString(AppConstants.FLAG_KEY, Flags.AP.name());
fragment.setArguments(args); fragment.setArguments(args);
@@ -122,7 +122,7 @@ public class GateStartPhaseFragment extends RaceFragment implements GateStartPha
private void showPathFinderDialog() { private void showPathFinderDialog() {
FragmentManager fragmentManager = getFragmentManager(); FragmentManager fragmentManager = getFragmentManager();
RaceDialogFragment fragment = new RaceChoosePathFinderDialog(); RaceDialogFragment fragment = new RaceChoosePathFinderDialog();
Bundle args = getParameterBundle(); Bundle args = getRecentArguments();
fragment.setArguments(args); fragment.setArguments(args);
fragment.show(fragmentManager, null); fragment.show(fragmentManager, null);
} }
@@ -130,7 +130,7 @@ public class GateStartPhaseFragment extends RaceFragment implements GateStartPha
private void showLineOpeningTimeDialog() { private void showLineOpeningTimeDialog() {
FragmentManager fragmentManager = getFragmentManager(); FragmentManager fragmentManager = getFragmentManager();
RaceDialogFragment fragment = new RaceChooseLineOpeningTimeDialog(); RaceDialogFragment fragment = new RaceChooseLineOpeningTimeDialog();
Bundle args = getParameterBundle(); Bundle args = getRecentArguments();
fragment.setArguments(args); fragment.setArguments(args);
fragment.show(fragmentManager, null); fragment.show(fragmentManager, null);
} }
@@ -204,7 +204,7 @@ public class GateStartPhaseFragment extends RaceFragment implements GateStartPha
RaceDialogFragment fragment = new AbortModeSelectionDialog(); RaceDialogFragment fragment = new AbortModeSelectionDialog();
Bundle args = getParameterBundle(); Bundle args = getRecentArguments();
args.putString(AppConstants.FLAG_KEY, Flags.AP.name()); args.putString(AppConstants.FLAG_KEY, Flags.AP.name());
fragment.setArguments(args); fragment.setArguments(args);
@@ -92,7 +92,7 @@ public class StartphaseRaceFragment extends RaceFragment {
RaceDialogFragment fragment = new AbortModeSelectionDialog(); RaceDialogFragment fragment = new AbortModeSelectionDialog();
Bundle args = getParameterBundle(); Bundle args = getRecentArguments();
args.putString(AppConstants.FLAG_KEY, Flags.AP.name()); args.putString(AppConstants.FLAG_KEY, Flags.AP.name());
fragment.setArguments(args); fragment.setArguments(args);