Java tutorial
/** Cycle Altanta, Copyright 2012 Georgia Institute of Technology * Atlanta, GA. USA * * @author Christopher Le Dantec <ledantec@gatech.edu> * @author Anhong Guo <guoanhong15@gmail.com> * * Updated/Modified for Atlanta's app deployment. Based on the * CycleTracks codebase for SFCTA. * * CycleTracks, Copyright 2009,2010 San Francisco County Transportation Authority * San Francisco, CA, USA * * @author Billy Charlton <billy.charlton@sfcta.org> * * This file is part of CycleTracks. * * CycleTracks is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * CycleTracks is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CycleTracks. If not, see <http://www.gnu.org/licenses/>. */ package edu.auburn.ppl.cyclecolumbus; import android.content.Context; import android.database.Cursor; import android.os.AsyncTask; import android.provider.Settings.System; import android.util.Log; import android.widget.ListView; import android.widget.Toast; import org.json.JSONException; import org.json.JSONObject; import java.io.DataOutputStream; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.text.SimpleDateFormat; import java.util.HashMap; import java.util.Map; import java.util.Vector; public class NoteUploader extends AsyncTask<Long, Integer, Boolean> { Context mCtx; DbAdapter mDb; byte[] imageData; Boolean imageDataNull; public static final int kSaveNoteProtocolVersion = 4; public static final String NOTE_RECORDED = "r"; public static final String NOTE_LAT = "l"; public static final String NOTE_LGT = "n"; public static final String NOTE_HACC = "h"; public static final String NOTE_VACC = "v"; public static final String NOTE_ALT = "a"; public static final String NOTE_SPEED = "s"; public static final String NOTE_TYPE = "t"; public static final String NOTE_DETAILS = "d"; public static final String NOTE_IMGURL = "i"; private String responseMessage = "nullMsg"; private int responseCode = -1; private String deviceId = ""; String boundary = "cycle*******notedata*******columbus"; /* Constructor */ public NoteUploader(Context ctx) { super(); this.mCtx = ctx; this.mDb = new DbAdapter(this.mCtx); } /****************************************************************************************** * Generates JSONObject form of a note to be uploaded ****************************************************************************************** * @param noteId Unique note ID to be uploaded * @return JSONObject of the note * @throws JSONException ******************************************************************************************/ private JSONObject getNoteJSON(long noteId) throws JSONException { SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); mDb.openReadOnly(); Cursor noteCursor = mDb.fetchNote(noteId); Map<String, Integer> fieldMap = new HashMap<String, Integer>(); fieldMap.put(NOTE_RECORDED, noteCursor.getColumnIndex(DbAdapter.K_NOTE_RECORDED)); fieldMap.put(NOTE_LAT, noteCursor.getColumnIndex(DbAdapter.K_NOTE_LAT)); fieldMap.put(NOTE_LGT, noteCursor.getColumnIndex(DbAdapter.K_NOTE_LGT)); fieldMap.put(NOTE_HACC, noteCursor.getColumnIndex(DbAdapter.K_NOTE_ACC)); fieldMap.put(NOTE_VACC, noteCursor.getColumnIndex(DbAdapter.K_NOTE_ACC)); fieldMap.put(NOTE_ALT, noteCursor.getColumnIndex(DbAdapter.K_NOTE_ALT)); fieldMap.put(NOTE_SPEED, noteCursor.getColumnIndex(DbAdapter.K_NOTE_SPEED)); fieldMap.put(NOTE_TYPE, noteCursor.getColumnIndex(DbAdapter.K_NOTE_TYPE)); fieldMap.put(NOTE_DETAILS, noteCursor.getColumnIndex(DbAdapter.K_NOTE_DETAILS)); fieldMap.put(NOTE_IMGURL, noteCursor.getColumnIndex(DbAdapter.K_NOTE_IMGURL)); JSONObject note = new JSONObject(); note.put(NOTE_RECORDED, df.format(noteCursor.getDouble(fieldMap.get(NOTE_RECORDED)))); note.put(NOTE_LAT, noteCursor.getDouble(fieldMap.get(NOTE_LAT)) / 1E6); note.put(NOTE_LGT, noteCursor.getDouble(fieldMap.get(NOTE_LGT)) / 1E6); note.put(NOTE_HACC, noteCursor.getDouble(fieldMap.get(NOTE_HACC))); note.put(NOTE_VACC, noteCursor.getDouble(fieldMap.get(NOTE_VACC))); note.put(NOTE_ALT, noteCursor.getDouble(fieldMap.get(NOTE_ALT))); note.put(NOTE_SPEED, noteCursor.getDouble(fieldMap.get(NOTE_SPEED))); note.put(NOTE_TYPE, noteCursor.getInt(fieldMap.get(NOTE_TYPE))); note.put(NOTE_DETAILS, noteCursor.getString(fieldMap.get(NOTE_DETAILS))); note.put(NOTE_IMGURL, noteCursor.getString(fieldMap.get(NOTE_IMGURL))); if (noteCursor.getString(fieldMap.get(NOTE_IMGURL)).equals("")) { imageDataNull = true; } else { imageDataNull = false; imageData = noteCursor.getBlob(noteCursor.getColumnIndex(DbAdapter.K_NOTE_IMGDATA)); } noteCursor.close(); mDb.close(); return note; } /****************************************************************************************** * Generates a length 32 string that is the device ID * Must be 32 to match iOS because server looks for length 32 ****************************************************************************************** * @return String form of the device ID ******************************************************************************************/ public String getDeviceId() { String androidId = System.getString(this.mCtx.getContentResolver(), System.ANDROID_ID); String androidBase = "androidDeviceId-"; if (androidId == null) { // This happens when running in the Emulator final String emulatorId = "android-RunningAsTestingDeleteMe"; return emulatorId; } String deviceId = androidBase.concat(androidId); // Fix String Length int a = deviceId.length(); if (a < 32) { for (int i = 0; i < 32 - a; i++) { deviceId = deviceId.concat("0"); } } else { deviceId = deviceId.substring(0, 32); } return deviceId; } /****************************************************************************************** * Uploads the note to the server ****************************************************************************************** * @param currentNoteId Unique note ID to be uploaded * @return True if uploaded, false if not ******************************************************************************************/ boolean uploadOneNote(long currentNoteId) { boolean result = false; final String postUrl = "http://FountainCityCycling.org/post/"; try { URL url = new URL(postUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setDoInput(true); // Allow Inputs conn.setDoOutput(true); // Allow Outputs conn.setUseCaches(false); // Don't use a Cached Copy conn.setRequestMethod("POST"); conn.setRequestProperty("Connection", "Keep-Alive"); conn.setRequestProperty("ENCTYPE", "multipart/form-data"); conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); conn.setRequestProperty("Cycleatl-Protocol-Version", "4"); /* Change protocol to 2 for Note, and change the point where you zip up the body. (Dont zip up trip body) Since notes don't work either, this may not solve it. */ DataOutputStream dos = new DataOutputStream(conn.getOutputStream()); JSONObject note = getNoteJSON(currentNoteId); deviceId = getDeviceId(); dos.writeBytes("--cycle*******notedata*******columbus\r\n" + "Content-Disposition: form-data; name=\"note\"\r\n\r\n" + note.toString() + "\r\n"); dos.writeBytes("--cycle*******notedata*******columbus\r\n" + "Content-Disposition: form-data; name=\"version\"\r\n\r\n" + String.valueOf(kSaveNoteProtocolVersion) + "\r\n"); dos.writeBytes("--cycle*******notedata*******columbus\r\n" + "Content-Disposition: form-data; name=\"device\"\r\n\r\n" + deviceId + "\r\n"); if (imageDataNull == false) { dos.writeBytes("--cycle*******notedata*******columbus\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\"" + deviceId + ".jpg\"\r\n" + "Content-Type: image/jpeg\r\n\r\n"); dos.write(imageData); dos.writeBytes("\r\n"); } dos.writeBytes("--cycle*******notedata*******columbus--\r\n"); dos.flush(); dos.close(); int serverResponseCode = conn.getResponseCode(); String serverResponseMessage = conn.getResponseMessage(); // JSONObject responseData = new JSONObject(serverResponseMessage); Log.v("KENNY", "HTTP Response is : " + serverResponseMessage + ": " + serverResponseCode); responseMessage = serverResponseMessage; responseCode = serverResponseCode; // 200 - 202 means successfully went to server and uploaded if (serverResponseCode == 200 || serverResponseCode == 201 || serverResponseCode == 202) { mDb.open(); mDb.updateNoteStatus(currentNoteId, NoteData.STATUS_SENT); mDb.close(); result = true; } } catch (IllegalStateException e) { Log.d("KENNY", "Note Catch: Illegal State Exception: " + e); e.printStackTrace(); return false; } catch (IOException e) { Log.d("KENNY", "Note Catch: IOException: " + e); e.printStackTrace(); return false; } catch (JSONException e) { Log.d("KENNY", "Note Catch: JSONException: " + e); e.printStackTrace(); return false; } return result; } @Override protected Boolean doInBackground(Long... noteid) { // First, send the note user asked for: Boolean result = true; if (noteid.length != 0) { result = uploadOneNote(noteid[0]); } // Then, automatically try and send previously-completed notes // that were not sent successfully. Vector<Long> unsentNotes = new Vector<Long>(); mDb.openReadOnly(); Cursor cur = mDb.fetchUnsentNotes(); if (cur != null && cur.getCount() > 0) { // pd.setMessage("Sent. You have previously unsent notes; submitting those now."); while (!cur.isAfterLast()) { unsentNotes.add(Long.valueOf(cur.getLong(0))); cur.moveToNext(); } cur.close(); } mDb.close(); for (Long note : unsentNotes) { result &= uploadOneNote(note); } return result; } @Override protected void onPreExecute() { Toast.makeText(mCtx.getApplicationContext(), "Submitting. Thanks for using Fountain City Cycling!", Toast.LENGTH_LONG).show(); } private SavedNotesAdapter mSavedNotesAdapter; public SavedNotesAdapter setSavedNotesAdapter(SavedNotesAdapter mSavedNotesAdapter) { this.mSavedNotesAdapter = mSavedNotesAdapter; return mSavedNotesAdapter; } private FragmentSavedNotesSection fragmentSavedNotesSection; public FragmentSavedNotesSection setFragmentSavedNotesSection( FragmentSavedNotesSection fragmentSavedNotesSection) { this.fragmentSavedNotesSection = fragmentSavedNotesSection; return fragmentSavedNotesSection; } private ListView listSavedNotes; public ListView setListView(ListView listSavedNotes) { this.listSavedNotes = listSavedNotes; return listSavedNotes; } @Override protected void onPostExecute(Boolean result) { try { if (mSavedNotesAdapter != null) { mSavedNotesAdapter.notifyDataSetChanged(); } if (fragmentSavedNotesSection != null) { listSavedNotes.invalidate(); fragmentSavedNotesSection.populateNoteList(listSavedNotes); } Log.d("KENNY", "Device ID: " + deviceId); if (result) { Toast.makeText(mCtx.getApplicationContext(), "Note uploaded successfully.", Toast.LENGTH_SHORT) .show(); } else { Toast.makeText(mCtx.getApplicationContext(), "Fountain City Cycling could not upload the note, and will retry when your next note is completed.", Toast.LENGTH_LONG).show(); } } catch (Exception e) { // Just don't toast if the view has gone out of context } } }