com.ushahidi.android.app.ui.phone.AddReportActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.ushahidi.android.app.ui.phone.AddReportActivity.java

Source

/**
 ** Copyright (c) 2010 Ushahidi Inc
 ** All rights reserved
 ** Contact: team@ushahidi.com
 ** Website: http://www.ushahidi.com
 **
 ** GNU Lesser General Public License Usage
 ** This file may be used under the terms of the GNU Lesser
 ** General Public License version 3 as published by the Free Software
 ** Foundation and appearing in the file LICENSE.LGPL included in the
 ** packaging of this file. Please review the following information to
 ** ensure the GNU Lesser General Public License version 3 requirements
 ** will be met: http://www.gnu.org/licenses/lgpl.html.
 **
 **
 ** If you have questions regarding the use of this file, please contact
 ** Ushahidi developers at team@ushahidi.com.
 **
 **/

package com.ushahidi.android.app.ui.phone;

import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Vector;

import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.app.TimePickerDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.location.Location;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.view.MenuItem;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.DatePicker;
import android.widget.ImageSwitcher;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TimePicker;
import android.widget.ViewSwitcher;

import com.ushahidi.android.app.ImageManager;
import com.ushahidi.android.app.R;
import com.ushahidi.android.app.activities.BaseEditMapActivity;
import com.ushahidi.android.app.adapters.UploadPhotoAdapter;
import com.ushahidi.android.app.entities.Category;
import com.ushahidi.android.app.entities.Media;
import com.ushahidi.android.app.entities.Photo;
import com.ushahidi.android.app.entities.Report;
import com.ushahidi.android.app.entities.ReportCategory;
import com.ushahidi.android.app.models.AddReportModel;
import com.ushahidi.android.app.models.ListReportModel;
import com.ushahidi.android.app.tasks.GeocoderTask;
import com.ushahidi.android.app.util.PhotoUtils;
import com.ushahidi.android.app.util.Util;
import com.ushahidi.android.app.views.AddReportView;

/**
 * @author eyedol
 */
public class AddReportActivity extends BaseEditMapActivity<AddReportView, AddReportModel>
        implements OnClickListener, ViewSwitcher.ViewFactory, OnItemClickListener {

    private ReverseGeocoderTask reverseGeocoderTask;

    private static final int DIALOG_ERROR_NETWORK = 0;

    private static final int DIALOG_ERROR_SAVING = 1;

    private static final int DIALOG_CHOOSE_IMAGE_METHOD = 2;

    private static final int DIALOG_MULTIPLE_CATEGORY = 3;

    private static final int TIME_DIALOG_ID = 4;

    private static final int DATE_DIALOG_ID = 5;

    private static final int DIALOG_SHOW_MESSAGE = 6;

    private static final int DIALOG_SHOW_REQUIRED = 7;

    private static final int DIALOG_SHOW_PROMPT = 8;

    private static final int DIALOG_SHOW_DELETE_PROMPT = 9;

    private static final int REQUEST_CODE_CAMERA = 0;

    private static final int REQUEST_CODE_IMAGE = 1;

    private Calendar mCalendar;

    private String mDateToSubmit = "";

    private int mCategoryLength;

    private Vector<String> mVectorCategories = new Vector<String>();

    private Vector<String> mCategoriesId = new Vector<String>();

    private HashMap<String, String> mCategoriesTitle = new HashMap<String, String>();

    private boolean mError = false;

    private int id = 0;

    private UploadPhotoAdapter pendingPhoto;

    private String mErrorMessage;

    private String photoName;

    private AddReportModel model;

    public AddReportActivity() {
        super(AddReportView.class, R.layout.add_report, R.menu.add_report, R.id.location_map);
        model = new AddReportModel();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        view.mLatitude.addTextChangedListener(latLonTextWatcher);
        view.mLongitude.addTextChangedListener(latLonTextWatcher);
        mapController = view.mapView.getController();
        view.mBtnPicture.setOnClickListener(this);
        view.mBtnAddCategory.setOnClickListener(this);
        view.mPickDate.setOnClickListener(this);
        view.mPickTime.setOnClickListener(this);
        mCalendar = Calendar.getInstance();
        pendingPhoto = new UploadPhotoAdapter(this);
        view.gallery.setAdapter(pendingPhoto);
        view.gallery.setOnItemClickListener(this);
        view.mSwitcher.setFactory(this);
        if (getIntent().getExtras() != null) {
            this.id = getIntent().getExtras().getInt("id", 0);
        }
        // edit existing report
        if (id > 0) {

            // make the delete button visible because we're editing
            view.mDeleteReport.setOnClickListener(this);
            view.mDeleteReport.setVisibility(View.VISIBLE);
            setSavedReport(id);
        } else {
            // add a new report
            updateDisplay();
            pendingPhoto.refresh();
        }

        registerForContextMenu(view.gallery);
    }

    @Override
    protected void onStart() {
        super.onStart();
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (reverseGeocoderTask != null) {
            reverseGeocoderTask.cancel(true);
        }
    }

    /**
     * Upon being resumed we can retrieve the current state. This allows us to
     * update the state if it was changed at any time while paused.
     */
    @Override
    protected void onResume() {
        getSharedText();
        super.onResume();
    }

    // Context Menu Stuff
    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        new MenuInflater(this).inflate(R.menu.photo_context, menu);

    }

    @Override
    public boolean onContextItemSelected(android.view.MenuItem item) {
        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
        boolean result = performAction(item, info.position);

        if (!result) {
            result = super.onContextItemSelected(item);
        }

        return result;

    }

    public boolean performAction(android.view.MenuItem item, int position) {

        if (item.getItemId() == R.id.remove_photo) {

            // adding a new report
            if (id == 0) {

                // Delete by name
                if (ImageManager.deletePendingPhoto(this, "/" + pendingPhoto.getItem(position).getPhoto())) {
                    pendingPhoto.refresh();
                }
                return true;
            } else {

                // editing existing report
                if (ImageManager.deletePendingPhoto(this, "/" + pendingPhoto.getItem(position).getPhoto())) {

                    pendingPhoto.removeItem(position);
                }
                return true;
            }

        }
        return false;

    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == android.R.id.home) {
            showDialog();
            return true;

        } else if (item.getItemId() == R.id.menu_send) {
            validateReports();
            return true;
        } else if (item.getItemId() == R.id.menu_clear) {
            showDialog(DIALOG_SHOW_PROMPT);
            return true;
        }
        return super.onOptionsItemSelected(item);

    }

    @Override
    public void onClick(View button) {
        if (button.getId() == R.id.btnPicture) {
            // get a file name for the photo to be uploaded
            photoName = Util.getDateTime() + ".jpg";
            showDialog(DIALOG_CHOOSE_IMAGE_METHOD);

        } else if (button.getId() == R.id.add_category) {
            showDialog(DIALOG_MULTIPLE_CATEGORY);
        } else if (button.getId() == R.id.pick_date) {
            showDialog(DATE_DIALOG_ID);
        } else if (button.getId() == R.id.pick_time) {
            showDialog(TIME_DIALOG_ID);
        } else if (button.getId() == R.id.delete_report) {
            showDialog(DIALOG_SHOW_DELETE_PROMPT);
        }

    }

    private void validateReports() {
        // Dipo Fix
        mError = false;
        boolean required = false;
        // @inoran
        // validate the title field
        if (TextUtils.isEmpty(view.mIncidentTitle.getText())) {
            mErrorMessage = getString(R.string.title) + "\n";
            required = true;

        } else if (view.mIncidentTitle.getText().length() < 3 || view.mIncidentTitle.getText().length() > 200) {
            mErrorMessage = getString(R.string.less_report_title) + "\n";
            mError = true;
        }

        if (TextUtils.isEmpty(view.mIncidentDesc.getText())) {
            mErrorMessage += getString(R.string.description) + "\n";
            required = true;
        }

        // Dipo Fix
        if (mVectorCategories.size() == 0) {
            mErrorMessage += getString(R.string.category) + "\n";
            required = true;
        }

        // validate lat long
        if (TextUtils.isEmpty(view.mLatitude.getText().toString())) {
            mErrorMessage += getString(R.string.latitude) + "\n";
            required = true;
        } else {

            try {
                Double.parseDouble(view.mLatitude.getText().toString());
            } catch (NumberFormatException ex) {
                mErrorMessage += getString(R.string.invalid_latitude) + "\n";
                mError = true;
            }
        }

        // validate lat long
        if (TextUtils.isEmpty(view.mLongitude.getText().toString())) {
            mErrorMessage += getString(R.string.longitude) + "\n";
            mError = true;
        } else {

            try {
                Double.parseDouble(view.mLongitude.getText().toString());
            } catch (NumberFormatException ex) {
                mErrorMessage += getString(R.string.invalid_longitude) + "\n";
                mError = true;
            }
        }

        // validate location
        if (TextUtils.isEmpty(view.mIncidentLocation.getText())) {
            mErrorMessage += getString(R.string.location);
            required = true;
        }

        if (required) {
            showDialog(DIALOG_SHOW_REQUIRED);
        } else if (mError) {
            showDialog(DIALOG_SHOW_MESSAGE);
        } else {
            new SaveTask(this).execute((String) null);

        }
    }

    /**
     * Post to local database
     * 
     * @author henryaddo
     */
    private boolean addReport() {
        log("Adding new reports to");
        File[] pendingPhotos = PhotoUtils.getPendingPhotos(this);

        Report report = new Report();

        report.setTitle(view.mIncidentTitle.getText().toString());
        report.setDescription(view.mIncidentDesc.getText().toString());
        report.setLatitude(view.mLongitude.getText().toString());
        report.setLongitude(view.mLatitude.getText().toString());
        report.setLocationName(view.mIncidentLocation.getText().toString());
        report.setReportDate(mDateToSubmit);
        report.setMode(String.valueOf(0));
        report.setVerified(String.valueOf(0));
        report.setPending(1);

        if (id == 0) {
            // Add a new pending report
            if (model.addPendingReport(report, mVectorCategories, pendingPhotos, view.mNews.getText().toString())) {
                // move saved photos
                log("Moving photos to fetched folder");
                ImageManager.movePendingPhotos(this);
                return true;
            }
        } else {
            // Update exisiting report
            List<Photo> photos = new ArrayList<Photo>();
            for (int i = 0; i < pendingPhoto.getCount(); i++) {
                photos.add(pendingPhoto.getItem(i));
            }
            if (model.updatePendingReport(id, report, mVectorCategories, photos, view.mNews.getText().toString())) {
                // move saved photos
                log("Moving photos to fetched folder");
                ImageManager.movePendingPhotos(this);
                return true;
            }
        }

        return false;

    }

    /**
     * Edit existing report
     * 
     * @author henryaddo
     */
    private void setSavedReport(int reportId) {

        // set text part of reports
        Report report = model.fetchPendingReportById(reportId);
        if (report != null) {
            view.mIncidentTitle.setText(report.getTitle());
            view.mIncidentDesc.setText(report.getDescription());
            view.mLongitude.setText(report.getLongitude());
            view.mLatitude.setText(report.getLatitude());
            view.mIncidentLocation.setText(report.getLocationName());

            // set date and time
            setDateAndTime(report.getReportDate());
        }

        // set Categories.
        mVectorCategories.clear();
        for (ReportCategory reportCategory : model.fetchReportCategories(reportId)) {
            mVectorCategories.add(String.valueOf(reportCategory.getCategoryId()));
        }
        setSelectedCategories(mVectorCategories);

        // set the photos
        pendingPhoto.refresh(id);

        // set news
        List<Media> newsMedia = model.fetchReportNews(reportId);
        if (newsMedia != null && newsMedia.size() > 0) {
            view.mNews.setText(newsMedia.get(0).getLink());
        }
    }

    private void deleteReport() {
        // make sure it's an existing report
        if (id > 0) {
            if (model.deleteReport(id)) {
                // delete images
                for (int i = 0; i < pendingPhoto.getCount(); i++) {
                    ImageManager.deletePendingPhoto(this, "/" + pendingPhoto.getItem(i).getPhoto());
                }
                // return to report listing page.
                finish();
            }
        }
    }

    /**
     * Create various dialog
     */
    @Override
    protected Dialog onCreateDialog(int id) {
        switch (id) {
        case DIALOG_ERROR_NETWORK: {
            AlertDialog dialog = (new AlertDialog.Builder(this)).create();
            dialog.setTitle(getString(R.string.network_error));
            dialog.setMessage(getString(R.string.network_error_msg));
            dialog.setButton2(getString(R.string.ok), new Dialog.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                }
            });
            dialog.setCancelable(false);
            return dialog;
        }
        case DIALOG_ERROR_SAVING: {
            AlertDialog dialog = (new AlertDialog.Builder(this)).create();
            dialog.setTitle(getString(R.string.network_error));
            dialog.setMessage(getString(R.string.file_system_error_msg));
            dialog.setButton2(getString(R.string.ok), new Dialog.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                }
            });
            dialog.setCancelable(false);
            return dialog;
        }

        case DIALOG_CHOOSE_IMAGE_METHOD: {

            AlertDialog dialog = (new AlertDialog.Builder(this)).create();
            dialog.setTitle(getString(R.string.choose_method));
            dialog.setMessage(getString(R.string.how_to_select_pic));
            dialog.setButton(getString(R.string.gallery_option), new Dialog.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    Intent intent = new Intent();
                    intent.setAction(Intent.ACTION_PICK);
                    intent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                    startActivityForResult(intent, REQUEST_CODE_IMAGE);
                    dialog.dismiss();
                }
            });
            dialog.setButton2(getString(R.string.cancel), new Dialog.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                }
            });
            dialog.setButton3(getString(R.string.camera_option), new Dialog.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
                    intent.putExtra(MediaStore.EXTRA_OUTPUT,
                            PhotoUtils.getPhotoUri(photoName, AddReportActivity.this));
                    startActivityForResult(intent, REQUEST_CODE_CAMERA);
                    dialog.dismiss();
                }
            });

            dialog.setCancelable(false);
            return dialog;
        }

        case DIALOG_MULTIPLE_CATEGORY: {
            if (showCategories() != null) {
                return new AlertDialog.Builder(this).setTitle(R.string.choose_categories)
                        .setMultiChoiceItems(showCategories(), setCheckedCategories(),
                                new DialogInterface.OnMultiChoiceClickListener() {
                                    public void onClick(DialogInterface dialog, int whichButton,
                                            boolean isChecked) {
                                        // see if categories have previously

                                        if (isChecked) {
                                            mVectorCategories.add(mCategoriesId.get(whichButton));

                                            mError = false;
                                        } else {
                                            mVectorCategories.remove(mCategoriesId.get(whichButton));
                                        }

                                        setSelectedCategories(mVectorCategories);
                                    }
                                })
                        .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int whichButton) {

                                /* User clicked Yes so do some stuff */
                            }
                        }).create();
            }
        }

        case TIME_DIALOG_ID:
            return new TimePickerDialog(this, mTimeSetListener, mCalendar.get(Calendar.HOUR),
                    mCalendar.get(Calendar.MINUTE), false);

        case DATE_DIALOG_ID:
            return new DatePickerDialog(this, mDateSetListener, mCalendar.get(Calendar.YEAR),
                    mCalendar.get(Calendar.MONTH), mCalendar.get(Calendar.DAY_OF_MONTH));

        case DIALOG_SHOW_MESSAGE:
            AlertDialog.Builder messageBuilder = new AlertDialog.Builder(this);
            messageBuilder.setMessage(mErrorMessage).setPositiveButton(getString(R.string.ok),
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            dialog.cancel();
                        }
                    });

            AlertDialog showDialog = messageBuilder.create();
            showDialog.show();
            break;

        case DIALOG_SHOW_REQUIRED:
            AlertDialog.Builder requiredBuilder = new AlertDialog.Builder(this);
            requiredBuilder.setTitle(R.string.required_fields);
            requiredBuilder.setMessage(mErrorMessage).setPositiveButton(getString(R.string.ok),
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            dialog.cancel();
                        }
                    });

            AlertDialog showRequiredDialog = requiredBuilder.create();
            showRequiredDialog.show();
            break;

        // prompt for unsaved changes
        case DIALOG_SHOW_PROMPT: {
            AlertDialog dialog = (new AlertDialog.Builder(this)).create();
            dialog.setTitle(getString(R.string.unsaved_changes));
            dialog.setMessage(getString(R.string.want_to_cancel));
            dialog.setButton(getString(R.string.no), new Dialog.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {

                    dialog.dismiss();
                }
            });
            dialog.setButton2(getString(R.string.yes), new Dialog.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    finish();
                    dialog.dismiss();
                }
            });

            dialog.setCancelable(false);
            return dialog;
        }

        // prompt for report deletion
        case DIALOG_SHOW_DELETE_PROMPT: {
            AlertDialog dialog = (new AlertDialog.Builder(this)).create();
            dialog.setTitle(getString(R.string.delete_report));
            dialog.setMessage(getString(R.string.want_to_delete));
            dialog.setButton(getString(R.string.no), new Dialog.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {

                    dialog.dismiss();
                }
            });
            dialog.setButton2(getString(R.string.yes), new Dialog.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    // delete report
                    deleteReport();
                    dialog.dismiss();
                }
            });

            dialog.setCancelable(false);
            return dialog;
        }

        }
        return null;
    }

    @Override
    protected void onPrepareDialog(int id, Dialog dialog) {
        switch (id) {
        case TIME_DIALOG_ID:
            ((TimePickerDialog) dialog).updateTime(mCalendar.get(Calendar.HOUR_OF_DAY),
                    mCalendar.get(Calendar.MINUTE));
            break;
        case DATE_DIALOG_ID:
            ((DatePickerDialog) dialog).updateDate(mCalendar.get(Calendar.YEAR), mCalendar.get(Calendar.MONTH),
                    mCalendar.get(Calendar.DAY_OF_MONTH));
            break;

        case DIALOG_MULTIPLE_CATEGORY:
            final AlertDialog alert = (AlertDialog) dialog;
            final ListView list = alert.getListView();
            // been
            // selected, then uncheck
            // selected categories
            if (mVectorCategories.size() > 0) {
                for (String s : mVectorCategories) {
                    try {
                        // @inoran fix
                        if (list != null) {
                            list.setItemChecked(mCategoryLength - Integer.parseInt(s), true);
                        }
                    } catch (NumberFormatException e) {
                        log("NumberFormatException", e);
                    }
                }
            } else {
                if (list != null) {
                    list.clearChoices();
                }
            }

            break;

        }
    }

    // fetch categories
    public String[] showCategories() {
        ListReportModel mListReportModel = new ListReportModel();
        List<Category> listCategories = mListReportModel.getCategories(this);
        if (listCategories != null && listCategories.size() > 0) {
            int categoryCount = listCategories.size();
            int categoryAmount = 0;
            if (categoryCount > 0) {
                categoryAmount = categoryCount;
            } else {
                mCategoriesId.clear();
                mCategoriesTitle.clear();
                categoryAmount = 1;
            }

            String categories[] = new String[categoryAmount];
            mCategoryLength = categories.length;

            int i = 0;
            for (Category category : mListReportModel.getCategories(this)) {

                categories[i] = category.getCategoryTitle();
                mCategoriesTitle.put(String.valueOf(category.getCategoryId()), category.getCategoryTitle());
                mCategoriesId.add(String.valueOf(category.getCategoryId()));
                i++;
            }
            return categories;
        }
        return null;
    }

    private void updateDisplay() {
        Date date = mCalendar.getTime();
        if (date != null) {
            SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM dd, yyyy");
            view.mPickDate.setText(dateFormat.format(date));

            SimpleDateFormat timeFormat = new SimpleDateFormat("h:mm a");
            view.mPickTime.setText(timeFormat.format(date));

            // Because the API doesn't support dates in diff Locale mode, force
            // it to show time in US
            SimpleDateFormat submitFormat = new SimpleDateFormat("yyy-MM-dd kk:mm:ss", Locale.US);
            mDateToSubmit = submitFormat.format(date);
        } else {
            view.mPickDate.setText(R.string.change_date);
            view.mPickTime.setText(R.string.change_time);
            mDateToSubmit = null;
        }
    }

    private void setDateAndTime(String dateTime) {

        if (dateTime != null && !(TextUtils.isEmpty(dateTime))) {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyy-MM-dd kk:mm:ss", Locale.US);
            Date date;
            try {

                date = dateFormat.parse(dateTime);

                if (date != null) {
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MMMM dd, yyyy");
                    view.mPickDate.setText(simpleDateFormat.format(date));

                    SimpleDateFormat timeFormat = new SimpleDateFormat("h:mm a");
                    view.mPickTime.setText(timeFormat.format(date));

                    // Because the API doesn't support dates in diff Locale
                    // mode,
                    // force
                    // it to show time in US
                    SimpleDateFormat submitFormat = new SimpleDateFormat("yyy-MM-dd kk:mm:ss", Locale.US);
                    mDateToSubmit = submitFormat.format(date);
                } else {
                    view.mPickDate.setText(R.string.change_date);
                    view.mPickTime.setText(R.string.change_time);
                    mDateToSubmit = null;
                }

            } catch (ParseException e) {
                log(e.getMessage());

            }
        }
    }

    private DatePickerDialog.OnDateSetListener mDateSetListener = new DatePickerDialog.OnDateSetListener() {
        public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
            mCalendar.set(year, monthOfYear, dayOfMonth);
            updateDisplay();
        }
    };

    private TimePickerDialog.OnTimeSetListener mTimeSetListener = new TimePickerDialog.OnTimeSetListener() {
        public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
            mCalendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
            mCalendar.set(Calendar.MINUTE, minute);
            updateDisplay();
        }
    };

    /**
     * Sets the selected categories for submission
     * 
     * @param aSelectedCategories
     */
    private void setSelectedCategories(Vector<String> aSelectedCategories) {
        // initilaize categories
        showCategories();

        // clear
        view.mBtnAddCategory.setText(R.string.select_category);
        if (aSelectedCategories.size() > 0) {
            StringBuilder categories = new StringBuilder();
            for (String category : aSelectedCategories) {
                if (categories.length() > 0) {
                    categories.append(", ");
                }
                if (!TextUtils.isEmpty(category)) {
                    categories.append(mCategoriesTitle.get(category));
                }
            }

            if (!TextUtils.isEmpty(categories.toString())) {
                view.mBtnAddCategory.setText(categories.toString());
            } else {
                view.mBtnAddCategory.setText(R.string.select_category);
            }
        }
    }

    /**
     * Get check selected categories
     * 
     * @param aSelectedCategories
     */
    private boolean[] setCheckedCategories() {
        // FIXME: Look into making this more efficient
        if (mVectorCategories != null && mVectorCategories.size() > 0) {
            ListReportModel mListReportModel = new ListReportModel();
            List<Category> listCategories = mListReportModel.getCategories(this);
            if (listCategories != null && listCategories.size() > 0) {
                int categoryCount = listCategories.size();
                int categoryAmount = 0;
                if (categoryCount > 0) {
                    categoryAmount = categoryCount;
                } else {
                    categoryAmount = 1;
                }

                boolean categories[] = new boolean[categoryAmount];
                mCategoryLength = categories.length;

                int i = 0;
                for (Category category : mListReportModel.getCategories(this)) {

                    if (mVectorCategories.contains(String.valueOf(category.getCategoryId()))) {

                        categories[i] = true;
                    } else {
                        categories[i] = false;
                    }

                    i++;
                }
                return categories;

            }
        }
        return null;
    }

    /**
     * Set photo to be attached to an existing report
     */
    private void addPhotoToReport() {
        File[] pendingPhotos = PhotoUtils.getPendingPhotos(this);
        if (pendingPhotos != null && pendingPhotos.length > 0) {
            int id = 0;
            for (File file : pendingPhotos) {
                if (file.exists()) {
                    id += 1;
                    Photo photo = new Photo();
                    photo.setDbId(id);
                    photo.setPhoto("pending/" + file.getName());
                    pendingPhoto.addItem(photo);
                }
            }
        }
    }

    /**
     * Get shared text from other Android applications
     */
    public void getSharedText() {
        Intent intent = getIntent();
        String action = intent.getAction();
        if (action != null) {
            if (action.equals(Intent.ACTION_SEND) || action.equals(Intent.ACTION_CHOOSER)) {
                CharSequence text = intent.getCharSequenceExtra(Intent.EXTRA_TEXT);
                if (text != null) {
                    view.mIncidentDesc.setText(text);
                }
            }
        }
    }

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

                Uri uri = PhotoUtils.getPhotoUri(photoName, this);
                Bitmap bitmap = PhotoUtils.getCameraPhoto(this, uri);
                PhotoUtils.savePhoto(this, bitmap, photoName);
                log(String.format("REQUEST_CODE_CAMERA %dx%d", bitmap.getWidth(), bitmap.getHeight()));

            } else if (requestCode == REQUEST_CODE_IMAGE) {
                Bitmap bitmap = PhotoUtils.getGalleryPhoto(this, data.getData());
                PhotoUtils.savePhoto(this, bitmap, photoName);
                log(String.format("REQUEST_CODE_IMAGE %dx%d", bitmap.getWidth(), bitmap.getHeight()));
            }

            if (id > 0) {
                addPhotoToReport();
            } else {
                pendingPhoto.refresh();
            }
        }
    }

    @Override
    protected void locationChanged(double latitude, double longitude) {
        updateMarker(latitude, longitude, true);
        if (!view.mLatitude.hasFocus() && !view.mLongitude.hasFocus()) {
            view.mLatitude.setText(String.valueOf(latitude));
            view.mLongitude.setText(String.valueOf(longitude));
        }
        if (reverseGeocoderTask == null || !reverseGeocoderTask.isExecuting()) {
            reverseGeocoderTask = new ReverseGeocoderTask(this);
            reverseGeocoderTask.execute(latitude, longitude);
        }

    }

    /**
     * Asynchronous Reverse Geocoder Task
     */
    private class ReverseGeocoderTask extends GeocoderTask {

        public ReverseGeocoderTask(Context context) {
            super(context);
        }

        @Override
        protected void onPostExecute(String result) {
            log(getClass().getSimpleName(), String.format("onPostExecute %s", result));
            if (TextUtils.isEmpty(view.mIncidentLocation.getText().toString()))
                view.mIncidentLocation.setText(result);
            executing = false;
        }
    }

    private TextWatcher latLonTextWatcher = new TextWatcher() {
        public void afterTextChanged(Editable s) {
        }

        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        public void onTextChanged(CharSequence s, int start, int before, int count) {
            try {
                if (view.mLatitude.hasFocus() || view.mLongitude.hasFocus()) {
                    locationChanged(Double.parseDouble(view.mLatitude.getText().toString()),
                            Double.parseDouble(view.mLongitude.getText().toString()));
                }
            } catch (Exception ex) {
                log("TextWatcher", ex);
            }
        }
    };

    /**
     * Go to reports screen
     */
    public void goToReports() {
        finish();
    }

    public void onLocationChanged(Location arg0) {
    }

    public void onProviderDisabled(String provider) {
    }

    public void onProviderEnabled(String provider) {
    }

    public void onStatusChanged(String provider, int status, Bundle extras) {
    }

    @Override
    protected boolean onSaveChanges() {
        return addReport();
    }

    @Override
    protected boolean isRouteDisplayed() {
        return false;
    }

    /*
     * (non-Javadoc)
     * 
     * @see android.widget.ViewSwitcher.ViewFactory#makeView()
     */
    @Override
    public View makeView() {
        ImageView i = new ImageView(this);
        i.setAdjustViewBounds(true);
        i.setScaleType(ImageView.ScaleType.FIT_CENTER);
        i.setLayoutParams(new ImageSwitcher.LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT,
                android.view.ViewGroup.LayoutParams.WRAP_CONTENT));

        return i;
    }

    /**
     * (non-Javadoc)
     * 
     * @see android.widget.AdapterView.OnItemClickListener#onItemClick(android.widget
     *      .AdapterView, android.view.View, int, long)
     */
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        this.view.mSwitcher.setImageDrawable(ImageManager.getPendingDrawables(this,
                pendingPhoto.getItem(position).getPhoto(), Util.getScreenWidth(this)));

    }

}