package org.droidplanner.android.proxy.mission; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import android.support.v4.content.LocalBroadcastManager; import android.support.v4.util.CircularArray; import android.util.Pair; import android.widget.Toast; import com.google.android.gms.analytics.HitBuilders; import com.o3dr.android.client.Drone; import com.o3dr.android.client.apis.MissionApi; import com.o3dr.services.android.lib.coordinate.LatLong; import com.o3dr.services.android.lib.coordinate.LatLongAlt; import com.o3dr.services.android.lib.drone.attribute.AttributeEvent; import com.o3dr.services.android.lib.drone.attribute.AttributeType; import com.o3dr.services.android.lib.drone.mission.Mission; import com.o3dr.services.android.lib.drone.mission.MissionItemType; import com.o3dr.services.android.lib.drone.mission.item.MissionItem; import com.o3dr.services.android.lib.drone.mission.item.MissionItem.SpatialItem; import com.o3dr.services.android.lib.drone.mission.item.command.ChangeSpeed; import com.o3dr.services.android.lib.drone.mission.item.command.ReturnToLaunch; import com.o3dr.services.android.lib.drone.mission.item.command.Takeoff; import com.o3dr.services.android.lib.drone.mission.item.complex.SplineSurvey; import com.o3dr.services.android.lib.drone.mission.item.complex.StructureScanner; import com.o3dr.services.android.lib.drone.mission.item.complex.Survey; import com.o3dr.services.android.lib.drone.mission.item.complex.SurveyDetail; import com.o3dr.services.android.lib.drone.mission.item.spatial.BaseSpatialItem; import com.o3dr.services.android.lib.drone.mission.item.spatial.RegionOfInterest; import com.o3dr.services.android.lib.drone.mission.item.spatial.SplineWaypoint; import com.o3dr.services.android.lib.drone.mission.item.spatial.Waypoint; import com.o3dr.services.android.lib.model.AbstractCommandListener; import com.o3dr.services.android.lib.util.MathUtils; import org.droidplanner.android.DroidPlannerApp; import org.droidplanner.android.R; import org.droidplanner.android.maps.DPMap; import org.droidplanner.android.proxy.mission.item.MissionItemProxy; import org.droidplanner.android.utils.Utils; import org.droidplanner.android.utils.analytics.GAUtils; import org.droidplanner.android.utils.prefs.DroidPlannerPrefs; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; /** * This class is used as a wrapper to {@link com.o3dr.services.android.lib.drone.mission.Mission} * object on the Android side. */ public class MissionProxy implements DPMap.PathSource { public static final String ACTION_MISSION_PROXY_UPDATE = Utils.PACKAGE_NAME + ".ACTION_MISSION_PROXY_UPDATE"; private static final int UNDO_BUFFER_SIZE = 30; private static final IntentFilter eventFilter = new IntentFilter(); static { eventFilter.addAction(AttributeEvent.MISSION_DRONIE_CREATED); eventFilter.addAction(AttributeEvent.MISSION_UPDATED); eventFilter.addAction(AttributeEvent.MISSION_RECEIVED); } private final BroadcastReceiver eventReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); switch (action) { case AttributeEvent.MISSION_DRONIE_CREATED: case AttributeEvent.MISSION_UPDATED: case AttributeEvent.MISSION_RECEIVED: Mission droneMission = drone.getAttribute(AttributeType.MISSION); load(droneMission); break; } } }; private final Drone.OnMissionItemsBuiltCallback missionItemsBuiltListener = new Drone.OnMissionItemsBuiltCallback() { @Override public void onMissionItemsBuilt(MissionItem.ComplexItem[] complexItems) { notifyMissionUpdate(false); } }; /** * Stores all the mission item renders for this mission render. */ private final List<MissionItemProxy> missionItemProxies = new ArrayList<MissionItemProxy>(); private final LocalBroadcastManager lbm; private final DroidPlannerPrefs dpPrefs; private final Context context; private final DroidPlannerApp dpApp; private final Drone drone; private final CircularArray<Mission> undoBuffer = new CircularArray<>(UNDO_BUFFER_SIZE); private Mission currentMission; public MissionSelection selection = new MissionSelection(); public MissionProxy(DroidPlannerApp app, Drone drone) { this.dpApp = app; this.context = app.getApplicationContext(); this.drone = drone; this.currentMission = generateMission(true); lbm = LocalBroadcastManager.getInstance(context); lbm.registerReceiver(eventReceiver, eventFilter); dpPrefs = DroidPlannerPrefs.getInstance(context); } public void notifyMissionUpdate() { notifyMissionUpdate(true); } public boolean canUndoMission() { return !undoBuffer.isEmpty(); } public void undoMission() { if (!canUndoMission()) throw new IllegalStateException("Invalid state for mission undoing."); Mission previousMission = undoBuffer.popLast(); load(previousMission, false); } public void notifyMissionUpdate(boolean saveMission) { if (saveMission && currentMission != null) { //Store the current state of the mission. undoBuffer.addLast(currentMission); } currentMission = generateMission(true); lbm.sendBroadcast(new Intent(ACTION_MISSION_PROXY_UPDATE)); } public List<MissionItemProxy> getItems() { return missionItemProxies; } private MissionItem[] getMissionItems() { List<MissionItem> missionItems = new ArrayList<MissionItem>(missionItemProxies.size()); for (MissionItemProxy mip : missionItemProxies) missionItems.add(mip.getMissionItem()); return missionItems.toArray(new MissionItem[missionItems.size()]); } public Drone getDrone() { return this.drone; } /** * Update the state for this object based on the state of the Mission * object. */ private void load(Mission mission) { load(mission, true); } private void load(Mission mission, boolean isNew) { if (mission == null) return; if(!mission.equals(currentMission)) { if (isNew) { currentMission = null; clearUndoBuffer(); } selection.mSelectedItems.clear(); missionItemProxies.clear(); for (MissionItem item : mission.getMissionItems()) { missionItemProxies.add(new MissionItemProxy(this, item)); } selection.notifySelectionUpdate(); notifyMissionUpdate(isNew); } } private void clearUndoBuffer(){ while(!undoBuffer.isEmpty()) undoBuffer.popLast(); } /** * Checks if this mission render contains the passed argument. * * @param item mission item render object * @return true if this mission render contains the passed argument */ public boolean contains(MissionItemProxy item) { return missionItemProxies.contains(item); } /** * Removes a waypoint mission item from the set of mission items commands. * * @param item item to remove */ public void removeItem(MissionItemProxy item) { missionItemProxies.remove(item); selection.mSelectedItems.remove(item); selection.notifySelectionUpdate(); notifyMissionUpdate(); } /** * Adds a survey mission item to the set. * * @param points 2D points making up the survey */ public void addSurveyPolygon(List<LatLong> points, boolean spline) { Survey survey; if(spline){ survey = new SplineSurvey(); }else { survey = new Survey(); } survey.setPolygonPoints(points); // Load the last survey preferences. dpPrefs.loadSurveyPreferences(drone, survey); addMissionItem(survey); } /** * Add a set of waypoints generated around the passed 2D points. * * @param points list of points used to generate the mission waypoints */ public void addWaypoints(List<LatLong> points) { double alt = getLastAltitude(); List<MissionItem> missionItemsToAdd = new ArrayList<MissionItem>(points.size()); for (LatLong point : points) { Waypoint waypoint = new Waypoint(); waypoint.setCoordinate(new LatLongAlt(point.getLatitude(), point.getLongitude(), (float) alt)); missionItemsToAdd.add(waypoint); } addMissionItems(missionItemsToAdd); } public double getLastAltitude() { if (!missionItemProxies.isEmpty()) { MissionItem lastItem = missionItemProxies.get(missionItemProxies.size() - 1).getMissionItem(); if (lastItem instanceof MissionItem.SpatialItem && !(lastItem instanceof RegionOfInterest)) { return ((MissionItem.SpatialItem) lastItem).getCoordinate().getAltitude(); } } return dpPrefs.getDefaultAltitude(); } /** * Add a set of spline waypoints generated around the passed 2D points. * * @param points list of points used as location for the spline waypoints */ public void addSplineWaypoints(List<LatLong> points) { double alt = getLastAltitude(); List<MissionItem> missionItemsToAdd = new ArrayList<MissionItem>(points.size()); for (LatLong point : points) { SplineWaypoint splineWaypoint = new SplineWaypoint(); splineWaypoint.setCoordinate(new LatLongAlt(point.getLatitude(), point.getLongitude(), (float) alt)); missionItemsToAdd.add(splineWaypoint); } addMissionItems(missionItemsToAdd); } public void addMissionItems(List<MissionItem> missionItems) { for (MissionItem missionItem : missionItems) { missionItemProxies.add(new MissionItemProxy(this, missionItem)); } notifyMissionUpdate(); } public void addSpatialWaypoint(BaseSpatialItem spatialItem, LatLong point) { double alt = getLastAltitude(); spatialItem.setCoordinate(new LatLongAlt(point.getLatitude(), point.getLongitude(), alt)); addMissionItem(spatialItem); } /** * Add a waypoint generated around the passed 2D point. * * @param point point used to generate the mission waypoint */ public void addWaypoint(LatLong point) { double alt = getLastAltitude(); Waypoint waypoint = new Waypoint(); waypoint.setCoordinate(new LatLongAlt(point.getLatitude(), point.getLongitude(), alt)); addMissionItem(waypoint); } /** * Add a spline waypoint generated around the passed 2D point. * * @param point point used as location for the spline waypoint. */ public void addSplineWaypoint(LatLong point) { double alt = getLastAltitude(); SplineWaypoint splineWaypoint = new SplineWaypoint(); splineWaypoint.setCoordinate(new LatLongAlt(point.getLatitude(), point.getLongitude(), alt)); addMissionItem(splineWaypoint); } private void addMissionItem(MissionItem missionItem) { missionItemProxies.add(new MissionItemProxy(this, missionItem)); notifyMissionUpdate(); } private void addMissionItem(int index, MissionItem missionItem) { missionItemProxies.add(index, new MissionItemProxy(this, missionItem)); notifyMissionUpdate(); } public void addTakeoff() { Takeoff takeoff = new Takeoff(); takeoff.setTakeoffAltitude(dpPrefs.getDefaultAltitude()); addMissionItem(takeoff); } public boolean hasTakeoffAndLandOrRTL() { if (missionItemProxies.size() >= 2) { if (isFirstItemTakeoff() && isLastItemLandOrRTL()) { return true; } } return false; } public boolean isFirstItemTakeoff() { return !missionItemProxies.isEmpty() && missionItemProxies.get(0).getMissionItem().getType() == MissionItemType.TAKEOFF; } public boolean isLastItemLandOrRTL() { int itemsCount = missionItemProxies.size(); if (itemsCount == 0) return false; MissionItemType itemType = missionItemProxies.get(itemsCount - 1).getMissionItem() .getType(); return itemType == MissionItemType.RETURN_TO_LAUNCH || itemType == MissionItemType.LAND; } public void addTakeOffAndRTL() { if (!isFirstItemTakeoff()) { double defaultAlt = dpPrefs.getDefaultAltitude(); if (!missionItemProxies.isEmpty()) { MissionItem firstItem = missionItemProxies.get(0).getMissionItem(); if (firstItem instanceof MissionItem.SpatialItem) defaultAlt = ((MissionItem.SpatialItem) firstItem).getCoordinate().getAltitude(); else if (firstItem instanceof Survey) { SurveyDetail surveyDetail = ((Survey) firstItem).getSurveyDetail(); if (surveyDetail != null) defaultAlt = surveyDetail.getAltitude(); } } Takeoff takeOff = new Takeoff(); takeOff.setTakeoffAltitude(defaultAlt); addMissionItem(0, takeOff); } if (!isLastItemLandOrRTL()) { ReturnToLaunch rtl = new ReturnToLaunch(); addMissionItem(rtl); } } /** * Returns the order for the given argument in the mission set. * * @param item * @return order of the given argument */ public int getOrder(MissionItemProxy item) { return missionItemProxies.indexOf(item) + 1; } /** * @return The order of the first waypoint. */ public int getFirstWaypoint(){ if(missionItemProxies.isEmpty()) return 0; return getOrder(missionItemProxies.get(0)); } /** * @return The order for the last waypoint. */ public int getLastWaypoint(){ int lastIndex = missionItemProxies.size() -1; if(lastIndex < 0) return 0; return getOrder(missionItemProxies.get(lastIndex)); } /** * Updates a mission item render * * @param oldItem mission item render to update * @param newItem new mission item render */ public void replace(MissionItemProxy oldItem, MissionItemProxy newItem) { int index = missionItemProxies.indexOf(oldItem); if (index == -1) return; missionItemProxies.remove(index); missionItemProxies.add(index, newItem); if (selection.selectionContains(oldItem)) { selection.removeItemFromSelection(oldItem); selection.addToSelection(newItem); } notifyMissionUpdate(); } public void replaceAll(List<Pair<MissionItemProxy, List<MissionItemProxy>>> oldNewList) { if (oldNewList == null) { return; } int pairSize = oldNewList.size(); if (pairSize == 0) { return; } List<MissionItemProxy> selectionsToRemove = new ArrayList<>(pairSize); List<MissionItemProxy> itemsToSelect = new ArrayList<>(pairSize); for (int i = 0; i < pairSize; i++) { MissionItemProxy oldItem = oldNewList.get(i).first; int index = missionItemProxies.indexOf(oldItem); if (index == -1) { continue; } missionItemProxies.remove(index); List<MissionItemProxy> newItems = oldNewList.get(i).second; missionItemProxies.addAll(index, newItems); if (selection.selectionContains(oldItem)) { selectionsToRemove.add(oldItem); itemsToSelect.addAll(newItems); } } //Update the selection list. selection.removeItemsFromSelection(selectionsToRemove); selection.addToSelection(itemsToSelect); notifyMissionUpdate(); } public void swap(int fromIndex, int toIndex) { MissionItemProxy from = missionItemProxies.get(fromIndex); MissionItemProxy to = missionItemProxies.get(toIndex); missionItemProxies.set(toIndex, from); missionItemProxies.set(fromIndex, to); notifyMissionUpdate(); } public void clear() { selection.clearSelection(); missionItemProxies.clear(); notifyMissionUpdate(); } public double getAltitudeDiffFromPreviousItem(MissionItemProxy waypointRender) { int itemsCount = missionItemProxies.size(); if (itemsCount < 2) return 0; MissionItem waypoint = waypointRender.getMissionItem(); if (!(waypoint instanceof MissionItem.SpatialItem)) return 0; int index = missionItemProxies.indexOf(waypointRender); if (index == -1 || index == 0) return 0; MissionItem previous = missionItemProxies.get(index - 1).getMissionItem(); if (previous instanceof MissionItem.SpatialItem) { return ((MissionItem.SpatialItem) waypoint).getCoordinate().getAltitude() - ((MissionItem.SpatialItem) previous).getCoordinate().getAltitude(); } return 0; } public double getDistanceFromLastWaypoint(MissionItemProxy waypointRender) { if (missionItemProxies.size() < 2) return 0; MissionItem waypoint = waypointRender.getMissionItem(); if (!(waypoint instanceof MissionItem.SpatialItem)) return 0; int index = missionItemProxies.indexOf(waypointRender); if (index == -1 || index == 0) return 0; MissionItem previous = missionItemProxies.get(index - 1).getMissionItem(); if (previous instanceof MissionItem.SpatialItem) { return MathUtils.getDistance3D(((MissionItem.SpatialItem) waypoint).getCoordinate(), ((MissionItem.SpatialItem) previous).getCoordinate()); } return 0; } @Override public List<LatLong> getPathPoints() { if (missionItemProxies.isEmpty()) { return Collections.emptyList(); } // Partition the mission items into spline/non-spline buckets. List<Pair<Boolean, List<MissionItemProxy>>> bucketsList = new ArrayList<>(); boolean isSpline = false; List<MissionItemProxy> currentBucket = new ArrayList<>(); for (MissionItemProxy missionItemProxy : missionItemProxies) { MissionItem missionItem = missionItemProxy.getMissionItem(); if (missionItem instanceof MissionItem.Command) { //Skip commands continue; } if (missionItem instanceof SplineWaypoint || missionItem instanceof SplineSurvey) { if (!isSpline) { if (!currentBucket.isEmpty()) { // Get the last item from the current bucket. It will become the first // anchor point for the spline path. MissionItemProxy lastItem = currentBucket.get(currentBucket.size() - 1); // Store the previous item bucket. bucketsList.add(new Pair<>(Boolean.FALSE, currentBucket)); // Create a new bucket for this category and update 'isSpline' currentBucket = new ArrayList<>(); currentBucket.add(lastItem); } isSpline = true; } // Add the current element into the bucket currentBucket.add(missionItemProxy); } else { if (isSpline) { // Add the current item to the spline bucket. It will act as the end anchor // point for the spline path. if (!currentBucket.isEmpty()) { currentBucket.add(missionItemProxy); // Store the previous item bucket. bucketsList.add(new Pair<>(Boolean.TRUE, currentBucket)); currentBucket = new ArrayList<>(); } isSpline = false; } // Add the current element into the bucket currentBucket.add(missionItemProxy); } } bucketsList.add(new Pair<>(isSpline, currentBucket)); List<LatLong> pathPoints = new ArrayList<>(); LatLong lastPoint = null; for (Pair<Boolean, List<MissionItemProxy>> bucketEntry : bucketsList) { List<MissionItemProxy> bucket = bucketEntry.second; if (bucketEntry.first) { List<LatLong> splinePoints = new ArrayList<>(); int bucketSize = bucket.size(); for(int i = 0; i < bucketSize; i++){ MissionItemProxy missionItemProxy = bucket.get(i); MissionItemType missionItemType = missionItemProxy.getMissionItem().getType(); List<LatLong> missionItemPath = missionItemProxy.getPath(lastPoint); switch(missionItemType){ case SURVEY: if(!missionItemPath.isEmpty()) { if (i == 0) splinePoints.add(missionItemPath.get(0)); else { splinePoints.add(missionItemPath.get(missionItemPath.size() - 1)); } } break; default: splinePoints.addAll(missionItemPath); break; } if (!splinePoints.isEmpty()) { lastPoint = splinePoints.get(splinePoints.size() - 1); } } pathPoints.addAll(MathUtils.SplinePath.process(splinePoints)); } else { for (MissionItemProxy missionItemProxy : bucket) { pathPoints.addAll(missionItemProxy.getPath(lastPoint)); if (!pathPoints.isEmpty()) { lastPoint = pathPoints.get(pathPoints.size() - 1); } } } } return pathPoints; } public void removeSelection(MissionSelection missionSelection) { missionItemProxies.removeAll(missionSelection.mSelectedItems); missionSelection.clearSelection(); notifyMissionUpdate(); } public void move(MissionItemProxy item, LatLong position) { MissionItem missionItem = item.getMissionItem(); if (missionItem instanceof SpatialItem) { SpatialItem spatialItem = (SpatialItem) missionItem; spatialItem.setCoordinate(new LatLongAlt(position.getLatitude(), position.getLongitude(), spatialItem.getCoordinate().getAltitude())); if (spatialItem instanceof StructureScanner) { this.drone.buildMissionItemsAsync(new StructureScanner[]{(StructureScanner) spatialItem}, missionItemsBuiltListener); } notifyMissionUpdate(); } } public List<LatLong> getVisibleCoords() { return getVisibleCoords(missionItemProxies); } public void movePolygonPoint(Survey survey, int index, LatLong position) { survey.getPolygonPoints().get(index).set(position); this.drone.buildMissionItemsAsync(new Survey[]{survey}, missionItemsBuiltListener); notifyMissionUpdate(); } public static List<LatLong> getVisibleCoords(List<MissionItemProxy> mipList) { List<LatLong> coords = new ArrayList<LatLong>(); if (mipList == null || mipList.isEmpty()) { return coords; } for (MissionItemProxy itemProxy : mipList) { MissionItem item = itemProxy.getMissionItem(); if (!(item instanceof SpatialItem)) continue; LatLong coordinate = ((SpatialItem) item).getCoordinate(); if (coordinate.getLatitude() == 0 || coordinate.getLongitude() == 0) continue; coords.add(coordinate); } return coords; } private Mission generateMission() { return generateMission(false); } private Mission generateMission(boolean isDeepCopy) { Mission mission = new Mission(); if (!missionItemProxies.isEmpty()) { for (MissionItemProxy itemProxy : missionItemProxies) { MissionItem sourceItem = itemProxy.getMissionItem(); MissionItem destItem = isDeepCopy ? sourceItem.clone() : sourceItem; mission.addMissionItem(destItem); } } return mission; } public void sendMissionToAPM(Drone drone) { MissionApi.getApi(drone).setMission(generateMission(), true); int missionItemsCount = missionItemProxies.size(); String missionItemsList = "["; if (missionItemsCount > 0) { boolean isFirst = true; for (MissionItemProxy itemProxy : missionItemProxies) { if (isFirst) isFirst = false; else missionItemsList += ", "; missionItemsList += itemProxy.getMissionItem().getType().getLabel(); } } missionItemsList += "]"; HitBuilders.EventBuilder eventBuilder = new HitBuilders.EventBuilder() .setCategory(GAUtils.Category.MISSION_PLANNING) .setAction("Mission sent to drone") .setLabel("Mission items: " + missionItemsList); GAUtils.sendEvent(eventBuilder); //Send an event for the created mission eventBuilder = new HitBuilders.EventBuilder() .setCategory(GAUtils.Category.MISSION_PLANNING) .setAction("Mission sent to drone") .setLabel("Mission items count") .setValue(missionItemsCount); GAUtils.sendEvent(eventBuilder); } public Pair<Double, Double> getMissionFlightTime() { if (missionItemProxies.isEmpty()) { return Pair.create(0.0, 0.0); } double currentSpeed = dpApp.getVehicleSpeed(); double accumulatedDistance = 0; double accumulatedDelay = 0; LatLong lastPoint = null; List<Pair<Double, Double>> speedPerDistance = new LinkedList<>(); for (MissionItemProxy proxy : missionItemProxies) { final MissionItem missionItem = proxy.getMissionItem(); if (!(missionItem instanceof MissionItem.Command)) { // If the mission item has a spatial component, retrieve that component. List<LatLong> path = proxy.getPath(lastPoint); if (!path.isEmpty()) { for (LatLong point : path) { if (lastPoint != null) { // Accumulate the distance between the last point and the current point. accumulatedDistance += MathUtils.getDistance2D(lastPoint, point); } lastPoint = point; } } if (missionItem instanceof Waypoint){ accumulatedDelay += ((Waypoint) missionItem).getDelay(); }else if (missionItem instanceof SplineWaypoint){ accumulatedDelay += ((SplineWaypoint) missionItem).getDelay(); } } else if (missionItem instanceof ChangeSpeed) { // We're updating the vehicle speed, so let's store the distance accumulated at // the current speed. if (accumulatedDistance > 0) { speedPerDistance.add(Pair.create(currentSpeed, accumulatedDistance)); accumulatedDistance = 0; } currentSpeed = ((ChangeSpeed) missionItem).getSpeed(); } } if (accumulatedDistance > 0) { speedPerDistance.add(Pair.create(currentSpeed, accumulatedDistance)); } if (speedPerDistance.isEmpty()) { return Pair.create(0.0, 0.0); } else { double totalFlightDistance = 0; double totalFlightTime = 0; for (Pair<Double, Double> entry : speedPerDistance) { double speed = entry.first; double distance = entry.second; totalFlightDistance += distance; if (speed <= 0) { // No way the vehicle is completing its mission if the speed is less or equal to // 0. totalFlightTime += Double.POSITIVE_INFINITY; } else { totalFlightTime += distance / speed; } } totalFlightTime += accumulatedDelay; return Pair.create(totalFlightDistance, totalFlightTime); } } public double getAccumulatedMissionDelay(){ double accumulatedDelay = 0; //time in decimal seconds for (MissionItemProxy itemProxy : missionItemProxies) { MissionItem missionItem = itemProxy.getMissionItem(); switch (missionItem.getType()) { case WAYPOINT: accumulatedDelay += ((Waypoint) missionItem).getDelay(); break; case SPLINE_WAYPOINT: accumulatedDelay += ((SplineWaypoint) missionItem).getDelay(); break; default: break; } } return accumulatedDelay; } public void makeAndUploadDronie(Drone drone) { MissionApi.getApi(drone).generateDronie(); } public List<List<LatLong>> getPolygonsPath() { ArrayList<List<LatLong>> polygonPaths = new ArrayList<List<LatLong>>(); for (MissionItemProxy itemProxy : missionItemProxies) { MissionItem item = itemProxy.getMissionItem(); if (item instanceof Survey) { polygonPaths.add(((Survey) item).getPolygonPoints()); } } return polygonPaths; } public void writeMissionToFile(Uri saveUri){ MissionApi.getApi(drone).saveMission(generateMission(), saveUri, new AbstractCommandListener() { @Override public void onSuccess() { Toast.makeText(context, R.string.file_saved_success, Toast.LENGTH_SHORT) .show(); final HitBuilders.EventBuilder eventBuilder = new HitBuilders.EventBuilder() .setCategory(GAUtils.Category.MISSION_PLANNING) .setAction("Mission saved to file") .setLabel("Mission items count"); GAUtils.sendEvent(eventBuilder); } @Override public void onError(int executionError) { Toast.makeText(context, R.string.file_saved_error, Toast.LENGTH_SHORT).show(); } @Override public void onTimeout() { Toast.makeText(context, R.string.file_saved_error, Toast.LENGTH_SHORT).show(); } }); } public void readMissionFromFile(final Uri fileUri){ MissionApi.getApi(drone).loadAndSetMission(fileUri, new MissionApi.LoadingCallback<Mission>() { @Override public void onLoadingStart() { Toast.makeText(context, "Loading mission...", Toast.LENGTH_SHORT).show(); } @Override public void onLoadingComplete(Mission loaded) { load(loaded); Toast.makeText(context, "Mission loaded!", Toast.LENGTH_SHORT).show(); } @Override public void onLoadingFailed() { Toast.makeText(context, "Mission loading failed!", Toast.LENGTH_SHORT).show(); } }); } }