package com.love.apps.BT4U; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.StringReader; import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.DialogInterface.OnClickListener; import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; import android.os.Vibrator; import android.preference.PreferenceManager; import android.util.Log; import android.view.View; import android.view.WindowManager; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.Toast; import com.actionbarsherlock.app.SherlockListFragment; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import com.love.apps.BT4U.webservice.BT4U; import com.love.apps.BT4U.webservice.ScheduledDeparture; public class Favorites extends SherlockListFragment { static private String[] Items = null;// used to hold items that are in the // list view private boolean longClick_ = false; // used to tell the gui if click was // long click or short click ArrayAdapter<String> adapter_ = null; // holds list for listview static Map<Integer, FavoriteStop> favorites_ = new HashMap<Integer, FavoriteStop>();// holds // all // data // for // each // favorite AlertDialog.Builder alert = null; // pop window public static final String PREFS_NAME = "MyPrefsFile"; static private Favorites favs = null; static public Favorites getFavorites() { return favs; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); favs = this; } static SherlockListFragment currActivity = null; @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setHasOptionsMenu(true); currActivity = this; favorites_.put(0, new FavoriteStop()); this.getActivity() .getWindow() .setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); boolean isSDpresent = android.os.Environment.getExternalStorageState() .equals(android.os.Environment.MEDIA_MOUNTED); if (isSDpresent) { updateFavorites(getActivity()); } if (Items == (null)) { Items = new String[1]; Items[0] = "EMPTY"; } adapter_ = new ArrayAdapter<String>(currActivity.getActivity(), R.layout.list_item, Items); setListAdapter(adapter_); ListView lv = getListView(); lv.setTextFilterEnabled(true); // sets up what happens if items are clicked lv.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { if (longClick_) { longClick_ = false; return; } if (favorites_.isEmpty()) return; showDialog(favorites_.get(arg2)); updateAdapter(currActivity.getActivity()); makeToast("Getting Stop Data"); } }); // sets up what happens if items are long clicked lv.setOnItemLongClickListener(new OnItemLongClickListener() { public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { // Get instance of Vibrator from current Context Vibrator v = (Vibrator) currActivity.getActivity() .getSystemService(Context.VIBRATOR_SERVICE); // Vibrate for 300 milliseconds v.vibrate(50); longClick_ = true; AlertDialog.Builder alert = getRemoveDialog(favorites_, arg2); alert.show(); return false; } }); } // updates the list adapter if a stop is added or removed protected void updateAdapter(Context currActivity) { adapter_ = new ArrayAdapter<String>(currActivity, R.layout.list_item, Items); setListAdapter(adapter_); adapter_.notifyDataSetChanged(); } // shows the stop times in new window for giiven stop private void showDialog(FavoriteStop s) { if (favorites_.isEmpty()) return; alert = new AlertDialog.Builder(currActivity.getActivity()); TimeGetter tg = new TimeGetter(); tg.execute(s.shortRoute, s.stopCode); } // puts up toast notification that says message public static void makeToast(String message) { Toast.makeText(currActivity.getActivity(), message, Toast.LENGTH_SHORT) .show(); } // shows remove dialog for given stop private AlertDialog.Builder getRemoveDialog( final Map<Integer, FavoriteStop> favorites, final int index) { AlertDialog.Builder alert = new AlertDialog.Builder( currActivity.getActivity()); alert.setTitle("Remove Favorite"); alert.setMessage("would you like to remove this stop?"); // Set an EditText view to get user input alert.setPositiveButton("Yes", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // String value = input.getText().toString(); // Do something with value! favorites.remove(index); Object[] keys = favorites.keySet().toArray(); String fileData = ""; for (int i = 0; i < favorites.size(); i++) { FavoriteStop temp = favorites.get(keys[i]); fileData += temp.name + "," + temp.shortRoute + "," + temp.location + "," + temp.stopCode + "\n"; } File storage = getOrCreateFavoritesStorage(getActivity()); if (storage == null) { Toast.makeText(getActivity(), "Unable to load favorites. Is your SD card busy?", Toast.LENGTH_LONG).show(); return; } /* * FileWriter writer = null; try { writer = new * FileWriter(storage); writer.write(fileData); } catch * (IOException e) { e.printStackTrace(); } finally { try { * writer.close(); } catch (IOException e) { * e.printStackTrace(); } } */ FileOutputStream fos = null; try { fos = new FileOutputStream(storage); fos.write(fileData.getBytes()); fos.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } updateFavorites(getActivity()); updateAdapter(currActivity.getActivity()); makeToast("Stop was removed"); } }); alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { } }); return alert; } /** * * @return null if an error occurs, such as the SD card not being present. * Otherwise returns a write-ready file that can be wrappered with * something like {@link FileOutputStream} */ // Due to a bug in Froyo (see // https://groups.google.com/forum/?fromgroups=#!topic/android-developers/to1AsfE-Et8) // the app files (e.g. favorites list) will be deleted when a user updates // the application. It's hard to tell what devices this affects, but it // will not affect pushing this application version out, because we are // moving from the old (non proper) storage scheme. Version after this may // encounter the issue. public static File getOrCreateFavoritesStorage(Context c) { File directory = c.getExternalFilesDir(null); if (directory == null) { log("External storage not available"); return null; } File favs = new File(directory, "favorites.txt"); try { favs.createNewFile(); } catch (IOException e) { log("Unable to create new favorite file"); e.printStackTrace(); } return favs; } // class for holding stop information // refreshes the items list private static void refreshItems() { if (favorites_.isEmpty()) return; Items = new String[favorites_.size()]; for (int i = 0; i < favorites_.size(); i++) { FavoriteStop temp = favorites_.get(i); Items[i] = "Route: " + temp.name + "\nLocation:" + temp.location.split("-")[1] + "\nStop Code: " + temp.stopCode; } try { if (favs != null && currActivity != null) favs.setListAdapter(new ArrayAdapter<String>(currActivity .getActivity(), R.layout.list_item, Items)); } catch (Exception e) {// Catch exception if any Log.i("Favorites", "null pointer oh well"); } } // updates entire favorites list public void updateFavorites(Context c) { log("Updating favorites"); try { File favs = getOrCreateFavoritesStorage(c); if (favs == null) { log("Unable to update favorites"); return; } BufferedReader br = new BufferedReader(new InputStreamReader( new FileInputStream(favs))); String strLine = ""; // Read File Line By Line int i = 0; favorites_.clear(); while ((strLine = br.readLine()) != null) { // Print the content on the console // String[] allWords; StringTokenizer st = new StringTokenizer(strLine, ","); FavoriteStop stop = new FavoriteStop(); stop.name = st.nextToken(); stop.shortRoute = st.nextToken(); stop.location = st.nextToken(); stop.stopCode = st.nextToken(); favorites_.put(i, stop); i++; } br.close(); refreshItems(); } catch (FileNotFoundException fnf) { log("Favorites storage file not found"); } catch (Exception e) { log("Unknown exception when updating favorites: " + e.getMessage()); e.printStackTrace(); } } class TimeGetter extends AsyncTask<Object, Void, List<Arrival>> { /** * Our @link TimeGetter requires two parameters. params[0] should be the * route code, such as HWD, and params[1] should be the stop code, such * as 1103 (as either a String or Integer) */ @Override protected List<Arrival> doInBackground(Object... params) { String routeCode = (String) params[0]; int stopCode = -1; try { stopCode = Integer.parseInt((String) params[1]); } catch (NumberFormatException nfe) { log("TimeGetter was passed " + params[1] + ", which could not be parsed to an int"); return new ArrayList<Arrival>(); } ///New Stuff Here List<Arrival> AdjustedDepartureTimes = new ArrayList<Arrival>(); BufferedReader in = null; try { HttpClient client = new DefaultHttpClient(); //HttpGet request = new HttpGet(); HttpPost request = new HttpPost(); request.setURI(new URI("http://www.bt4u.org/webservices/bt4u_webservice.asmx/GetNextDepartures")); ArrayList<NameValuePair> params1 = new ArrayList<NameValuePair>(); params1.add(new BasicNameValuePair("routeShortName", routeCode)); params1.add(new BasicNameValuePair("stopCode", (String) params[1])); UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(params1); request.setEntity(formEntity); HttpResponse response = client.execute(request); in = new BufferedReader (new InputStreamReader(response.getEntity().getContent())); StringBuffer sb = new StringBuffer(""); String line = ""; String NL = System.getProperty("line.separator"); while ((line = in.readLine()) != null) { sb.append(line + NL); } in.close(); String page = sb.toString(); //System.out.println("HERE IS Time Getter Response\n\n" + page); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); InputSource is = new InputSource(new StringReader(page)); Document doc = builder.parse(is); NodeList currentRoutesRunning = doc.getElementsByTagName("NextDepartures"); log("Number of nodes in TimeGetter: " + currentRoutesRunning.getLength()); for (int i = 0; i < currentRoutesRunning.getLength(); ++i) { //log("Node Value: " + ((Element) currentRoutesRunning.item(i)).getElementsByTagName("RouteShortName").item(0).getNodeValue()); Element currentRoute = (Element) currentRoutesRunning.item(i); //String labTestType = currentRoute.getAttribute("RouteShortName"); Element AdjustedDepartureTime = (Element) (currentRoute.getElementsByTagName("AdjustedDepartureTime").item(0)); String AdjustedDepartureTimeString = AdjustedDepartureTime.getFirstChild().getNodeValue(); Arrival tempArrival = new Arrival(AdjustedDepartureTimeString); AdjustedDepartureTimes.add(tempArrival); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } //END if (AdjustedDepartureTimes.size() == 0) return new ArrayList<Arrival>(); SharedPreferences sharedPref = PreferenceManager .getDefaultSharedPreferences(Favorites.this.getActivity()); int timesToShow = Integer.parseInt(sharedPref.getString("timesToShow", "5")); int i = 0; List<Arrival> result = new ArrayList<Arrival>(); for (Arrival arrival : AdjustedDepartureTimes) { if (i++ > timesToShow) break; Arrival a = arrival; result.add(a); } return result; } @Override protected void onPostExecute(List<Arrival> stops) { if(stops.size() == 0) { showNoStopAlert(); return; } try { SharedPreferences sharedPref = PreferenceManager .getDefaultSharedPreferences(Favorites.this .getActivity()); int times2Show = Integer.parseInt(sharedPref.getString("timesToShow", "5")); StringBuffer buffer = new StringBuffer(""); int i = 0; for (Arrival a : stops) { if (i++ > times2Show) break; buffer.append(a.getTime()).append(" - ") .append(a.timeUntil()); if (a.note.length() != 0) buffer.append(" *").append(a.note); buffer.append("\n"); } alert.setTitle("Next Stop Times"); alert.setMessage(buffer.toString()); // Set an EditText view to get user input alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // String value = input.getText().toString(); // Do something with value! } }); alert.show(); } catch (Exception e) { e.printStackTrace(); } } } static class FavoriteStop { public String name = null; public String location = null; public String stopCode = null; public String shortRoute = null; } private final int settingsId = 1; @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { MenuItem addFavItem = menu.add(Menu.NONE, settingsId, settingsId, "Settings"); addFavItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case settingsId: Intent i = new Intent(this.getActivity(), SettingsActivity.class); startActivity(i); return true; } return false; } @Override public void onResume() { super.onResume(); adapter_ = new ArrayAdapter<String>(this.getActivity(), R.layout.list_item, Items); setListAdapter(adapter_); log("OnResume"); } private static void log(String message) { Log.i("Favorites", message); } public static void addStopToFavorites(Context c, String routeName, String routeCode, String stopName, String stopCode) { File favs = Favorites.getOrCreateFavoritesStorage(c); if (favs == null) { Toast.makeText(c, "Unable to access favorites. Is your SD card available?", Toast.LENGTH_LONG).show(); return; } String yourdata = routeName + "," + routeCode + "," + stopName + "," + stopCode + "\n"; BufferedOutputStream output; try { output = new BufferedOutputStream(new FileOutputStream(favs, true)); output.write(yourdata.getBytes()); output.close(); } catch (FileNotFoundException e) { log("Unable to find the favorites"); e.printStackTrace(); Toast.makeText(c, "Error: Unable to access favorites", Toast.LENGTH_SHORT).show(); return; } catch (IOException e) { log("Unable to write favorites"); e.printStackTrace(); Toast.makeText(c, "Error: Unable to access favorites", Toast.LENGTH_SHORT).show(); return; } Toast.makeText(c, "Saved to Favorites", Toast.LENGTH_SHORT).show(); } public static void checkForOldFavorites(Context c) { boolean isSDpresent = android.os.Environment.getExternalStorageState() .equals(android.os.Environment.MEDIA_MOUNTED); if (isSDpresent) { String path = Environment.getExternalStorageDirectory() + "/BT4U/"; File root = new File(path); File f = new File(root, "favorites.txt"); if (!f.exists()) { log("Old favorites not found"); return; } log("Old Favorite file found, migrating contents"); // Copy old favorites content String content = ""; FileReader r; try { r = new FileReader(f); c.openFileOutput("favorites.txt", Context.MODE_APPEND); BufferedReader br = new BufferedReader(r); String line = null; while ((line = br.readLine()) != null) { content += line; content += "\n"; } br.close(); } catch (FileNotFoundException e) { log("Unable to load the old favorites file. Aborting"); e.printStackTrace(); return; } catch (IOException e) { log("Unable to read the old favorites file. Aborting"); e.printStackTrace(); return; } // Write new file before deleting old one File favs = getOrCreateFavoritesStorage(c); if (favs == null) { log("Unable to get a handle on new favorites file, aborting"); return; } BufferedOutputStream output; try { output = new BufferedOutputStream(new FileOutputStream(favs)); output.write(content.getBytes()); output.close(); } catch (FileNotFoundException e) { log("Unable to load the new favorites file. Aborting"); e.printStackTrace(); return; } catch (IOException e) { log("Unable to write the new favorites file. Aborting"); e.printStackTrace(); return; } log("Migration of contents successful"); log("Deleting old favorites.txt: " + f.delete()); log("Deleting BT4U folder: " + root.delete()); } } private void showNoStopAlert() { AlertDialog.Builder builder = new AlertDialog.Builder(Favorites.this.getActivity()); builder.setTitle("No More Scheduled Stops"); builder.setMessage("There doesn't seem to be any more scheduled stops here for today" + "\n\nYou may want to start walking..."); builder.setPositiveButton("OK", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub } }); builder.show(); } }