diff --git a/mobile/com.sap.sailing.racecommittee.app/res/drawable-hdpi/ic_change_role_white_48dp.png b/mobile/com.sap.sailing.racecommittee.app/res/drawable-hdpi/ic_change_role_white_48dp.png deleted file mode 100644 index c29cb246f25..00000000000 Binary files a/mobile/com.sap.sailing.racecommittee.app/res/drawable-hdpi/ic_change_role_white_48dp.png and /dev/null differ diff --git a/mobile/com.sap.sailing.racecommittee.app/res/drawable-mdpi/ic_change_role_white_48dp.png b/mobile/com.sap.sailing.racecommittee.app/res/drawable-mdpi/ic_change_role_white_48dp.png deleted file mode 100644 index e966f5104b8..00000000000 Binary files a/mobile/com.sap.sailing.racecommittee.app/res/drawable-mdpi/ic_change_role_white_48dp.png and /dev/null differ diff --git a/mobile/com.sap.sailing.racecommittee.app/res/drawable-xhdpi/ic_change_role_white_48dp.png b/mobile/com.sap.sailing.racecommittee.app/res/drawable-xhdpi/ic_change_role_white_48dp.png deleted file mode 100644 index b811a20b301..00000000000 Binary files a/mobile/com.sap.sailing.racecommittee.app/res/drawable-xhdpi/ic_change_role_white_48dp.png and /dev/null differ diff --git a/mobile/com.sap.sailing.racecommittee.app/res/drawable-xxhdpi/ic_change_role_white_48dp.png b/mobile/com.sap.sailing.racecommittee.app/res/drawable-xxhdpi/ic_change_role_white_48dp.png deleted file mode 100644 index 02076b894fb..00000000000 Binary files a/mobile/com.sap.sailing.racecommittee.app/res/drawable-xxhdpi/ic_change_role_white_48dp.png and /dev/null differ diff --git a/mobile/com.sap.sailing.racecommittee.app/res/drawable-xxxhdpi/ic_change_role_white_48dp.png b/mobile/com.sap.sailing.racecommittee.app/res/drawable-xxxhdpi/ic_change_role_white_48dp.png deleted file mode 100644 index e4cf3914bd9..00000000000 Binary files a/mobile/com.sap.sailing.racecommittee.app/res/drawable-xxxhdpi/ic_change_role_white_48dp.png and /dev/null differ diff --git a/mobile/com.sap.sailing.racecommittee.app/res/layout/race_list_header_content.xml b/mobile/com.sap.sailing.racecommittee.app/res/layout/race_list_header_content.xml index 88b2d17c939..b77bf67bbb8 100644 --- a/mobile/com.sap.sailing.racecommittee.app/res/layout/race_list_header_content.xml +++ b/mobile/com.sap.sailing.racecommittee.app/res/layout/race_list_header_content.xml @@ -26,7 +26,7 @@ android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_margin="@dimen/default_margin" - android:src="@drawable/ic_change_role_white_48dp"/> + android:src="@drawable/ic_refresh_white_48dp"/> + android:title="@string/reset_race" /> + android:title="@string/options_menu_settings" /> + android:title="@string/options_menu_info" /> + + + android:title="@string/logout" /> \ No newline at end of file diff --git a/mobile/com.sap.sailing.racecommittee.app/res/values-de/strings.xml b/mobile/com.sap.sailing.racecommittee.app/res/values-de/strings.xml index 53d90b8bf10..7ccaf9b8572 100644 --- a/mobile/com.sap.sailing.racecommittee.app/res/values-de/strings.xml +++ b/mobile/com.sap.sailing.racecommittee.app/res/values-de/strings.xml @@ -500,6 +500,7 @@ Zeige nicht öffentliche Events Lade alle Events, auch die nicht öffentlichen. + Rolle wechseln Konfiguration vom Server laden Rennen abbrechen diff --git a/mobile/com.sap.sailing.racecommittee.app/res/values/strings.xml b/mobile/com.sap.sailing.racecommittee.app/res/values/strings.xml index 65eaf5d2b3f..448dedfeab0 100644 --- a/mobile/com.sap.sailing.racecommittee.app/res/values/strings.xml +++ b/mobile/com.sap.sailing.racecommittee.app/res/values/strings.xml @@ -528,6 +528,7 @@ Show Non Public Events Load all events including the no public one. + Change Regatta Reload Configuration from Server Abort Races diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/AppConstants.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/AppConstants.java index 8c5cd7fd0b7..0845520c5ab 100755 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/AppConstants.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/AppConstants.java @@ -22,11 +22,15 @@ public class AppConstants { public final static String DARK_THEME = "dark"; public final static String LIGHT_THEME = "light"; - public final static String INTENT_ACTION_RESET = PACKAGE_NAME + ".action.reset"; - public final static String INTENT_ACTION_REGISTER_RACE = PACKAGE_NAME + ".action.registerRace"; - public final static String INTENT_ACTION_CLEAR_RACES = PACKAGE_NAME + ".action.clearRaces"; - public final static String INTENT_ACTION_ALARM_ACTION = PACKAGE_NAME + ".action.alarmAction"; - public final static String INTENT_ACTION_START_PROCEDURE_SPECIFIC_ACTION = PACKAGE_NAME + ".action.startProcedureSpecificAction"; + private final static String INTENT_ACTION = PACKAGE_NAME + ".action"; + public final static String INTENT_ACTION_RESET = INTENT_ACTION + ".reset"; + public final static String INTENT_ACTION_REGISTER_RACE = INTENT_ACTION + ".registerRace"; + public final static String INTENT_ACTION_UNREGISTER_RACE = INTENT_ACTION + ".unregisterRace"; + public final static String INTENT_ACTION_CLEAR_RACES = INTENT_ACTION + ".clearRaces"; + public final static String INTENT_ACTION_CLEANUP_RACES = INTENT_ACTION + ".cleanupRaces"; + public final static String INTENT_ACTION_ALARM_ACTION = INTENT_ACTION + ".alarmAction"; + public final static String INTENT_ACTION_RELOAD_RACES = INTENT_ACTION + ".reloadRaces"; + public final static String INTENT_ACTION_START_PROCEDURE_SPECIFIC_ACTION = INTENT_ACTION + ".startProcedureSpecificAction"; // Login activity public final static String EventIdTag = "EventId"; @@ -66,6 +70,7 @@ public class AppConstants { public final static String INTENT_ACTION_SHOW_ONBOARDING = "show_onboarding"; public final static String INTENT_ACTION_SHOW_LOGIN = "show_login"; public final static String INTENT_ACTION_VALID_DATA = "valid_data"; + public final static String INTENT_ACTION_SHOW_WELCOME = "show_welcome"; // clears all toggle buttons public final static String INTENT_ACTION_CLEAR_TOGGLE = PACKAGE_NAME + ".action.toggle.clear"; diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/DataManager.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/DataManager.java index 37d61f22fb4..86500daef9c 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/DataManager.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/DataManager.java @@ -63,4 +63,9 @@ public abstract class DataManager implements ReadonlyDataManager { context.startService(intent); } + + public void stopService() { + Intent intent = new Intent(context, RaceStateService.class); + context.stopService(intent); + } } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/DataStore.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/DataStore.java index c7f5875aabc..f980b97c709 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/DataStore.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/DataStore.java @@ -32,10 +32,12 @@ public interface DataStore { Collection getRaces(); void addRace(ManagedRace race); - public ManagedRace getRace(String id); - public ManagedRace getRace(SimpleRaceLogIdentifier id); - public boolean hasRace(String id); - public boolean hasRace(SimpleRaceLogIdentifier id); + void addRace(int index, ManagedRace race); + void removeRace(ManagedRace race); + ManagedRace getRace(String id); + ManagedRace getRace(SimpleRaceLogIdentifier id); + boolean hasRace(String id); + boolean hasRace(SimpleRaceLogIdentifier id); Collection getMarks(); Mark getMark(Serializable id); diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/InMemoryDataStore.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/InMemoryDataStore.java index 5f74ce4e0c2..8f6c9244c5b 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/InMemoryDataStore.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/InMemoryDataStore.java @@ -4,6 +4,7 @@ import java.io.Serializable; import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.Map; import java.util.Set; import java.util.UUID; @@ -61,18 +62,22 @@ public enum InMemoryDataStore implements DataStore { * * * * * * */ + @Override public Collection getEvents() { return eventsById.values(); } - + + @Override public void addEvent(EventBase event) { eventsById.put(event.getId(), event); } + @Override public EventBase getEvent(Serializable id) { return eventsById.get(id); } + @Override public boolean hasEvent(Serializable id) { return eventsById.containsKey(id); } @@ -83,6 +88,7 @@ public enum InMemoryDataStore implements DataStore { * * * * * * * * */ + @Override public Collection getCourseAreas(EventBase event) { if (event.getVenue() != null) { return CollectionUtils.newArrayList(event.getVenue().getCourseAreas()); @@ -102,6 +108,7 @@ public enum InMemoryDataStore implements DataStore { return null; } + @Override public CourseArea getCourseArea(Serializable id) { for (EventBase event : eventsById.values()) { for (CourseArea courseArea : getCourseAreas(event)) { @@ -113,6 +120,7 @@ public enum InMemoryDataStore implements DataStore { return null; } + @Override public boolean hasCourseArea(Serializable id) { for (EventBase event : eventsById.values()) { for (CourseArea courseArea : getCourseAreas(event)) { @@ -124,6 +132,7 @@ public enum InMemoryDataStore implements DataStore { return false; } + @Override public void addCourseArea(EventBase event, CourseArea courseArea) { if (event.getVenue() != null) { event.getVenue().addCourseArea(courseArea); @@ -136,14 +145,49 @@ public enum InMemoryDataStore implements DataStore { * * * * * * * * */ + @Override public Collection getRaces() { return managedRaceById.values(); } + @Override public void addRace(ManagedRace race) { managedRaceById.put(convertManagedRaceIdentifierToSimpleRaceLogIdentifier(race.getIdentifier()), race); } + @Override + public void addRace(int index, ManagedRace race) { + if (index >= 0 && index <= managedRaceById.size()) { + LinkedHashMap output = new LinkedHashMap<>(); + int i = 0; + if (index == 0) { + output.put(convertManagedRaceIdentifierToSimpleRaceLogIdentifier(race.getIdentifier()), race); + output.putAll(managedRaceById); + } else { + for (Map.Entry entry : managedRaceById.entrySet()) { + if (i == index) { + output.put(convertManagedRaceIdentifierToSimpleRaceLogIdentifier(race.getIdentifier()), race); + } + output.put(entry.getKey(), entry.getValue()); + i++; + } + } + if (index == managedRaceById.size()) { + output.put(convertManagedRaceIdentifierToSimpleRaceLogIdentifier(race.getIdentifier()), race); + } + managedRaceById.clear(); + managedRaceById.putAll(output); + output.clear(); + } else { + throw new IndexOutOfBoundsException("index " + index + " must be greater than zero and less than size of the map"); + } + } + + @Override + public void removeRace(ManagedRace race) { + managedRaceById.remove(convertManagedRaceIdentifierToSimpleRaceLogIdentifier(race.getIdentifier())); + } + private SimpleRaceLogIdentifier convertManagedRaceIdentifierToSimpleRaceLogIdentifier(ManagedRaceIdentifier id) { return new SimpleRaceLogIdentifierImpl(id.getRaceGroup().getName(), id.getRaceName(), id.getFleet().getName()); } @@ -165,19 +209,17 @@ public enum InMemoryDataStore implements DataStore { /** * Parses a serialized version of a ManagedRaceIdentifier and creates a SimpleRaceLogIdentifier - * this is needed as the serialized version is passed around in the bundle context, but the - * InMemoryDataStore now has to use SimpleRaceLogIdentifier as key in the managedRaces HashMap in - * order to allow for retrieving a managed race with exclusively the information provided by a + * this is needed as the serialized version is passed around in the bundle context, but the + * InMemoryDataStore now has to use SimpleRaceLogIdentifier as key in the managedRaces HashMap in + * order to allow for retrieving a managed race with exclusively the information provided by a * SimpleRaceLogIdentifier (which is less than the information provided by a ManagedRaceIdentifier) - * - * @param escapedId - * serialized version of a ManagedRaceIdentifier - * @return - * corresponding SimpleRaceLogIdentifier + * + * @param escapedId serialized version of a ManagedRaceIdentifier + * @return corresponding SimpleRaceLogIdentifier */ public SimpleRaceLogIdentifier parseManagedRaceLogIdentifier(final String escapedId) { //Undo escaping - final Triple id = FleetIdentifierImpl.unescape(escapedId); + final Triple id = FleetIdentifierImpl.unescape(escapedId); return new SimpleRaceLogIdentifierImpl(id.getA(), id.getB(), id.getC()); } @@ -230,7 +272,7 @@ public enum InMemoryDataStore implements DataStore { } return raceGroups; } - + @Override public RaceGroup getRaceGroup(String name) { for (RaceGroup group : getRaceGroups()) { diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/OnlineDataManager.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/OnlineDataManager.java index 1971c145688..d0f9f44a117 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/OnlineDataManager.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/OnlineDataManager.java @@ -96,8 +96,9 @@ public class OnlineDataManager extends DataManager { } public void addRaces(Collection data) { + int index = 0; for (ManagedRace race : data) { - dataStore.addRace(race); + dataStore.addRace(index++, race); } } @@ -110,12 +111,11 @@ public class OnlineDataManager extends DataManager { @Override public LoaderCallbacks>> createEventsLoader( LoadClient> callback) { - return new DataLoaderCallbacks>(callback, new LoaderCreator>() { + return new DataLoaderCallbacks<>(callback, new LoaderCreator>() { @Override public Loader>> create(int id, Bundle args) throws Exception { ExLog.i(context, TAG, String.format("Creating Events-OnlineDataLoader %d", id)); - EventBaseJsonDeserializer serializer = new EventBaseJsonDeserializer(new VenueJsonDeserializer( - new CourseAreaJsonDeserializer(domainFactory)), new LeaderboardGroupBaseJsonDeserializer()); + EventBaseJsonDeserializer serializer = new EventBaseJsonDeserializer(new VenueJsonDeserializer(new CourseAreaJsonDeserializer(domainFactory)), new LeaderboardGroupBaseJsonDeserializer()); DataParser> parser = new EventsDataParser(serializer); DataHandler> handler = new EventsDataHandler(OnlineDataManager.this); @@ -123,8 +123,7 @@ public class OnlineDataManager extends DataManager { List> params = new ArrayList<>(); params.add(new Util.Pair("showNonPublic", AppPreferences.on(context).showNonPublic())); URL url = UrlHelper.generateUrl(preferences.getServerBaseURL(), "/sailingserver/api/v1/events", params); - return new OnlineDataLoader>(context, - url, parser, handler); + return new OnlineDataLoader>(context, url, parser, handler); } }, getContext()); } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/handlers/ManagedRacesDataHandler.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/handlers/ManagedRacesDataHandler.java index 6be6e8cee77..cfb83fa2889 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/handlers/ManagedRacesDataHandler.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/handlers/ManagedRacesDataHandler.java @@ -27,6 +27,15 @@ public class ManagedRacesDataHandler extends DataHandler @Override public void onResult(Collection data) { + Set deleteList = new HashSet<>(); + for (ManagedRace race : manager.getDataStore().getRaces()) { + if (!data.contains(race)) { + deleteList.add(new DeleteFromDataStore(manager, race)); + } + } + for (DeleteFromDataStore action : deleteList) { + action.run(); + } manager.addRaces(data); calcRaceState(data); } @@ -54,4 +63,20 @@ public class ManagedRacesDataHandler extends DataHandler raceStatesWithUnresolvedStartTimes.removeAll(resolved); } while (oldNumberOfRaceStatesWithUnresolvedStartTimes != raceStatesWithUnresolvedStartTimes.size()); } + + private static class DeleteFromDataStore implements Runnable { + + private final OnlineDataManager mManager; + private final ManagedRace mRace; + + public DeleteFromDataStore(OnlineDataManager manager, ManagedRace race) { + mManager = manager; + mRace = race; + } + + @Override + public void run() { + mManager.getDataStore().removeRace(mRace); + } + } } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/RaceStateService.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/RaceStateService.java index 0baed8f581e..d67e5690f11 100755 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/RaceStateService.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/RaceStateService.java @@ -3,9 +3,11 @@ package com.sap.sailing.racecommittee.app.services; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.UUID; import android.annotation.TargetApi; @@ -19,6 +21,7 @@ import android.graphics.BitmapFactory; import android.os.Binder; import android.os.Build; import android.os.IBinder; +import android.support.annotation.NonNull; import android.support.v4.app.NotificationCompat; import android.util.Pair; @@ -74,7 +77,7 @@ public class RaceStateService extends Service { private Map registeredLogListeners; private Map registeredStateEventSchedulers; - private Map>> managedIntents; + private Map>> managedIntents; private NotificationManager notificationManager; private NotificationCompat.Builder notificationBuilder; @@ -146,10 +149,12 @@ public class RaceStateService extends Service { for (Entry entry : registeredLogListeners.entrySet()) { entry.getKey().getState().getRaceLog().removeListener(entry.getValue()); } + registeredLogListeners.clear(); for (Entry entry : registeredStateEventSchedulers.entrySet()) { entry.getKey().getState().setStateEventScheduler(null); } + registeredStateEventSchedulers.clear(); for (List> intents : managedIntents.values()) { for (Pair intentPair : intents) { @@ -161,12 +166,35 @@ public class RaceStateService extends Service { ExLog.i(this, TAG, "All races unregistered."); } + private void unregisterRace(ManagedRace race) { + poller.unregister(race); + + race.getState().getRaceLog().removeAllListeners(); + registeredLogListeners.remove(race); + + race.getState().setStateEventScheduler(null); + registeredStateEventSchedulers.remove(race); + + List> intents = managedIntents.get(race.getId()); + for (Pair intentPair : intents) { + alarmManager.cancel(intentPair.first); + } + managedIntents.remove(race.getId()); + + ExLog.i(this, TAG, "Race " + race.getId() + " unregistered"); + } + private void handleStartCommand(Intent intent) { String action = intent.getAction(); ExLog.i(this, TAG, String.format("Command action '%s' received.", action)); if (AppConstants.INTENT_ACTION_CLEAR_RACES.equals(action)) { - handleClearRaces(intent); + handleClearRaces(); + return; + } + + if (AppConstants.INTENT_ACTION_CLEANUP_RACES.equals(action)) { + handleCleanupRaces(); return; } @@ -175,6 +203,11 @@ public class RaceStateService extends Service { return; } + if (AppConstants.INTENT_ACTION_UNREGISTER_RACE.equals(action)) { + handleUnregisterRace(intent); + return; + } + if (!serviceId.equals(intent.getSerializableExtra(EXTRAS_SERVICE_ID))) { ExLog.w(this, TAG, "Received event for different service version."); return; @@ -196,7 +229,7 @@ public class RaceStateService extends Service { } } - private void handleClearRaces(Intent intent) { + private void handleClearRaces() { unregisterAllRaces(); DataStore dataStore = dataManager.getDataStore(); dataStore.getRaces().clear(); @@ -206,6 +239,46 @@ public class RaceStateService extends Service { stopForeground(true); } + private class RemoveRaceAction implements Runnable { + + private final ManagedRace managedRace; + + public RemoveRaceAction(@NonNull ManagedRace race) { + managedRace = race; + } + + @Override + public void run() { + unregisterRace(managedRace); + } + } + + private void handleCleanupRaces() { + Set actions = new HashSet<>(); + for (String raceId : managedIntents.keySet()) { + if (!inDataStore(raceId)) { + for (ManagedRace race : registeredLogListeners.keySet()) { + if (race.getId().equals(raceId)) { + actions.add(new RemoveRaceAction(race)); + } + } + } + } + for (RemoveRaceAction action : actions) { + action.run(); + } + updateNotification(); + } + + private boolean inDataStore(String raceId) { + for (ManagedRace race : dataManager.getDataStore().getRaces()) { + if (race.getId().equals(raceId)) { + return true; + } + } + return false; + } + private void handleRegisterRace(Intent intent) { ManagedRace race = getRaceFromIntent(intent); if (race == null) { @@ -214,6 +287,21 @@ public class RaceStateService extends Service { } registerRace(race); + updateNotification(); + } + + private void handleUnregisterRace(Intent intent) { + ManagedRace race = getRaceFromIntent(intent); + if (race == null) { + ExLog.w(this, TAG, "Intent did not carry valid race information"); + return; + } + unregisterRace(race); + + updateNotification(); + } + + private void updateNotification() { int numRaces = managedIntents.keySet().size(); notificationManager.notify(NOTIFICATION_ID, notificationBuilder .setContentText(getString(R.string.service_text_num_races, numRaces)) diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/polling/RaceLogPoller.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/polling/RaceLogPoller.java index 43443f842ab..3a2f458ed9b 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/polling/RaceLogPoller.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/services/polling/RaceLogPoller.java @@ -49,7 +49,7 @@ public class RaceLogPoller implements PollingActiveChangedListener { // We want to use the main (UI) loop this.pollingHandler = new Handler(Looper.getMainLooper()); this.pollingWorker = new PollingWorker(this, context); - this.races = new HashMap(); + this.races = new HashMap<>(); this.appPreferences = AppPreferences.on(context); this.appPreferences.registerPollingActiveChangedListener(this); this.hasRacesToPoll = false; @@ -70,6 +70,10 @@ public class RaceLogPoller implements PollingActiveChangedListener { } } + public void unregister(ManagedRace race) { + races.remove(race); + } + private URL createURL(ManagedRace race) throws MalformedURLException, UnsupportedEncodingException { return new URL(MessageSendingService.getRaceLogEventSendAndReceiveUrl(context, race.getRaceGroup().getName(), race.getName(), race.getFleet().getName())); diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/RacingActivity.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/RacingActivity.java index aaa4d68f19a..d5edaf27b80 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/RacingActivity.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/RacingActivity.java @@ -14,6 +14,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; +import android.content.Loader; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; @@ -23,7 +24,6 @@ import android.support.annotation.IdRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.content.LocalBroadcastManager; -import android.support.v4.view.ViewCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.AlertDialog; import android.support.v7.internal.widget.TintImageView; @@ -38,9 +38,11 @@ import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.Toast; + import com.sap.sailing.android.shared.logging.ExLog; import com.sap.sailing.android.shared.util.AppUtils; import com.sap.sailing.android.shared.util.BitmapHelper; +import com.sap.sailing.android.shared.util.BroadcastManager; import com.sap.sailing.android.shared.util.CollectionUtils; import com.sap.sailing.android.shared.util.ViewHelper; import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier; @@ -55,6 +57,7 @@ import com.sap.sailing.racecommittee.app.data.DataManager; import com.sap.sailing.racecommittee.app.data.DataStore; import com.sap.sailing.racecommittee.app.data.ReadonlyDataManager; import com.sap.sailing.racecommittee.app.data.clients.LoadClient; +import com.sap.sailing.racecommittee.app.data.loaders.DataLoaderResult; import com.sap.sailing.racecommittee.app.domain.ManagedRace; import com.sap.sailing.racecommittee.app.domain.impl.RaceGroupSeriesFleet; import com.sap.sailing.racecommittee.app.logging.LogEvent; @@ -93,6 +96,7 @@ public class RacingActivity extends SessionActivity implements RaceListCallbacks private RaceListFragment mRaceList; private ManagedRace mSelectedRace; private TimePoint startTime; + private Loader>> raceLoader; private Collection lastSeenRaces = null; private Serializable getCourseAreaIdFromIntent() { @@ -126,7 +130,11 @@ public class RacingActivity extends SessionActivity implements RaceListCallbacks setProgressSpinnerVisibility(true); ExLog.i(this, TAG, "Issuing loading of managed races from data manager"); - getLoaderManager().initLoader(RacesLoaderId, null, dataManager.createRacesLoader(courseArea.getId(), new RaceLoadClient(courseArea))); + if (raceLoader == null) { + raceLoader = getLoaderManager().initLoader(RacesLoaderId, null, dataManager.createRacesLoader(courseArea.getId(), new RaceLoadClient(courseArea))); + } else { + raceLoader.forceLoad(); + } } private boolean resetEditFragments(@IdRes int id, String action) { @@ -253,7 +261,9 @@ public class RacingActivity extends SessionActivity implements RaceListCallbacks IntentFilter filter = new IntentFilter(); filter.addAction(AppConstants.INTENT_ACTION_SHOW_MAIN_CONTENT); filter.addAction(AppConstants.INTENT_ACTION_SHOW_SUMMARY_CONTENT); + filter.addAction(AppConstants.INTENT_ACTION_SHOW_WELCOME); filter.addAction(AppConstants.INTENT_ACTION_REMOVE_PROTEST); + filter.addAction(AppConstants.INTENT_ACTION_RELOAD_RACES); LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filter); } @@ -350,6 +360,10 @@ public class RacingActivity extends SessionActivity implements RaceListCallbacks resetRace(); return true; + case R.id.options_menu_role: + logoutSession(); + return true; + default: return super.onOptionsItemSelected(item); } @@ -383,18 +397,29 @@ public class RacingActivity extends SessionActivity implements RaceListCallbacks } private void registerOnService(final Collection races) { + // close current race, if no longer on server + if (!races.contains(mSelectedRace)) { + BroadcastManager.getInstance(this).addIntent(new Intent(AppConstants.INTENT_ACTION_SHOW_WELCOME)); + mSelectedRace = null; + } + // since the service is the long-living component // he should decide whether these races are already // registered or not. new Thread(new Runnable() { @Override public void run() { + // add all received races to the service for (ManagedRace race : races) { Intent registerIntent = new Intent(RacingActivity.this, RaceStateService.class); registerIntent.setAction(AppConstants.INTENT_ACTION_REGISTER_RACE); registerIntent.putExtra(AppConstants.RACE_ID_KEY, race.getId()); RacingActivity.this.startService(registerIntent); } + + Intent cleanupIntent = new Intent(RacingActivity.this, RaceStateService.class); + cleanupIntent.setAction(AppConstants.INTENT_ACTION_CLEANUP_RACES); + RacingActivity.this.startService(cleanupIntent); } }).start(); } @@ -610,6 +635,14 @@ public class RacingActivity extends SessionActivity implements RaceListCallbacks transaction.remove(extra); } } + } + + if (AppConstants.INTENT_ACTION_SHOW_WELCOME.equals(action)) { + loadWelcomeFragment(); + } + + if (AppConstants.INTENT_ACTION_RELOAD_RACES.equals(action)) { + loadRaces(dataManager.getDataStore().getCourseArea(getCourseAreaIdFromIntent())); } transaction.commit(); diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/RaceListFragment.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/RaceListFragment.java index 1c781517c0e..203f571fbd9 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/RaceListFragment.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/RaceListFragment.java @@ -56,7 +56,6 @@ 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.impl.RaceGroupSeriesFleet; -import com.sap.sailing.racecommittee.app.ui.activities.RacingActivity; import com.sap.sailing.racecommittee.app.ui.activities.SessionActivity; import com.sap.sailing.racecommittee.app.ui.adapters.racelist.ManagedRaceListAdapter; import com.sap.sailing.racecommittee.app.ui.adapters.racelist.RaceListDataType; @@ -270,7 +269,7 @@ public class RaceListFragment extends LoggableFragment implements OnItemClickLis @Override public void onClick(View v) { - ((RacingActivity) getActivity()).logoutSession(); + BroadcastManager.getInstance(getActivity()).addIntent(new Intent(AppConstants.INTENT_ACTION_RELOAD_RACES)); } }); }