diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index d71fdbe..7ed173a 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -61,10 +61,22 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/com/dougkeen/bart/AlarmBroadcastReceiver.java b/src/com/dougkeen/bart/AlarmBroadcastReceiver.java
new file mode 100644
index 0000000..554adce
--- /dev/null
+++ b/src/com/dougkeen/bart/AlarmBroadcastReceiver.java
@@ -0,0 +1,22 @@
+package com.dougkeen.bart;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public class AlarmBroadcastReceiver extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ WakeLocker.acquire(context);
+
+ Intent targetIntent = new Intent(Intent.ACTION_VIEW, intent.getData());
+ targetIntent.putExtra("boardedDeparture", intent.getExtras()
+ .getParcelable("departure"));
+ targetIntent.putExtra("isAlarm", true);
+ targetIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ context.startActivity(targetIntent);
+ }
+
+}
diff --git a/src/com/dougkeen/bart/NotificationService.java b/src/com/dougkeen/bart/NotificationService.java
new file mode 100644
index 0000000..223c6fb
--- /dev/null
+++ b/src/com/dougkeen/bart/NotificationService.java
@@ -0,0 +1,258 @@
+package com.dougkeen.bart;
+
+import java.util.List;
+
+import android.app.AlarmManager;
+import android.app.IntentService;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.SystemClock;
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.app.NotificationCompat.Builder;
+
+import com.dougkeen.bart.EtdService.EtdServiceBinder;
+import com.dougkeen.bart.EtdService.EtdServiceListener;
+import com.dougkeen.bart.model.Constants;
+import com.dougkeen.bart.model.Departure;
+import com.dougkeen.bart.model.StationPair;
+
+public class NotificationService extends IntentService implements
+ EtdServiceListener {
+
+ private static final int DEPARTURE_NOTIFICATION_ID = 123;
+ private boolean mBound = false;
+ private EtdService mEtdService;
+ private Departure mDeparture;
+ private StationPair mStationPair;
+ private NotificationManager mNotificationManager;
+ private AlarmManager mAlarmManager;
+ private PendingIntent mNotificationIntent;
+ private PendingIntent mAlarmPendingIntent;
+ private int mAlertLeadTime;
+ private Handler mHandler;
+
+ public NotificationService() {
+ super("BartRunnerNotificationService");
+ }
+
+ private final ServiceConnection mConnection = new ServiceConnection() {
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mEtdService = null;
+ mBound = false;
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mEtdService = ((EtdServiceBinder) service).getService();
+ if (getStationPair() != null) {
+ mEtdService.registerListener(NotificationService.this);
+ }
+ mBound = true;
+ }
+ };
+
+ @Override
+ public void onCreate() {
+ bindService(new Intent(this, EtdService.class), mConnection,
+ Context.BIND_AUTO_CREATE);
+ mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ mAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
+ mHandler = new Handler();
+ super.onCreate();
+ }
+
+ @Override
+ public void onDestroy() {
+ if (mBound)
+ unbindService(mConnection);
+ super.onDestroy();
+ }
+
+ @Override
+ protected void onHandleIntent(Intent intent) {
+ Bundle bundle = intent.getExtras();
+ Departure departure = (Departure) bundle.getParcelable("departure");
+ mStationPair = (StationPair) bundle.getParcelable("stationPair");
+ mAlertLeadTime = bundle.getInt("alertLeadTime");
+
+ if (mEtdService != null && mDeparture != null
+ && !mDeparture.equals(departure)) {
+ mEtdService.unregisterListener(this);
+ }
+
+ mDeparture = departure;
+
+ if (getStationPair() != null && mEtdService != null) {
+ mEtdService.registerListener(this);
+ }
+
+ updateNotification();
+
+ Intent targetIntent = new Intent(Intent.ACTION_VIEW,
+ mStationPair.getUri());
+ targetIntent.putExtra("boardedDeparture", mDeparture);
+ targetIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ mNotificationIntent = PendingIntent.getActivity(this, 0, targetIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+
+ setAlarm();
+
+ pollDepartureStatus();
+ }
+
+ private void refreshAlarmPendingIntent() {
+ final Intent alarmIntent = new Intent(Constants.ACTION_ALARM,
+ getStationPair().getUri());
+ alarmIntent.putExtra("departure", mDeparture);
+ mAlarmPendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
+ private void setAlarm() {
+ cancelAlarm();
+
+ if (mAlertLeadTime > 0) {
+ long alertTime = getAlertClockTime();
+ if (alertTime > System.currentTimeMillis()) {
+ refreshAlarmPendingIntent();
+ mAlarmManager.set(AlarmManager.RTC_WAKEUP, alertTime,
+ mAlarmPendingIntent);
+ }
+ }
+ }
+
+ private void triggerAlarmImmediately() {
+ cancelAlarm();
+ refreshAlarmPendingIntent();
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + 100, mAlarmPendingIntent);
+ }
+
+ private long getAlertClockTime() {
+ return mDeparture.getMeanEstimate() - mAlertLeadTime * 60 * 1000;
+ }
+
+ private void cancelAlarm() {
+ mAlarmManager.cancel(mAlarmPendingIntent);
+ }
+
+ @Override
+ public void onETDChanged(List departures) {
+ for (Departure departure : departures) {
+ if (departure.equals(mDeparture)
+ && (mDeparture.getMeanSecondsLeft() != departure
+ .getMeanSecondsLeft() || mDeparture
+ .getUncertaintySeconds() != departure
+ .getUncertaintySeconds())) {
+ long initialAlertClockTime = getAlertClockTime();
+
+ mDeparture.mergeEstimate(departure);
+
+ final long now = System.currentTimeMillis();
+ if (initialAlertClockTime > now
+ && getAlertClockTime() <= System.currentTimeMillis()) {
+ // Alert time was changed to the past
+ triggerAlarmImmediately();
+ } else if (getAlertClockTime() > System.currentTimeMillis()) {
+ // Alert time is still in the future
+ setAlarm();
+ }
+
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void onError(String errorMessage) {
+ // Do nothing
+ }
+
+ @Override
+ public void onRequestStarted() {
+ // Do nothing
+ }
+
+ @Override
+ public void onRequestEnded() {
+ // Do nothing
+ }
+
+ @Override
+ public StationPair getStationPair() {
+ return mStationPair;
+ }
+
+ private long mNextScheduledCheckClockTime = 0;
+
+ private void pollDepartureStatus() {
+ if (mDeparture.hasDeparted()) {
+ shutDown();
+ }
+
+ updateNotification();
+
+ final int pollIntervalMillis = getPollIntervalMillis();
+ final long scheduledCheckClockTime = System.currentTimeMillis()
+ + pollIntervalMillis;
+ if (mNextScheduledCheckClockTime < scheduledCheckClockTime) {
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ pollDepartureStatus();
+ }
+ }, pollIntervalMillis);
+ mNextScheduledCheckClockTime = scheduledCheckClockTime;
+ }
+ }
+
+ private void shutDown() {
+ mEtdService.unregisterListener(this);
+ mNotificationManager.cancel(DEPARTURE_NOTIFICATION_ID);
+ cancelAlarm();
+ stopSelf();
+ }
+
+ private void updateNotification() {
+ Builder notificationBuilder = new NotificationCompat.Builder(this);
+ notificationBuilder.setOngoing(true);
+ notificationBuilder.setSmallIcon(R.drawable.icon);
+ final int minutes = mDeparture.getMeanSecondsLeft() / 60;
+ final String minutesText = (minutes == 0) ? "Less than one minute"
+ : (minutes + " minute" + ((minutes != 1) ? "s" : ""));
+ notificationBuilder.setContentTitle(mStationPair.getDestination().name);
+ notificationBuilder.setContentText(minutesText + " until departure");
+ notificationBuilder.setContentIntent(mNotificationIntent);
+ mNotificationManager.notify(DEPARTURE_NOTIFICATION_ID,
+ notificationBuilder.getNotification());
+ }
+
+ private int getPollIntervalMillis() {
+ final int secondsToAlarm = mDeparture.getMeanSecondsLeft()
+ - mAlertLeadTime * 60;
+
+ if (secondsToAlarm < -20) {
+ /* Alarm should have already gone off by now */
+ shutDown();
+ return 10000000; // Arbitrarily large number
+ }
+
+ if (secondsToAlarm > 10 * 60) {
+ return 60 * 1000;
+ } else if (secondsToAlarm > 5 * 60) {
+ return 60 * 1000;
+ } else if (secondsToAlarm > 3 * 60) {
+ return 30 * 1000;
+ } else {
+ return 10 * 1000;
+ }
+ }
+}
diff --git a/src/com/dougkeen/bart/TrainAlertDialogFragment.java b/src/com/dougkeen/bart/TrainAlertDialogFragment.java
index 9386d46..13604b2 100644
--- a/src/com/dougkeen/bart/TrainAlertDialogFragment.java
+++ b/src/com/dougkeen/bart/TrainAlertDialogFragment.java
@@ -4,6 +4,7 @@ import net.simonvt.widget.NumberPicker;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
@@ -12,15 +13,18 @@ import android.support.v4.app.FragmentActivity;
import com.WazaBe.HoloEverywhere.AlertDialog;
import com.dougkeen.bart.model.Departure;
+import com.dougkeen.bart.model.StationPair;
public class TrainAlertDialogFragment extends DialogFragment {
- private static final String KEY_LAST_ALERT_DELAY = "lastAlertDelay";
+ private static final String KEY_LAST_ALERT_LEAD_TIME = "lastAlertLeadTime";
private Departure mDeparture;
+ private StationPair mStationPair;
- public TrainAlertDialogFragment(Departure mDeparture) {
+ public TrainAlertDialogFragment(Departure departure, StationPair stationPair) {
super();
- this.mDeparture = mDeparture;
+ this.mDeparture = departure;
+ this.mStationPair = stationPair;
}
@Override
@@ -29,7 +33,7 @@ public class TrainAlertDialogFragment extends DialogFragment {
SharedPreferences preferences = getActivity().getPreferences(
Context.MODE_PRIVATE);
- int lastAlertDelay = preferences.getInt(KEY_LAST_ALERT_DELAY, 5);
+ int lastAlertLeadTime = preferences.getInt(KEY_LAST_ALERT_LEAD_TIME, 5);
NumberPicker numberPicker = (NumberPicker) getDialog().findViewById(
R.id.numberPicker);
@@ -44,8 +48,8 @@ public class TrainAlertDialogFragment extends DialogFragment {
numberPicker.setMaxValue(maxValue);
numberPicker.setDisplayedValues(displayedValues);
- if (maxValue >= lastAlertDelay) {
- numberPicker.setValue(lastAlertDelay);
+ if (maxValue >= lastAlertLeadTime) {
+ numberPicker.setValue(lastAlertLeadTime);
} else if (maxValue >= 5) {
numberPicker.setValue(5);
} else if (maxValue >= 3) {
@@ -70,12 +74,22 @@ public class TrainAlertDialogFragment extends DialogFragment {
int which) {
NumberPicker numberPicker = (NumberPicker) getDialog()
.findViewById(R.id.numberPicker);
+ final int alertLeadTime = numberPicker
+ .getValue();
+ // Save most recent selection
Editor editor = getActivity().getPreferences(
Context.MODE_PRIVATE).edit();
- editor.putInt(KEY_LAST_ALERT_DELAY,
- numberPicker.getValue());
+ editor.putInt(KEY_LAST_ALERT_LEAD_TIME,
+ alertLeadTime);
editor.commit();
+
+ Intent intent = new Intent(getActivity(),
+ NotificationService.class);
+ intent.putExtra("departure", mDeparture);
+ intent.putExtra("stationPair", mStationPair);
+ intent.putExtra("alertLeadTime", alertLeadTime);
+ getActivity().startService(intent);
}
})
.setNegativeButton(R.string.skip_alert,
diff --git a/src/com/dougkeen/bart/ViewDeparturesActivity.java b/src/com/dougkeen/bart/ViewDeparturesActivity.java
index 62b69b6..19698e7 100644
--- a/src/com/dougkeen/bart/ViewDeparturesActivity.java
+++ b/src/com/dougkeen/bart/ViewDeparturesActivity.java
@@ -13,7 +13,6 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcelable;
-import android.os.PowerManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
@@ -21,6 +20,7 @@ import android.text.format.DateFormat;
import android.text.util.Linkify;
import android.util.Log;
import android.view.View;
+import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListAdapter;
@@ -62,8 +62,6 @@ public class ViewDeparturesActivity extends SherlockFragmentActivity implements
private TextView mEmptyView;
private ProgressBar mProgress;
- private PowerManager.WakeLock mWakeLock;
-
private ActionMode mActionMode;
private EtdService mEtdService;
@@ -73,6 +71,7 @@ public class ViewDeparturesActivity extends SherlockFragmentActivity implements
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
setContentView(R.layout.departures);
final Intent intent = getIntent();
@@ -92,6 +91,7 @@ public class ViewDeparturesActivity extends SherlockFragmentActivity implements
.getString("origin"));
mDestination = Station.getByAbbreviation(savedInstanceState
.getString("destination"));
+ setListTitle();
} else {
getSupportLoaderManager().initLoader(LOADER_ID, null,
new LoaderCallbacks() {
@@ -117,9 +117,7 @@ public class ViewDeparturesActivity extends SherlockFragmentActivity implements
mDestination = Station.getByAbbreviation(cursor
.getString(1));
cursor.close();
- ((TextView) findViewById(R.id.listTitle))
- .setText(mOrigin.name + " to "
- + mDestination.name);
+ setListTitle();
if (mBound && mEtdService != null)
mEtdService
.registerListener(ViewDeparturesActivity.this);
@@ -141,6 +139,13 @@ public class ViewDeparturesActivity extends SherlockFragmentActivity implements
mDeparturesAdapter = new DepartureArrayAdapter(this,
R.layout.departure_listing);
+
+ if (intent.getExtras() != null
+ && intent.getExtras().containsKey("boardedDeparture")) {
+ mBoardedDeparture = (Departure) intent.getExtras().getParcelable(
+ "boardedDeparture");
+ }
+
if (savedInstanceState != null) {
if (savedInstanceState.containsKey("departures")) {
for (Parcelable departure : savedInstanceState
@@ -186,6 +191,11 @@ public class ViewDeparturesActivity extends SherlockFragmentActivity implements
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
+ private void setListTitle() {
+ ((TextView) findViewById(R.id.listTitle)).setText(mOrigin.name + " to "
+ + mDestination.name);
+ }
+
@SuppressWarnings("unchecked")
private AdapterView getListView() {
return (AdapterView) findViewById(android.R.id.list);
@@ -225,6 +235,7 @@ public class ViewDeparturesActivity extends SherlockFragmentActivity implements
if (mBound)
unbindService(mConnection);
Ticker.getInstance().stopTicking();
+ WakeLocker.release();
}
@Override
@@ -254,14 +265,10 @@ public class ViewDeparturesActivity extends SherlockFragmentActivity implements
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
- PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
- mWakeLock = powerManager
- .newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK,
- "ViewDeparturesActivity");
- mWakeLock.acquire();
+ getWindow()
+ .addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ Ticker.getInstance().startTicking();
refreshBoardedDeparture();
- } else if (mWakeLock != null) {
- mWakeLock.release();
}
}
@@ -276,7 +283,10 @@ public class ViewDeparturesActivity extends SherlockFragmentActivity implements
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
if (itemId == android.R.id.home) {
- finish();
+ Intent intent = new Intent(Intent.ACTION_VIEW,
+ Constants.FAVORITE_CONTENT_URI);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(intent);
return true;
} else if (itemId == R.id.view_on_bart_site_button) {
startActivity(new Intent(
@@ -381,8 +391,9 @@ public class ViewDeparturesActivity extends SherlockFragmentActivity implements
// Don't prompt for alert if train is about to leave
if (mBoardedDeparture.getMeanSecondsLeft() / 60 > 1) {
- new TrainAlertDialogFragment(mBoardedDeparture).show(
- getSupportFragmentManager(), "dialog");
+ new TrainAlertDialogFragment(mBoardedDeparture,
+ getStationPair()).show(getSupportFragmentManager(),
+ "dialog");
}
mode.finish();
@@ -440,7 +451,6 @@ public class ViewDeparturesActivity extends SherlockFragmentActivity implements
} else {
final DepartureArrayAdapter listAdapter = getListAdapter();
listAdapter.clear();
- // addAll() method isn't available until API level 11
for (Departure departure : departures) {
listAdapter.add(departure);
}
@@ -449,7 +459,7 @@ public class ViewDeparturesActivity extends SherlockFragmentActivity implements
if (mBoardedDeparture != null) {
for (Departure departure : departures) {
if (departure.equals(mBoardedDeparture)) {
- mBoardedDeparture = departure;
+ mBoardedDeparture.mergeEstimate(departure);
refreshBoardedDeparture();
break;
}
diff --git a/src/com/dougkeen/bart/WakeLocker.java b/src/com/dougkeen/bart/WakeLocker.java
new file mode 100644
index 0000000..f08d48b
--- /dev/null
+++ b/src/com/dougkeen/bart/WakeLocker.java
@@ -0,0 +1,29 @@
+package com.dougkeen.bart;
+
+import android.content.Context;
+import android.os.PowerManager;
+
+import com.dougkeen.bart.model.Constants;
+
+public abstract class WakeLocker {
+ private static PowerManager.WakeLock wakeLock;
+
+ public static void acquire(Context ctx) {
+ if (wakeLock != null)
+ wakeLock.release();
+
+ PowerManager pm = (PowerManager) ctx
+ .getSystemService(Context.POWER_SERVICE);
+ wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK
+ | PowerManager.ACQUIRE_CAUSES_WAKEUP
+ | PowerManager.ON_AFTER_RELEASE
+ | PowerManager.SCREEN_DIM_WAKE_LOCK, Constants.TAG);
+ wakeLock.acquire();
+ }
+
+ public static void release() {
+ if (wakeLock != null)
+ wakeLock.release();
+ wakeLock = null;
+ }
+}
\ No newline at end of file
diff --git a/src/com/dougkeen/bart/model/Constants.java b/src/com/dougkeen/bart/model/Constants.java
index 0a47659..479a077 100644
--- a/src/com/dougkeen/bart/model/Constants.java
+++ b/src/com/dougkeen/bart/model/Constants.java
@@ -14,6 +14,7 @@ public class Constants {
.parse("content://" + AUTHORITY + "/route");
public static final String MAP_URL = "http://m.bart.gov/images/global/system-map29.gif";
- public static final String TAG = "BartRunner";
+ public static final String TAG = "com.dougkeen.BartRunner";
public static final String API_KEY = "5LD9-IAYI-TRAT-MHHW";
+ public static final String ACTION_ALARM = "com.dougkeen.action.ALARM";
}
diff --git a/src/com/dougkeen/bart/model/Departure.java b/src/com/dougkeen/bart/model/Departure.java
index f26a696..0f79e4c 100644
--- a/src/com/dougkeen/bart/model/Departure.java
+++ b/src/com/dougkeen/bart/model/Departure.java
@@ -7,6 +7,7 @@ import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.format.DateFormat;
+import android.util.Log;
public class Departure implements Parcelable, Comparable {
private static final int MINIMUM_MERGE_OVERLAP_MILLIS = 10000;
@@ -206,11 +207,19 @@ public class Departure implements Parcelable, Comparable {
}
public int getMeanSecondsLeft() {
- return (int) ((getMeanEstimate() - System.currentTimeMillis()) / 1000);
+ return (int) getMeanSecondsLeft(getMinEstimate(), getMaxEstimate());
+ }
+
+ public int getMeanSecondsLeft(long min, long max) {
+ return (int) ((getMeanEstimate(min, max) - System.currentTimeMillis()) / 1000);
}
public long getMeanEstimate() {
- return (getMinEstimate() + getMaxEstimate()) / 2;
+ return getMeanEstimate(getMinEstimate(), getMaxEstimate());
+ }
+
+ public long getMeanEstimate(long min, long max) {
+ return (min + max) / 2;
}
public long getArrivalTimeOverride() {
@@ -280,15 +289,25 @@ public class Departure implements Parcelable, Comparable {
public void mergeEstimate(Departure departure) {
if (departure.hasDeparted() && origin.longStationLinger
&& getMinEstimate() > 0 && !beganAsDeparted) {
- // This is probably not a true departure, but an indication that
- // the train is in the station. Don't update the estimates.
+ /*
+ * This is probably not a true departure, but an indication that the
+ * train is in the station. Don't update the estimates.
+ */
return;
}
+ boolean wasDeparted = hasDeparted();
+ if (!hasAnyArrivalEstimate() && departure.hasAnyArrivalEstimate()) {
+ setArrivalTimeOverride(departure.getArrivalTimeOverride());
+ setEstimatedTripTime(departure.getEstimatedTripTime());
+ }
+
if ((getMaxEstimate() - departure.getMinEstimate()) < MINIMUM_MERGE_OVERLAP_MILLIS
|| departure.getMaxEstimate() - getMinEstimate() < MINIMUM_MERGE_OVERLAP_MILLIS) {
- // The estimate must have changed... just use the latest incoming
- // values
+ /*
+ * The estimate must have changed... just use the latest incoming
+ * values
+ */
setMinEstimate(departure.getMinEstimate());
setMaxEstimate(departure.getMaxEstimate());
return;
@@ -298,15 +317,23 @@ public class Departure implements Parcelable, Comparable {
departure.getMinEstimate());
final long newMax = Math.min(getMaxEstimate(),
departure.getMaxEstimate());
+
+ /*
+ * If the new departure would mark this as departed, and we have < 1
+ * minute left on a fairly accurate local estimate, ignore the incoming
+ * departure
+ */
+ if (!wasDeparted && getMeanSecondsLeft(newMin, newMax) < 0
+ && getMeanSecondsLeft() < 60 && getUncertaintySeconds() < 30) {
+ Log.d(Constants.TAG,
+ "Skipping estimate merge, since it would make this departure show as 'departed' prematurely");
+ return;
+ }
+
if (newMax > newMin) { // We can never have 0 or negative uncertainty
setMinEstimate(newMin);
setMaxEstimate(newMax);
}
-
- if (!hasAnyArrivalEstimate() && departure.hasAnyArrivalEstimate()) {
- setArrivalTimeOverride(departure.getArrivalTimeOverride());
- setEstimatedTripTime(departure.getEstimatedTripTime());
- }
}
public int compareTo(Departure another) {
@@ -435,6 +462,7 @@ public class Departure implements Parcelable, Comparable {
}
public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(origin.abbreviation);
dest.writeString(destination.abbreviation);
dest.writeString(destinationColor);
dest.writeString(platform);
@@ -445,9 +473,15 @@ public class Departure implements Parcelable, Comparable {
dest.writeInt(minutes);
dest.writeLong(minEstimate);
dest.writeLong(maxEstimate);
+ dest.writeLong(arrivalTimeOverride);
+ dest.writeInt(estimatedTripTime);
+ dest.writeInt(line.ordinal());
+ dest.writeBooleanArray(new boolean[] { beganAsDeparted, bikeAllowed,
+ requiresTransfer, transferScheduled });
}
private void readFromParcel(Parcel in) {
+ origin = Station.getByAbbreviation(in.readString());
destination = Station.getByAbbreviation(in.readString());
destinationColor = in.readString();
platform = in.readString();
@@ -458,6 +492,15 @@ public class Departure implements Parcelable, Comparable {
minutes = in.readInt();
minEstimate = in.readLong();
maxEstimate = in.readLong();
+ arrivalTimeOverride = in.readLong();
+ estimatedTripTime = in.readInt();
+ line = Line.values()[in.readInt()];
+ boolean[] bools = new boolean[4];
+ in.readBooleanArray(bools);
+ beganAsDeparted = bools[0];
+ bikeAllowed = bools[1];
+ requiresTransfer = bools[2];
+ transferScheduled = bools[3];
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
diff --git a/src/com/dougkeen/bart/model/Station.java b/src/com/dougkeen/bart/model/Station.java
index 9874fe7..3368d5e 100644
--- a/src/com/dougkeen/bart/model/Station.java
+++ b/src/com/dougkeen/bart/model/Station.java
@@ -64,7 +64,7 @@ public enum Station {
public final boolean longStationLinger;
public final int departureEqualityTolerance;
- public final static int DEFAULT_DEPARTURE_EQUALITY_TOLERANCE = 59999;
+ public final static int DEFAULT_DEPARTURE_EQUALITY_TOLERANCE = 119999;
private Station(String abbreviation, String name, boolean invertDirection,
boolean endOfLine) {
diff --git a/src/com/dougkeen/bart/model/StationPair.java b/src/com/dougkeen/bart/model/StationPair.java
index 31ed9f0..01e0180 100644
--- a/src/com/dougkeen/bart/model/StationPair.java
+++ b/src/com/dougkeen/bart/model/StationPair.java
@@ -1,12 +1,20 @@
package com.dougkeen.bart.model;
-public class StationPair {
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class StationPair implements Parcelable {
public StationPair(Station origin, Station destination) {
super();
this.origin = origin;
this.destination = destination;
}
+ public StationPair(Parcel in) {
+ readFromParcel(in);
+ }
+
private Station origin;
private Station destination;
@@ -23,6 +31,16 @@ public class StationPair {
|| (origin.equals(station2) && destination.equals(station1));
}
+ public Uri getUri() {
+ if (getOrigin() != null && getDestination() != null) {
+ return Constants.ARBITRARY_ROUTE_CONTENT_URI_ROOT.buildUpon()
+ .appendPath(getOrigin().abbreviation)
+ .appendPath(getDestination().abbreviation).build();
+ } else {
+ return null;
+ }
+ }
+
@Override
public int hashCode() {
final int prime = 31;
@@ -49,4 +67,28 @@ public class StationPair {
return true;
}
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(origin.abbreviation);
+ dest.writeString(destination.abbreviation);
+ }
+
+ private void readFromParcel(Parcel in) {
+ origin = Station.getByAbbreviation(in.readString());
+ destination = Station.getByAbbreviation(in.readString());
+ }
+
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public StationPair createFromParcel(Parcel in) {
+ return new StationPair(in);
+ }
+
+ public StationPair[] newArray(int size) {
+ return new StationPair[size];
+ }
+ };
}
\ No newline at end of file