BartRunnerAndroid/src/com/dougkeen/bart/ViewArrivalsActivity.java

295 lines
8.2 KiB
Java
Raw Normal View History

2011-05-23 18:59:34 +00:00
package com.dougkeen.bart;
import java.io.IOException;
import java.util.List;
import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcelable;
2011-05-23 18:59:34 +00:00
import android.os.PowerManager;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
2011-05-23 18:59:34 +00:00
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;
2011-06-01 03:42:32 +00:00
import com.dougkeen.bart.data.RoutesColumns;
2011-05-23 18:59:34 +00:00
public class ViewArrivalsActivity extends ListActivity {
private static final int UNCERTAINTY_THRESHOLD = 17;
2011-05-23 18:59:34 +00:00
private Uri mUri;
private Station mOrigin;
private Station mDestination;
private ArrayAdapter<Arrival> mArrivalsAdapter;
private TextView mListTitleView;
private AsyncTask<Params, Integer, RealTimeArrivals> mGetArrivalsTask;
private boolean mIsAutoUpdating = false;
private final Runnable AUTO_UPDATE_RUNNABLE = new Runnable() {
@Override
public void run() {
runAutoUpdate();
}
};
private PowerManager.WakeLock mWakeLock;
private boolean mFetchArrivalsOnNextFocus;
2011-05-23 18:59:34 +00:00
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Intent intent = getIntent();
String action = intent.getAction();
if (Intent.ACTION_VIEW.equals(action)) {
mUri = intent.getData();
}
Cursor cursor = managedQuery(mUri, new String[] {
RoutesColumns.FROM_STATION.string,
RoutesColumns.TO_STATION.string }, null, null, null);
2011-05-23 18:59:34 +00:00
if (!cursor.moveToFirst()) {
throw new IllegalStateException("URI not found: " + mUri.toString());
}
mOrigin = Station.getByAbbreviation(cursor.getString(0));
mDestination = Station.getByAbbreviation(cursor.getString(1));
String header = 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);
mArrivalsAdapter = new ArrivalArrayAdapter(this,
R.layout.arrival_listing);
if (savedInstanceState != null
&& savedInstanceState.containsKey("arrivals")) {
for (Parcelable arrival : savedInstanceState
.getParcelableArray("arrivals")) {
mArrivalsAdapter.add((Arrival) arrival);
}
}
2011-05-23 18:59:34 +00:00
setListAdapter(mArrivalsAdapter);
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);
2011-05-23 18:59:34 +00:00
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
if (mFetchArrivalsOnNextFocus) {
fetchLatestArrivals();
mFetchArrivalsOnNextFocus = false;
}
2011-05-23 18:59:34 +00:00
PowerManager powerManaer = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManaer.newWakeLock(
PowerManager.SCREEN_DIM_WAKE_LOCK, "ViewArrivalsActivity");
mWakeLock.acquire();
if (mArrivalsAdapter != null && !mArrivalsAdapter.isEmpty()) {
mIsAutoUpdating = true;
}
runAutoUpdate();
2011-05-23 18:59:34 +00:00
} else if (mWakeLock != null) {
mWakeLock.release();
}
}
private void fetchLatestArrivals() {
if (!hasWindowFocus())
return;
2011-06-01 03:42:32 +00:00
if (mGetArrivalsTask != null
&& mGetArrivalsTask.getStatus()
.equals(AsyncTask.Status.RUNNING)) {
// Don't overlap fetches
return;
}
2011-05-23 18:59:34 +00:00
mGetArrivalsTask = new GetRealTimeArrivalsTask() {
@Override
public void onResult(RealTimeArrivals result) {
2011-06-01 03:42:32 +00:00
Log.i(Constants.TAG, "Processing data from server");
2011-05-23 18:59:34 +00:00
processLatestArrivals(result);
2011-06-01 03:42:32 +00:00
Log.i(Constants.TAG, "Done processing data from server");
2011-05-23 18:59:34 +00:00
}
@Override
public void onNetworkError(IOException e) {
2011-06-01 03:42:32 +00:00
Log.w(Constants.TAG, e.getMessage());
Toast.makeText(ViewArrivalsActivity.this,
R.string.could_not_connect,
Toast.LENGTH_LONG).show();
((TextView) findViewById(android.R.id.empty))
.setText(R.string.could_not_connect);
2011-05-23 18:59:34 +00:00
}
};
2011-06-01 03:42:32 +00:00
Log.i(Constants.TAG, "Fetching data from server");
2011-05-23 18:59:34 +00:00
mGetArrivalsTask.execute(new GetRealTimeArrivalsTask.Params(mOrigin,
mDestination));
}
protected void processLatestArrivals(RealTimeArrivals result) {
if (result.getArrivals().isEmpty()) {
((TextView) findViewById(android.R.id.empty))
.setText(R.string.no_data_message);
return;
}
boolean needsBetterAccuracy = false;
2011-05-23 18:59:34 +00:00
Arrival firstArrival = null;
final List<Arrival> arrivals = result.getArrivals();
if (mArrivalsAdapter.getCount() > 0) {
int adapterIndex = -1;
for (Arrival arrival : arrivals) {
adapterIndex++;
Arrival existingArrival = null;
if (adapterIndex < mArrivalsAdapter.getCount()) {
existingArrival = mArrivalsAdapter.getItem(adapterIndex);
}
while (existingArrival != null
&& !arrival.equals(existingArrival)) {
mArrivalsAdapter.remove(existingArrival);
if (adapterIndex < mArrivalsAdapter.getCount()) {
existingArrival = mArrivalsAdapter
.getItem(adapterIndex);
} else {
existingArrival = null;
}
}
if (existingArrival != null) {
existingArrival.mergeEstimate(arrival);
} else {
mArrivalsAdapter.add(arrival);
existingArrival = arrival;
}
if (firstArrival == null) {
firstArrival = existingArrival;
}
if (existingArrival.getUncertaintySeconds() > UNCERTAINTY_THRESHOLD) {
needsBetterAccuracy = true;
}
2011-05-23 18:59:34 +00:00
}
} else {
for (Arrival arrival : arrivals) {
if (firstArrival == null) {
firstArrival = arrival;
}
mArrivalsAdapter.add(arrival);
}
needsBetterAccuracy = true;
2011-05-23 18:59:34 +00:00
}
mArrivalsAdapter.notifyDataSetChanged();
if (hasWindowFocus() && firstArrival != null) {
if (needsBetterAccuracy
|| firstArrival.hasArrived()) {
2011-05-23 18:59:34 +00:00
// Get more data in 20s
mListTitleView.postDelayed(new Runnable() {
@Override
public void run() {
fetchLatestArrivals();
}
}, 20000);
2011-06-01 03:42:32 +00:00
Log.i(Constants.TAG, "Scheduled another data fetch in 20s");
2011-05-23 18:59:34 +00:00
} else {
// Get more when next train arrives
final int interval = firstArrival.getMinSecondsLeft() * 1000;
2011-05-23 18:59:34 +00:00
mListTitleView.postDelayed(new Runnable() {
@Override
public void run() {
fetchLatestArrivals();
}
}, interval);
2011-06-01 03:42:32 +00:00
Log.i(Constants.TAG, "Scheduled another data fetch in "
+ interval / 1000
+ "s");
2011-05-23 18:59:34 +00:00
}
if (!mIsAutoUpdating) {
mIsAutoUpdating = true;
}
} else {
mIsAutoUpdating = false;
}
}
private void runAutoUpdate() {
if (mIsAutoUpdating && mArrivalsAdapter != null) {
2011-05-23 18:59:34 +00:00
mArrivalsAdapter.notifyDataSetChanged();
}
if (hasWindowFocus()) {
mListTitleView.postDelayed(AUTO_UPDATE_RUNNABLE, 1000);
} else {
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);
}
}
2011-05-23 18:59:34 +00:00
}