rpassmore.app.fillthathole.ViewHazardActivity.java Source code

Java tutorial

Introduction

Here is the source code for rpassmore.app.fillthathole.ViewHazardActivity.java

Source

/**
 * File: FillThatHole.java Project: FillThatHole
 *
 * Created: 20 Feb 2011
 *
 * Copyright (C) 2011 Robert Passmore
 * 
 * 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 2
 * of the License, or (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, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package rpassmore.app.fillthathole;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
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.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.provider.MediaStore;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.Images.Media;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.Toast;

public class ViewHazardActivity extends Activity {

    private static final int PICK_PHOTO_ACTIVITY = 1;
    private static final int PICTURE_ACTIVITY = 10;
    private static final int LOCATION_MAP_ACTIVITY = 20;

    private static final int ADD_PHOTO_DIALOG_ID = 100;
    private static final String SAVED_HAZARD_ID = "hazardId";

    private DBAdapter dbAdapter;

    private Button locateOnMap;
    private EditText locationDesc;
    private ImageView image;
    private Button addImage;
    private Spinner hazardType;
    private EditText hazardDesc;
    private CheckBox additionalInfo;
    private EditText hazardDepth;
    private EditText hazardSize;
    private EditText hazardDistFromKerb;
    private CheckBox onRedRoute;
    private CheckBox onLevelCrossing;
    private CheckBox onTowPath;
    private Button submitBtn;
    private RelativeLayout additionalInfoLayout;
    private TextView depthUnits;
    private TextView sizeUnits;
    private TextView distUnits;

    private Hazard hazard;
    private String measurementUnits;
    private Uri capturedImageURI;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.view_hazard_activity);

        locateOnMap = (Button) findViewById(R.id.locateOnMap);
        locationDesc = (EditText) findViewById(R.id.locationDesc);
        image = (ImageView) findViewById(R.id.image);
        addImage = (Button) findViewById(R.id.addImage);
        hazardType = (Spinner) findViewById(R.id.hazardType);
        hazardDesc = (EditText) findViewById(R.id.hazardDesc);
        additionalInfo = (CheckBox) findViewById(R.id.additionalInfo);
        hazardDepth = (EditText) findViewById(R.id.hazardDepth);
        hazardSize = (EditText) findViewById(R.id.hazardSize);
        hazardDistFromKerb = (EditText) findViewById(R.id.hazardDistFromKerb);
        onRedRoute = (CheckBox) findViewById(R.id.onRedRoute);
        onLevelCrossing = (CheckBox) findViewById(R.id.onLevelCrossing);
        onTowPath = (CheckBox) findViewById(R.id.onTowPath);
        submitBtn = (Button) findViewById(R.id.submit);
        additionalInfoLayout = (RelativeLayout) findViewById(R.id.additionalInfoLayout);
        depthUnits = (TextView) findViewById(R.id.hazardDepthUnits);
        sizeUnits = (TextView) findViewById(R.id.hazardSizeUnits);
        distUnits = (TextView) findViewById(R.id.hazardDistKerbUnits);

        // read in preferences for measurement units
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);

        measurementUnits = prefs.getString(getResources().getString(R.string.measurementUnits), "cm");
        depthUnits.setText(measurementUnits);
        sizeUnits.setText(measurementUnits);
        distUnits.setText(measurementUnits);

        dbAdapter = new DBAdapter(this.getApplicationContext());

        //try and load a hazard if onCreate called from resuming an activity
        if (!createFromBundle(savedInstanceState)) {
            //try and load a hazard if onCreate called from startActivity()
            Bundle b = this.getIntent().getExtras();
            if (!createFromBundle(b)) {
                //no hazard to load so create one
                hazard = new Hazard();
            }
        }
    }

    /**
     * loads the hazard and populates the ui from the id supplied in the bundle
     * @param b
     * @return bool - true if a hazard was loaded
     */
    private boolean createFromBundle(Bundle b) {
        if (b != null) {
            long id = b.getLong(SAVED_HAZARD_ID);
            if (id == -1) {
                hazard = new Hazard();
            } else {
                try {
                    dbAdapter.open();
                    hazard = dbAdapter.load(id);
                    populateFromHazard();
                    makeActivityReadOnly();
                } catch (SQLException e) {
                    Log.e(getPackageName(), e.toString());
                } finally {
                    dbAdapter.close();
                }
            }
            return true;
        }
        return false;
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putLong(SAVED_HAZARD_ID, hazard.getId());
    }

    @Override
    public void onPause() {
        super.onPause();
        persistHazard();
    }

    /**
     * 
     */
    private void makeActivityReadOnly() {
        if (hazard.getState() != Hazard.State.UNSUBMITTED) {
            locationDesc.setEnabled(false);
            hazardType.setEnabled(false);
            hazardDesc.setEnabled(false);
            submitBtn.setEnabled(false);
            if (hazard.isHasAdditionalInfo()) {
                additionalInfo.setEnabled(false);
                hazardDepth.setEnabled(false);
                hazardSize.setEnabled(false);
                hazardDistFromKerb.setEnabled(false);
                onRedRoute.setEnabled(false);
                onLevelCrossing.setEnabled(false);
                onTowPath.setEnabled(false);
                additionalInfoLayout.setVisibility(View.VISIBLE);
            }
        }
        if (hazard.getState() == Hazard.State.FIXED || hazard.isHasPhoto()) {
            image.setEnabled(false);
            addImage.setEnabled(false);
        }
    }

    private void populateFromHazard() {
        locationDesc.setText(hazard.getLocationDesc());
        // Photo set from photo handlers
        hazardType.setSelection(hazard.getHazardType());
        locationDesc.setText(hazard.getHazardDesc());
        // display the thumbnail
        if (hazard.getPhoto() != null) {
            image.setImageBitmap(BitmapFactory.decodeByteArray(hazard.getPhoto(), 0, hazard.getPhoto().length));
        }

        additionalInfo.setChecked(hazard.isHasAdditionalInfo());

        hazardDepth.setText(Double.toString(hazard.getDepth()));
        hazardSize.setText(Double.toString(hazard.getSize()));
        hazardDistFromKerb.setText(Double.toString(hazard.getDistFromKerb()));
        onRedRoute.setChecked(hazard.isOnRedRoute());
        onLevelCrossing.setChecked(hazard.isOnLevelCrossing());
        onTowPath.setChecked(hazard.isOnTowPath());
    }

    public void submitClickHandler(View view) {
        switch (view.getId()) {
        case R.id.submit:

            String error = null;
            try {
                WebSiteComms.submit(hazard);
            } catch (WebSiteCommsException e) {
                Log.e(getPackageName(), "Error submitting hazard", e);
                error = e.getMessage();
            }

            persistHazard();

            // TODO        
            // if photo has been submitted successfully set hasPhoto true
            /*
                    String error = null;
                    try {                            
                      HttpClient client = new DefaultHttpClient();  
                      String postURL = "http://www.fillthathole.org.uk/services/submit_hazard";
                      HttpPost post = new HttpPost(postURL); 
                      //hopefully dont need to set user agent
                      //post.setHeader("User-Agent", "Fill%20That%20Hole/1.11 CFNetwork/485.12.7 Darwin/10.4.0");      
                      ByteArrayEntity ent = new ByteArrayEntity(hazard.createSubmitStr().getBytes("UTF8"));          
                      ent.setContentType("application/x-www-form-urlencoded");       
                      post.setEntity(ent);          
                      HttpResponse responsePOST = client.execute(post);  
                      HttpEntity resEntity = responsePOST.getEntity();            
                      if (resEntity != null) {    
                        String result = EntityUtils.toString(resEntity);
                
                        JSONObject json = new JSONObject(result);
                        if(json != null) {
                          String hazard_id = json.getString("hazard_id");
                          String reporter_key = json.getString("reporter_key");
                          if(hazard_id == null || reporter_key == null) {
            //somekind of error occured try and get an error string
            error = json.getString("error");              
            Log.e(getPackageName(), "Error submitting hazard: " + error);
                          } else {
            //store the returned hazard key
            hazard.setHazardId(hazard_id);
            hazard.setReporterKey(reporter_key);
            hazard.setState(Hazard.State.SUBMITTED);
                
            persistHazard();
                          }
                        } else {
                          error = "Unreconised response from web server";              
                          Log.e(getPackageName(), "Error submitting hazard: empty response");
                        }
                      }
                    } catch (Exception e) {          
                      error = "Web server could not contacted";
                      Log.e(getPackageName(), "Error submitting hazard", e);
                    }            
            */
            //display any error to the user
            if (error != null) {
                Toast toast = Toast.makeText(getApplicationContext(), error, Toast.LENGTH_LONG);
                toast.show();
            } else {
                if (hazard.getPhoto() != null) {
                    //submit the attached photo
                    submitPhoto();
                }

                //inform user submission complete
                Toast toast = Toast.makeText(getApplicationContext(), "Hazard submitted successfully",
                        Toast.LENGTH_SHORT);
                toast.show();
            }
            break;
        }
        finish();
    }

    /**
     * 
     */
    private void submitPhoto() {
        // TODO Auto-generated method stub
        hazard.setHasPhoto(true);
        persistHazard();
    }

    /**
     * 
     */
    private void persistHazard() {
        // populate the hazard and persist it
        hazard.setLocationDesc(locationDesc.getText().toString());
        // Photo set from photo handlers
        hazard.setHazardType(hazardType.getSelectedItemPosition());
        hazard.setHazardDesc(hazardDesc.getText().toString());
        hazard.setHasAdditionalInfo(additionalInfo.isChecked());

        if (hazardDepth.getText() != null && !hazardDepth.getText().toString().equals("")) {
            hazard.setDepth(Double.parseDouble(hazardDepth.getText().toString()));
        }
        if (hazardSize.getText() != null && !hazardSize.getText().toString().equals("")) {
            hazard.setSize(Double.parseDouble(hazardSize.getText().toString()));
        }
        if (hazardDistFromKerb.getText() != null && !hazardDistFromKerb.getText().toString().equals("")) {
            hazard.setDistFromKerb(Double.parseDouble(hazardDistFromKerb.getText().toString()));
        }
        hazard.setOnRedRoute(onRedRoute.isChecked());
        hazard.setOnLevelCrossing(onLevelCrossing.isChecked());
        hazard.setOnTowPath(onTowPath.isChecked());

        dbAdapter.open();
        long id = dbAdapter.save(hazard);
        hazard.setId(id);
        dbAdapter.close();
    }

    public void additionalInfoClickHandler(View view) {
        if (additionalInfo.isChecked()) {
            additionalInfoLayout.setVisibility(View.VISIBLE);
        } else {
            additionalInfoLayout.setVisibility(View.GONE);
        }
    }

    public void addPhotoClickHandler(View view) {
        // take photo/select pic dialog
        showDialog(ADD_PHOTO_DIALOG_ID);
    }

    private void storeNewPhoto(Bitmap bitmap, String photoUrl) {
        // shrink bitmap for thumb nail image
        Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, 120, 120, false);

        // save scaled image to jpg byte array
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        scaledBitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
        // store thumb nail from photo
        hazard.setPhoto(out.toByteArray());
        hazard.setPhotoUrl(photoUrl);
        try {
            out.close();
        } catch (IOException e) {
            Log.e(getPackageName(), "Error scaling and storing thumbnail", e);
        }

        // display the thumbnail
        image.setImageBitmap(scaledBitmap);

        dbAdapter.open();
        long id = dbAdapter.save(hazard);
        hazard.setId(id);
        dbAdapter.close();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        switch (requestCode) {
        case PICK_PHOTO_ACTIVITY: {
            if (resultCode == RESULT_OK) {
                Bitmap bitmap;
                try {
                    bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(data.getData()));
                    storeNewPhoto(bitmap, data.getData().toString());
                } catch (FileNotFoundException ex) {
                    Log.e(getPackageName(), "Error loading image file", ex);
                }
            }
            break;
        }
        case PICTURE_ACTIVITY: {
            if (resultCode == RESULT_OK) {

                String[] projection = { MediaStore.Images.Media.DATA };
                Cursor cursor = managedQuery(capturedImageURI, projection, null, null, null);
                int column_index_data = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                cursor.moveToFirst();
                String capturedImageFilePath = cursor.getString(column_index_data);

                Bitmap bitmap = BitmapFactory.decodeFile(capturedImageFilePath);

                storeNewPhoto(bitmap, capturedImageFilePath);
            }
            break;
        }
        case LOCATION_MAP_ACTIVITY: {
            if (resultCode == RESULT_OK) {
                Bundle extras = data.getExtras();
                if (extras != null) {
                    hazard.setLattitude(extras.getLong(LocationActivity.LOCATION_LAT) / 1.0E6);
                    hazard.setLongitude(extras.getLong(LocationActivity.LOCATION_LONG) / 1.0E6);
                    if (extras.getString("Address") != null) {
                        hazard.setAddress(extras.getString(LocationActivity.LOCATION_ADDRESS));
                    }
                }
            }
            break;
        }
        }
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        switch (id) {
        case ADD_PHOTO_DIALOG_ID:
            // Create our AlertDialog
            Builder builder = new AlertDialog.Builder(this);
            builder.setMessage(
                    "You can attach a photo of the hazard to your report. Would you like to take a new photo or use an existing one?")
                    .setCancelable(true).setPositiveButton("New photo", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            String filename = System.currentTimeMillis() + ".jpg";
                            File imageDirectory = new File(
                                    Environment.getExternalStorageDirectory() + "/FillThatHole", filename);
                            ContentValues values = new ContentValues();
                            values.put(Images.Media.MIME_TYPE, "image/jpeg");
                            values.put(Media.DESCRIPTION, "FillThatHole Image");
                            values.put(Media.DATA, imageDirectory.getPath());
                            values.put(MediaStore.Images.Media.TITLE, filename);

                            // start the camera and take a new photo
                            Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                            capturedImageURI = getContentResolver()
                                    .insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

                            cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, capturedImageURI);
                            startActivityForResult(cameraIntent, PICTURE_ACTIVITY);
                        }
                    }).setNegativeButton("Existing photo", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            // select photo from gallery
                            Intent intent = new Intent(Intent.ACTION_PICK,
                                    android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                            startActivityForResult(intent, PICK_PHOTO_ACTIVITY);
                        }
                    });
            AlertDialog dialog = builder.create();
            dialog.show();
            return dialog;

        }
        return super.onCreateDialog(id);
    }

    public void locateClickHandler(View view) {
        // display location map activity
        Intent myIntent = new Intent(view.getContext(), LocationActivity.class);

        Bundle bundle = new Bundle();
        if (hazard.getState() != Hazard.State.UNSUBMITTED) {
            bundle.putBoolean(LocationActivity.LOCATION_CAN_DRAG, false);
        } else {
            bundle.putBoolean(LocationActivity.LOCATION_CAN_DRAG, true);
        }

        if (hazard.getLattitude() != null && hazard.getLongitude() != null) {
            bundle.putLong(LocationActivity.LOCATION_LAT, (long) (hazard.getLattitude() * 1E6));
            bundle.putLong(LocationActivity.LOCATION_LONG, (long) (hazard.getLongitude() * 1E6));
            bundle.putBoolean(LocationActivity.LOCATION_CAN_CREATE, false);
        } else {
            bundle.putBoolean(LocationActivity.LOCATION_CAN_CREATE, true);
        }

        myIntent.putExtras(bundle);
        startActivityForResult(myIntent, LOCATION_MAP_ACTIVITY);
    }
}