Java tutorial
/* This program 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 (props, at your option) any later version. This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ package org.openplans.rcavl; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONTokener; import org.openplans.rcavl.ConfigDialog.Configured; import org.openplans.rcavl.LocationService.LocalBinder; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.os.AsyncTask; import android.os.Bundle; import android.os.IBinder; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; public class RCAVL extends Activity implements Configured { String TAG = "RCAVL"; public String apiRequestUrl = "https://apps.rideconnection.org/ridepilot"; private ProgressBar spinner; public LocationService locationService; private AutoCompleteTextView emailField; private TextView passwordField; public int pingInterval = 60; private String userEmail; private LocationServiceConnection serviceConnection; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent intent = new Intent(RCAVL.this, LocationService.class); startService(intent); serviceConnection = new LocationServiceConnection(); bindService(intent, serviceConnection, 0); } private class LoginTask extends AsyncTask<Void, Void, String> { protected String doInBackground(Void... params) { // make login request, which really is just a GET request for // the ping URL String postUrl = apiRequestUrl + "/device_pool_drivers.json"; HttpClient client = HttpUtils.getNewHttpClient(); HttpPost request = new HttpPost(postUrl); try { List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2); String email = emailField.getText().toString(); String password = passwordField.getText().toString(); nameValuePairs.add(new BasicNameValuePair("user[email]", email)); nameValuePairs.add(new BasicNameValuePair("user[password]", password)); request.setEntity(new UrlEncodedFormEntity(nameValuePairs)); HttpResponse response = client.execute(request); HttpEntity entity = response.getEntity(); String json = EntityUtils.toString(entity); if (!json.startsWith("{")) { // not really json toast("Got an unexpected response from the server. Are you sure you have the URL right?"); return null; } JSONTokener tokener = new JSONTokener(json); JSONObject data = (JSONObject) tokener.nextValue(); Object url = data.get("resource_url"); if (url instanceof String) return (String) url; else toast("Bad response from server: " + url); } catch (ClientProtocolException e) { Log.e(TAG, "exception logging in", e); toast("Error logging in. Try again."); } catch (IOException e) { Log.e(TAG, "exception logging in", e); toast("Error logging in. Try again."); } catch (JSONException e) { Log.e(TAG, "exception logging in", e); toast("Error logging in. Check your password and try again."); } catch (Exception e) { Log.e(TAG, "exception logging in", e); toast("Error logging in."); } return null; } protected void onPostExecute(String url) { if (url == null) { spinner.setIndeterminate(false); spinner.setVisibility(View.INVISIBLE); return; } loggedIn(); Intent intent = new Intent(RCAVL.this, LocationService.class); intent.putExtra("pingUrl", url); String email = emailField.getText().toString(); String password = passwordField.getText().toString(); intent.putExtra("email", email); intent.putExtra("password", password); intent.putExtra("pingInterval", pingInterval); locationService.realStart(intent); } } void setupUI() { if (locationService == null || locationService.getStatus().equals(LocationService.INACTIVE) || locationService.getStatus().equals(LocationService.NOT_STARTED)) { //the service is inactive or will shut down switchToLogin(); } else { userEmail = locationService.getEmail(); switchToRunning(); } } // this is called from the LocationService after its thread has been initialized and started. // The location update request has to be started from the UI thread (I am not sure why), // or no location updates are delivered to the LocationServiceThread instance! public void startLocation() { runOnUiThread(new Thread() { public void run() { locationService.startReceivingLocation(); } }); } class LocationServiceConnection implements ServiceConnection { public void onServiceConnected(ComponentName className, IBinder service) { // We've bound to LocalService, cast the IBinder and get // LocalService instance LocalBinder binder = (LocalBinder) service; locationService = binder.getService(); locationService.setActivity(RCAVL.this); //this happens a bit after startup, so we need to call a callback to set up the UI runOnUiThread(new Thread() { public void run() { setupUI(); } }); } public void onServiceDisconnected(ComponentName arg0) { // notify the user toast("Location service disconnected"); } } public void toast(final String text) { runOnUiThread(new Runnable() { public void run() { Context context = getApplicationContext(); int duration = Toast.LENGTH_SHORT; Toast toast = Toast.makeText(context, text, duration); toast.show(); } }); } public void loggedIn() { spinner.setIndeterminate(false); spinner.setVisibility(View.INVISIBLE); /* * Handle adding the user's email address to the frequently used email * address list */ SharedPreferences preferences = getPreferences(MODE_PRIVATE); String emails = preferences.getString("emails", null); userEmail = emailField.getText().toString(); if (emails == null) { emails = userEmail; } else { String[] past_emails = emails.split(","); if (!Arrays.asList(past_emails).contains(userEmail)) { emails = emails + "," + userEmail; } } Editor editor = preferences.edit(); editor.putString("emails", emails); editor.commit(); toast("Logged in"); switchToRunning(); } private void switchToLogin() { setContentView(R.layout.login); SharedPreferences preferences = getPreferences(MODE_PRIVATE); String emails = preferences.getString("emails", ""); String[] past_emails = emails.split(","); if (past_emails == null) { past_emails = new String[0]; } emailField = (AutoCompleteTextView) findViewById(R.id.emailField); passwordField = (TextView) findViewById(R.id.passwordField); ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.list_item, past_emails); emailField.setAdapter(adapter); spinner = (ProgressBar) findViewById(R.id.loginProgressBar); View loginButton = findViewById(R.id.loginButton); loginButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { spinner.setIndeterminate(true); spinner.setVisibility(View.VISIBLE); new LoginTask().execute(); } }); View configButton = findViewById(R.id.configButton); configButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { ConfigDialog dialog = new ConfigDialog(RCAVL.this); dialog.setConfigured(RCAVL.this); dialog.show(); } }); apiRequestUrl = preferences.getString("apiRequestUrl", apiRequestUrl); pingInterval = preferences.getInt("pingInterval", pingInterval); } private void switchToRunning() { setContentView(R.layout.running); TextView userField = (TextView) findViewById(R.id.loggedInAsLabel); userField.setText("Logged in as " + userEmail); final Button breakButton = (Button) findViewById(R.id.breakButton); if (locationService.getStatus().equals(LocationService.BREAK)) breakButton.setText(R.string.return_from_break); else breakButton.setText(R.string.take_a_break); breakButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { runOnUiThread(new Thread() { public void run() { if (locationService.isActive()) { locationService.setStatus(LocationService.BREAK, false); breakButton.setText(R.string.return_from_break); } else { locationService.setStatus(LocationService.ACTIVE, true); breakButton.setText(R.string.take_a_break); } } }); } }); final Button logoutButton = (Button) findViewById(R.id.logoutButton); logoutButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { locationService.setStatus(LocationService.INACTIVE, false); stopService(new Intent(RCAVL.this, LocationService.class)); switchToLogin(); } }); } @Override public void onDestroy() { super.onDestroy(); unbindService(serviceConnection); } public void ping() { runOnUiThread(new Thread() { public void run() { TextView pingField = (TextView) findViewById(R.id.lastPingLabel); if (pingField != null) { String now = new SimpleDateFormat("HH:mm:ss").format(new Date()); pingField.setText("Last contacted server " + now); } } }); } /* configuration dialog callbacks */ public String getServerUrl() { return apiRequestUrl; } public int getPingInterval() { return pingInterval; } public void setConfig(String serverUrl, int pingInterval) { apiRequestUrl = serverUrl; this.pingInterval = pingInterval; SharedPreferences preferences = getPreferences(MODE_PRIVATE); Editor editor = preferences.edit(); editor.putString("apiRequestUrl", apiRequestUrl); editor.putInt("pingInterval", pingInterval); editor.commit(); } }