package boston.Bus.Map.main; import com.google.common.base.Optional; import com.schneeloch.bostonbusmap_library.data.GroupKey; import com.schneeloch.bostonbusmap_library.data.Selection; import boston.Bus.Map.data.UpdateArguments; import com.schneeloch.bostonbusmap_library.transit.TransitSystem; import com.schneeloch.bostonbusmap_library.util.Constants; import com.google.android.maps.GeoPoint; import com.schneeloch.bostonbusmap_library.util.LogUtil; import android.os.Handler; import android.os.Message; import java.util.concurrent.ConcurrentLinkedQueue; public class UpdateHandler extends Handler { /** * An update which refreshes from the internet */ public static final int MAJOR = 1; /** * An update where we just moved the map */ public static final int MINOR = 2; /** * The last time we updated, in milliseconds. Used to make sure we don't update more frequently than * every 10 seconds, to avoid unnecessary strain on their server */ private long lastUpdateTime; private final int maxOverlays = 175; private final int IMMEDIATE_REFRESH = 1; private int updateConstantlyInterval; private boolean hideHighlightCircle; private boolean showUnpredictable; private boolean changeRouteIfSelected; private AdjustUIAsyncTask minorUpdate; private final UpdateArguments guiArguments; private boolean showTraffic = false; private final ConcurrentLinkedQueue<Runnable> afterRefresh = new ConcurrentLinkedQueue<>(); private final ConcurrentLinkedQueue<Runnable> afterUpdate = new ConcurrentLinkedQueue<>(); public UpdateHandler(UpdateArguments guiArguments) { this.guiArguments = guiArguments; lastUpdateTime = System.currentTimeMillis(); } @Override public void handleMessage(Message msg) { switch (msg.what) { case MAJOR: //remove duplicates long currentTime = System.currentTimeMillis(); int interval = getUpdateConstantlyInterval() * 1000; // schedule this before RefreshAsyncTask since that will block other threads runMinorUpdateTask(); runUpdateTask(); //make updateBuses execute every 10 seconds (or whatever fetchDelay is) //to disable this, the user should go into the settings and uncheck 'Run in background' if (msg.arg1 != IMMEDIATE_REFRESH && interval != 0) { removeMessages(MAJOR); sendEmptyMessageDelayed(MAJOR, interval); } break; case MINOR: //don't do two updates at once if (minorUpdate != null) { if (minorUpdate.getStatus().equals(UpdateAsyncTask.Status.FINISHED) == false) { //task is not finished yet return; } } //remove duplicate messages removeMessages(MINOR); runMinorUpdateTask(); break; } } private void runMinorUpdateTask() { Selection selection = guiArguments.getBusLocations().getSelection(); minorUpdate = new AdjustUIAsyncTask(guiArguments, getShowUnpredictable(), maxOverlays, selection, this, afterUpdate.poll()); minorUpdate.runUpdate(); } public void removeAllMessages() { removeMessages(MAJOR); removeMessages(MINOR); //removeMessages(LOCATION_NOT_FOUND); //removeMessages(LOCATION_FOUND); } public void kill() { if (guiArguments.getMajorHandler() != null) { guiArguments.getMajorHandler().cancel(true); } if (minorUpdate != null) { minorUpdate.cancel(true); } } /** * executes the update */ private void runUpdateTask() { //make sure we don't update too often lastUpdateTime = System.currentTimeMillis(); //don't do two updates at once if (guiArguments.getMajorHandler() != null) { if (guiArguments.getMajorHandler().getStatus().equals(UpdateAsyncTask.Status.FINISHED) == false) { //task is not finished yet LogUtil.i("MAJOR task is not finished yet"); return; } } Selection selection = guiArguments.getBusLocations().getSelection(); final RefreshAsyncTask updateAsyncTask = new RefreshAsyncTask( guiArguments, getShowUnpredictable(), maxOverlays, selection, this, afterRefresh.poll() ); guiArguments.setMajorHandler(updateAsyncTask); updateAsyncTask.runUpdate(); } public void triggerRefresh(long millis) { removeMessages(MAJOR); sendEmptyMessageDelayed(MAJOR, millis); removeMessages(MINOR); sendEmptyMessageDelayed(MINOR, millis); } public void triggerRefreshThen(Runnable runnable) { afterRefresh.add(runnable); triggerRefresh(0); } public boolean instantRefresh() { //removeAllMessages(); if(getUpdateConstantlyInterval() != Main.UPDATE_INTERVAL_NONE) { //if the runInBackground checkbox is clicked, start the handler updating removeMessages(MAJOR); sendEmptyMessageDelayed(MAJOR, getUpdateConstantlyInterval() * 1000); } runMinorUpdateTask(); runUpdateTask(); return true; } public int getUpdateConstantlyInterval() { return updateConstantlyInterval; } public void setUpdateConstantlyInterval(int updateConstantlyInterval) { this.updateConstantlyInterval = updateConstantlyInterval; } public void setLastUpdateTime(long lastUpdateTime) { this.lastUpdateTime = lastUpdateTime; } public long getLastUpdateTime() { return lastUpdateTime; } public void setShowUnpredictable(boolean b) { showUnpredictable = b; } public boolean getShowUnpredictable() { return showUnpredictable; } public void triggerUpdate(int millis) { sendEmptyMessageDelayed(MINOR, millis); } public void triggerUpdate() { sendEmptyMessage(MINOR); } public void triggerUpdateThen(Runnable runnable) { afterUpdate.add(runnable); triggerUpdate(); } public void triggerUpdateThenSelect(final Optional<GroupKey> toSelect) { triggerUpdateThen(new Runnable() { @Override public void run() { guiArguments.getOverlayGroup().setSelectedBusId(toSelect); triggerUpdate(); } }); } public void resume() { //removeAllMessages(); if(getUpdateConstantlyInterval() != Main.UPDATE_INTERVAL_NONE) { //if the runInBackground checkbox is clicked, start the handler updating instantRefresh(); } } public void immediateRefresh() { Message msg = new Message(); msg.arg1 = IMMEDIATE_REFRESH; msg.what = MAJOR; sendMessage(msg); } public void nullifyProgress() { if (guiArguments.getMajorHandler() != null) { guiArguments.getMajorHandler().nullifyProgress(); } if (minorUpdate != null) { //probably not in the middle of something but just in case minorUpdate.nullifyProgress(); } } }