diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java b/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java index 3b39541e2..78b4470c6 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java +++ b/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java @@ -32,6 +32,7 @@ import com.google.android.apps.mytracks.io.TrackWriterFactory; import com.google.android.apps.mytracks.io.TrackWriterFactory.TrackFileFormat; import com.google.android.apps.mytracks.services.ITrackRecordingService; import com.google.android.apps.mytracks.services.TrackRecordingService; +import com.google.android.apps.mytracks.util.FileUtils; import com.google.android.maps.mytracks.R; import android.app.Activity; @@ -62,9 +63,9 @@ import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; -import android.view.Window; import android.view.View.OnTouchListener; import android.view.ViewGroup.LayoutParams; +import android.view.Window; import android.view.WindowManager.BadTokenException; import android.widget.RelativeLayout; import android.widget.TabHost; @@ -1506,18 +1507,11 @@ public class MyTracks extends TabActivity implements OnTouchListener, final TrackWriter writer = TrackWriterFactory.newWriter(this, providerUtils, trackId, format); - String sep = System.getProperty("file.separator"); + FileUtils fileUtils = new FileUtils(); String extension = format.getExtension(); - StringBuilder dirNameBuilder = new StringBuilder(); - dirNameBuilder.append(Environment.getExternalStorageDirectory()); - dirNameBuilder.append(sep); - dirNameBuilder.append(MyTracksConstants.SDCARD_TOP_DIR); - dirNameBuilder.append(sep); - dirNameBuilder.append(extension); - dirNameBuilder.append(sep); - dirNameBuilder.append("tmp"); + String dirName = fileUtils.buildExternalDirectoryPath(extension, "tmp"); - File dir = new File(dirNameBuilder.toString()); + File dir = new File(dirName); writer.setDirectory(dir); writer.setOnCompletion(new Runnable() { public void run() { diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/TrackWriter.java b/MyTracks/src/com/google/android/apps/mytracks/io/TrackWriter.java index ef0ebd6f7..437e7d3c7 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/TrackWriter.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/TrackWriter.java @@ -20,6 +20,7 @@ import com.google.android.apps.mytracks.content.MyTracksProviderUtils; import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.content.TrackBuffer; import com.google.android.apps.mytracks.content.Waypoint; +import com.google.android.apps.mytracks.util.FileUtils; import com.google.android.apps.mytracks.util.MyTracksUtils; import com.google.android.maps.mytracks.R; @@ -27,14 +28,12 @@ import android.app.Activity; import android.content.Context; import android.database.Cursor; import android.location.Location; -import android.os.Environment; import android.util.Log; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.OutputStream; -import java.util.HashSet; /** * The class which exports tracks to the SD card. @@ -51,39 +50,20 @@ public class TrackWriter { private final MyTracksProviderUtils providerUtils; private final Track track; private final TrackFormatWriter writer; + private final FileUtils fileUtils; private Runnable onCompletion = null; private boolean success = false; private int errorMessage = -1; private File directory = null; private File file = null; - /** - * A set of characters that are prohibited from being in file names. - */ - private static final HashSet PROHIBITED_CHARACTERS = - new HashSet(); - - static { - for (int i = 0; i < 48; i++) { - PROHIBITED_CHARACTERS.add(new Character((char) i)); - } - for (int i = 58; i < 65; i++) { - PROHIBITED_CHARACTERS.add(new Character((char) i)); - } - for (int i = 91; i < 97; i++) { - PROHIBITED_CHARACTERS.add(new Character((char) i)); - } - for (int i = 123; i < 128; i++) { - PROHIBITED_CHARACTERS.add(new Character((char) i)); - } - } - public TrackWriter(Context context, MyTracksProviderUtils providerUtils, Track track, TrackFormatWriter writer) { this.context = context; this.providerUtils = providerUtils; this.track = track; this.writer = writer; + this.fileUtils = new FileUtils(); } /** @@ -149,26 +129,6 @@ public class TrackWriter { * =============== */ - /** - * Makes sure the given directory exists, creating it if necessary. - * - * @param dir the directory to ensure exists - * @return True on success - */ - private static boolean ensureExists(File dir) { - if (dir.exists()) { - return true; - } - File parent = dir.getParentFile(); - if (parent == null) { - return true; - } - if (!ensureExists(parent)) { - return false; - } - return dir.mkdir(); - } - private void finished() { if (onCompletion != null) { runOnUiThread(onCompletion); @@ -197,7 +157,7 @@ public class TrackWriter { // Make sure the name will work on FAT String fileName = - sanitizeName(track.getName()) + "." + writer.getExtension(); + fileUtils.sanitizeName(track.getName() + "." + writer.getExtension()); Log.i(MyTracksConstants.TAG, "Writing track to: " + fileName); try { writer.prepare(track, newOutputStream(fileName)); @@ -214,23 +174,16 @@ public class TrackWriter { */ protected boolean canWriteFile() { if (directory == null) { - String sep = System.getProperty("file.separator"); - StringBuilder dirNameBuilder = new StringBuilder(); - dirNameBuilder.append(Environment.getExternalStorageDirectory()); - dirNameBuilder.append(sep); - dirNameBuilder.append(MyTracksConstants.SDCARD_TOP_DIR); - dirNameBuilder.append(sep); - dirNameBuilder.append(writer.getExtension()); - directory = newFile(dirNameBuilder.toString()); + String dirName = fileUtils.buildExternalDirectoryPath(writer.getExtension()); + directory = newFile(dirName); } - if (!Environment.getExternalStorageState() - .equals(Environment.MEDIA_MOUNTED)) { + if (!fileUtils.isSdCardAvailable()) { Log.i(MyTracksConstants.TAG, "Could not find SD card."); errorMessage = R.string.io_no_external_storage_found; return false; } - if (!ensureExists(directory)) { + if (!fileUtils.ensureDirectoryExists(directory)) { Log.i(MyTracksConstants.TAG, "Could not create export directory."); errorMessage = R.string.io_create_dir_failed; return false; @@ -257,25 +210,6 @@ public class TrackWriter { return new File(path); } - /** - * Normalizes the input string and make sure it is a valid fat32 file name. - */ - static String sanitizeName(String name) { - StringBuilder cleaned = new StringBuilder(); - for (int i = 0; i < name.length(); i++) { - char c = name.charAt(i); - if (!PROHIBITED_CHARACTERS.contains(c)) { - cleaned.append(c); - } - } - - // Max = 260 - // Boiler plate /[gpx|kml]/ .[gpx|kml] = 8 - return (cleaned.length() > 252) - ? cleaned.substring(0, 252) - : cleaned.toString(); - } - /** * Writes the waypoints for the given track. * diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/FileUtils.java b/MyTracks/src/com/google/android/apps/mytracks/util/FileUtils.java new file mode 100644 index 000000000..e694701e7 --- /dev/null +++ b/MyTracks/src/com/google/android/apps/mytracks/util/FileUtils.java @@ -0,0 +1,106 @@ +/* + * Copyright 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.android.apps.mytracks.util; + +import com.google.android.apps.mytracks.MyTracksConstants; + +import android.os.Environment; + +import java.io.File; +import java.util.HashSet; + +/** + * Utilities for dealing with files. + * + * @author Rodrigo Damazio + */ +public class FileUtils { + + /** + * A set of characters that are prohibited from being in file names. + */ + private static final HashSet PROHIBITED_CHARACTERS = + new HashSet(); + + static { + for (int i = 0; i < 48; i++) { + PROHIBITED_CHARACTERS.add(new Character((char) i)); + } + for (int i = 58; i < 65; i++) { + PROHIBITED_CHARACTERS.add(new Character((char) i)); + } + for (int i = 91; i < 97; i++) { + PROHIBITED_CHARACTERS.add(new Character((char) i)); + } + for (int i = 123; i < 128; i++) { + PROHIBITED_CHARACTERS.add(new Character((char) i)); + } + } + + /** + * Builds a path inside the My Tracks directory in the SD card. + * + * @param components the path components inside the mytracks directory + * @return the full path to the destination + */ + public String buildExternalDirectoryPath(String... components) { + StringBuilder dirNameBuilder = new StringBuilder(); + dirNameBuilder.append(Environment.getExternalStorageDirectory()); + dirNameBuilder.append(File.separatorChar); + dirNameBuilder.append(MyTracksConstants.SDCARD_TOP_DIR); + for (String component : components) { + dirNameBuilder.append(File.separatorChar); + dirNameBuilder.append(component); + } + return dirNameBuilder.toString(); + } + + /** + * Returns whether the SD card is available. + */ + public boolean isSdCardAvailable() { + return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()); + } + + /** + * Normalizes the input string and make sure it is a valid fat32 file name. + */ + public String sanitizeName(String name) { + StringBuilder cleaned = new StringBuilder(); + for (int i = 0; i < name.length(); i++) { + char c = name.charAt(i); + if (!PROHIBITED_CHARACTERS.contains(c)) { + cleaned.append(c); + } + } + + return (cleaned.length() > 260) + ? cleaned.substring(0, 260) + : cleaned.toString(); + } + + public boolean ensureDirectoryExists(File dir) { + if (dir.exists() && dir.isDirectory()) { + return true; + } + + if (dir.mkdirs()) { + return true; + } + + return false; + } +} diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/TrackWriterTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/TrackWriterTest.java index def7c764d..e9fa4f979 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/io/TrackWriterTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/TrackWriterTest.java @@ -117,7 +117,6 @@ public class TrackWriterTest extends AndroidTestCase { private static final long TRACK_ID = 1234567L; private static final String EXTENSION = "ext"; private static final String TRACK_NAME = "Swimming across the pacific"; - private static final String TRACK_SANITIZED_NAME = "Swimmingacrossthepacific"; private static final String FULL_TRACK_NAME = "Swimmingacrossthepacific.ext"; private Track track; @@ -188,10 +187,6 @@ public class TrackWriterTest extends AndroidTestCase { mocksControl.verify(); } - public void testSanitizeName() { - assertEquals(TRACK_SANITIZED_NAME, TrackWriter.sanitizeName(TRACK_NAME)); - } - public void testOpenFile() { final ByteArrayOutputStream stream = new ByteArrayOutputStream(); writer = new OpenFileTrackWriter( diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/util/FileUtilsTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/util/FileUtilsTest.java new file mode 100644 index 000000000..3d3332e96 --- /dev/null +++ b/MyTracksTest/src/com/google/android/apps/mytracks/util/FileUtilsTest.java @@ -0,0 +1,62 @@ +/* + * Copyright 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.android.apps.mytracks.util; + +import com.google.android.apps.mytracks.MyTracksConstants; + +import android.os.Environment; + +import java.io.File; + +import junit.framework.TestCase; + +/** + * Tests for {@link FileUtils}. + * + * @author Rodrigo Damazio + */ +public class FileUtilsTest extends TestCase { + private static final String ORIGINAL_NAME = "Swimming across the pacific"; + private static final String SANITIZED_NAME = "Swimmingacrossthepacific"; + + private FileUtils fileUtils; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + fileUtils = new FileUtils(); + } + + public void testBuildExternalDirectoryPath() { + String expectedName = Environment.getExternalStorageDirectory() + + File.separator + + MyTracksConstants.SDCARD_TOP_DIR + + File.separator + + "a" + + File.separator + + "b" + + File.separator + + "c"; + + String dirName = fileUtils.buildExternalDirectoryPath("a", "b", "c"); + assertEquals(expectedName, dirName); + } + + public void testSanitizeName() { + assertEquals(SANITIZED_NAME, fileUtils.sanitizeName(ORIGINAL_NAME)); + } +}