Store photos in /MyTracks/pictures directory

This commit is contained in:
Jimmy Shih
2013-10-03 18:04:17 -07:00
parent b182c1cb80
commit 9c938b1260
7 changed files with 79 additions and 54 deletions
@@ -51,7 +51,6 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment;
import android.os.Parcelable; import android.os.Parcelable;
import android.provider.MediaStore; import android.provider.MediaStore;
import android.support.v4.app.TaskStackBuilder; import android.support.v4.app.TaskStackBuilder;
@@ -216,8 +215,10 @@ public class TrackDetailActivity extends AbstractSendToGoogleActivity implements
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
hasCamera = getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA); hasCamera = getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
photoUri = savedInstanceState != null ? (Uri) savedInstanceState.getParcelable(PHOTO_URI_KEY) : null; photoUri = savedInstanceState != null ? (Uri) savedInstanceState.getParcelable(PHOTO_URI_KEY)
hasPhoto = savedInstanceState != null ? savedInstanceState.getBoolean(HAS_PHOTO_KEY, false) : false; : null;
hasPhoto = savedInstanceState != null ? savedInstanceState.getBoolean(HAS_PHOTO_KEY, false)
: false;
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(this); myTracksProviderUtils = MyTracksProviderUtils.Factory.get(this);
handleIntent(getIntent()); handleIntent(getIntent());
@@ -397,9 +398,7 @@ public class TrackDetailActivity extends AbstractSendToGoogleActivity implements
} }
File dir = new File( File dir = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), FileUtils.getDirectoryPath(FileUtils.PICTURES_DIR, Long.toString(trackId)));
FileUtils.SDCARD_TOP_DIR);
FileUtils.ensureDirectoryExists(dir); FileUtils.ensureDirectoryExists(dir);
String fileName = SimpleDateFormat.getDateTimeInstance().format(new Date()); String fileName = SimpleDateFormat.getDateTimeInstance().format(new Date());
@@ -25,6 +25,7 @@ import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
import com.google.android.apps.mytracks.services.TrackRecordingService; import com.google.android.apps.mytracks.services.TrackRecordingService;
import com.google.android.apps.mytracks.stats.TripStatistics; import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.stats.TripStatisticsUpdater; import com.google.android.apps.mytracks.stats.TripStatisticsUpdater;
import com.google.android.apps.mytracks.util.FileUtils;
import com.google.android.apps.mytracks.util.LocationUtils; import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils; import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.StringUtils; import com.google.android.apps.mytracks.util.StringUtils;
@@ -461,6 +462,19 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
locator.getLineNumber(), locator.getColumnNumber(), message); locator.getLineNumber(), locator.getColumnNumber(), message);
} }
/**
* Gets the photo url for a file.
*
* @param fileName the file name
*/
protected String getPhotoUrl(String fileName) {
if (importTrackId == -1L) {
return null;
}
return FileUtils.getDirectoryPath(
FileUtils.PICTURES_DIR, Long.toString(importTrackId), fileName);
}
/** /**
* Creates a location. * Creates a location.
*/ */
@@ -16,16 +16,17 @@
package com.google.android.apps.mytracks.io.file.importer; package com.google.android.apps.mytracks.io.file.importer;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.io.file.TrackFileFormat; import com.google.android.apps.mytracks.io.file.TrackFileFormat;
import com.google.android.apps.mytracks.io.file.exporter.KmzTrackExporter; import com.google.android.apps.mytracks.io.file.exporter.KmzTrackExporter;
import com.google.android.apps.mytracks.util.FileUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils; import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.SystemUtils; import com.google.android.apps.mytracks.util.SystemUtils;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
import android.content.Context; import android.content.Context;
import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Environment;
import android.os.PowerManager.WakeLock; import android.os.PowerManager.WakeLock;
import android.util.Log; import android.util.Log;
@@ -179,14 +180,12 @@ public class ImportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
String name = file.getName(); String name = file.getName();
if (name.endsWith("." + TrackFileFormat.KML.getExtension())) { if (name.endsWith("." + TrackFileFormat.KML.getExtension())) {
trackImporter = new KmlFileTrackImporter(context, -1L, null); trackImporter = new KmlFileTrackImporter(context, -1L, null);
} else { } else {
File dir = new File( MyTracksProviderUtils myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), Uri uri = myTracksProviderUtils.insertTrack(new Track());
FileUtils.SDCARD_TOP_DIR); long newId = Long.parseLong(uri.getLastPathSegment());
FileUtils.ensureDirectoryExists(dir);
dir = new File(dir, name.substring(0, name.lastIndexOf('.'))); trackImporter = new KmzTrackImporter(context, newId);
FileUtils.ensureDirectoryExists(dir);
trackImporter = new KmzTrackImporter(context, dir.getPath());
} }
} else { } else {
trackImporter = new GpxFileTrackImporter(context); trackImporter = new GpxFileTrackImporter(context);
@@ -27,7 +27,6 @@ import android.content.Context;
import android.location.Location; import android.location.Location;
import android.net.Uri; import android.net.Uri;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
@@ -65,7 +64,6 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
private static final String ATTRIBUTE_NAME = "name"; private static final String ATTRIBUTE_NAME = "name";
private final String photoPath;
private boolean trackStarted = false; private boolean trackStarted = false;
private String sensorName; private String sensorName;
private ArrayList<Location> locationList; private ArrayList<Location> locationList;
@@ -79,15 +77,14 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
* @param context the context * @param context the context
* @param importTrackId track id to import to. -1L to import to a new track. * @param importTrackId track id to import to. -1L to import to a new track.
*/ */
public KmlFileTrackImporter(Context context, long importTrackId, String photoPath) { public KmlFileTrackImporter(Context context, long importTrackId) {
this(context, importTrackId, photoPath, MyTracksProviderUtils.Factory.get(context)); this(context, importTrackId, MyTracksProviderUtils.Factory.get(context));
} }
@VisibleForTesting @VisibleForTesting
public KmlFileTrackImporter(Context context, long importTrackId, String photoPath, public KmlFileTrackImporter(
MyTracksProviderUtils myTracksProviderUtils) { Context context, long importTrackId, MyTracksProviderUtils myTracksProviderUtils) {
super(context, importTrackId, myTracksProviderUtils); super(context, importTrackId, myTracksProviderUtils);
this.photoPath = photoPath;
} }
@Override @Override
@@ -184,9 +181,9 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
if (type == null) { if (type == null) {
return; return;
} }
if (photoUrl != null && photoPath != null) { if (photoUrl != null) {
Uri uri = Uri.parse(photoUrl); Uri uri = Uri.parse(photoUrl);
photoUrl = photoPath + File.separatorChar + uri.getLastPathSegment(); photoUrl = getPhotoUrl(uri.getLastPathSegment());
} }
addWaypoint(type); addWaypoint(type);
} }
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks.io.file.importer;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils; import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.io.file.exporter.KmzTrackExporter; import com.google.android.apps.mytracks.io.file.exporter.KmzTrackExporter;
import com.google.android.apps.mytracks.util.FileUtils;
import android.content.Context; import android.content.Context;
import android.util.Log; import android.util.Log;
@@ -42,17 +43,24 @@ public class KmzTrackImporter implements TrackImporter {
private static final int BUFFER_SIZE = 4096; private static final int BUFFER_SIZE = 4096;
private final Context context; private final Context context;
private final String photoPath; private final long importTrackId;
public KmzTrackImporter(Context context, String photoPath) { /**
* Constructor.
*
* @param context the context
* @param importTrackId track id to import to. This should not be -1L so that
* images in the kmz file can be imported.
*/
public KmzTrackImporter(Context context, long importTrackId) {
this.context = context; this.context = context;
this.photoPath = photoPath; this.importTrackId = importTrackId;
} }
@Override @Override
public long importFile(InputStream inputStream) { public long importFile(InputStream inputStream) {
ZipInputStream zipInputStream = null; ZipInputStream zipInputStream = null;
long importedTrackId = -1L; long trackId = importTrackId;
try { try {
ZipEntry zipEntry; ZipEntry zipEntry;
@@ -60,15 +68,15 @@ public class KmzTrackImporter implements TrackImporter {
while ((zipEntry = zipInputStream.getNextEntry()) != null) { while ((zipEntry = zipInputStream.getNextEntry()) != null) {
if (Thread.interrupted()) { if (Thread.interrupted()) {
Log.d(TAG, "Thread interrupted"); Log.d(TAG, "Thread interrupted");
cleanImport(importedTrackId); cleanImport(trackId);
return -1L; return -1L;
} }
String fileName = zipEntry.getName(); String fileName = zipEntry.getName();
if (fileName.equals(KmzTrackExporter.KMZ_KML_FILE)) { if (fileName.equals(KmzTrackExporter.KMZ_KML_FILE)) {
importedTrackId = parseKml(zipInputStream); trackId = parseKml(zipInputStream);
if (importedTrackId == -1L) { if (trackId == -1L) {
Log.d(TAG, "Unable to parse kml in kmz"); Log.d(TAG, "Unable to parse kml in kmz");
cleanImport(importedTrackId); cleanImport(trackId);
return -1L; return -1L;
} }
} else { } else {
@@ -79,10 +87,10 @@ public class KmzTrackImporter implements TrackImporter {
} }
zipInputStream.closeEntry(); zipInputStream.closeEntry();
} }
return importedTrackId; return trackId;
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "Unable to import file", e); Log.e(TAG, "Unable to import file", e);
cleanImport(importedTrackId); cleanImport(trackId);
return -1L; return -1L;
} finally { } finally {
if (zipInputStream != null) { if (zipInputStream != null) {
@@ -98,15 +106,17 @@ public class KmzTrackImporter implements TrackImporter {
/** /**
* Cleans up import. * Cleans up import.
* *
* @param importedTrackId the imported track id * @param trackId the trackId
*/ */
private void cleanImport(long importedTrackId) { private void cleanImport(long trackId) {
if (importedTrackId != -1L) { if (trackId != -1L) {
MyTracksProviderUtils myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context); MyTracksProviderUtils myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
myTracksProviderUtils.deleteTrack(importedTrackId); myTracksProviderUtils.deleteTrack(trackId);
} }
if (photoPath != null) {
File dir = new File(photoPath); if (importTrackId != -1L) {
File dir = new File(
FileUtils.getDirectoryPath(FileUtils.PICTURES_DIR, Long.toString(importTrackId)));
if (dir.exists() && dir.isDirectory()) { if (dir.exists() && dir.isDirectory()) {
for (File file : dir.listFiles()) { for (File file : dir.listFiles()) {
file.delete(); file.delete();
@@ -125,7 +135,7 @@ public class KmzTrackImporter implements TrackImporter {
private long parseKml(ZipInputStream zipInputStream) throws IOException { private long parseKml(ZipInputStream zipInputStream) throws IOException {
ByteArrayInputStream byteArrayInputStream = null; ByteArrayInputStream byteArrayInputStream = null;
try { try {
KmlFileTrackImporter kmlFileTrackImporter = new KmlFileTrackImporter(context, -1L, photoPath); KmlFileTrackImporter kmlFileTrackImporter = new KmlFileTrackImporter(context, importTrackId);
byteArrayInputStream = new ByteArrayInputStream(getKml(zipInputStream)); byteArrayInputStream = new ByteArrayInputStream(getKml(zipInputStream));
return kmlFileTrackImporter.importFile(byteArrayInputStream); return kmlFileTrackImporter.importFile(byteArrayInputStream);
} finally { } finally {
@@ -166,7 +176,14 @@ public class KmzTrackImporter implements TrackImporter {
private void readImageFile(ZipInputStream zipInputStream, String fileName) throws IOException { private void readImageFile(ZipInputStream zipInputStream, String fileName) throws IOException {
FileOutputStream fileOutputStream = null; FileOutputStream fileOutputStream = null;
try { try {
fileOutputStream = new FileOutputStream(photoPath + File.separatorChar + fileName); if (importTrackId == -1L) {
return;
}
File dir = new File(
FileUtils.getDirectoryPath(FileUtils.PICTURES_DIR, Long.toString(importTrackId)));
FileUtils.ensureDirectoryExists(dir);
fileOutputStream = new FileOutputStream(new File(dir, fileName));
byte[] buffer = new byte[BUFFER_SIZE]; byte[] buffer = new byte[BUFFER_SIZE];
int count; int count;
while ((count = zipInputStream.read(buffer)) != -1) { while ((count = zipInputStream.read(buffer)) != -1) {
@@ -30,14 +30,16 @@ public class FileUtils {
private FileUtils() {} private FileUtils() {}
public static final String BACKUPS_DIR = "backups";
/** /**
* Name of the top-level directory inside the SD card where our files will be * Name of the top-level directory inside the SD card where our files will be
* read from/written to. * read from/written to.
*/ */
public static final String SDCARD_TOP_DIR = "MyTracks"; protected static final String SDCARD_TOP_DIR = "MyTracks";
public static final String BACKUPS_DIR = "backups";
public static final String PICTURES_DIR = "pictures";
/** /**
* The maximum FAT32 path length. See the FAT32 spec at * The maximum FAT32 path length. See the FAT32 spec at
* http://msdn.microsoft.com/en-us/windows/hardware/gg463080 * http://msdn.microsoft.com/en-us/windows/hardware/gg463080
@@ -20,7 +20,6 @@ import static com.google.android.testing.mocking.AndroidMock.eq;
import static com.google.android.testing.mocking.AndroidMock.expect; import static com.google.android.testing.mocking.AndroidMock.expect;
import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.io.file.importer.KmlFileTrackImporter;
import com.google.android.testing.mocking.AndroidMock; import com.google.android.testing.mocking.AndroidMock;
import android.location.Location; import android.location.Location;
@@ -73,8 +72,7 @@ public class KmlFileTrackImporterTest extends AbstractTestFileTrackImporter {
Location location0 = createLocation(0, DATE_FORMAT_0.parse(TRACK_TIME_0).getTime()); Location location0 = createLocation(0, DATE_FORMAT_0.parse(TRACK_TIME_0).getTime());
Location location1 = createLocation(1, DATE_FORMAT_1.parse(TRACK_TIME_1).getTime()); Location location1 = createLocation(1, DATE_FORMAT_1.parse(TRACK_TIME_1).getTime());
expect(myTracksProviderUtils.insertTrack((Track) AndroidMock.anyObject())) myTracksProviderUtils.clearTrack(TRACK_ID_0);
.andReturn(TRACK_ID_0_URI);
expectFirstTrackPoint(location0, TRACK_ID_0, TRACK_POINT_ID_0); expectFirstTrackPoint(location0, TRACK_ID_0, TRACK_POINT_ID_0);
// A flush happens at the end // A flush happens at the end
@@ -87,7 +85,7 @@ public class KmlFileTrackImporterTest extends AbstractTestFileTrackImporter {
InputStream inputStream = new ByteArrayInputStream(VALID_ONE_TRACK_ONE_SEGMENT_GPX.getBytes()); InputStream inputStream = new ByteArrayInputStream(VALID_ONE_TRACK_ONE_SEGMENT_GPX.getBytes());
KmlFileTrackImporter kmlFileTrackImporter = new KmlFileTrackImporter( KmlFileTrackImporter kmlFileTrackImporter = new KmlFileTrackImporter(
getContext(), -1L, null, myTracksProviderUtils); getContext(), TRACK_ID_0, myTracksProviderUtils);
long trackId = kmlFileTrackImporter.importFile(inputStream); long trackId = kmlFileTrackImporter.importFile(inputStream);
assertEquals(TRACK_ID_0, trackId); assertEquals(TRACK_ID_0, trackId);
@@ -106,8 +104,7 @@ public class KmlFileTrackImporterTest extends AbstractTestFileTrackImporter {
Location location0 = createLocation(0, DATE_FORMAT_0.parse(TRACK_TIME_0).getTime()); Location location0 = createLocation(0, DATE_FORMAT_0.parse(TRACK_TIME_0).getTime());
expect(myTracksProviderUtils.insertTrack((Track) AndroidMock.anyObject())) myTracksProviderUtils.clearTrack(TRACK_ID_0);
.andReturn(TRACK_ID_0_URI);
expectFirstTrackPoint(location0, TRACK_ID_0, TRACK_POINT_ID_0); expectFirstTrackPoint(location0, TRACK_ID_0, TRACK_POINT_ID_0);
// A flush happens at the end // A flush happens at the end
@@ -120,7 +117,7 @@ public class KmlFileTrackImporterTest extends AbstractTestFileTrackImporter {
InputStream inputStream = new ByteArrayInputStream(VALID_ONE_TRACK_TWO_SEGMENTS_GPX.getBytes()); InputStream inputStream = new ByteArrayInputStream(VALID_ONE_TRACK_TWO_SEGMENTS_GPX.getBytes());
KmlFileTrackImporter kmlFileTrackImporter = new KmlFileTrackImporter( KmlFileTrackImporter kmlFileTrackImporter = new KmlFileTrackImporter(
getContext(), -1L, null, myTracksProviderUtils); getContext(), TRACK_ID_0, myTracksProviderUtils);
long trackId = kmlFileTrackImporter.importFile(inputStream); long trackId = kmlFileTrackImporter.importFile(inputStream);
assertEquals(TRACK_ID_0, trackId); assertEquals(TRACK_ID_0, trackId);