Added bike and xfer icons.
Now more well-behaved when switching orientations. Added option to view routes on m.bart.gov --HG-- rename : res/menu/favorite_context_menu.xml => res/menu/route_context_menu.xml rename : res/menu/favorites_menu.xml => res/menu/routes_list_menu.xml rename : src/com/dougkeen/bart/AddFavoriteActivity.java => src/com/dougkeen/bart/AddRouteActivity.java rename : src/com/dougkeen/bart/FavoritesDashboardActivity.java => src/com/dougkeen/bart/RoutesListActivity.java rename : src/com/dougkeen/bart/data/FavoritesColumns.java => src/com/dougkeen/bart/data/RoutesColumns.java
@ -1,3 +1,9 @@
|
|||||||
|
|
||||||
syntax: glob
|
syntax: glob
|
||||||
bin/*
|
bin/*
|
||||||
|
syntax: regexp
|
||||||
|
^app_icon\.psd$
|
||||||
|
syntax: regexp
|
||||||
|
^bart-train\.jpg$
|
||||||
|
syntax: regexp
|
||||||
|
^colorscheme\.jpg$
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.dougkeen.bart" android:versionCode="2"
|
package="com.dougkeen.bart" android:versionCode="3"
|
||||||
android:versionName="1.0">
|
android:versionName="1.0">
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
<application android:icon="@drawable/icon" android:label="@string/app_name"
|
<application android:icon="@drawable/icon" android:label="@string/app_name"
|
||||||
android:debuggable="true">
|
android:debuggable="true">
|
||||||
<activity android:name=".FavoritesDashboardActivity"
|
<activity android:name="RoutesListActivity"
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
@ -28,7 +28,7 @@
|
|||||||
<data android:mimeType="vnd.android.cursor.item/com.dougkeen.bart.favorite" />
|
<data android:mimeType="vnd.android.cursor.item/com.dougkeen.bart.favorite" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".AddFavoriteActivity" android:label="@string/app_name">
|
<activity android:name="AddRouteActivity" android:label="@string/app_name">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.INSERT" />
|
<action android:name="android.intent.action.INSERT" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:shape="rectangle">
|
android:shape="rectangle">
|
||||||
<size android:height="15dp" android:width="60dp" />
|
<size android:height="45dp" android:width="15dp" />
|
||||||
</shape>
|
</shape>
|
BIN
res/drawable/bike.png
Normal file
After Width: | Height: | Size: 1008 B |
BIN
res/drawable/xfer.png
Normal file
After Width: | Height: | Size: 839 B |
@ -5,7 +5,7 @@
|
|||||||
<TextView android:id="@+id/form_header" android:layout_width="wrap_content"
|
<TextView android:id="@+id/form_header" android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content" android:textSize="24dp"
|
android:layout_height="wrap_content" android:textSize="24dp"
|
||||||
android:textStyle="bold" android:layout_alignParentTop="true"
|
android:textStyle="bold" android:layout_alignParentTop="true"
|
||||||
android:text="@string/add_favorite_route" android:paddingBottom="10dp" />
|
android:text="@string/add_route" android:paddingBottom="10dp" />
|
||||||
<TextView android:id="@+id/origin_label" android:text="@string/origin"
|
<TextView android:id="@+id/origin_label" android:text="@string/origin"
|
||||||
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||||
android:textSize="15dp" android:layout_below="@+id/form_header"
|
android:textSize="15dp" android:layout_below="@+id/form_header"
|
||||||
|
@ -1,12 +1,22 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="fill_parent" android:layout_height="fill_parent">
|
android:layout_width="fill_parent" android:layout_height="fill_parent">
|
||||||
<TextView android:id="@+id/destinationText" style="@style/ArrivalDestinationText"
|
|
||||||
android:layout_alignParentTop="true" android:layout_alignParentLeft="true" />
|
|
||||||
<ImageView android:id="@+id/destinationColorBar" android:src="@drawable/basic_rectangle"
|
<ImageView android:id="@+id/destinationColorBar" android:src="@drawable/basic_rectangle"
|
||||||
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentLeft="true" android:layout_centerVertical="true" />
|
||||||
|
<TextView android:id="@+id/destinationText" style="@style/ArrivalDestinationText"
|
||||||
|
android:layout_alignParentTop="true" android:layout_toRightOf="@id/destinationColorBar" />
|
||||||
|
<TextView android:id="@+id/trainLengthText" style="@style/ArrivalTrainLengthText"
|
||||||
|
android:layout_toRightOf="@id/destinationColorBar"
|
||||||
android:layout_below="@id/destinationText" />
|
android:layout_below="@id/destinationText" />
|
||||||
<TextView android:layout_centerVertical="true"
|
<TextView android:layout_alignParentRight="true" android:id="@+id/countdown"
|
||||||
android:layout_alignParentRight="true" android:id="@+id/countdown"
|
|
||||||
style="@style/ArrivalCountdownText" />
|
style="@style/ArrivalCountdownText" />
|
||||||
|
<TextView android:layout_alignParentRight="true" android:id="@+id/uncertainty"
|
||||||
|
android:layout_below="@id/countdown" style="@style/ArrivalUncertaintyText" />
|
||||||
|
<ImageView android:id="@+id/bikeIcon" android:src="@drawable/bike"
|
||||||
|
android:layout_alignParentTop="true" android:layout_alignParentRight="true"
|
||||||
|
style="@style/BikeIcon" />
|
||||||
|
<ImageView android:id="@+id/xferIcon" android:src="@drawable/xfer"
|
||||||
|
android:layout_below="@id/bikeIcon" android:layout_alignParentRight="true"
|
||||||
|
style="@style/XferIcon" />
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
@ -3,6 +3,6 @@
|
|||||||
android:layout_width="fill_parent" android:layout_height="wrap_content"
|
android:layout_width="fill_parent" android:layout_height="wrap_content"
|
||||||
android:paddingTop="15dip" android:paddingBottom="15dip"
|
android:paddingTop="15dip" android:paddingBottom="15dip"
|
||||||
android:paddingLeft="5dip" android:paddingRight="5dip" android:id="@android:id/text1"
|
android:paddingLeft="5dip" android:paddingRight="5dip" android:id="@android:id/text1"
|
||||||
android:textColor="#cccccc" android:ellipsize="marquee"
|
android:ellipsize="marquee" android:textColor="@color/black"
|
||||||
android:singleLine="true">
|
android:singleLine="true">
|
||||||
</TextView>
|
</TextView>
|
||||||
|
5
res/menu/route_menu.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:title="@string/view_on_bart_site" android:icon="@android:drawable/ic_menu_view"
|
||||||
|
android:id="@+id/view_on_bart_site_button"></item>
|
||||||
|
</menu>
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:title="@string/add_favorite" android:icon="@android:drawable/ic_menu_add"
|
<item android:title="@string/add_route" android:icon="@android:drawable/ic_menu_add"
|
||||||
android:id="@+id/add_favorite_menu_button"></item>
|
android:id="@+id/add_favorite_menu_button"></item>
|
||||||
</menu>
|
</menu>
|
@ -2,23 +2,24 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Bart Catcher</string>
|
<string name="app_name">Bart Catcher</string>
|
||||||
<string name="favorite_routes">Favorite Routes</string>
|
<string name="favorite_routes">Favorite Routes</string>
|
||||||
<string name="empty_favorites_list_message">Press the menu button and select "Add
|
<string name="empty_favorites_list_message">Press the menu button and select \"Add route\" to add
|
||||||
favorite" to
|
a route</string>
|
||||||
add a route</string>
|
<string name="add_route">Add a route</string>
|
||||||
<string name="add_favorite">Add favorite</string>
|
|
||||||
<string name="add_favorite_route">Add a favorite route</string>
|
|
||||||
<string name="origin">Origin</string>
|
<string name="origin">Origin</string>
|
||||||
<string name="destination">Destination</string>
|
<string name="destination">Destination</string>
|
||||||
<string name="save">Save</string>
|
<string name="save">Save</string>
|
||||||
<string name="error_matching_origin_and_destination">The origin and destination stations must be different</string>
|
<string name="error_matching_origin_and_destination">The origin and destination stations must be
|
||||||
|
different</string>
|
||||||
<string name="error_null_destination">You must select a destination station</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="error_null_origin">You must select an origin station</string>
|
||||||
<string name="arrival_wait_message">Please wait while real time arrival data is loaded...</string>
|
<string name="arrival_wait_message">Please wait while real time arrival data is
|
||||||
<string name="no_data_message">No arrival data is currently available for this route</string>
|
loaded...</string>
|
||||||
|
<string name="no_data_message">No arrival data is currently available for this
|
||||||
|
route</string>
|
||||||
<string name="view">View</string>
|
<string name="view">View</string>
|
||||||
<string name="view_arrivals">View arrivals</string>
|
<string name="view_arrivals">View arrivals</string>
|
||||||
<string name="delete">Delete</string>
|
<string name="delete">Delete</string>
|
||||||
<string name="yes">Yes</string>
|
<string name="yes">Yes</string>
|
||||||
<string name="cancel">Cancel</string>
|
<string name="cancel">Cancel</string>
|
||||||
|
<string name="view_on_bart_site">View details on BART site</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -21,8 +21,18 @@
|
|||||||
<style name="ArrivalDestinationText">
|
<style name="ArrivalDestinationText">
|
||||||
<item name="android:layout_width">wrap_content</item>
|
<item name="android:layout_width">wrap_content</item>
|
||||||
<item name="android:layout_height">wrap_content</item>
|
<item name="android:layout_height">wrap_content</item>
|
||||||
<item name="android:textSize">20dp</item>
|
<item name="android:textSize">22dp</item>
|
||||||
|
<item name="android:textStyle">bold</item>
|
||||||
<item name="android:singleLine">true</item>
|
<item name="android:singleLine">true</item>
|
||||||
|
<item name="android:layout_marginLeft">3dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="ArrivalTrainLengthText">
|
||||||
|
<item name="android:layout_width">wrap_content</item>
|
||||||
|
<item name="android:layout_height">wrap_content</item>
|
||||||
|
<item name="android:textSize">18dp</item>
|
||||||
|
<item name="android:singleLine">true</item>
|
||||||
|
<item name="android:layout_marginLeft">3dp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="ArrivalCountdownText">
|
<style name="ArrivalCountdownText">
|
||||||
@ -31,4 +41,22 @@
|
|||||||
<item name="android:textSize">20dp</item>
|
<item name="android:textSize">20dp</item>
|
||||||
<item name="android:singleLine">true</item>
|
<item name="android:singleLine">true</item>
|
||||||
</style>
|
</style>
|
||||||
|
<style name="ArrivalUncertaintyText">
|
||||||
|
<item name="android:layout_width">wrap_content</item>
|
||||||
|
<item name="android:layout_height">wrap_content</item>
|
||||||
|
<item name="android:textSize">16dp</item>
|
||||||
|
<item name="android:singleLine">true</item>
|
||||||
|
</style>
|
||||||
|
<style name="BikeIcon">
|
||||||
|
<item name="android:layout_width">wrap_content</item>
|
||||||
|
<item name="android:layout_height">wrap_content</item>
|
||||||
|
<item name="android:layout_marginRight">100dp</item>
|
||||||
|
<item name="android:layout_marginTop">5dp</item>
|
||||||
|
</style>
|
||||||
|
<style name="XferIcon">
|
||||||
|
<item name="android:layout_width">wrap_content</item>
|
||||||
|
<item name="android:layout_height">wrap_content</item>
|
||||||
|
<item name="android:layout_marginRight">97dp</item>
|
||||||
|
<item name="android:layout_marginTop">5dp</item>
|
||||||
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package com.dougkeen.bart;
|
package com.dougkeen.bart;
|
||||||
|
|
||||||
import com.dougkeen.bart.data.FavoritesColumns;
|
import com.dougkeen.bart.data.RoutesColumns;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
@ -14,7 +14,7 @@ import android.widget.Spinner;
|
|||||||
import android.widget.SpinnerAdapter;
|
import android.widget.SpinnerAdapter;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
public class AddFavoriteActivity extends Activity {
|
public class AddRouteActivity extends Activity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
@ -80,8 +80,8 @@ public class AddFavoriteActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put(FavoritesColumns.FROM_STATION.string, origin.abbreviation);
|
values.put(RoutesColumns.FROM_STATION.string, origin.abbreviation);
|
||||||
values.put(FavoritesColumns.TO_STATION.string, destination.abbreviation);
|
values.put(RoutesColumns.TO_STATION.string, destination.abbreviation);
|
||||||
|
|
||||||
Uri newUri = getContentResolver().insert(
|
Uri newUri = getContentResolver().insert(
|
||||||
Constants.FAVORITE_CONTENT_URI, values);
|
Constants.FAVORITE_CONTENT_URI, values);
|
90
src/com/dougkeen/bart/ArrivalArrayAdapter.java
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
package com.dougkeen.bart;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.drawable.GradientDrawable;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.RelativeLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.dougkeen.bart.data.Arrival;
|
||||||
|
|
||||||
|
public class ArrivalArrayAdapter extends ArrayAdapter<Arrival> {
|
||||||
|
|
||||||
|
public ArrivalArrayAdapter(Context context, int textViewResourceId,
|
||||||
|
Arrival[] objects) {
|
||||||
|
super(context, textViewResourceId, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrivalArrayAdapter(Context context, int resource,
|
||||||
|
int textViewResourceId, Arrival[] objects) {
|
||||||
|
super(context, resource, textViewResourceId, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrivalArrayAdapter(Context context, int resource,
|
||||||
|
int textViewResourceId, List<Arrival> objects) {
|
||||||
|
super(context, resource, textViewResourceId, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrivalArrayAdapter(Context context, int resource,
|
||||||
|
int textViewResourceId) {
|
||||||
|
super(context, resource, textViewResourceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrivalArrayAdapter(Context context, int textViewResourceId,
|
||||||
|
List<Arrival> objects) {
|
||||||
|
super(context, textViewResourceId, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrivalArrayAdapter(Context context, int textViewResourceId) {
|
||||||
|
super(context, textViewResourceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
|
View view;
|
||||||
|
if (convertView != null && convertView instanceof RelativeLayout) {
|
||||||
|
view = convertView;
|
||||||
|
} else {
|
||||||
|
LayoutInflater inflater = LayoutInflater.from(getContext());
|
||||||
|
view = inflater.inflate(R.layout.arrival_listing, parent, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Arrival arrival = getItem(position);
|
||||||
|
((TextView) view.findViewById(R.id.destinationText)).setText(arrival
|
||||||
|
.getDestination().toString());
|
||||||
|
((TextView) view.findViewById(R.id.trainLengthText)).setText(arrival
|
||||||
|
.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
|
||||||
|
.getCountdownText());
|
||||||
|
((TextView) view.findViewById(R.id.uncertainty)).setText(arrival
|
||||||
|
.getUncertaintyText());
|
||||||
|
if (arrival.isBikeAllowed()) {
|
||||||
|
((ImageView) view.findViewById(R.id.bikeIcon))
|
||||||
|
.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
((ImageView) view.findViewById(R.id.bikeIcon))
|
||||||
|
.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
if (arrival.getRequiresTransfer()) {
|
||||||
|
((ImageView) view.findViewById(R.id.xferIcon))
|
||||||
|
.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
((ImageView) view.findViewById(R.id.xferIcon))
|
||||||
|
.setVisibility(View.INVISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -40,7 +40,11 @@ public abstract class GetRealTimeArrivalsTask extends
|
|||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isCancelled()) {
|
||||||
return getArrivalsFromNetwork(params, sourceUrl, 0);
|
return getArrivalsFromNetwork(params, sourceUrl, 0);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private RealTimeArrivals getArrivalsFromNetwork(Params params,
|
private RealTimeArrivals getArrivalsFromNetwork(Params params,
|
||||||
@ -48,6 +52,9 @@ public abstract class GetRealTimeArrivalsTask extends
|
|||||||
try {
|
try {
|
||||||
EtdContentHandler handler = new EtdContentHandler(params.origin,
|
EtdContentHandler handler = new EtdContentHandler(params.origin,
|
||||||
params.destination, mRoutes);
|
params.destination, mRoutes);
|
||||||
|
if (isCancelled()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
Xml.parse(sourceUrl.openStream(), Xml.findEncodingByName("UTF-8"),
|
Xml.parse(sourceUrl.openStream(), Xml.findEncodingByName("UTF-8"),
|
||||||
handler);
|
handler);
|
||||||
final RealTimeArrivals realTimeArrivals = handler
|
final RealTimeArrivals realTimeArrivals = handler
|
||||||
|
@ -5,6 +5,7 @@ public class Route {
|
|||||||
private Station destination;
|
private Station destination;
|
||||||
private Line line;
|
private Line line;
|
||||||
private boolean requiresTransfer;
|
private boolean requiresTransfer;
|
||||||
|
private Station transferStation;
|
||||||
private String direction;
|
private String direction;
|
||||||
|
|
||||||
public Station getOrigin() {
|
public Station getOrigin() {
|
||||||
@ -39,6 +40,14 @@ public class Route {
|
|||||||
this.requiresTransfer = requiresTransfer;
|
this.requiresTransfer = requiresTransfer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Station getTransferStation() {
|
||||||
|
return transferStation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTransferStation(Station transferStation) {
|
||||||
|
this.transferStation = transferStation;
|
||||||
|
}
|
||||||
|
|
||||||
public String getDirection() {
|
public String getDirection() {
|
||||||
return direction;
|
return direction;
|
||||||
}
|
}
|
||||||
@ -58,6 +67,8 @@ public class Route {
|
|||||||
builder.append(line);
|
builder.append(line);
|
||||||
builder.append(", requiresTransfer=");
|
builder.append(", requiresTransfer=");
|
||||||
builder.append(requiresTransfer);
|
builder.append(requiresTransfer);
|
||||||
|
builder.append(", transferStation=");
|
||||||
|
builder.append(transferStation);
|
||||||
builder.append(", direction=");
|
builder.append(", direction=");
|
||||||
builder.append(direction);
|
builder.append(direction);
|
||||||
builder.append("]");
|
builder.append("]");
|
||||||
|
@ -24,9 +24,9 @@ import android.widget.SimpleCursorAdapter.ViewBinder;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.dougkeen.bart.data.CursorUtils;
|
import com.dougkeen.bart.data.CursorUtils;
|
||||||
import com.dougkeen.bart.data.FavoritesColumns;
|
import com.dougkeen.bart.data.RoutesColumns;
|
||||||
|
|
||||||
public class FavoritesDashboardActivity extends ListActivity {
|
public class RoutesListActivity extends ListActivity {
|
||||||
private static final int DIALOG_DELETE_EVENT = 0;
|
private static final int DIALOG_DELETE_EVENT = 0;
|
||||||
|
|
||||||
protected Cursor mQuery;
|
protected Cursor mQuery;
|
||||||
@ -41,22 +41,17 @@ public class FavoritesDashboardActivity extends ListActivity {
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.main);
|
setContentView(R.layout.main);
|
||||||
|
|
||||||
((TextView) findViewById(R.id.listTitle))
|
|
||||||
.setText(R.string.favorite_routes);
|
|
||||||
((TextView) findViewById(android.R.id.empty))
|
|
||||||
.setText(R.string.empty_favorites_list_message);
|
|
||||||
|
|
||||||
mQuery = managedQuery(Constants.FAVORITE_CONTENT_URI, new String[] {
|
mQuery = managedQuery(Constants.FAVORITE_CONTENT_URI, new String[] {
|
||||||
FavoritesColumns._ID.string,
|
RoutesColumns._ID.string,
|
||||||
FavoritesColumns.FROM_STATION.string,
|
RoutesColumns.FROM_STATION.string,
|
||||||
FavoritesColumns.TO_STATION.string }, null, null,
|
RoutesColumns.TO_STATION.string }, null, null,
|
||||||
FavoritesColumns._ID.string);
|
RoutesColumns._ID.string);
|
||||||
|
|
||||||
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
|
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
|
||||||
R.layout.favorite_listing,
|
R.layout.favorite_listing,
|
||||||
mQuery,
|
mQuery,
|
||||||
new String[] { FavoritesColumns.FROM_STATION.string,
|
new String[] { RoutesColumns.FROM_STATION.string,
|
||||||
FavoritesColumns.TO_STATION.string },
|
RoutesColumns.TO_STATION.string },
|
||||||
new int[] { R.id.originText,
|
new int[] { R.id.originText,
|
||||||
R.id.destinationText });
|
R.id.destinationText });
|
||||||
adapter.setViewBinder(new ViewBinder() {
|
adapter.setViewBinder(new ViewBinder() {
|
||||||
@ -74,10 +69,19 @@ public class FavoritesDashboardActivity extends ListActivity {
|
|||||||
registerForContextMenu(getListView());
|
registerForContextMenu(getListView());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
((TextView) findViewById(R.id.listTitle))
|
||||||
|
.setText(R.string.favorite_routes);
|
||||||
|
((TextView) findViewById(android.R.id.empty))
|
||||||
|
.setText(R.string.empty_favorites_list_message);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
MenuInflater inflater = getMenuInflater();
|
MenuInflater inflater = getMenuInflater();
|
||||||
inflater.inflate(R.menu.favorites_menu, menu);
|
inflater.inflate(R.menu.routes_list_menu, menu);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,15 +109,15 @@ public class FavoritesDashboardActivity extends ListActivity {
|
|||||||
super.onCreateContextMenu(menu, v, menuInfo);
|
super.onCreateContextMenu(menu, v, menuInfo);
|
||||||
|
|
||||||
MenuInflater inflater = getMenuInflater();
|
MenuInflater inflater = getMenuInflater();
|
||||||
inflater.inflate(R.menu.favorite_context_menu, menu);
|
inflater.inflate(R.menu.route_context_menu, menu);
|
||||||
|
|
||||||
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
|
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
|
||||||
CursorWrapper item = (CursorWrapper) getListAdapter().getItem(
|
CursorWrapper item = (CursorWrapper) getListAdapter().getItem(
|
||||||
info.position);
|
info.position);
|
||||||
Station orig = Station.getByAbbreviation(CursorUtils.getString(item,
|
Station orig = Station.getByAbbreviation(CursorUtils.getString(item,
|
||||||
FavoritesColumns.FROM_STATION));
|
RoutesColumns.FROM_STATION));
|
||||||
Station dest = Station.getByAbbreviation(CursorUtils.getString(item,
|
Station dest = Station.getByAbbreviation(CursorUtils.getString(item,
|
||||||
FavoritesColumns.TO_STATION));
|
RoutesColumns.TO_STATION));
|
||||||
mCurrentlySelectedRouteName = orig.name + " - " + dest.name;
|
mCurrentlySelectedRouteName = orig.name + " - " + dest.name;
|
||||||
menu.setHeaderTitle(mCurrentlySelectedRouteName);
|
menu.setHeaderTitle(mCurrentlySelectedRouteName);
|
||||||
}
|
}
|
@ -115,10 +115,11 @@ public enum Station {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<Route> getRoutesForDestination(Station dest) {
|
public List<Route> getRoutesForDestination(Station dest) {
|
||||||
return getRoutesForDestination(dest, false);
|
return getRoutesForDestination(dest, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Route> getRoutesForDestination(Station dest, boolean isTransfer) {
|
public List<Route> getRoutesForDestination(Station dest,
|
||||||
|
Station transferStation) {
|
||||||
if (dest == null)
|
if (dest == null)
|
||||||
return null;
|
return null;
|
||||||
Boolean isNorth = null;
|
Boolean isNorth = null;
|
||||||
@ -140,7 +141,7 @@ public enum Station {
|
|||||||
route.setDestination(dest);
|
route.setDestination(dest);
|
||||||
route.setDirection(isNorth ? "n" : "s");
|
route.setDirection(isNorth ? "n" : "s");
|
||||||
route.setLine(line);
|
route.setLine(line);
|
||||||
if (isTransfer || line.requiresTransfer) {
|
if (transferStation != null || line.requiresTransfer) {
|
||||||
route.setTransfer(true);
|
route.setTransfer(true);
|
||||||
} else {
|
} else {
|
||||||
route.setTransfer(false);
|
route.setTransfer(false);
|
||||||
@ -149,11 +150,14 @@ public enum Station {
|
|||||||
}
|
}
|
||||||
if (isNorth == null) {
|
if (isNorth == null) {
|
||||||
if (outboundTransferStation != null) {
|
if (outboundTransferStation != null) {
|
||||||
returnList.addAll(getOutboundTransferStation()
|
returnList
|
||||||
.getRoutesForDestination(dest, true));
|
.addAll(getOutboundTransferStation()
|
||||||
|
.getRoutesForDestination(dest,
|
||||||
|
getOutboundTransferStation()));
|
||||||
} else {
|
} else {
|
||||||
returnList.addAll(getRoutesForDestination(dest
|
returnList.addAll(getRoutesForDestination(dest
|
||||||
.getInboundTransferStation(), true));
|
.getInboundTransferStation(), dest
|
||||||
|
.getInboundTransferStation()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return returnList;
|
return returnList;
|
||||||
|
@ -10,18 +10,29 @@ import android.database.Cursor;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Parcelable;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
|
import android.text.format.DateFormat;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.TimeFormatException;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.dougkeen.bart.GetRealTimeArrivalsTask.Params;
|
import com.dougkeen.bart.GetRealTimeArrivalsTask.Params;
|
||||||
import com.dougkeen.bart.data.Arrival;
|
import com.dougkeen.bart.data.Arrival;
|
||||||
import com.dougkeen.bart.data.FavoritesColumns;
|
import com.dougkeen.bart.data.RoutesColumns;
|
||||||
import com.dougkeen.bart.data.RealTimeArrivals;
|
import com.dougkeen.bart.data.RealTimeArrivals;
|
||||||
|
|
||||||
public class ViewArrivalsActivity extends ListActivity {
|
public class ViewArrivalsActivity extends ListActivity {
|
||||||
|
|
||||||
|
private static final String TAG = "BartCatcher";
|
||||||
|
|
||||||
|
private static final int UNCERTAINTY_THRESHOLD = 17;
|
||||||
|
|
||||||
private Uri mUri;
|
private Uri mUri;
|
||||||
|
|
||||||
private Station mOrigin;
|
private Station mOrigin;
|
||||||
@ -44,9 +55,10 @@ public class ViewArrivalsActivity extends ListActivity {
|
|||||||
|
|
||||||
private PowerManager.WakeLock mWakeLock;
|
private PowerManager.WakeLock mWakeLock;
|
||||||
|
|
||||||
|
private boolean mFetchArrivalsOnNextFocus;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
// TODO Auto-generated method stub
|
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.main);
|
setContentView(R.layout.main);
|
||||||
|
|
||||||
@ -59,8 +71,8 @@ public class ViewArrivalsActivity extends ListActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Cursor cursor = managedQuery(mUri, new String[] {
|
Cursor cursor = managedQuery(mUri, new String[] {
|
||||||
FavoritesColumns.FROM_STATION.string,
|
RoutesColumns.FROM_STATION.string,
|
||||||
FavoritesColumns.TO_STATION.string }, null, null, null);
|
RoutesColumns.TO_STATION.string }, null, null, null);
|
||||||
|
|
||||||
if (!cursor.moveToFirst()) {
|
if (!cursor.moveToFirst()) {
|
||||||
throw new IllegalStateException("URI not found: " + mUri.toString());
|
throw new IllegalStateException("URI not found: " + mUri.toString());
|
||||||
@ -75,31 +87,69 @@ public class ViewArrivalsActivity extends ListActivity {
|
|||||||
((TextView) findViewById(android.R.id.empty))
|
((TextView) findViewById(android.R.id.empty))
|
||||||
.setText(R.string.arrival_wait_message);
|
.setText(R.string.arrival_wait_message);
|
||||||
|
|
||||||
mArrivalsAdapter = new ArrayAdapter<Arrival>(
|
mArrivalsAdapter = new ArrivalArrayAdapter(this,
|
||||||
this, R.layout.simple_spinner_item);
|
R.layout.arrival_listing);
|
||||||
|
if (savedInstanceState != null
|
||||||
|
&& savedInstanceState.containsKey("arrivals")) {
|
||||||
|
for (Parcelable arrival : savedInstanceState
|
||||||
|
.getParcelableArray("arrivals")) {
|
||||||
|
mArrivalsAdapter.add((Arrival) arrival);
|
||||||
|
}
|
||||||
|
}
|
||||||
setListAdapter(mArrivalsAdapter);
|
setListAdapter(mArrivalsAdapter);
|
||||||
|
|
||||||
fetchLatestArrivals();
|
mFetchArrivalsOnNextFocus = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
if (mGetArrivalsTask != null) {
|
||||||
|
mGetArrivalsTask.cancel(true);
|
||||||
|
}
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
outState.putParcelableArray("arrivals", arrivals);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onWindowFocusChanged(boolean hasFocus) {
|
public void onWindowFocusChanged(boolean hasFocus) {
|
||||||
super.onWindowFocusChanged(hasFocus);
|
super.onWindowFocusChanged(hasFocus);
|
||||||
if (hasFocus) {
|
if (hasFocus) {
|
||||||
|
if (mFetchArrivalsOnNextFocus) {
|
||||||
|
fetchLatestArrivals();
|
||||||
|
mFetchArrivalsOnNextFocus = false;
|
||||||
|
}
|
||||||
PowerManager powerManaer = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
PowerManager powerManaer = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
||||||
mWakeLock = powerManaer.newWakeLock(
|
mWakeLock = powerManaer.newWakeLock(
|
||||||
PowerManager.SCREEN_DIM_WAKE_LOCK, "ViewArrivalsActivity");
|
PowerManager.SCREEN_DIM_WAKE_LOCK, "ViewArrivalsActivity");
|
||||||
mWakeLock.acquire();
|
mWakeLock.acquire();
|
||||||
|
if (mArrivalsAdapter != null && !mArrivalsAdapter.isEmpty()) {
|
||||||
|
mIsAutoUpdating = true;
|
||||||
|
}
|
||||||
|
runAutoUpdate();
|
||||||
} else if (mWakeLock != null) {
|
} else if (mWakeLock != null) {
|
||||||
mWakeLock.release();
|
mWakeLock.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetchLatestArrivals() {
|
private void fetchLatestArrivals() {
|
||||||
|
if (!hasWindowFocus())
|
||||||
|
return;
|
||||||
|
|
||||||
mGetArrivalsTask = new GetRealTimeArrivalsTask() {
|
mGetArrivalsTask = new GetRealTimeArrivalsTask() {
|
||||||
@Override
|
@Override
|
||||||
public void onResult(RealTimeArrivals result) {
|
public void onResult(RealTimeArrivals result) {
|
||||||
|
Log.i(TAG, "Processing data from server");
|
||||||
processLatestArrivals(result);
|
processLatestArrivals(result);
|
||||||
|
Log.i(TAG, "Done processing data from server");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -108,6 +158,7 @@ public class ViewArrivalsActivity extends ListActivity {
|
|||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Log.i(TAG, "Fetching data from server");
|
||||||
mGetArrivalsTask.execute(new GetRealTimeArrivalsTask.Params(mOrigin,
|
mGetArrivalsTask.execute(new GetRealTimeArrivalsTask.Params(mOrigin,
|
||||||
mDestination));
|
mDestination));
|
||||||
}
|
}
|
||||||
@ -119,6 +170,7 @@ public class ViewArrivalsActivity extends ListActivity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean needsBetterAccuracy = false;
|
||||||
Arrival firstArrival = null;
|
Arrival firstArrival = null;
|
||||||
final List<Arrival> arrivals = result.getArrivals();
|
final List<Arrival> arrivals = result.getArrivals();
|
||||||
if (mArrivalsAdapter.getCount() > 0) {
|
if (mArrivalsAdapter.getCount() > 0) {
|
||||||
@ -148,6 +200,9 @@ public class ViewArrivalsActivity extends ListActivity {
|
|||||||
if (firstArrival == null) {
|
if (firstArrival == null) {
|
||||||
firstArrival = existingArrival;
|
firstArrival = existingArrival;
|
||||||
}
|
}
|
||||||
|
if (existingArrival.getUncertaintySeconds() > UNCERTAINTY_THRESHOLD) {
|
||||||
|
needsBetterAccuracy = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (Arrival arrival : arrivals) {
|
for (Arrival arrival : arrivals) {
|
||||||
@ -156,12 +211,13 @@ public class ViewArrivalsActivity extends ListActivity {
|
|||||||
}
|
}
|
||||||
mArrivalsAdapter.add(arrival);
|
mArrivalsAdapter.add(arrival);
|
||||||
}
|
}
|
||||||
|
needsBetterAccuracy = true;
|
||||||
}
|
}
|
||||||
mArrivalsAdapter.notifyDataSetChanged();
|
mArrivalsAdapter.notifyDataSetChanged();
|
||||||
|
|
||||||
if (hasWindowFocus() && firstArrival != null) {
|
if (hasWindowFocus() && firstArrival != null) {
|
||||||
if (firstArrival.getUncertaintySeconds() > 17
|
if (needsBetterAccuracy
|
||||||
|| firstArrival.getMinutes() == 0) {
|
|| firstArrival.hasArrived()) {
|
||||||
// Get more data in 20s
|
// Get more data in 20s
|
||||||
mListTitleView.postDelayed(new Runnable() {
|
mListTitleView.postDelayed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
@ -169,27 +225,29 @@ public class ViewArrivalsActivity extends ListActivity {
|
|||||||
fetchLatestArrivals();
|
fetchLatestArrivals();
|
||||||
}
|
}
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
Log.i(TAG, "Scheduled another data fetch in 20s");
|
||||||
} else {
|
} else {
|
||||||
// Get more when next train arrives
|
// Get more when next train arrives
|
||||||
|
final int interval = firstArrival.getMinSecondsLeft() * 1000;
|
||||||
mListTitleView.postDelayed(new Runnable() {
|
mListTitleView.postDelayed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
fetchLatestArrivals();
|
fetchLatestArrivals();
|
||||||
}
|
}
|
||||||
}, firstArrival.getMinSecondsLeft() * 1000);
|
}, interval);
|
||||||
|
Log.i(TAG, "Scheduled another data fetch in " + interval / 1000
|
||||||
|
+ "s");
|
||||||
}
|
}
|
||||||
if (!mIsAutoUpdating) {
|
if (!mIsAutoUpdating) {
|
||||||
mIsAutoUpdating = true;
|
mIsAutoUpdating = true;
|
||||||
runAutoUpdate();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mIsAutoUpdating = false;
|
mIsAutoUpdating = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runAutoUpdate() {
|
private void runAutoUpdate() {
|
||||||
if (mIsAutoUpdating) {
|
if (mIsAutoUpdating && mArrivalsAdapter != null) {
|
||||||
mArrivalsAdapter.notifyDataSetChanged();
|
mArrivalsAdapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
if (hasWindowFocus()) {
|
if (hasWindowFocus()) {
|
||||||
@ -198,4 +256,30 @@ public class ViewArrivalsActivity extends ListActivity {
|
|||||||
mIsAutoUpdating = false;
|
mIsAutoUpdating = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
MenuInflater inflater = getMenuInflater();
|
||||||
|
inflater.inflate(R.menu.route_menu, menu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
int itemId = item.getItemId();
|
||||||
|
if (itemId == R.id.view_on_bart_site_button) {
|
||||||
|
startActivity(new Intent(
|
||||||
|
Intent.ACTION_VIEW,
|
||||||
|
Uri.parse("http://m.bart.gov/schedules/qp_results.aspx?type=departure&date=today&time="
|
||||||
|
+ DateFormat.format("h:mmaa",
|
||||||
|
System.currentTimeMillis()) + "&orig="
|
||||||
|
+ mOrigin.abbreviation
|
||||||
|
+ "&dest="
|
||||||
|
+ mDestination.abbreviation)));
|
||||||
|
mFetchArrivalsOnNextFocus = true;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
package com.dougkeen.bart.data;
|
package com.dougkeen.bart.data;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
import com.dougkeen.bart.Station;
|
import com.dougkeen.bart.Station;
|
||||||
|
|
||||||
public class Arrival implements Comparable<Arrival> {
|
public class Arrival implements Parcelable, Comparable<Arrival> {
|
||||||
public Arrival() {
|
public Arrival() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
@ -20,6 +23,10 @@ public class Arrival implements Comparable<Arrival> {
|
|||||||
this.minutes = minutes;
|
this.minutes = minutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Arrival(Parcel in) {
|
||||||
|
readFromParcel(in);
|
||||||
|
}
|
||||||
|
|
||||||
private Station destination;
|
private Station destination;
|
||||||
private String destinationColor;
|
private String destinationColor;
|
||||||
private String platform;
|
private String platform;
|
||||||
@ -93,6 +100,10 @@ public class Arrival implements Comparable<Arrival> {
|
|||||||
this.trainLength = trainLength;
|
this.trainLength = trainLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getTrainLengthText() {
|
||||||
|
return trainLength + " car train";
|
||||||
|
}
|
||||||
|
|
||||||
public boolean getRequiresTransfer() {
|
public boolean getRequiresTransfer() {
|
||||||
return requiresTransfer;
|
return requiresTransfer;
|
||||||
}
|
}
|
||||||
@ -142,14 +153,24 @@ public class Arrival implements Comparable<Arrival> {
|
|||||||
.currentTimeMillis()) / 1000);
|
.currentTimeMillis()) / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasArrived() {
|
||||||
|
return getMinutes() == 0 || getMeanSecondsLeft() < 0;
|
||||||
|
}
|
||||||
|
|
||||||
public void calculateEstimates(long originalEstimateTime) {
|
public void calculateEstimates(long originalEstimateTime) {
|
||||||
setMinEstimate(originalEstimateTime + (getMinutes() * 60 * 1000));
|
setMinEstimate(originalEstimateTime + (getMinutes() * 60 * 1000));
|
||||||
setMaxEstimate(getMinEstimate() + (59 * 1000));
|
setMaxEstimate(getMinEstimate() + (59 * 1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void mergeEstimate(Arrival arrival) {
|
public void mergeEstimate(Arrival arrival) {
|
||||||
setMinEstimate(Math.max(getMinEstimate(), arrival.getMinEstimate()));
|
final long newMin = Math
|
||||||
setMaxEstimate(Math.min(getMaxEstimate(), arrival.getMaxEstimate()));
|
.max(getMinEstimate(), arrival.getMinEstimate());
|
||||||
|
final long newMax = Math
|
||||||
|
.min(getMaxEstimate(), arrival.getMaxEstimate());
|
||||||
|
if (newMax > newMin) { // We can never have 0 or negative uncertainty
|
||||||
|
setMinEstimate(newMin);
|
||||||
|
setMaxEstimate(newMax);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -193,27 +214,79 @@ public class Arrival implements Comparable<Arrival> {
|
|||||||
return delta > -60000 && delta < 60000;
|
return delta > -60000 && delta < 60000;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public String getCountdownText() {
|
||||||
public String toString() {
|
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
builder.append(destination);
|
|
||||||
if(requiresTransfer) {
|
|
||||||
builder.append(" (w/ xfer)");
|
|
||||||
}
|
|
||||||
builder.append(", ");
|
|
||||||
builder.append(trainLength);
|
|
||||||
int secondsLeft = getMeanSecondsLeft();
|
int secondsLeft = getMeanSecondsLeft();
|
||||||
if (getMinutes() == 0 || secondsLeft < 0) {
|
if (hasArrived()) {
|
||||||
builder.append(" car train has arrived");
|
builder.append("Arrived");
|
||||||
} else {
|
} else {
|
||||||
builder.append(" car train in ");
|
|
||||||
builder.append(secondsLeft / 60);
|
builder.append(secondsLeft / 60);
|
||||||
builder.append("m, ");
|
builder.append("m, ");
|
||||||
builder.append(secondsLeft % 60);
|
builder.append(secondsLeft % 60);
|
||||||
builder.append("s, ±");
|
|
||||||
builder.append(getUncertaintySeconds());
|
|
||||||
builder.append("s");
|
builder.append("s");
|
||||||
}
|
}
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getUncertaintyText() {
|
||||||
|
if (hasArrived()) {
|
||||||
|
return "";
|
||||||
|
} else {
|
||||||
|
return "(±" + getUncertaintySeconds() + "s)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append(destination);
|
||||||
|
if (requiresTransfer) {
|
||||||
|
builder.append(" (w/ xfer)");
|
||||||
|
}
|
||||||
|
builder.append(", ");
|
||||||
|
builder.append(getCountdownText());
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeString(destination.abbreviation);
|
||||||
|
dest.writeString(destinationColor);
|
||||||
|
dest.writeString(platform);
|
||||||
|
dest.writeString(direction);
|
||||||
|
dest.writeByte((byte) (bikeAllowed ? 1 : 0));
|
||||||
|
dest.writeInt(trainLength);
|
||||||
|
dest.writeByte((byte) (requiresTransfer ? 1 : 0));
|
||||||
|
dest.writeInt(minutes);
|
||||||
|
dest.writeLong(minEstimate);
|
||||||
|
dest.writeLong(maxEstimate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readFromParcel(Parcel in) {
|
||||||
|
destination = Station.getByAbbreviation(in.readString());
|
||||||
|
destinationColor = in.readString();
|
||||||
|
platform = in.readString();
|
||||||
|
direction = in.readString();
|
||||||
|
bikeAllowed = in.readByte() != 0;
|
||||||
|
trainLength = in.readInt();
|
||||||
|
requiresTransfer = in.readByte() != 0;
|
||||||
|
minutes = in.readInt();
|
||||||
|
minEstimate = in.readLong();
|
||||||
|
maxEstimate = in.readLong();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<Arrival> CREATOR = new Parcelable.Creator<Arrival>() {
|
||||||
|
public Arrival createFromParcel(Parcel in) {
|
||||||
|
return new Arrival(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Arrival[] newArray(int size) {
|
||||||
|
return new Arrival[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
@ -26,7 +26,7 @@ public class BartContentProvider extends ContentProvider {
|
|||||||
/**
|
/**
|
||||||
* The default sort order for events
|
* The default sort order for events
|
||||||
*/
|
*/
|
||||||
private static final String DEFAULT_SORT_ORDER = FavoritesColumns.FROM_STATION.string
|
private static final String DEFAULT_SORT_ORDER = RoutesColumns.FROM_STATION.string
|
||||||
+ " DESC";
|
+ " DESC";
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@ -35,12 +35,12 @@ public class BartContentProvider extends ContentProvider {
|
|||||||
sUriMatcher.addURI(Constants.AUTHORITY, "favorites/#", FAVORITE_ID);
|
sUriMatcher.addURI(Constants.AUTHORITY, "favorites/#", FAVORITE_ID);
|
||||||
|
|
||||||
sFavoritesProjectionMap = new HashMap<String, String>();
|
sFavoritesProjectionMap = new HashMap<String, String>();
|
||||||
sFavoritesProjectionMap.put(FavoritesColumns._ID.string,
|
sFavoritesProjectionMap.put(RoutesColumns._ID.string,
|
||||||
FavoritesColumns._ID.string);
|
RoutesColumns._ID.string);
|
||||||
sFavoritesProjectionMap.put(FavoritesColumns.FROM_STATION.string,
|
sFavoritesProjectionMap.put(RoutesColumns.FROM_STATION.string,
|
||||||
FavoritesColumns.FROM_STATION.string);
|
RoutesColumns.FROM_STATION.string);
|
||||||
sFavoritesProjectionMap.put(FavoritesColumns.TO_STATION.string,
|
sFavoritesProjectionMap.put(RoutesColumns.TO_STATION.string,
|
||||||
FavoritesColumns.TO_STATION.string);
|
RoutesColumns.TO_STATION.string);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DatabaseHelper mDatabaseHelper;
|
private DatabaseHelper mDatabaseHelper;
|
||||||
@ -81,7 +81,7 @@ public class BartContentProvider extends ContentProvider {
|
|||||||
} else if (match == FAVORITE_ID) {
|
} else if (match == FAVORITE_ID) {
|
||||||
qb.setTables(DatabaseHelper.FAVORITES_TABLE_NAME);
|
qb.setTables(DatabaseHelper.FAVORITES_TABLE_NAME);
|
||||||
qb.setProjectionMap(sFavoritesProjectionMap);
|
qb.setProjectionMap(sFavoritesProjectionMap);
|
||||||
qb.appendWhere(FavoritesColumns._ID + " = "
|
qb.appendWhere(RoutesColumns._ID + " = "
|
||||||
+ uri.getPathSegments().get(1));
|
+ uri.getPathSegments().get(1));
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Unknown URI " + uri);
|
throw new IllegalArgumentException("Unknown URI " + uri);
|
||||||
@ -121,12 +121,12 @@ public class BartContentProvider extends ContentProvider {
|
|||||||
long rowId = -1;
|
long rowId = -1;
|
||||||
Cursor cursor = db
|
Cursor cursor = db
|
||||||
.query(DatabaseHelper.FAVORITES_TABLE_NAME,
|
.query(DatabaseHelper.FAVORITES_TABLE_NAME,
|
||||||
new String[] { FavoritesColumns._ID.string },
|
new String[] { RoutesColumns._ID.string },
|
||||||
FavoritesColumns.FROM_STATION + "=? AND "
|
RoutesColumns.FROM_STATION + "=? AND "
|
||||||
+ FavoritesColumns.TO_STATION + "=?",
|
+ RoutesColumns.TO_STATION + "=?",
|
||||||
new String[] {
|
new String[] {
|
||||||
values.getAsString(FavoritesColumns.FROM_STATION.string),
|
values.getAsString(RoutesColumns.FROM_STATION.string),
|
||||||
values.getAsString(FavoritesColumns.TO_STATION.string) },
|
values.getAsString(RoutesColumns.TO_STATION.string) },
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null);
|
null);
|
||||||
@ -139,7 +139,7 @@ public class BartContentProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
if (rowId < 0) {
|
if (rowId < 0) {
|
||||||
rowId = db.insert(DatabaseHelper.FAVORITES_TABLE_NAME,
|
rowId = db.insert(DatabaseHelper.FAVORITES_TABLE_NAME,
|
||||||
FavoritesColumns.FROM_STATION.string, values);
|
RoutesColumns.FROM_STATION.string, values);
|
||||||
}
|
}
|
||||||
if (rowId > 0) {
|
if (rowId > 0) {
|
||||||
Uri eventUri = ContentUris.withAppendedId(
|
Uri eventUri = ContentUris.withAppendedId(
|
||||||
@ -174,7 +174,7 @@ public class BartContentProvider extends ContentProvider {
|
|||||||
} else if (match == FAVORITE_ID) {
|
} else if (match == FAVORITE_ID) {
|
||||||
String favoriteId = uri.getPathSegments().get(1);
|
String favoriteId = uri.getPathSegments().get(1);
|
||||||
count = db.delete(DatabaseHelper.FAVORITES_TABLE_NAME,
|
count = db.delete(DatabaseHelper.FAVORITES_TABLE_NAME,
|
||||||
FavoritesColumns._ID + " = "
|
RoutesColumns._ID + " = "
|
||||||
+ favoriteId
|
+ favoriteId
|
||||||
+ (!TextUtils.isEmpty(where) ? " AND (" + where
|
+ (!TextUtils.isEmpty(where) ? " AND (" + where
|
||||||
+ ')' : ""), whereArgs);
|
+ ')' : ""), whereArgs);
|
||||||
|
@ -13,7 +13,7 @@ public final class CursorUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String getString(Cursor cursor, FavoritesColumns column) {
|
public static final String getString(Cursor cursor, RoutesColumns column) {
|
||||||
return cursor.getString(cursor.getColumnIndex(column.string));
|
return cursor.getString(cursor.getColumnIndex(column.string));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,9 +18,9 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(SQLiteDatabase db) {
|
public void onCreate(SQLiteDatabase db) {
|
||||||
db.execSQL("CREATE TABLE " + FAVORITES_TABLE_NAME + " (" +
|
db.execSQL("CREATE TABLE " + FAVORITES_TABLE_NAME + " (" +
|
||||||
FavoritesColumns._ID.getColumnDef() + " PRIMARY KEY, " +
|
RoutesColumns._ID.getColumnDef() + " PRIMARY KEY, " +
|
||||||
FavoritesColumns.FROM_STATION.getColumnDef() + ", " +
|
RoutesColumns.FROM_STATION.getColumnDef() + ", " +
|
||||||
FavoritesColumns.TO_STATION.getColumnDef() + ");");
|
RoutesColumns.TO_STATION.getColumnDef() + ");");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package com.dougkeen.bart.data;
|
package com.dougkeen.bart.data;
|
||||||
|
|
||||||
public enum FavoritesColumns {
|
public enum RoutesColumns {
|
||||||
_ID("_id", "INTEGER"),
|
_ID("_id", "INTEGER"),
|
||||||
FROM_STATION("FROM_STATION", "TEXT"),
|
FROM_STATION("FROM_STATION", "TEXT"),
|
||||||
TO_STATION("TO_STATION", "TEXT");
|
TO_STATION("TO_STATION", "TEXT");
|
||||||
|
|
||||||
// This class cannot be instantiated
|
// This class cannot be instantiated
|
||||||
private FavoritesColumns(String string, String type) {
|
private RoutesColumns(String string, String type) {
|
||||||
this.string = string;
|
this.string = string;
|
||||||
this.sqliteType = type;
|
this.sqliteType = type;
|
||||||
}
|
}
|
109
xfer.svg
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="32px"
|
||||||
|
height="32px"
|
||||||
|
id="svg2383"
|
||||||
|
sodipodi:version="0.32"
|
||||||
|
inkscape:version="0.46"
|
||||||
|
sodipodi:docname="xfer.svg"
|
||||||
|
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
||||||
|
<defs
|
||||||
|
id="defs2385">
|
||||||
|
<inkscape:perspective
|
||||||
|
sodipodi:type="inkscape:persp3d"
|
||||||
|
inkscape:vp_x="0 : 16 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_z="32 : 16 : 1"
|
||||||
|
inkscape:persp3d-origin="16 : 10.666667 : 1"
|
||||||
|
id="perspective2391" />
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="22.395604"
|
||||||
|
inkscape:cx="14.100126"
|
||||||
|
inkscape:cy="15.964773"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:grid-bbox="true"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1125"
|
||||||
|
inkscape:window-x="1911"
|
||||||
|
inkscape:window-y="-9" />
|
||||||
|
<metadata
|
||||||
|
id="metadata2388">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
id="layer1"
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer">
|
||||||
|
<path
|
||||||
|
style="fill:#29716d;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="M 6.117272,8.0220801 L 0.58047106,15.702158 L 26.255152,15.702158 L 26.255152,11.460255 L 6.117272,11.504906 L 6.117272,8.0220801 z"
|
||||||
|
id="path2393"
|
||||||
|
sodipodi:nodetypes="cccccc"
|
||||||
|
inkscape:export-filename="C:\Users\dkeen\Workspaces\AndroidExperiments\DontMissTheBart\res\drawable\xfer.png"
|
||||||
|
inkscape:export-xdpi="117.18631"
|
||||||
|
inkscape:export-ydpi="117.18631" />
|
||||||
|
<path
|
||||||
|
style="fill:#143635;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="M 25.964917,23.382236 L 31.501718,15.702158 L 5.8270365,15.702158 L 5.8270365,19.944061 L 25.964917,19.89941 L 25.964917,23.382236 z"
|
||||||
|
id="path3165"
|
||||||
|
sodipodi:nodetypes="cccccc"
|
||||||
|
inkscape:export-filename="C:\Users\dkeen\Workspaces\AndroidExperiments\DontMissTheBart\res\drawable\xfer.png"
|
||||||
|
inkscape:export-xdpi="117.18631"
|
||||||
|
inkscape:export-ydpi="117.18631" />
|
||||||
|
<flowRoot
|
||||||
|
xml:space="preserve"
|
||||||
|
id="flowRoot3167"
|
||||||
|
style="font-size:4;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
||||||
|
transform="translate(8.0372916,9.5554467)"
|
||||||
|
inkscape:export-filename="C:\Users\dkeen\Workspaces\AndroidExperiments\DontMissTheBart\res\drawable\xfer.png"
|
||||||
|
inkscape:export-xdpi="117.18631"
|
||||||
|
inkscape:export-ydpi="117.18631"><flowRegion
|
||||||
|
id="flowRegion3169"><rect
|
||||||
|
id="rect3171"
|
||||||
|
width="17.63739"
|
||||||
|
height="10.359176"
|
||||||
|
x="3.2595682"
|
||||||
|
y="4.2266922"
|
||||||
|
style="font-size:4px;fill:#000000" /></flowRegion><flowPara
|
||||||
|
id="flowPara3173"
|
||||||
|
style="font-size:4" /></flowRoot> <text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:4px;font-style:normal;font-weight:normal;line-height:125%;fill:#f2f3ed;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
||||||
|
x="10.001963"
|
||||||
|
y="18.068693"
|
||||||
|
id="text3175"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
inkscape:export-xdpi="117.18631"
|
||||||
|
inkscape:export-ydpi="117.18631"
|
||||||
|
inkscape:export-filename="C:\Users\dkeen\Workspaces\AndroidExperiments\DontMissTheBart\res\drawable\xfer.png"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3177"
|
||||||
|
x="10.001963"
|
||||||
|
y="18.068693"
|
||||||
|
style="font-size:6px;font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Helvetica Inserat LT Std;-inkscape-font-specification:Helvetica Inserat LT Std Ultra-Bold;fill:#f2f3ed">XFER</tspan></text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4.7 KiB |