2012-09-25 21:31:06 +00:00
|
|
|
package com.dougkeen.bart.activities;
|
|
|
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
import android.app.AlertDialog;
|
|
|
|
import android.app.AlertDialog.Builder;
|
|
|
|
import android.content.ComponentName;
|
|
|
|
import android.content.Context;
|
|
|
|
import android.content.DialogInterface;
|
|
|
|
import android.content.Intent;
|
|
|
|
import android.content.ServiceConnection;
|
|
|
|
import android.database.Cursor;
|
|
|
|
import android.media.MediaPlayer;
|
|
|
|
import android.media.RingtoneManager;
|
|
|
|
import android.net.Uri;
|
|
|
|
import android.os.Bundle;
|
|
|
|
import android.os.Handler;
|
|
|
|
import android.os.IBinder;
|
|
|
|
import android.os.Parcelable;
|
2012-10-09 21:43:48 +00:00
|
|
|
import android.os.Vibrator;
|
2012-09-25 21:31:06 +00:00
|
|
|
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
|
|
|
import android.support.v4.content.CursorLoader;
|
|
|
|
import android.support.v4.content.Loader;
|
|
|
|
import android.text.format.DateFormat;
|
|
|
|
import android.text.util.Linkify;
|
|
|
|
import android.util.Log;
|
|
|
|
import android.view.View;
|
|
|
|
import android.view.WindowManager;
|
|
|
|
import android.widget.AdapterView;
|
2012-10-02 04:03:08 +00:00
|
|
|
import android.widget.Checkable;
|
2012-09-25 21:31:06 +00:00
|
|
|
|
2012-10-03 19:29:31 +00:00
|
|
|
import com.WazaBe.HoloEverywhere.sherlock.SActivity;
|
|
|
|
import com.WazaBe.HoloEverywhere.widget.ListView;
|
|
|
|
import com.WazaBe.HoloEverywhere.widget.ProgressBar;
|
|
|
|
import com.WazaBe.HoloEverywhere.widget.TextView;
|
|
|
|
import com.WazaBe.HoloEverywhere.widget.Toast;
|
2012-09-25 21:31:06 +00:00
|
|
|
import com.actionbarsherlock.view.ActionMode;
|
|
|
|
import com.actionbarsherlock.view.Menu;
|
|
|
|
import com.actionbarsherlock.view.MenuInflater;
|
|
|
|
import com.actionbarsherlock.view.MenuItem;
|
|
|
|
import com.dougkeen.bart.BartRunnerApplication;
|
|
|
|
import com.dougkeen.bart.R;
|
2012-10-05 05:52:42 +00:00
|
|
|
import com.dougkeen.bart.controls.SwipeHelper;
|
2012-09-25 21:31:06 +00:00
|
|
|
import com.dougkeen.bart.controls.Ticker;
|
2012-10-02 04:03:08 +00:00
|
|
|
import com.dougkeen.bart.controls.YourTrainLayout;
|
2012-09-25 21:31:06 +00:00
|
|
|
import com.dougkeen.bart.data.DepartureArrayAdapter;
|
|
|
|
import com.dougkeen.bart.data.RoutesColumns;
|
|
|
|
import com.dougkeen.bart.model.Constants;
|
|
|
|
import com.dougkeen.bart.model.Departure;
|
|
|
|
import com.dougkeen.bart.model.Station;
|
|
|
|
import com.dougkeen.bart.model.StationPair;
|
2012-10-02 04:03:08 +00:00
|
|
|
import com.dougkeen.bart.services.BoardedDepartureService;
|
2012-09-25 21:31:06 +00:00
|
|
|
import com.dougkeen.bart.services.EtdService;
|
|
|
|
import com.dougkeen.bart.services.EtdService.EtdServiceBinder;
|
|
|
|
import com.dougkeen.bart.services.EtdService.EtdServiceListener;
|
|
|
|
import com.dougkeen.util.Observer;
|
|
|
|
import com.dougkeen.util.WakeLocker;
|
|
|
|
|
2012-10-03 19:29:31 +00:00
|
|
|
public class ViewDeparturesActivity extends SActivity implements
|
2012-09-25 21:31:06 +00:00
|
|
|
EtdServiceListener {
|
|
|
|
|
|
|
|
private static final int LOADER_ID = 123;
|
|
|
|
|
|
|
|
private Uri mUri;
|
|
|
|
|
|
|
|
private Station mOrigin;
|
|
|
|
private Station mDestination;
|
|
|
|
|
|
|
|
private Departure mSelectedDeparture;
|
2012-10-09 19:29:38 +00:00
|
|
|
private View mSelectedRow;
|
2012-09-25 21:31:06 +00:00
|
|
|
|
|
|
|
private DepartureArrayAdapter mDeparturesAdapter;
|
|
|
|
|
|
|
|
private TextView mEmptyView;
|
|
|
|
private ProgressBar mProgress;
|
|
|
|
|
|
|
|
private ActionMode mActionMode;
|
|
|
|
|
|
|
|
private EtdService mEtdService;
|
|
|
|
|
|
|
|
private Handler mHandler = new Handler();
|
|
|
|
|
|
|
|
private boolean mBound = false;
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
|
|
super.onCreate(savedInstanceState);
|
|
|
|
|
|
|
|
setContentView(R.layout.departures);
|
|
|
|
|
|
|
|
final Intent intent = getIntent();
|
|
|
|
|
|
|
|
String action = intent.getAction();
|
|
|
|
|
|
|
|
if (Intent.ACTION_VIEW.equals(action)) {
|
|
|
|
mUri = intent.getData();
|
|
|
|
}
|
|
|
|
|
|
|
|
final Uri uri = mUri;
|
|
|
|
|
2012-10-02 04:03:08 +00:00
|
|
|
final BartRunnerApplication bartRunnerApplication = (BartRunnerApplication) getApplication();
|
|
|
|
|
2012-09-25 21:31:06 +00:00
|
|
|
if (savedInstanceState != null
|
|
|
|
&& savedInstanceState.containsKey("origin")
|
|
|
|
&& savedInstanceState.containsKey("destination")) {
|
|
|
|
mOrigin = Station.getByAbbreviation(savedInstanceState
|
|
|
|
.getString("origin"));
|
|
|
|
mDestination = Station.getByAbbreviation(savedInstanceState
|
|
|
|
.getString("destination"));
|
|
|
|
setListTitle();
|
|
|
|
} else {
|
|
|
|
getSupportLoaderManager().initLoader(LOADER_ID, null,
|
|
|
|
new LoaderCallbacks<Cursor>() {
|
|
|
|
@Override
|
|
|
|
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
|
|
|
return new CursorLoader(
|
|
|
|
ViewDeparturesActivity.this, uri,
|
|
|
|
new String[] {
|
|
|
|
RoutesColumns.FROM_STATION.string,
|
|
|
|
RoutesColumns.TO_STATION.string },
|
|
|
|
null, null, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onLoadFinished(Loader<Cursor> loader,
|
|
|
|
Cursor cursor) {
|
|
|
|
if (!cursor.moveToFirst()) {
|
|
|
|
Log.wtf(Constants.TAG,
|
|
|
|
"Couldn't find Route record for the current Activity");
|
|
|
|
}
|
|
|
|
mOrigin = Station.getByAbbreviation(cursor
|
|
|
|
.getString(0));
|
|
|
|
mDestination = Station.getByAbbreviation(cursor
|
|
|
|
.getString(1));
|
|
|
|
setListTitle();
|
|
|
|
if (mBound && mEtdService != null)
|
|
|
|
mEtdService.registerListener(
|
|
|
|
ViewDeparturesActivity.this, false);
|
2012-10-09 21:22:21 +00:00
|
|
|
refreshBoardedDeparture(false);
|
2012-09-25 21:31:06 +00:00
|
|
|
|
|
|
|
getSupportLoaderManager().destroyLoader(LOADER_ID);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onLoaderReset(Loader<Cursor> loader) {
|
|
|
|
// ignore
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
mEmptyView = (TextView) findViewById(android.R.id.empty);
|
|
|
|
mEmptyView.setText(R.string.departure_wait_message);
|
|
|
|
|
|
|
|
mProgress = (ProgressBar) findViewById(android.R.id.progress);
|
|
|
|
|
|
|
|
mDeparturesAdapter = new DepartureArrayAdapter(this,
|
|
|
|
R.layout.departure_listing);
|
|
|
|
|
|
|
|
if (savedInstanceState != null) {
|
|
|
|
if (savedInstanceState.containsKey("departures")) {
|
|
|
|
for (Parcelable departure : savedInstanceState
|
|
|
|
.getParcelableArray("departures")) {
|
|
|
|
mDeparturesAdapter.add((Departure) departure);
|
|
|
|
}
|
|
|
|
mDeparturesAdapter.notifyDataSetChanged();
|
|
|
|
}
|
|
|
|
if (savedInstanceState.containsKey("selectedDeparture")) {
|
|
|
|
mSelectedDeparture = (Departure) savedInstanceState
|
|
|
|
.getParcelable("selectedDeparture");
|
|
|
|
}
|
2012-10-02 04:03:08 +00:00
|
|
|
if (savedInstanceState.getBoolean("hasDepartureActionMode")
|
2012-09-25 21:31:06 +00:00
|
|
|
&& mSelectedDeparture != null) {
|
|
|
|
startDepartureActionMode();
|
|
|
|
}
|
2012-10-02 04:03:08 +00:00
|
|
|
if (savedInstanceState.getBoolean("hasYourTrainActionMode")
|
|
|
|
&& mSelectedDeparture != null) {
|
|
|
|
((Checkable) findViewById(R.id.yourTrainSection))
|
|
|
|
.setChecked(true);
|
2012-10-11 00:21:30 +00:00
|
|
|
startYourTrainActionMode();
|
2012-10-02 04:03:08 +00:00
|
|
|
}
|
2012-09-25 21:31:06 +00:00
|
|
|
}
|
|
|
|
setListAdapter(mDeparturesAdapter);
|
2012-09-27 15:56:27 +00:00
|
|
|
final ListView listView = getListView();
|
|
|
|
listView.setEmptyView(findViewById(android.R.id.empty));
|
2012-10-02 04:03:08 +00:00
|
|
|
listView.setOnItemClickListener(mListItemClickListener);
|
|
|
|
listView.setOnItemLongClickListener(mListItemLongClickListener);
|
2012-09-25 21:31:06 +00:00
|
|
|
|
2012-10-03 19:29:31 +00:00
|
|
|
mMissingDepartureText = findViewById(R.id.missingDepartureText);
|
|
|
|
mMissingDepartureText.setVisibility(View.VISIBLE);
|
2012-09-25 21:31:06 +00:00
|
|
|
|
2012-10-03 20:07:19 +00:00
|
|
|
mYourTrainSection = (YourTrainLayout) findViewById(R.id.yourTrainSection);
|
|
|
|
mYourTrainSection.setOnClickListener(mYourTrainSectionClickListener);
|
2012-10-05 05:52:42 +00:00
|
|
|
mSwipeHelper = new SwipeHelper(mYourTrainSection, null,
|
|
|
|
new SwipeHelper.OnDismissCallback() {
|
2012-10-03 20:07:19 +00:00
|
|
|
@Override
|
|
|
|
public void onDismiss(View view, Object token) {
|
|
|
|
dismissYourTrainSelection();
|
|
|
|
if (isYourTrainActionModeActive()) {
|
|
|
|
mActionMode.finish();
|
|
|
|
}
|
|
|
|
}
|
2012-10-05 05:52:42 +00:00
|
|
|
});
|
|
|
|
mYourTrainSection.setOnTouchListener(mSwipeHelper);
|
2012-10-02 04:03:08 +00:00
|
|
|
|
2012-10-09 21:22:21 +00:00
|
|
|
refreshBoardedDeparture(false);
|
2012-09-25 21:31:06 +00:00
|
|
|
|
|
|
|
getSupportActionBar().setHomeButtonEnabled(true);
|
|
|
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
|
|
|
|
|
|
|
if (bartRunnerApplication.shouldPlayAlarmRingtone()) {
|
|
|
|
soundTheAlarm();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bartRunnerApplication.isAlarmSounding()) {
|
|
|
|
Builder builder = new AlertDialog.Builder(this);
|
2012-10-02 04:03:08 +00:00
|
|
|
builder.setMessage(R.string.train_alarm_text)
|
2012-09-25 21:31:06 +00:00
|
|
|
.setCancelable(false)
|
|
|
|
.setNeutralButton(R.string.silence_alarm,
|
|
|
|
new DialogInterface.OnClickListener() {
|
|
|
|
@Override
|
|
|
|
public void onClick(DialogInterface dialog,
|
|
|
|
int which) {
|
|
|
|
silenceAlarm();
|
|
|
|
dialog.dismiss();
|
|
|
|
}
|
|
|
|
}).show();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void soundTheAlarm() {
|
|
|
|
final BartRunnerApplication application = (BartRunnerApplication) getApplication();
|
|
|
|
|
2012-10-02 04:03:08 +00:00
|
|
|
Uri alarmSound = RingtoneManager
|
2012-09-25 21:31:06 +00:00
|
|
|
.getDefaultUri(RingtoneManager.TYPE_ALARM);
|
|
|
|
|
2012-10-02 04:03:08 +00:00
|
|
|
if (alarmSound == null || !tryToPlayRingtone(alarmSound)) {
|
|
|
|
alarmSound = RingtoneManager
|
2012-09-25 21:31:06 +00:00
|
|
|
.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
|
2012-10-02 04:03:08 +00:00
|
|
|
if (alarmSound == null || !tryToPlayRingtone(alarmSound)) {
|
|
|
|
alarmSound = RingtoneManager
|
2012-09-25 21:31:06 +00:00
|
|
|
.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (application.getAlarmMediaPlayer() == null) {
|
2012-10-02 04:03:08 +00:00
|
|
|
tryToPlayRingtone(alarmSound);
|
2012-09-25 21:31:06 +00:00
|
|
|
}
|
2012-10-09 21:43:48 +00:00
|
|
|
final Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
|
2012-10-11 00:21:30 +00:00
|
|
|
vibrator.vibrate(new long[] { 0, 500, 500 }, 1);
|
2012-09-25 21:31:06 +00:00
|
|
|
mHandler.postDelayed(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
silenceAlarm();
|
|
|
|
}
|
|
|
|
}, 20000);
|
|
|
|
|
|
|
|
application.setPlayAlarmRingtone(false);
|
|
|
|
application.setAlarmSounding(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean tryToPlayRingtone(Uri alertSound) {
|
|
|
|
MediaPlayer mediaPlayer = MediaPlayer.create(this, alertSound);
|
|
|
|
if (mediaPlayer == null)
|
|
|
|
return false;
|
|
|
|
mediaPlayer.setLooping(true);
|
|
|
|
mediaPlayer.start();
|
|
|
|
((BartRunnerApplication) getApplication())
|
|
|
|
.setAlarmMediaPlayer(mediaPlayer);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void silenceAlarm() {
|
|
|
|
final BartRunnerApplication application = (BartRunnerApplication) getApplication();
|
|
|
|
final MediaPlayer mediaPlayer = application.getAlarmMediaPlayer();
|
|
|
|
application.setAlarmSounding(false);
|
|
|
|
application.setAlarmMediaPlayer(null);
|
2012-10-09 21:43:48 +00:00
|
|
|
final Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
|
2012-10-11 00:21:30 +00:00
|
|
|
vibrator.cancel();
|
2012-09-25 21:31:06 +00:00
|
|
|
try {
|
|
|
|
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
|
|
|
|
mediaPlayer.stop();
|
|
|
|
mediaPlayer.release();
|
|
|
|
}
|
|
|
|
} catch (IllegalStateException e) {
|
|
|
|
Log.e(Constants.TAG,
|
|
|
|
"Couldn't stop media player; It was in an invalid state", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void setListTitle() {
|
|
|
|
((TextView) findViewById(R.id.listTitle)).setText(mOrigin.name + " to "
|
|
|
|
+ mDestination.name);
|
|
|
|
}
|
|
|
|
|
2012-09-27 15:56:27 +00:00
|
|
|
private ListView getListView() {
|
|
|
|
return (ListView) findViewById(android.R.id.list);
|
2012-09-25 21:31:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private final ServiceConnection mConnection = new ServiceConnection() {
|
|
|
|
@Override
|
|
|
|
public void onServiceDisconnected(ComponentName name) {
|
|
|
|
mEtdService = null;
|
|
|
|
mBound = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onServiceConnected(ComponentName name, IBinder service) {
|
|
|
|
mEtdService = ((EtdServiceBinder) service).getService();
|
|
|
|
mBound = true;
|
|
|
|
if (getStationPair() != null) {
|
|
|
|
mEtdService
|
|
|
|
.registerListener(ViewDeparturesActivity.this, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-10-02 04:03:08 +00:00
|
|
|
private boolean mWasLongClick = false;
|
|
|
|
|
|
|
|
private final AdapterView.OnItemClickListener mListItemClickListener = new AdapterView.OnItemClickListener() {
|
|
|
|
@Override
|
|
|
|
public void onItemClick(AdapterView<?> adapterView, View view,
|
|
|
|
int position, long id) {
|
|
|
|
if (mWasLongClick) {
|
|
|
|
mWasLongClick = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mActionMode != null) {
|
|
|
|
/*
|
|
|
|
* If action mode is displayed, cancel out of that
|
|
|
|
*/
|
|
|
|
mActionMode.finish();
|
|
|
|
getListView().clearChoices();
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Otherwise select the clicked departure as the one the user
|
|
|
|
* wants to board
|
|
|
|
*/
|
|
|
|
mSelectedDeparture = (Departure) getListAdapter().getItem(
|
|
|
|
position);
|
|
|
|
setBoardedDeparture(mSelectedDeparture);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
private final AdapterView.OnItemLongClickListener mListItemLongClickListener = new AdapterView.OnItemLongClickListener() {
|
|
|
|
@Override
|
|
|
|
public boolean onItemLongClick(AdapterView<?> adapterView, View view,
|
|
|
|
int position, long id) {
|
|
|
|
mWasLongClick = true;
|
|
|
|
mSelectedDeparture = (Departure) getListAdapter().getItem(position);
|
2012-10-09 19:29:38 +00:00
|
|
|
mSelectedRow = view;
|
|
|
|
((Checkable) mSelectedRow).setChecked(true);
|
2012-10-02 04:03:08 +00:00
|
|
|
startDepartureActionMode();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
private final View.OnClickListener mYourTrainSectionClickListener = new View.OnClickListener() {
|
|
|
|
@Override
|
|
|
|
public void onClick(View v) {
|
|
|
|
((Checkable) v).setChecked(true);
|
2012-10-11 00:21:30 +00:00
|
|
|
startYourTrainActionMode();
|
2012-10-02 04:03:08 +00:00
|
|
|
}
|
|
|
|
};
|
2012-09-25 21:31:06 +00:00
|
|
|
|
2012-10-03 19:29:31 +00:00
|
|
|
private View mMissingDepartureText;
|
|
|
|
|
2012-10-03 20:07:19 +00:00
|
|
|
private YourTrainLayout mYourTrainSection;
|
|
|
|
|
2012-10-05 05:52:42 +00:00
|
|
|
private SwipeHelper mSwipeHelper;
|
|
|
|
|
2012-09-25 21:31:06 +00:00
|
|
|
protected DepartureArrayAdapter getListAdapter() {
|
|
|
|
return mDeparturesAdapter;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void setListAdapter(DepartureArrayAdapter adapter) {
|
|
|
|
mDeparturesAdapter = adapter;
|
|
|
|
getListView().setAdapter(mDeparturesAdapter);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onStop() {
|
|
|
|
super.onStop();
|
|
|
|
if (mEtdService != null)
|
|
|
|
mEtdService.unregisterListener(this);
|
|
|
|
if (mBound)
|
|
|
|
unbindService(mConnection);
|
|
|
|
Ticker.getInstance().stopTicking(this);
|
|
|
|
WakeLocker.release();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onSaveInstanceState(Bundle outState) {
|
|
|
|
super.onSaveInstanceState(outState);
|
|
|
|
if (mOrigin != null || mDestination != null) {
|
|
|
|
/*
|
|
|
|
* If origin or destination are null, this thing was never
|
|
|
|
* initialized in the first place, so there's really nothing to save
|
|
|
|
*/
|
|
|
|
Departure[] departures = new Departure[mDeparturesAdapter
|
|
|
|
.getCount()];
|
|
|
|
for (int i = mDeparturesAdapter.getCount() - 1; i >= 0; i--) {
|
|
|
|
departures[i] = mDeparturesAdapter.getItem(i);
|
|
|
|
}
|
|
|
|
outState.putParcelableArray("departures", departures);
|
|
|
|
outState.putParcelable("selectedDeparture", mSelectedDeparture);
|
2012-10-02 04:03:08 +00:00
|
|
|
outState.putBoolean("hasDepartureActionMode",
|
|
|
|
isDepartureActionModeActive());
|
|
|
|
outState.putBoolean("hasYourTrainActionMode",
|
|
|
|
isYourTrainActionModeActive());
|
2012-09-25 21:31:06 +00:00
|
|
|
outState.putString("origin", mOrigin.abbreviation);
|
|
|
|
outState.putString("destination", mDestination.abbreviation);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onStart() {
|
|
|
|
super.onStart();
|
|
|
|
bindService(new Intent(this, EtdService.class), mConnection,
|
|
|
|
Context.BIND_AUTO_CREATE);
|
|
|
|
Ticker.getInstance().startTicking(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onWindowFocusChanged(boolean hasFocus) {
|
|
|
|
super.onWindowFocusChanged(hasFocus);
|
|
|
|
if (hasFocus) {
|
|
|
|
getWindow()
|
|
|
|
.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
|
|
|
Ticker.getInstance().startTicking(this);
|
2012-10-09 21:22:21 +00:00
|
|
|
refreshBoardedDeparture(false);
|
2012-09-25 21:31:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onCreateOptionsMenu(Menu menu) {
|
|
|
|
MenuInflater inflater = getSupportMenuInflater();
|
|
|
|
inflater.inflate(R.menu.route_menu, menu);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onOptionsItemSelected(MenuItem item) {
|
|
|
|
int itemId = item.getItemId();
|
|
|
|
if (itemId == android.R.id.home) {
|
|
|
|
Intent intent = new Intent(Intent.ACTION_VIEW,
|
|
|
|
Constants.FAVORITE_CONTENT_URI);
|
|
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
|
|
|
startActivity(intent);
|
|
|
|
return true;
|
|
|
|
} else if (itemId == R.id.view_on_bart_site_button) {
|
|
|
|
startActivity(new Intent(
|
|
|
|
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)));
|
|
|
|
return true;
|
|
|
|
} else if (itemId == R.id.view_system_map_button) {
|
|
|
|
startActivity(new Intent(this, ViewMapActivity.class));
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return super.onOptionsItemSelected(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-09 21:22:21 +00:00
|
|
|
private void refreshBoardedDeparture(boolean animate) {
|
2012-10-11 00:21:30 +00:00
|
|
|
final Departure boardedDeparture = getBoardedDeparture();
|
2012-10-03 20:07:19 +00:00
|
|
|
int currentVisibility = mYourTrainSection.getVisibility();
|
2012-09-28 17:10:54 +00:00
|
|
|
|
2012-10-11 00:21:30 +00:00
|
|
|
if (!doesDepartureApply(boardedDeparture)) {
|
2012-09-28 17:10:54 +00:00
|
|
|
if (currentVisibility != View.GONE) {
|
2012-10-02 04:03:08 +00:00
|
|
|
hideYourTrainSection();
|
2012-09-28 17:10:54 +00:00
|
|
|
}
|
2012-09-25 21:31:06 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-10-11 00:21:30 +00:00
|
|
|
mYourTrainSection.updateFromBoardedDeparture();
|
2012-09-25 21:31:06 +00:00
|
|
|
|
2012-10-02 04:03:08 +00:00
|
|
|
if (currentVisibility != View.VISIBLE) {
|
2012-10-09 21:22:21 +00:00
|
|
|
showYourTrainSection(animate);
|
2012-09-25 21:31:06 +00:00
|
|
|
}
|
2012-10-02 04:03:08 +00:00
|
|
|
}
|
2012-09-28 17:10:54 +00:00
|
|
|
|
2012-10-11 00:21:30 +00:00
|
|
|
private boolean doesDepartureApply(final Departure departure) {
|
|
|
|
return departure != null && departure.getStationPair() != null
|
|
|
|
&& departure.getStationPair().equals(getStationPair());
|
|
|
|
}
|
|
|
|
|
2012-10-02 04:03:08 +00:00
|
|
|
private void setBoardedDeparture(Departure selectedDeparture) {
|
|
|
|
final BartRunnerApplication application = (BartRunnerApplication) getApplication();
|
|
|
|
selectedDeparture.setPassengerDestination(mDestination);
|
|
|
|
application.setBoardedDeparture(selectedDeparture);
|
2012-10-09 21:22:21 +00:00
|
|
|
refreshBoardedDeparture(true);
|
2012-10-02 04:03:08 +00:00
|
|
|
|
|
|
|
// Start the notification service
|
|
|
|
startService(new Intent(ViewDeparturesActivity.this,
|
|
|
|
BoardedDepartureService.class));
|
2012-09-25 21:31:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void startDepartureActionMode() {
|
2012-09-27 15:56:27 +00:00
|
|
|
if (mActionMode == null)
|
|
|
|
mActionMode = startActionMode(new DepartureActionMode());
|
2012-09-25 21:31:06 +00:00
|
|
|
mActionMode.setTitle(mSelectedDeparture.getTrainDestinationName());
|
|
|
|
mActionMode.setSubtitle(mSelectedDeparture.getTrainLengthText());
|
|
|
|
}
|
|
|
|
|
|
|
|
private class DepartureActionMode implements ActionMode.Callback {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
|
|
|
mode.getMenuInflater().inflate(R.menu.departure_context_menu, menu);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
2012-10-02 04:03:08 +00:00
|
|
|
((Checkable) findViewById(R.id.yourTrainSection)).setChecked(false);
|
2012-09-25 21:31:06 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
|
|
|
if (item.getItemId() == R.id.boardTrain) {
|
2012-10-02 04:03:08 +00:00
|
|
|
setBoardedDeparture(mSelectedDeparture);
|
2012-09-25 21:31:06 +00:00
|
|
|
|
|
|
|
mode.finish();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDestroyActionMode(ActionMode mode) {
|
2012-10-09 19:29:38 +00:00
|
|
|
((Checkable) mSelectedRow).setChecked(false);
|
|
|
|
mSelectedRow = null;
|
2012-09-25 21:31:06 +00:00
|
|
|
mActionMode = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-10-11 00:21:30 +00:00
|
|
|
private void startYourTrainActionMode() {
|
2012-10-02 04:03:08 +00:00
|
|
|
if (mActionMode == null)
|
|
|
|
mActionMode = startActionMode(new YourTrainActionMode());
|
|
|
|
mActionMode.setTitle(R.string.your_train);
|
2012-10-11 00:21:30 +00:00
|
|
|
Departure boardedDeparture = getBoardedDeparture();
|
|
|
|
if (boardedDeparture != null && boardedDeparture.isAlarmPending()) {
|
|
|
|
int leadTime = boardedDeparture.getAlarmLeadTimeMinutes();
|
2012-10-02 04:03:08 +00:00
|
|
|
mActionMode.setSubtitle(getAlarmSubtitle(leadTime));
|
|
|
|
} else {
|
|
|
|
mActionMode.setSubtitle(null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private String getAlarmSubtitle(int leadTime) {
|
|
|
|
if (leadTime == 0)
|
|
|
|
return null;
|
|
|
|
return "Alarm " + leadTime + " minute" + (leadTime != 1 ? "s" : "")
|
|
|
|
+ " before departure";
|
|
|
|
}
|
|
|
|
|
|
|
|
private class YourTrainActionMode implements ActionMode.Callback {
|
|
|
|
private Observer<Boolean> mAlarmPendingObserver;
|
|
|
|
private Observer<Integer> mAlarmLeadTimeObserver;
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
|
|
|
mode.getMenuInflater()
|
|
|
|
.inflate(R.menu.your_train_context_menu, menu);
|
|
|
|
final MenuItem cancelAlarmButton = menu
|
|
|
|
.findItem(R.id.cancel_alarm_button);
|
|
|
|
final MenuItem setAlarmButton = menu
|
|
|
|
.findItem(R.id.set_alarm_button);
|
2012-10-11 00:21:30 +00:00
|
|
|
final Departure boardedDeparture = getBoardedDeparture();
|
2012-10-04 00:36:56 +00:00
|
|
|
|
|
|
|
if (boardedDeparture == null) {
|
|
|
|
mode.finish();
|
2012-10-09 21:22:21 +00:00
|
|
|
refreshBoardedDeparture(true);
|
2012-10-04 00:36:56 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-10-02 04:03:08 +00:00
|
|
|
if (boardedDeparture.isAlarmPending()) {
|
|
|
|
cancelAlarmButton.setVisible(true);
|
|
|
|
setAlarmButton.setIcon(R.drawable.ic_action_alarm);
|
|
|
|
} else if (boardedDeparture.getMeanSecondsLeft() > 60) {
|
|
|
|
setAlarmButton.setIcon(R.drawable.ic_action_add_alarm);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't allow alarm setting if train is about to leave
|
|
|
|
if (boardedDeparture.getMeanSecondsLeft() / 60 < 1) {
|
|
|
|
menu.findItem(R.id.set_alarm_button).setVisible(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
mAlarmPendingObserver = new Observer<Boolean>() {
|
|
|
|
@Override
|
|
|
|
public void onUpdate(final Boolean newValue) {
|
|
|
|
runOnUiThread(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
cancelAlarmButton.setVisible(newValue);
|
|
|
|
if (newValue) {
|
|
|
|
mActionMode
|
|
|
|
.setSubtitle(getAlarmSubtitle(boardedDeparture
|
|
|
|
.getAlarmLeadTimeMinutes()));
|
|
|
|
setAlarmButton
|
|
|
|
.setIcon(R.drawable.ic_action_alarm);
|
|
|
|
} else {
|
|
|
|
mActionMode.setSubtitle(null);
|
|
|
|
setAlarmButton
|
|
|
|
.setIcon(R.drawable.ic_action_add_alarm);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
mAlarmLeadTimeObserver = new Observer<Integer>() {
|
|
|
|
@Override
|
|
|
|
public void onUpdate(final Integer newValue) {
|
|
|
|
runOnUiThread(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
mActionMode.setSubtitle(getAlarmSubtitle(newValue));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
boardedDeparture.getAlarmPendingObservable().registerObserver(
|
|
|
|
mAlarmPendingObserver);
|
|
|
|
boardedDeparture.getAlarmLeadTimeMinutesObservable()
|
|
|
|
.registerObserver(mAlarmLeadTimeObserver);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
|
|
|
getListView().clearChoices();
|
|
|
|
getListView().requestLayout();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
|
|
|
final int itemId = item.getItemId();
|
|
|
|
if (itemId == R.id.set_alarm_button) {
|
|
|
|
// Don't prompt for alarm if train is about to leave
|
2012-10-11 00:21:30 +00:00
|
|
|
if (getBoardedDeparture().getMeanSecondsLeft() > 60) {
|
2012-10-03 19:29:31 +00:00
|
|
|
new TrainAlarmDialogFragment()
|
|
|
|
.show(getSupportFragmentManager()
|
|
|
|
.beginTransaction());
|
2012-10-02 04:03:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
} else if (itemId == R.id.cancel_alarm_button) {
|
|
|
|
Intent intent = new Intent(ViewDeparturesActivity.this,
|
|
|
|
BoardedDepartureService.class);
|
|
|
|
intent.putExtra("cancelNotifications", true);
|
|
|
|
startService(intent);
|
|
|
|
return true;
|
|
|
|
} else if (itemId == R.id.delete) {
|
2012-10-05 05:52:42 +00:00
|
|
|
mSwipeHelper.dismissWithAnimation(true);
|
2012-10-02 04:03:08 +00:00
|
|
|
mode.finish();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDestroyActionMode(ActionMode mode) {
|
|
|
|
((Checkable) findViewById(R.id.yourTrainSection)).setChecked(false);
|
|
|
|
|
2012-10-11 00:21:30 +00:00
|
|
|
final Departure boardedDeparture = getBoardedDeparture();
|
2012-10-02 04:03:08 +00:00
|
|
|
if (boardedDeparture != null) {
|
|
|
|
boardedDeparture.getAlarmPendingObservable()
|
|
|
|
.unregisterObserver(mAlarmPendingObserver);
|
|
|
|
boardedDeparture.getAlarmLeadTimeMinutesObservable()
|
|
|
|
.unregisterObserver(mAlarmLeadTimeObserver);
|
|
|
|
}
|
|
|
|
|
|
|
|
mAlarmPendingObserver = null;
|
|
|
|
mAlarmLeadTimeObserver = null;
|
|
|
|
mActionMode = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-03 20:07:19 +00:00
|
|
|
private void dismissYourTrainSelection() {
|
|
|
|
Intent intent = new Intent(ViewDeparturesActivity.this,
|
|
|
|
BoardedDepartureService.class);
|
|
|
|
intent.putExtra("clearBoardedDeparture", true);
|
|
|
|
startService(intent);
|
|
|
|
hideYourTrainSection();
|
|
|
|
}
|
|
|
|
|
2012-09-25 21:31:06 +00:00
|
|
|
@Override
|
|
|
|
public void onETDChanged(final List<Departure> departures) {
|
|
|
|
runOnUiThread(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
if (departures.isEmpty()) {
|
|
|
|
final TextView textView = mEmptyView;
|
|
|
|
textView.setText(R.string.no_data_message);
|
2012-10-03 19:29:31 +00:00
|
|
|
mProgress.setVisibility(View.GONE);
|
2012-09-25 21:31:06 +00:00
|
|
|
Linkify.addLinks(textView, Linkify.WEB_URLS);
|
|
|
|
} else {
|
2012-10-02 04:03:08 +00:00
|
|
|
// TODO: Figure out why Ticker occasionally stops
|
|
|
|
Ticker.getInstance().startTicking(
|
|
|
|
ViewDeparturesActivity.this);
|
|
|
|
|
2012-10-11 00:21:30 +00:00
|
|
|
Departure boardedDeparture = getBoardedDeparture();
|
|
|
|
boolean boardedDepartureFound = false;
|
|
|
|
|
2012-09-25 21:31:06 +00:00
|
|
|
// Merge lists
|
|
|
|
if (mDeparturesAdapter.getCount() > 0) {
|
|
|
|
int adapterIndex = -1;
|
|
|
|
for (Departure departure : departures) {
|
2012-10-11 00:21:30 +00:00
|
|
|
if (!boardedDepartureFound
|
|
|
|
&& departure.equals(boardedDeparture)) {
|
|
|
|
boardedDepartureFound = true;
|
|
|
|
}
|
|
|
|
|
2012-09-25 21:31:06 +00:00
|
|
|
adapterIndex++;
|
|
|
|
Departure existingDeparture = null;
|
|
|
|
if (adapterIndex < mDeparturesAdapter.getCount()) {
|
|
|
|
existingDeparture = mDeparturesAdapter
|
|
|
|
.getItem(adapterIndex);
|
|
|
|
}
|
|
|
|
while (existingDeparture != null
|
|
|
|
&& !departure.equals(existingDeparture)) {
|
|
|
|
mDeparturesAdapter.remove(existingDeparture);
|
|
|
|
if (adapterIndex < mDeparturesAdapter
|
|
|
|
.getCount()) {
|
|
|
|
existingDeparture = mDeparturesAdapter
|
|
|
|
.getItem(adapterIndex);
|
|
|
|
} else {
|
|
|
|
existingDeparture = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (existingDeparture != null) {
|
|
|
|
existingDeparture.mergeEstimate(departure);
|
|
|
|
} else {
|
|
|
|
mDeparturesAdapter.add(departure);
|
|
|
|
existingDeparture = departure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
final DepartureArrayAdapter listAdapter = getListAdapter();
|
|
|
|
listAdapter.clear();
|
|
|
|
for (Departure departure : departures) {
|
|
|
|
listAdapter.add(departure);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-11 00:21:30 +00:00
|
|
|
if (doesDepartureApply(boardedDeparture)
|
|
|
|
&& !boardedDepartureFound) {
|
|
|
|
boardedDeparture.setListedInETDs(false);
|
|
|
|
}
|
|
|
|
|
2012-10-09 21:22:21 +00:00
|
|
|
refreshBoardedDeparture(true);
|
2012-09-25 21:31:06 +00:00
|
|
|
|
|
|
|
getListAdapter().notifyDataSetChanged();
|
2012-10-05 05:52:42 +00:00
|
|
|
|
|
|
|
refreshListSelection();
|
2012-09-25 21:31:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2012-10-05 05:52:42 +00:00
|
|
|
private void refreshListSelection() {
|
|
|
|
getListView().clearChoices();
|
|
|
|
final Departure targetDeparture;
|
|
|
|
if (isDepartureActionModeActive() && mSelectedDeparture != null) {
|
|
|
|
targetDeparture = mSelectedDeparture;
|
|
|
|
} else {
|
2012-10-11 00:21:30 +00:00
|
|
|
targetDeparture = getBoardedDeparture();
|
2012-10-05 05:52:42 +00:00
|
|
|
}
|
|
|
|
for (int i = getListAdapter().getCount() - 1; i >= 0; i--) {
|
|
|
|
if (getListAdapter().getItem(i).equals(targetDeparture)) {
|
|
|
|
final int selectedIndex = i;
|
|
|
|
getListView().post(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
getListView().setSelection(selectedIndex);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
getListView().requestLayout();
|
|
|
|
}
|
|
|
|
|
2012-09-25 21:31:06 +00:00
|
|
|
@Override
|
|
|
|
public void onError(final String errorMessage) {
|
|
|
|
runOnUiThread(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
Toast.makeText(ViewDeparturesActivity.this, errorMessage,
|
|
|
|
Toast.LENGTH_LONG).show();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onRequestStarted() {
|
|
|
|
runOnUiThread(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
mProgress.setVisibility(View.VISIBLE);
|
2012-10-03 20:11:34 +00:00
|
|
|
mMissingDepartureText.setVisibility(View.GONE);
|
2012-09-25 21:31:06 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onRequestEnded() {
|
|
|
|
runOnUiThread(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
2012-10-03 19:29:31 +00:00
|
|
|
mProgress.setVisibility(View.GONE);
|
2012-10-03 20:11:34 +00:00
|
|
|
mMissingDepartureText.setVisibility(View.VISIBLE);
|
2012-09-25 21:31:06 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public StationPair getStationPair() {
|
|
|
|
if (mOrigin == null || mDestination == null)
|
|
|
|
return null;
|
|
|
|
return new StationPair(mOrigin, mDestination);
|
|
|
|
}
|
2012-10-02 04:03:08 +00:00
|
|
|
|
|
|
|
private void hideYourTrainSection() {
|
2012-10-05 05:52:42 +00:00
|
|
|
mYourTrainSection.setVisibility(View.GONE);
|
2012-10-02 04:03:08 +00:00
|
|
|
}
|
|
|
|
|
2012-10-09 21:22:21 +00:00
|
|
|
private void showYourTrainSection(boolean animate) {
|
2012-10-05 05:52:42 +00:00
|
|
|
mYourTrainSection.setVisibility(View.VISIBLE);
|
2012-10-09 21:22:21 +00:00
|
|
|
if (animate) {
|
|
|
|
mSwipeHelper.showWithAnimation();
|
|
|
|
}
|
2012-10-02 04:03:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private boolean isYourTrainActionModeActive() {
|
|
|
|
return mActionMode != null
|
|
|
|
&& mActionMode.getTitle()
|
|
|
|
.equals(getString(R.string.your_train));
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean isDepartureActionModeActive() {
|
|
|
|
return mActionMode != null
|
|
|
|
&& !mActionMode.getTitle().equals(
|
|
|
|
getString(R.string.your_train));
|
|
|
|
}
|
2012-10-11 00:21:30 +00:00
|
|
|
|
|
|
|
private Departure getBoardedDeparture() {
|
|
|
|
return ((BartRunnerApplication) getApplication()).getBoardedDeparture();
|
|
|
|
}
|
2012-09-25 21:31:06 +00:00
|
|
|
}
|