/* * Geopaparazzi - Digital field mapping on Android based devices * Copyright (C) 2010 HydroloGIS (www.hydrologis.com) * * 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 * (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 eu.geopaparazzi.library.camera; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.TimeZone; import android.app.Activity; import android.content.Intent; import android.database.Cursor; import android.media.ExifInterface; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; import eu.geopaparazzi.library.R; import eu.geopaparazzi.library.database.GPLog; import eu.geopaparazzi.library.sensors.SensorsManager; import eu.geopaparazzi.library.util.FileUtilities; import eu.geopaparazzi.library.util.LibraryConstants; import eu.geopaparazzi.library.util.ResourcesManager; import eu.geopaparazzi.library.util.Utilities; /** * The taking pictures activity. * * <p> * The image is created in a <b>media</b> folder inside the * application folder. If the intent bundle contains a * {@link LibraryConstants#PREFS_KEY_CAMERA_IMAGESAVEFOLDER} * value, that one is used as relative path inside the application folder. * </p> * <p> * The bundle is supposed to contain the gps position available through the keys: * {@link LibraryConstants#LONGITUDE},{@link LibraryConstants#LATITUDE}, * {@link LibraryConstants#ELEVATION},{@link LibraryConstants#AZIMUTH} * </p> * * <p> * The activity returns the relative path to the generated image, that can be * retrieved through the {@link LibraryConstants#PREFS_KEY_PATH} key from * the bundle. * </p> * * @author Andrea Antonello (www.hydrologis.com) */ @SuppressWarnings("nls") public class CameraActivity extends Activity { private static final int CAMERA_PIC_REQUEST = 1337; private File mediaFolder; private String currentDatestring; private String imageFilePath; private Date currentDate; private double lon; private double lat; private double elevation; private int lastImageId; private String imageName; private String imagePropertiesName; public void onCreate( Bundle icicle ) { super.onCreate(icicle); Bundle extras = getIntent().getExtras(); File imageSaveFolder = null; try { imageSaveFolder = ResourcesManager.getInstance(this).getMediaDir(); if (extras != null) { String imageSaveFolderRelativePath = extras.getString(LibraryConstants.PREFS_KEY_CAMERA_IMAGESAVEFOLDER); if (imageSaveFolderRelativePath != null && imageSaveFolderRelativePath.length() > 0) { File applicationDir = ResourcesManager.getInstance(this).getApplicationDir(); imageSaveFolder = new File(applicationDir, imageSaveFolderRelativePath); } imageName = extras.getString(LibraryConstants.PREFS_KEY_CAMERA_IMAGENAME); lon = extras.getDouble(LibraryConstants.LONGITUDE); lat = extras.getDouble(LibraryConstants.LATITUDE); elevation = extras.getDouble(LibraryConstants.ELEVATION); } else { throw new RuntimeException("Not implemented yet..."); } } catch (Exception e) { e.printStackTrace(); } if (!imageSaveFolder.exists()) { if (!imageSaveFolder.mkdirs()) { Runnable runnable = new Runnable(){ public void run() { finish(); } }; Utilities.messageDialog(this, getString(R.string.cantcreate_img_folder), runnable); return; } } mediaFolder = imageSaveFolder; currentDate = new Date(); currentDatestring = LibraryConstants.TIMESTAMPFORMATTER.format(currentDate); if (imageName == null) { imageName = "IMG_" + currentDatestring + ".jpg"; imagePropertiesName = "IMG_" + currentDatestring + ".properties"; } else { imageFilePath = mediaFolder.getAbsolutePath() + File.separator + imageName; File imgFile = new File(imageFilePath); String nameWithoutExtention = FileUtilities.getNameWithoutExtention(imgFile); imagePropertiesName = nameWithoutExtention + ".properties"; } imageFilePath = mediaFolder.getAbsolutePath() + File.separator + imageName; File imgFile = new File(imageFilePath); Uri outputFileUri = Uri.fromFile(imgFile); Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri); lastImageId = getLastImageId(); startActivityForResult(cameraIntent, CAMERA_PIC_REQUEST); } protected void onActivityResult( int requestCode, int resultCode, Intent data ) { if (requestCode == CAMERA_PIC_REQUEST) { checkTakenPictureConsistency(); SensorsManager sensorsManager = SensorsManager.getInstance(this); double azimuth = sensorsManager.getPictureAzimuth(); double latitude = lat; double longitude = lon; String latRef = "N"; String lonRef = "E"; if (lat < 0) { latRef = "S"; } if (lon < 0) { lonRef = "W"; } lat = Math.abs(lat); lon = Math.abs(lon); String latString = Utilities.degreeDecimal2ExifFormat(lat); String lonString = Utilities.degreeDecimal2ExifFormat(lon); String altimString = String.valueOf(elevation); String azimuthString = String.valueOf((int) azimuth); if (GPLog.LOG) { GPLog.addLogEntry(this, null, null, "Lat=" + lat + " -- Lon=" + lon + " -- Azim=" + azimuth + " -- Altim=" + altimString); } try { ExifInterface exif = new ExifInterface(imageFilePath); String latStringOld = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE); String lonStringOld = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE); String latRefStringOld = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF); String lonRefStringOld = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF); String dateOld = exif.getAttribute(ExifInterface.TAG_GPS_DATESTAMP); String timeOld = exif.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP); String dateTimeOld = exif.getAttribute(ExifInterface.TAG_DATETIME); Date date = LibraryConstants.TIMESTAMPFORMATTER.parse(currentDatestring); SimpleDateFormat exifFormatter = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss"); //$NON-NLS-1$ exifFormatter.setTimeZone(TimeZone.getTimeZone("UTC")); String exifDate = exifFormatter.format(date); String[] dateTimeSplit = exifDate.split("\\s+"); if (dateTimeOld == null || dateTimeOld.trim().length() <= 0) { exif.setAttribute(ExifInterface.TAG_DATETIME, exifDate); } if (dateOld == null || dateOld.trim().length() <= 0) { exif.setAttribute(ExifInterface.TAG_GPS_DATESTAMP, dateTimeSplit[0]); } if (timeOld == null || timeOld.trim().length() <= 0) { exif.setAttribute(ExifInterface.TAG_GPS_TIMESTAMP, dateTimeSplit[1]); } if (latStringOld == null || latRefStringOld == null || latStringOld.trim().length() <= 0) { exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, latString); exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, latRef); } if (lonStringOld == null || lonRefStringOld == null || lonStringOld.trim().length() <= 0) { exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, lonString); exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, lonRef); } String azz = (int) (azimuth * 100.0) + "/100"; String alt = (int) (elevation * 100.0) + "/100"; exif.setAttribute("GPSImgDirection", azz); // exif.setAttribute("GPSImgDirectionRef", "M"); exif.setAttribute("GPSAltitude", alt); // exif.setAttribute("GPSAltitudeRef", "0"); exif.saveAttributes(); // create props file String propertiesFilePath = mediaFolder.getAbsolutePath() + File.separator + imagePropertiesName; File propertiesFile = new File(propertiesFilePath); BufferedWriter bW = null; try { bW = new BufferedWriter(new FileWriter(propertiesFile)); bW.write("latitude="); bW.write(String.valueOf(lat)); bW.write("\nlongitude="); bW.write(String.valueOf(lon)); bW.write("\nazimuth="); bW.write(azimuthString); bW.write("\naltim="); bW.write(altimString); bW.write("\nutctimestamp="); bW.write(currentDatestring); } finally { bW.close(); } /* * add the image to the database */ String relativeImageFilePath = mediaFolder.getName() + File.separator + imageName; Intent intent = getIntent(); intent.putExtra(LibraryConstants.PREFS_KEY_PATH, relativeImageFilePath); intent.putExtra(LibraryConstants.LATITUDE, latitude); intent.putExtra(LibraryConstants.LONGITUDE, longitude); intent.putExtra(LibraryConstants.ELEVATION, elevation); intent.putExtra(LibraryConstants.AZIMUTH, azimuth); setResult(Activity.RESULT_OK, intent); } catch (Exception e) { Utilities.messageDialog(this, "An error occurred while adding gps info to the picture.", null); e.printStackTrace(); } finish(); } } private void checkTakenPictureConsistency() { /* * Checking for duplicate images * This is necessary because some camera implementation not only save where you want them to save but also in their default location. */ final String[] projection = {MediaStore.Images.ImageColumns.DATA, MediaStore.Images.ImageColumns.DATE_TAKEN, MediaStore.Images.ImageColumns.SIZE, MediaStore.Images.ImageColumns._ID}; final String imageOrderBy = MediaStore.Images.Media._ID + " DESC"; final String imageWhere = MediaStore.Images.Media._ID + ">?"; final String[] imageArguments = {Integer.toString(lastImageId)}; Cursor imageCursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, imageWhere, imageArguments, imageOrderBy); List<File> cameraTakenMediaFiles = new ArrayList<File>(); if (imageCursor.getCount() > 0) { while( imageCursor.moveToNext() ) { // int id = // imageCursor.getInt(imageCursor.getColumnIndex(MediaStore.Images.Media._ID)); String path = imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA)); // Long takenTimeStamp = // imageCursor.getLong(imageCursor.getColumnIndex(MediaStore.Images.Media.DATE_TAKEN)); // Long size = // imageCursor.getLong(imageCursor.getColumnIndex(MediaStore.Images.Media.SIZE)); cameraTakenMediaFiles.add(new File(path)); } } imageCursor.close(); File imageFile = new File(imageFilePath); if (!imageFile.exists() && cameraTakenMediaFiles.size() > 0) { // was not saved where I wanted, but the camera saved one in the media folder // try to copy over the one saved by the camera and then delete try { File cameraDoubleFile = cameraTakenMediaFiles.get(cameraTakenMediaFiles.size() - 1); FileUtilities.copyFile(cameraDoubleFile, imageFile); cameraDoubleFile.delete(); } catch (IOException e) { e.printStackTrace(); } } for( File cameraTakenFile : cameraTakenMediaFiles ) { // delete the one duplicated cameraTakenFile.delete(); } } /** * Gets the last image id from the media store. * * @return the last image id from the media store. */ private int getLastImageId() { final String[] imageColumns = {MediaStore.Images.Media._ID}; final String imageOrderBy = MediaStore.Images.Media._ID + " DESC"; final String imageWhere = null; final String[] imageArguments = null; Cursor imageCursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageColumns, imageWhere, imageArguments, imageOrderBy); if (imageCursor.moveToFirst()) { int id = imageCursor.getInt(imageCursor.getColumnIndex(MediaStore.Images.Media._ID)); imageCursor.close(); return id; } else { return 0; } } }