Changed arrivals to departures.
Added handling for WHITE and SPCL --HG-- rename : res/layout/arrival_listing.xml => res/layout/departure_listing.xml rename : src/com/dougkeen/bart/ArrivalArrayAdapter.java => src/com/dougkeen/bart/DepartureArrayAdapter.java rename : src/com/dougkeen/bart/GetRealTimeArrivalsTask.java => src/com/dougkeen/bart/GetRealTimeDeparturesTask.java rename : src/com/dougkeen/bart/ViewArrivalsActivity.java => src/com/dougkeen/bart/ViewDeparturesActivity.java rename : src/com/dougkeen/bart/data/Arrival.java => src/com/dougkeen/bart/data/Departure.java rename : src/com/dougkeen/bart/data/RealTimeArrivals.java => src/com/dougkeen/bart/data/RealTimeDepartures.java
This commit is contained in:
parent
67e6f5347d
commit
ca8f07b30a
@ -35,7 +35,7 @@
|
||||
<data android:mimeType="vnd.android.cursor.dir/com.dougkeen.bart.favorite" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".ViewArrivalsActivity"
|
||||
<activity android:name="ViewDeparturesActivity"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
@ -8,20 +8,20 @@
|
||||
android:layout_width="fill_parent" android:layout_height="wrap_content"
|
||||
android:layout_toRightOf="@id/destinationColorBar"
|
||||
android:layout_alignParentTop="true">
|
||||
<TextView android:id="@+id/destinationText" style="@style/ArrivalDestinationText"
|
||||
<TextView android:id="@+id/destinationText" style="@style/DepartureDestinationText"
|
||||
android:layout_weight="1" android:singleLine="true"
|
||||
android:ellipsize="marquee" />
|
||||
<ImageView android:id="@+id/bikeIcon" android:src="@drawable/bike"
|
||||
style="@style/BikeIcon" />
|
||||
<TextView android:id="@+id/countdown" style="@style/ArrivalCountdownText"
|
||||
<TextView android:id="@+id/countdown" style="@style/DepartureCountdownText"
|
||||
android:gravity="right" />
|
||||
</LinearLayout>
|
||||
<ImageView android:id="@+id/xferIcon" android:src="@drawable/xfer"
|
||||
android:layout_below="@id/topRow" android:layout_alignParentRight="true"
|
||||
style="@style/XferIcon" />
|
||||
<TextView android:id="@+id/trainLengthText" style="@style/ArrivalTrainLengthText"
|
||||
<TextView android:id="@+id/trainLengthText" style="@style/DepartureTrainLengthText"
|
||||
android:layout_toRightOf="@id/destinationColorBar"
|
||||
android:layout_below="@id/topRow" />
|
||||
<TextView android:layout_alignParentRight="true" android:id="@+id/uncertainty"
|
||||
android:layout_below="@id/topRow" style="@style/ArrivalUncertaintyText" />
|
||||
android:layout_below="@id/topRow" style="@style/DepartureUncertaintyText" />
|
||||
</RelativeLayout>
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:title="@string/view_arrivals" android:id="@+id/view"></item>
|
||||
<item android:title="@string/view_departures" android:id="@+id/view"></item>
|
||||
<item android:title="@string/delete" android:id="@+id/delete"></item>
|
||||
</menu>
|
||||
|
@ -2,7 +2,8 @@
|
||||
<resources>
|
||||
<string name="app_name">BART Catcher</string>
|
||||
<string name="favorite_routes">Favorite Routes</string>
|
||||
<string name="empty_favorites_list_message">Press the menu button and select \"Add route\" to add
|
||||
<string name="empty_favorites_list_message">Press the menu button and select \"Add route\" to
|
||||
add
|
||||
a route</string>
|
||||
<string name="add_route">Add a route</string>
|
||||
<string name="origin">Origin</string>
|
||||
@ -12,15 +13,17 @@
|
||||
different</string>
|
||||
<string name="error_null_destination">You must select a destination station</string>
|
||||
<string name="error_null_origin">You must select an origin station</string>
|
||||
<string name="arrival_wait_message">Please wait while real time arrival data is
|
||||
<string name="departure_wait_message">Please wait while real time departure data is
|
||||
loaded...</string>
|
||||
<string name="no_data_message">No arrival data is currently available for this
|
||||
route</string>
|
||||
<string name="no_data_message">No departure data is currently available for this
|
||||
route. Note that there may be service advisories posted at
|
||||
http://m.bart.gov/schedules/advisories/</string>
|
||||
<string name="view">View</string>
|
||||
<string name="view_arrivals">View arrivals</string>
|
||||
<string name="view_departures">View departures</string>
|
||||
<string name="delete">Delete</string>
|
||||
<string name="yes">Yes</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="view_on_bart_site">View details on BART site</string>
|
||||
<string name="could_not_connect">Could not connect to BART services. Please try again later.</string>
|
||||
<string name="could_not_connect">Could not connect to BART services. Please try
|
||||
again later.</string>
|
||||
</resources>
|
||||
|
@ -18,7 +18,7 @@
|
||||
<item name="android:singleLine">true</item>
|
||||
</style>
|
||||
|
||||
<style name="ArrivalDestinationText">
|
||||
<style name="DepartureDestinationText">
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:textSize">22dp</item>
|
||||
@ -27,7 +27,7 @@
|
||||
<item name="android:layout_marginLeft">3dp</item>
|
||||
</style>
|
||||
|
||||
<style name="ArrivalTrainLengthText">
|
||||
<style name="DepartureTrainLengthText">
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:textSize">18dp</item>
|
||||
@ -35,14 +35,14 @@
|
||||
<item name="android:layout_marginLeft">3dp</item>
|
||||
</style>
|
||||
|
||||
<style name="ArrivalCountdownText">
|
||||
<style name="DepartureCountdownText">
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:textSize">20dp</item>
|
||||
<item name="android:singleLine">true</item>
|
||||
<item name="android:width">90dp</item>
|
||||
</style>
|
||||
<style name="ArrivalUncertaintyText">
|
||||
<style name="DepartureUncertaintyText">
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:textSize">16dp</item>
|
||||
|
@ -13,36 +13,36 @@ import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.dougkeen.bart.data.Arrival;
|
||||
import com.dougkeen.bart.data.Departure;
|
||||
|
||||
public class ArrivalArrayAdapter extends ArrayAdapter<Arrival> {
|
||||
public class DepartureArrayAdapter extends ArrayAdapter<Departure> {
|
||||
|
||||
public ArrivalArrayAdapter(Context context, int textViewResourceId,
|
||||
Arrival[] objects) {
|
||||
public DepartureArrayAdapter(Context context, int textViewResourceId,
|
||||
Departure[] objects) {
|
||||
super(context, textViewResourceId, objects);
|
||||
}
|
||||
|
||||
public ArrivalArrayAdapter(Context context, int resource,
|
||||
int textViewResourceId, Arrival[] objects) {
|
||||
public DepartureArrayAdapter(Context context, int resource,
|
||||
int textViewResourceId, Departure[] objects) {
|
||||
super(context, resource, textViewResourceId, objects);
|
||||
}
|
||||
|
||||
public ArrivalArrayAdapter(Context context, int resource,
|
||||
int textViewResourceId, List<Arrival> objects) {
|
||||
public DepartureArrayAdapter(Context context, int resource,
|
||||
int textViewResourceId, List<Departure> objects) {
|
||||
super(context, resource, textViewResourceId, objects);
|
||||
}
|
||||
|
||||
public ArrivalArrayAdapter(Context context, int resource,
|
||||
public DepartureArrayAdapter(Context context, int resource,
|
||||
int textViewResourceId) {
|
||||
super(context, resource, textViewResourceId);
|
||||
}
|
||||
|
||||
public ArrivalArrayAdapter(Context context, int textViewResourceId,
|
||||
List<Arrival> objects) {
|
||||
public DepartureArrayAdapter(Context context, int textViewResourceId,
|
||||
List<Departure> objects) {
|
||||
super(context, textViewResourceId, objects);
|
||||
}
|
||||
|
||||
public ArrivalArrayAdapter(Context context, int textViewResourceId) {
|
||||
public DepartureArrayAdapter(Context context, int textViewResourceId) {
|
||||
super(context, textViewResourceId);
|
||||
}
|
||||
|
||||
@ -53,30 +53,30 @@ public class ArrivalArrayAdapter extends ArrayAdapter<Arrival> {
|
||||
view = convertView;
|
||||
} else {
|
||||
LayoutInflater inflater = LayoutInflater.from(getContext());
|
||||
view = inflater.inflate(R.layout.arrival_listing, parent, false);
|
||||
view = inflater.inflate(R.layout.departure_listing, parent, false);
|
||||
}
|
||||
|
||||
Arrival arrival = getItem(position);
|
||||
((TextView) view.findViewById(R.id.destinationText)).setText(arrival
|
||||
Departure departure = getItem(position);
|
||||
((TextView) view.findViewById(R.id.destinationText)).setText(departure
|
||||
.getDestination().toString());
|
||||
((TextView) view.findViewById(R.id.trainLengthText)).setText(arrival
|
||||
((TextView) view.findViewById(R.id.trainLengthText)).setText(departure
|
||||
.getTrainLengthText());
|
||||
ImageView colorBar = (ImageView) view
|
||||
.findViewById(R.id.destinationColorBar);
|
||||
((GradientDrawable) colorBar.getDrawable()).setColor(Color
|
||||
.parseColor(arrival.getDestinationColor()));
|
||||
((TextView) view.findViewById(R.id.countdown)).setText(arrival
|
||||
.parseColor(departure.getDestinationColor()));
|
||||
((TextView) view.findViewById(R.id.countdown)).setText(departure
|
||||
.getCountdownText());
|
||||
((TextView) view.findViewById(R.id.uncertainty)).setText(arrival
|
||||
((TextView) view.findViewById(R.id.uncertainty)).setText(departure
|
||||
.getUncertaintyText());
|
||||
if (arrival.isBikeAllowed()) {
|
||||
if (departure.isBikeAllowed()) {
|
||||
((ImageView) view.findViewById(R.id.bikeIcon))
|
||||
.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
((ImageView) view.findViewById(R.id.bikeIcon))
|
||||
.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
if (arrival.getRequiresTransfer()) {
|
||||
if (departure.getRequiresTransfer()) {
|
||||
((ImageView) view.findViewById(R.id.xferIcon))
|
||||
.setVisibility(View.VISIBLE);
|
||||
} else {
|
@ -10,32 +10,34 @@ import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.dougkeen.bart.data.Arrival;
|
||||
import com.dougkeen.bart.data.RealTimeArrivals;
|
||||
import com.dougkeen.bart.data.Departure;
|
||||
import com.dougkeen.bart.data.RealTimeDepartures;
|
||||
|
||||
public class EtdContentHandler extends DefaultHandler {
|
||||
public EtdContentHandler(Station origin, Station destination,
|
||||
List<Route> routes) {
|
||||
super();
|
||||
realTimeArrivals = new RealTimeArrivals(origin, destination, routes);
|
||||
realTimeDepartures = new RealTimeDepartures(origin, destination, routes);
|
||||
}
|
||||
|
||||
private final static List<String> TAGS = Arrays.asList("date", "time",
|
||||
"abbreviation", "minutes", "platform", "direction", "length",
|
||||
"color", "hexcolor", "bikeflag");
|
||||
|
||||
private RealTimeArrivals realTimeArrivals;
|
||||
private RealTimeDepartures realTimeDepartures;
|
||||
|
||||
public RealTimeArrivals getRealTimeArrivals() {
|
||||
return realTimeArrivals;
|
||||
public RealTimeDepartures getRealTimeDepartures() {
|
||||
return realTimeDepartures;
|
||||
}
|
||||
|
||||
private String date;
|
||||
private String currentDestination;
|
||||
private String currentValue;
|
||||
private Arrival currentArrival;
|
||||
private Departure currentDeparture;
|
||||
private boolean isParsingTag;
|
||||
|
||||
private boolean getDestinationFromLine;
|
||||
|
||||
@Override
|
||||
public void characters(char[] ch, int start, int length)
|
||||
throws SAXException {
|
||||
@ -51,11 +53,15 @@ public class EtdContentHandler extends DefaultHandler {
|
||||
isParsingTag = true;
|
||||
}
|
||||
if (localName.equals("estimate")) {
|
||||
currentArrival = new Arrival();
|
||||
currentArrival.setDestination(Station
|
||||
currentDeparture = new Departure();
|
||||
if (currentDestination.equalsIgnoreCase("SPCL")) {
|
||||
getDestinationFromLine = true;
|
||||
} else {
|
||||
currentDeparture.setDestination(Station
|
||||
.getByAbbreviation(currentDestination));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String qName)
|
||||
@ -63,40 +69,60 @@ public class EtdContentHandler extends DefaultHandler {
|
||||
if (localName.equals("date")) {
|
||||
date = currentValue;
|
||||
} else if (localName.equals("time")) {
|
||||
realTimeArrivals.setTime(Date.parse(date + " " + currentValue));
|
||||
realTimeDepartures.setTime(Date.parse(date + " " + currentValue));
|
||||
} else if (localName.equals("abbreviation")) {
|
||||
currentDestination = currentValue;
|
||||
} else if (localName.equals("minutes")) {
|
||||
if (currentValue.equalsIgnoreCase("arrived")) {
|
||||
currentArrival.setMinutes(0);
|
||||
currentDeparture.setMinutes(0);
|
||||
} else {
|
||||
currentArrival.setMinutes(Integer.parseInt(currentValue));
|
||||
currentDeparture.setMinutes(Integer.parseInt(currentValue));
|
||||
}
|
||||
} else if (localName.equals("platform")) {
|
||||
currentArrival.setPlatform(currentValue);
|
||||
currentDeparture.setPlatform(currentValue);
|
||||
} else if (localName.equals("direction")) {
|
||||
currentArrival.setDirection(currentValue);
|
||||
currentDeparture.setDirection(currentValue);
|
||||
} else if (localName.equals("length")) {
|
||||
currentArrival.setTrainLength(Integer.parseInt(currentValue));
|
||||
currentDeparture.setTrainLength(Integer.parseInt(currentValue));
|
||||
} else if (localName.equals("color")) {
|
||||
try {
|
||||
currentArrival.setLine(Line.valueOf(currentValue));
|
||||
if (getDestinationFromLine) {
|
||||
final Line line = Line.valueOf(currentValue);
|
||||
currentDeparture.setLine(line);
|
||||
currentDeparture.setDestination(line
|
||||
.getUsualTerminusForDirectionAndOrigin(
|
||||
currentDeparture.getDirection(),
|
||||
realTimeDepartures.getOrigin()));
|
||||
} else if (currentValue.equalsIgnoreCase("WHITE")) {
|
||||
for (Line line : Line.values()) {
|
||||
if (line.stations.indexOf(currentDeparture
|
||||
.getDestination()) >= 0
|
||||
&& line.stations.indexOf(realTimeDepartures
|
||||
.getDestination()) >= 0) {
|
||||
currentDeparture.setLine(line);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
currentDeparture.setLine(Line.valueOf(currentValue));
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.w("BartApp", "There is no line called '" + currentValue
|
||||
Log.w(Constants.TAG, "There is no line called '" + currentValue
|
||||
+ "'");
|
||||
}
|
||||
} else if (localName.equals("hexcolor")) {
|
||||
currentArrival.setDestinationColor("#ff"
|
||||
currentDeparture.setDestinationColor("#ff"
|
||||
+ currentValue.substring(1));
|
||||
} else if (localName.equals("bikeflag")) {
|
||||
currentArrival.setBikeAllowed(currentValue.equalsIgnoreCase("1"));
|
||||
currentDeparture.setBikeAllowed(currentValue.equalsIgnoreCase("1"));
|
||||
} else if (localName.equals("estimate")) {
|
||||
realTimeArrivals.addArrival(currentArrival);
|
||||
currentArrival = null;
|
||||
realTimeDepartures.addDeparture(currentDeparture);
|
||||
currentDeparture = null;
|
||||
getDestinationFromLine = false;
|
||||
} else if (localName.equals("etd")) {
|
||||
currentDestination = null;
|
||||
} else if (localName.equals("station")) {
|
||||
realTimeArrivals.sortArrivals();
|
||||
realTimeDepartures.sortDepartures();
|
||||
}
|
||||
isParsingTag = false;
|
||||
currentValue = null;
|
||||
|
@ -9,13 +9,13 @@ import java.util.List;
|
||||
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.dougkeen.bart.data.RealTimeArrivals;
|
||||
import com.dougkeen.bart.data.RealTimeDepartures;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Xml;
|
||||
|
||||
public abstract class GetRealTimeArrivalsTask extends
|
||||
AsyncTask<GetRealTimeArrivalsTask.Params, Integer, RealTimeArrivals> {
|
||||
public abstract class GetRealTimeDeparturesTask extends
|
||||
AsyncTask<GetRealTimeDeparturesTask.Params, Integer, RealTimeDepartures> {
|
||||
|
||||
private static final int CONNECTION_TIMEOUT_MILLIS = 10000;
|
||||
private final static String API_KEY = "5LD9-IAYI-TRAT-MHHW";
|
||||
@ -28,20 +28,20 @@ public abstract class GetRealTimeArrivalsTask extends
|
||||
private List<Route> mRoutes;
|
||||
|
||||
@Override
|
||||
protected RealTimeArrivals doInBackground(Params... paramsArray) {
|
||||
protected RealTimeDepartures doInBackground(Params... paramsArray) {
|
||||
// Always expect one param
|
||||
Params params = paramsArray[0];
|
||||
|
||||
mRoutes = params.origin.getRoutesForDestination(params.destination);
|
||||
|
||||
if (!isCancelled()) {
|
||||
return getArrivalsFromNetwork(params, 0);
|
||||
return getDeparturesFromNetwork(params, 0);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private RealTimeArrivals getArrivalsFromNetwork(Params params,
|
||||
private RealTimeDepartures getDeparturesFromNetwork(Params params,
|
||||
int attemptNumber) {
|
||||
try {
|
||||
URL sourceUrl = new URL(String.format(API_URL,
|
||||
@ -57,9 +57,9 @@ public abstract class GetRealTimeArrivalsTask extends
|
||||
Xml.parse(connection.getInputStream(),
|
||||
Xml.findEncodingByName("UTF-8"),
|
||||
handler);
|
||||
final RealTimeArrivals realTimeArrivals = handler
|
||||
.getRealTimeArrivals();
|
||||
return realTimeArrivals;
|
||||
final RealTimeDepartures realTimeDepartures = handler
|
||||
.getRealTimeDepartures();
|
||||
return realTimeDepartures;
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
@ -71,7 +71,7 @@ public abstract class GetRealTimeArrivalsTask extends
|
||||
} catch (InterruptedException interrupt) {
|
||||
// Ignore... just go on to next attempt
|
||||
}
|
||||
return getArrivalsFromNetwork(params, attemptNumber + 1);
|
||||
return getDeparturesFromNetwork(params, attemptNumber + 1);
|
||||
} else {
|
||||
mIOException = e;
|
||||
return null;
|
||||
@ -101,7 +101,7 @@ public abstract class GetRealTimeArrivalsTask extends
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(RealTimeArrivals result) {
|
||||
protected void onPostExecute(RealTimeDepartures result) {
|
||||
if (result != null) {
|
||||
onResult(result);
|
||||
} else {
|
||||
@ -109,7 +109,7 @@ public abstract class GetRealTimeArrivalsTask extends
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void onResult(RealTimeArrivals result);
|
||||
public abstract void onResult(RealTimeDepartures result);
|
||||
|
||||
public abstract void onNetworkError(IOException e);
|
||||
}
|
@ -92,4 +92,22 @@ public enum Line {
|
||||
|
||||
return destinations;
|
||||
}
|
||||
|
||||
public Station getUsualTerminusForDirectionAndOrigin(String direction,
|
||||
Station origin) {
|
||||
boolean isNorth = false;
|
||||
if (direction.toLowerCase().startsWith("s") && directionMayInvert
|
||||
&& origin.invertDirection) {
|
||||
isNorth = true;
|
||||
} else if (direction.toLowerCase().startsWith("n")
|
||||
&& !(directionMayInvert && origin.invertDirection)) {
|
||||
isNorth = true;
|
||||
}
|
||||
|
||||
if (isNorth) {
|
||||
return stations.get(stations.size() - 1);
|
||||
} else {
|
||||
return stations.get(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,8 @@ public enum Station {
|
||||
UCTY("ucty", "Union City", true, "bayf"),
|
||||
WCRK("wcrk", "Walnut Creek", false, "mcar"),
|
||||
WDUB("wdub", "West Dublin/Pleasanton", false, "bayf"),
|
||||
WOAK("woak", "West Oakland", false);
|
||||
WOAK("woak", "West Oakland", false),
|
||||
SPCL("spcl", "Special", false);
|
||||
|
||||
public final String abbreviation;
|
||||
public final String name;
|
||||
|
@ -13,6 +13,7 @@ import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.os.PowerManager;
|
||||
import android.text.format.DateFormat;
|
||||
import android.text.util.Linkify;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
@ -21,12 +22,12 @@ import android.widget.ArrayAdapter;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.dougkeen.bart.GetRealTimeArrivalsTask.Params;
|
||||
import com.dougkeen.bart.data.Arrival;
|
||||
import com.dougkeen.bart.data.RealTimeArrivals;
|
||||
import com.dougkeen.bart.GetRealTimeDeparturesTask.Params;
|
||||
import com.dougkeen.bart.data.Departure;
|
||||
import com.dougkeen.bart.data.RealTimeDepartures;
|
||||
import com.dougkeen.bart.data.RoutesColumns;
|
||||
|
||||
public class ViewArrivalsActivity extends ListActivity {
|
||||
public class ViewDeparturesActivity extends ListActivity {
|
||||
|
||||
private static final int UNCERTAINTY_THRESHOLD = 17;
|
||||
|
||||
@ -35,11 +36,11 @@ public class ViewArrivalsActivity extends ListActivity {
|
||||
private Station mOrigin;
|
||||
private Station mDestination;
|
||||
|
||||
private ArrayAdapter<Arrival> mArrivalsAdapter;
|
||||
private ArrayAdapter<Departure> mDeparturesAdapter;
|
||||
|
||||
private TextView mListTitleView;
|
||||
|
||||
private AsyncTask<Params, Integer, RealTimeArrivals> mGetArrivalsTask;
|
||||
private AsyncTask<Params, Integer, RealTimeDepartures> mGetDeparturesTask;
|
||||
|
||||
private boolean mIsAutoUpdating = false;
|
||||
|
||||
@ -52,7 +53,7 @@ public class ViewArrivalsActivity extends ListActivity {
|
||||
|
||||
private PowerManager.WakeLock mWakeLock;
|
||||
|
||||
private boolean mFetchArrivalsOnNextFocus;
|
||||
private boolean mFetchDeparturesOnNextFocus;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@ -77,31 +78,32 @@ public class ViewArrivalsActivity extends ListActivity {
|
||||
mOrigin = Station.getByAbbreviation(cursor.getString(0));
|
||||
mDestination = Station.getByAbbreviation(cursor.getString(1));
|
||||
|
||||
String header = mOrigin.name + " to " + mDestination.name;
|
||||
String header = "Departures:\n" + mOrigin.name + " to "
|
||||
+ mDestination.name;
|
||||
|
||||
mListTitleView = (TextView) findViewById(R.id.listTitle);
|
||||
mListTitleView.setText(header);
|
||||
((TextView) findViewById(android.R.id.empty))
|
||||
.setText(R.string.arrival_wait_message);
|
||||
.setText(R.string.departure_wait_message);
|
||||
|
||||
mArrivalsAdapter = new ArrivalArrayAdapter(this,
|
||||
R.layout.arrival_listing);
|
||||
mDeparturesAdapter = new DepartureArrayAdapter(this,
|
||||
R.layout.departure_listing);
|
||||
if (savedInstanceState != null
|
||||
&& savedInstanceState.containsKey("arrivals")) {
|
||||
for (Parcelable arrival : savedInstanceState
|
||||
.getParcelableArray("arrivals")) {
|
||||
mArrivalsAdapter.add((Arrival) arrival);
|
||||
&& savedInstanceState.containsKey("departures")) {
|
||||
for (Parcelable departure : savedInstanceState
|
||||
.getParcelableArray("departures")) {
|
||||
mDeparturesAdapter.add((Departure) departure);
|
||||
}
|
||||
}
|
||||
setListAdapter(mArrivalsAdapter);
|
||||
setListAdapter(mDeparturesAdapter);
|
||||
|
||||
mFetchArrivalsOnNextFocus = true;
|
||||
mFetchDeparturesOnNextFocus = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
if (mGetArrivalsTask != null) {
|
||||
mGetArrivalsTask.cancel(true);
|
||||
if (mGetDeparturesTask != null) {
|
||||
mGetDeparturesTask.cancel(true);
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
@ -109,26 +111,28 @@ public class ViewArrivalsActivity extends ListActivity {
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
Arrival[] arrivals = new Arrival[mArrivalsAdapter.getCount()];
|
||||
for (int i = mArrivalsAdapter.getCount() - 1; i >= 0; i--) {
|
||||
arrivals[i] = mArrivalsAdapter.getItem(i);
|
||||
Departure[] departures = new Departure[mDeparturesAdapter.getCount()];
|
||||
for (int i = mDeparturesAdapter.getCount() - 1; i >= 0; i--) {
|
||||
departures[i] = mDeparturesAdapter.getItem(i);
|
||||
}
|
||||
outState.putParcelableArray("arrivals", arrivals);
|
||||
outState.putParcelableArray("departures", departures);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
if (hasFocus) {
|
||||
if (mFetchArrivalsOnNextFocus) {
|
||||
fetchLatestArrivals();
|
||||
mFetchArrivalsOnNextFocus = false;
|
||||
if (mFetchDeparturesOnNextFocus) {
|
||||
fetchLatestDepartures();
|
||||
mFetchDeparturesOnNextFocus = false;
|
||||
}
|
||||
PowerManager powerManaer = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
||||
mWakeLock = powerManaer.newWakeLock(
|
||||
PowerManager.SCREEN_DIM_WAKE_LOCK, "ViewArrivalsActivity");
|
||||
mWakeLock = powerManaer
|
||||
.newWakeLock(
|
||||
PowerManager.SCREEN_DIM_WAKE_LOCK,
|
||||
"ViewDeparturesActivity");
|
||||
mWakeLock.acquire();
|
||||
if (mArrivalsAdapter != null && !mArrivalsAdapter.isEmpty()) {
|
||||
if (mDeparturesAdapter != null && !mDeparturesAdapter.isEmpty()) {
|
||||
mIsAutoUpdating = true;
|
||||
}
|
||||
runAutoUpdate();
|
||||
@ -137,28 +141,28 @@ public class ViewArrivalsActivity extends ListActivity {
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchLatestArrivals() {
|
||||
private void fetchLatestDepartures() {
|
||||
if (!hasWindowFocus())
|
||||
return;
|
||||
if (mGetArrivalsTask != null
|
||||
&& mGetArrivalsTask.getStatus()
|
||||
if (mGetDeparturesTask != null
|
||||
&& mGetDeparturesTask.getStatus()
|
||||
.equals(AsyncTask.Status.RUNNING)) {
|
||||
// Don't overlap fetches
|
||||
return;
|
||||
}
|
||||
|
||||
mGetArrivalsTask = new GetRealTimeArrivalsTask() {
|
||||
mGetDeparturesTask = new GetRealTimeDeparturesTask() {
|
||||
@Override
|
||||
public void onResult(RealTimeArrivals result) {
|
||||
public void onResult(RealTimeDepartures result) {
|
||||
Log.i(Constants.TAG, "Processing data from server");
|
||||
processLatestArrivals(result);
|
||||
processLatestDepartures(result);
|
||||
Log.i(Constants.TAG, "Done processing data from server");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNetworkError(IOException e) {
|
||||
Log.w(Constants.TAG, e.getMessage());
|
||||
Toast.makeText(ViewArrivalsActivity.this,
|
||||
Toast.makeText(ViewDeparturesActivity.this,
|
||||
R.string.could_not_connect,
|
||||
Toast.LENGTH_LONG).show();
|
||||
((TextView) findViewById(android.R.id.empty))
|
||||
@ -167,80 +171,96 @@ public class ViewArrivalsActivity extends ListActivity {
|
||||
}
|
||||
};
|
||||
Log.i(Constants.TAG, "Fetching data from server");
|
||||
mGetArrivalsTask.execute(new GetRealTimeArrivalsTask.Params(mOrigin,
|
||||
mGetDeparturesTask.execute(new GetRealTimeDeparturesTask.Params(
|
||||
mOrigin,
|
||||
mDestination));
|
||||
}
|
||||
|
||||
protected void processLatestArrivals(RealTimeArrivals result) {
|
||||
if (result.getArrivals().isEmpty()) {
|
||||
((TextView) findViewById(android.R.id.empty))
|
||||
.setText(R.string.no_data_message);
|
||||
protected void processLatestDepartures(RealTimeDepartures result) {
|
||||
if (result.getDepartures().isEmpty()) {
|
||||
final TextView textView = (TextView) findViewById(android.R.id.empty);
|
||||
textView.setText(R.string.no_data_message);
|
||||
Linkify.addLinks(textView, Linkify.WEB_URLS);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean needsBetterAccuracy = false;
|
||||
Arrival firstArrival = null;
|
||||
final List<Arrival> arrivals = result.getArrivals();
|
||||
if (mArrivalsAdapter.getCount() > 0) {
|
||||
Departure firstDeparture = null;
|
||||
final List<Departure> departures = result.getDepartures();
|
||||
if (mDeparturesAdapter.getCount() > 0) {
|
||||
int adapterIndex = -1;
|
||||
for (Arrival arrival : arrivals) {
|
||||
for (Departure departure : departures) {
|
||||
adapterIndex++;
|
||||
Arrival existingArrival = null;
|
||||
if (adapterIndex < mArrivalsAdapter.getCount()) {
|
||||
existingArrival = mArrivalsAdapter.getItem(adapterIndex);
|
||||
Departure existingDeparture = null;
|
||||
if (adapterIndex < mDeparturesAdapter.getCount()) {
|
||||
existingDeparture = mDeparturesAdapter
|
||||
.getItem(adapterIndex);
|
||||
}
|
||||
while (existingArrival != null
|
||||
&& !arrival.equals(existingArrival)) {
|
||||
mArrivalsAdapter.remove(existingArrival);
|
||||
if (adapterIndex < mArrivalsAdapter.getCount()) {
|
||||
existingArrival = mArrivalsAdapter
|
||||
while (existingDeparture != null
|
||||
&& !departure.equals(existingDeparture)) {
|
||||
mDeparturesAdapter.remove(existingDeparture);
|
||||
if (adapterIndex < mDeparturesAdapter.getCount()) {
|
||||
existingDeparture = mDeparturesAdapter
|
||||
.getItem(adapterIndex);
|
||||
} else {
|
||||
existingArrival = null;
|
||||
existingDeparture = null;
|
||||
}
|
||||
}
|
||||
if (existingArrival != null) {
|
||||
existingArrival.mergeEstimate(arrival);
|
||||
if (existingDeparture != null) {
|
||||
existingDeparture.mergeEstimate(departure);
|
||||
} else {
|
||||
mArrivalsAdapter.add(arrival);
|
||||
existingArrival = arrival;
|
||||
mDeparturesAdapter.add(departure);
|
||||
existingDeparture = departure;
|
||||
}
|
||||
if (firstArrival == null) {
|
||||
firstArrival = existingArrival;
|
||||
if (firstDeparture == null) {
|
||||
firstDeparture = existingDeparture;
|
||||
}
|
||||
if (existingArrival.getUncertaintySeconds() > UNCERTAINTY_THRESHOLD) {
|
||||
if (existingDeparture.getUncertaintySeconds() > UNCERTAINTY_THRESHOLD) {
|
||||
needsBetterAccuracy = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (Arrival arrival : arrivals) {
|
||||
if (firstArrival == null) {
|
||||
firstArrival = arrival;
|
||||
for (Departure departure : departures) {
|
||||
if (firstDeparture == null) {
|
||||
firstDeparture = departure;
|
||||
}
|
||||
mArrivalsAdapter.add(arrival);
|
||||
mDeparturesAdapter.add(departure);
|
||||
}
|
||||
needsBetterAccuracy = true;
|
||||
}
|
||||
mArrivalsAdapter.notifyDataSetChanged();
|
||||
mDeparturesAdapter.notifyDataSetChanged();
|
||||
|
||||
if (hasWindowFocus() && firstArrival != null) {
|
||||
if (hasWindowFocus() && firstDeparture != null) {
|
||||
if (needsBetterAccuracy
|
||||
|| firstArrival.hasArrived()) {
|
||||
|| firstDeparture.hasDeparted()) {
|
||||
// Get more data in 20s
|
||||
mListTitleView.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fetchLatestArrivals();
|
||||
fetchLatestDepartures();
|
||||
}
|
||||
}, 20000);
|
||||
Log.i(Constants.TAG, "Scheduled another data fetch in 20s");
|
||||
} else {
|
||||
// Get more when next train arrives
|
||||
final int interval = firstArrival.getMinSecondsLeft() * 1000;
|
||||
// Get more 90 seconds before next train arrives, right when
|
||||
// next train arrives, or 3 minutes, whichever is sooner
|
||||
final long now = System.currentTimeMillis();
|
||||
final long nextDepartureMillis = firstDeparture
|
||||
.getMinSecondsLeft() * 1000L;
|
||||
final int intervalUntilNextDeparture = (int) (nextDepartureMillis - now);
|
||||
final int alternativeInterval = 3 * 60 * 1000;
|
||||
|
||||
int interval = intervalUntilNextDeparture;
|
||||
if (intervalUntilNextDeparture > 95000
|
||||
&& intervalUntilNextDeparture < alternativeInterval) {
|
||||
interval = interval - 90 * 1000;
|
||||
} else if (intervalUntilNextDeparture > alternativeInterval) {
|
||||
interval = alternativeInterval;
|
||||
}
|
||||
mListTitleView.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fetchLatestArrivals();
|
||||
fetchLatestDepartures();
|
||||
}
|
||||
}, interval);
|
||||
Log.i(Constants.TAG, "Scheduled another data fetch in "
|
||||
@ -256,8 +276,8 @@ public class ViewArrivalsActivity extends ListActivity {
|
||||
}
|
||||
|
||||
private void runAutoUpdate() {
|
||||
if (mIsAutoUpdating && mArrivalsAdapter != null) {
|
||||
mArrivalsAdapter.notifyDataSetChanged();
|
||||
if (mIsAutoUpdating && mDeparturesAdapter != null) {
|
||||
mDeparturesAdapter.notifyDataSetChanged();
|
||||
}
|
||||
if (hasWindowFocus()) {
|
||||
mListTitleView.postDelayed(AUTO_UPDATE_RUNNABLE, 1000);
|
||||
@ -285,7 +305,7 @@ public class ViewArrivalsActivity extends ListActivity {
|
||||
+ mOrigin.abbreviation
|
||||
+ "&dest="
|
||||
+ mDestination.abbreviation)));
|
||||
mFetchArrivalsOnNextFocus = true;
|
||||
mFetchDeparturesOnNextFocus = true;
|
||||
return true;
|
||||
} else {
|
||||
return super.onOptionsItemSelected(item);
|
@ -6,12 +6,14 @@ import android.os.Parcelable;
|
||||
import com.dougkeen.bart.Line;
|
||||
import com.dougkeen.bart.Station;
|
||||
|
||||
public class Arrival implements Parcelable, Comparable<Arrival> {
|
||||
public Arrival() {
|
||||
public class Departure implements Parcelable, Comparable<Departure> {
|
||||
private static final int MINIMUM_MERGE_OVERLAP_MILLIS = 10000;
|
||||
|
||||
public Departure() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Arrival(String destinationAbbr, String destinationColor,
|
||||
public Departure(String destinationAbbr, String destinationColor,
|
||||
String platform, String direction, boolean bikeAllowed,
|
||||
int trainLength, int minutes) {
|
||||
super();
|
||||
@ -24,7 +26,7 @@ public class Arrival implements Parcelable, Comparable<Arrival> {
|
||||
this.minutes = minutes;
|
||||
}
|
||||
|
||||
public Arrival(Parcel in) {
|
||||
public Departure(Parcel in) {
|
||||
readFromParcel(in);
|
||||
}
|
||||
|
||||
@ -163,20 +165,30 @@ public class Arrival implements Parcelable, Comparable<Arrival> {
|
||||
.currentTimeMillis()) / 1000);
|
||||
}
|
||||
|
||||
public boolean hasArrived() {
|
||||
public boolean hasDeparted() {
|
||||
return getMinutes() == 0 || getMeanSecondsLeft() < 0;
|
||||
}
|
||||
|
||||
public void calculateEstimates(long originalEstimateTime) {
|
||||
setMinEstimate(originalEstimateTime + (getMinutes() * 60 * 1000));
|
||||
setMaxEstimate(getMinEstimate() + (59 * 1000));
|
||||
setMinEstimate(originalEstimateTime + (getMinutes() * 60 * 1000)
|
||||
- (30000));
|
||||
setMaxEstimate(getMinEstimate() + 60000);
|
||||
}
|
||||
|
||||
public void mergeEstimate(Departure departure) {
|
||||
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
|
||||
setMinEstimate(departure.getMinEstimate());
|
||||
setMaxEstimate(departure.getMaxEstimate());
|
||||
return;
|
||||
}
|
||||
|
||||
public void mergeEstimate(Arrival arrival) {
|
||||
final long newMin = Math
|
||||
.max(getMinEstimate(), arrival.getMinEstimate());
|
||||
.max(getMinEstimate(), departure.getMinEstimate());
|
||||
final long newMax = Math
|
||||
.min(getMaxEstimate(), arrival.getMaxEstimate());
|
||||
.min(getMaxEstimate(), departure.getMaxEstimate());
|
||||
if (newMax > newMin) { // We can never have 0 or negative uncertainty
|
||||
setMinEstimate(newMin);
|
||||
setMaxEstimate(newMax);
|
||||
@ -184,7 +196,7 @@ public class Arrival implements Parcelable, Comparable<Arrival> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Arrival another) {
|
||||
public int compareTo(Departure another) {
|
||||
return (this.getMinutes() > another.getMinutes()) ? 1 : (
|
||||
(this.getMinutes() == another.getMinutes()) ? 0 : -1);
|
||||
}
|
||||
@ -197,7 +209,7 @@ public class Arrival implements Parcelable, Comparable<Arrival> {
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Arrival other = (Arrival) obj;
|
||||
Departure other = (Departure) obj;
|
||||
if (bikeAllowed != other.bikeAllowed)
|
||||
return false;
|
||||
if (destination != other.destination)
|
||||
@ -227,8 +239,8 @@ public class Arrival implements Parcelable, Comparable<Arrival> {
|
||||
public String getCountdownText() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
int secondsLeft = getMeanSecondsLeft();
|
||||
if (hasArrived()) {
|
||||
builder.append("Arrived");
|
||||
if (hasDeparted()) {
|
||||
builder.append("Departed");
|
||||
} else {
|
||||
builder.append(secondsLeft / 60);
|
||||
builder.append("m, ");
|
||||
@ -239,7 +251,7 @@ public class Arrival implements Parcelable, Comparable<Arrival> {
|
||||
}
|
||||
|
||||
public String getUncertaintyText() {
|
||||
if (hasArrived()) {
|
||||
if (hasDeparted()) {
|
||||
return "";
|
||||
} else {
|
||||
return "(±" + getUncertaintySeconds() + "s)";
|
||||
@ -290,13 +302,13 @@ public class Arrival implements Parcelable, Comparable<Arrival> {
|
||||
maxEstimate = in.readLong();
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<Arrival> CREATOR = new Parcelable.Creator<Arrival>() {
|
||||
public Arrival createFromParcel(Parcel in) {
|
||||
return new Arrival(in);
|
||||
public static final Parcelable.Creator<Departure> CREATOR = new Parcelable.Creator<Departure>() {
|
||||
public Departure createFromParcel(Parcel in) {
|
||||
return new Departure(in);
|
||||
}
|
||||
|
||||
public Arrival[] newArray(int size) {
|
||||
return new Arrival[size];
|
||||
public Departure[] newArray(int size) {
|
||||
return new Departure[size];
|
||||
}
|
||||
};
|
||||
}
|
@ -7,8 +7,8 @@ import java.util.List;
|
||||
import com.dougkeen.bart.Route;
|
||||
import com.dougkeen.bart.Station;
|
||||
|
||||
public class RealTimeArrivals {
|
||||
public RealTimeArrivals(Station origin, Station destination,
|
||||
public class RealTimeDepartures {
|
||||
public RealTimeDepartures(Station origin, Station destination,
|
||||
List<Route> routes) {
|
||||
this.origin = origin;
|
||||
this.destination = destination;
|
||||
@ -19,7 +19,7 @@ public class RealTimeArrivals {
|
||||
private Station destination;
|
||||
private long time;
|
||||
|
||||
private List<Arrival> arrivals;
|
||||
private List<Departure> departures;
|
||||
|
||||
private List<Route> routes;
|
||||
|
||||
@ -47,32 +47,35 @@ public class RealTimeArrivals {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public List<Arrival> getArrivals() {
|
||||
if (arrivals == null) {
|
||||
arrivals = new ArrayList<Arrival>();
|
||||
public List<Departure> getDepartures() {
|
||||
if (departures == null) {
|
||||
departures = new ArrayList<Departure>();
|
||||
}
|
||||
return arrivals;
|
||||
return departures;
|
||||
}
|
||||
|
||||
public void setArrivals(List<Arrival> arrivals) {
|
||||
this.arrivals = arrivals;
|
||||
public void setDepartures(List<Departure> departures) {
|
||||
this.departures = departures;
|
||||
}
|
||||
|
||||
public void addArrival(Arrival arrival) {
|
||||
Station destination = Station.getByAbbreviation(arrival
|
||||
public void addDeparture(Departure departure) {
|
||||
Station destination = Station.getByAbbreviation(departure
|
||||
.getDestinationAbbreviation());
|
||||
if (departure.getLine() == null)
|
||||
return;
|
||||
for (Route route : routes) {
|
||||
if (route.trainDestinationIsApplicable(destination, arrival.getLine())) {
|
||||
arrival.setRequiresTransfer(route.hasTransfer());
|
||||
getArrivals().add(arrival);
|
||||
arrival.calculateEstimates(time);
|
||||
if (route.trainDestinationIsApplicable(destination,
|
||||
departure.getLine())) {
|
||||
departure.setRequiresTransfer(route.hasTransfer());
|
||||
getDepartures().add(departure);
|
||||
departure.calculateEstimates(time);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void sortArrivals() {
|
||||
Collections.sort(getArrivals());
|
||||
public void sortDepartures() {
|
||||
Collections.sort(getDepartures());
|
||||
}
|
||||
|
||||
public List<Route> getRoutes() {
|
||||
@ -86,14 +89,14 @@ public class RealTimeArrivals {
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("RealTimeArrivals [origin=");
|
||||
builder.append("RealTimeDepartures [origin=");
|
||||
builder.append(origin);
|
||||
builder.append(", destination=");
|
||||
builder.append(destination);
|
||||
builder.append(", time=");
|
||||
builder.append(time);
|
||||
builder.append(", arrivals=");
|
||||
builder.append(arrivals);
|
||||
builder.append(", departures=");
|
||||
builder.append(departures);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
Loading…
Reference in New Issue
Block a user