package com.transitwidget.fragments; import android.app.Activity; import android.database.Cursor; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.TextView; import com.actionbarsherlock.app.SherlockFragment; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import com.transitwidget.R; import com.transitwidget.api.NextBusAPI; import com.transitwidget.feed.model.BusPrediction; import com.transitwidget.feed.model.Direction; import com.transitwidget.feed.model.Favorite; import com.transitwidget.feed.model.Stop; import com.transitwidget.utils.TimeUtils; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; public class StopFragment extends SherlockFragment { private static final String TAG = StopFragment.class.getName(); public static final String ARG_STOP_TAG = "stop"; public static final String ARG_ROUTE_TAG = "route"; public static final String ARG_DIRECTION_TAG = "direction"; public static final String ARG_AGENCY_TAG = "agency"; public final static String ITEM_TITLE = "title"; public final static String ITEM_CAPTION = "caption"; private TextView mStopLabel; private TextView mNextTime; private TextView mAbsoluteTime; private ListView mMorePredictions; private Stop mStop; private String mDirection; private String mDirectionTitle; private String mRoute; private String mAgency; private List<BusPrediction> mPredictions; private boolean mFavorite = false; private Activity mActivity = null; public Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { } }; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.stop, container, false); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mStopLabel = (TextView) view.findViewById(R.id.stop); mNextTime = (TextView) view.findViewById(R.id.next_time); mAbsoluteTime = (TextView) view.findViewById(R.id.absolute_time); mMorePredictions = (ListView) view.findViewById(R.id.more_predictions); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mActivity = getActivity(); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { MenuItem.OnMenuItemClickListener listener = new MenuItem.OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem item) { Log.i(TAG, "Changing favorite status of stop " + mStop); String selection = Favorite.AGENCY + " = ? AND " + Favorite.ROUTE + " = ? AND " + Favorite.STOP + " = ?"; String[] selectionArgs = {mAgency, mRoute, mStop.getTag()}; if (mFavorite) { // remove favorite getActivity().getContentResolver().delete(Favorite.CONTENT_URI, selection, selectionArgs); } else { // add favorite Favorite fav = new Favorite(); fav.setAgency(mAgency); fav.setRoute(mRoute); fav.setStop(mStop.getTag()); fav.setDirection(mDirection); // convenience data for list display fav.setDirectionLabel(mDirectionTitle); fav.setStopLabel(mStop.getTitle()); getActivity().getContentResolver().insert(Favorite.CONTENT_URI, fav.getContentValues()); } mFavorite = !mFavorite; // flip menu item if (mFavorite) { item.setIcon(R.drawable.heart_red); item.setTitle("-Fav"); } else { item.setIcon(R.drawable.heart); item.setTitle("+Fav"); } return true; } }; MenuItem item; if (mFavorite) { item = menu.add("-Fav").setIcon(R.drawable.heart_red); } else { item = menu.add("+Fav").setIcon(R.drawable.heart); } item.setOnMenuItemClickListener(listener).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); } @Override public void onStart() { super.onStart(); final String stopTag = getArguments().getString(ARG_STOP_TAG); mAgency = getArguments().getString(ARG_AGENCY_TAG); mRoute = getArguments().getString(ARG_ROUTE_TAG); mDirection = getArguments().getString(ARG_DIRECTION_TAG); Log.i(TAG, "Loading stop with agency: " + mAgency + ", route: " + mRoute + ", direction: " + mDirection); // Lookup direction String selection = Direction.AGENCY + " = ? AND " + Direction.ROUTE + " = ? AND " + Direction.TAG + " = ?"; String[] selectionArgs = { mAgency, mRoute, mDirection }; Cursor c = getActivity().getContentResolver().query(Direction.CONTENT_URI, null, selection, selectionArgs, null); if (c.moveToFirst()) { mDirectionTitle = new Direction(c, getActivity()).getTitle(); } else { Log.e(TAG, "Unable to lookup direction with tag " + mDirection); mDirectionTitle = mDirection; } c.close(); // Lookup stop selection = Stop.TAG + " = ? AND " + Stop.AGENCY + " = ?"; selectionArgs = new String[] {stopTag, mAgency}; Cursor result = mActivity.getContentResolver().query(Stop.CONTENT_URI, null, selection, selectionArgs, null); if (result.moveToFirst()) { mStop = new Stop(result); mStopLabel.setText(mStop.getTitle()); mFavorite = isFavorite(); } result.close(); setHasOptionsMenu(true); } @Override public void onResume() { super.onResume(); Log.i(TAG, "Starting bus prediction check"); // mHandler.post(new UpdateRunnable()); mHandler.post(new UpdateRunnable()); } private boolean isFavorite() { boolean favorite = false; String selection = Favorite.AGENCY + " = ? AND " + Favorite.ROUTE + " = ? AND " + Favorite.STOP + " = ?"; String[] selectionArgs = {mAgency, mRoute, mStop.getTag()}; Cursor c = getActivity().getContentResolver().query(Favorite.CONTENT_URI, new String[] {Favorite._ID}, selection , selectionArgs, null); if (c.moveToFirst()) { favorite = true; } c.close(); return favorite; } class UpdateTask extends AsyncTask<String, String, List<BusPrediction>> { private final String TAG = UpdateTask.class.getName(); @Override protected List<BusPrediction> doInBackground(String... params) { // Update the data, send notification List<BusPrediction> predictions = new NextBusAPI().getPredictions(mAgency, mStop.getTag(), mDirection, mRoute); Log.i(TAG, "Got predictions: " + predictions); if (predictions == null) { Log.w(TAG, "Unable to load predictions"); return null; } return predictions; } @Override protected void onPostExecute(List<BusPrediction> predictions) { Log.i(TAG, "Got bus predictions: " + predictions); mPredictions = predictions; updateUI(); } } private void updateUI() { if (mPredictions == null) { // Show no data message } else if (mPredictions.size() == 0) { mNextTime.setText("No Prediction Data"); mAbsoluteTime.setText(""); mMorePredictions.setAdapter(null); } else { BusPrediction nextPrediction = mPredictions.get(0); String nextTime = TimeUtils.formatTimeOfNextBus(nextPrediction.getEpochTime()); String absoluteTime = TimeUtils.formatAbsoluteTimeOfNextBus(nextPrediction.getEpochTime()); mNextTime.setText(nextTime); mAbsoluteTime.setText(absoluteTime); List<Map<String,?>> predictionsList = new LinkedList<Map<String,?>>(); boolean skipFirst = true; for (BusPrediction prediction : mPredictions) { if (skipFirst) { skipFirst = false; continue; } long predictionTime = prediction.getEpochTime(); String timeUntil = TimeUtils.formatTimeOfNextBus(predictionTime); String timeAt = TimeUtils.formatAbsoluteTimeOfNextBus(predictionTime); Map<String,String> item = new HashMap<String, String>(); item.put(ITEM_TITLE, timeUntil); item.put(ITEM_CAPTION, timeAt); predictionsList.add(item); } String[] mapping = { ITEM_TITLE, ITEM_CAPTION }; int[] fields = { R.id.list_title, R.id.list_caption }; if (getActivity() != null) { mMorePredictions.setAdapter(new SimpleAdapter(getActivity(), predictionsList, R.layout.list_complex, mapping, fields)); } } } class UpdateRunnable implements Runnable { int i = 0; public void run() { // stop updating if this fragment is no longer visible if (isResumed()) { updateUI(); if (i % 20 == 0) { i = 0; new UpdateTask().execute(); } i++; mHandler.postDelayed(this, 1000); } else { Log.i(TAG, "Stopping prediction check"); } } } }