diff --git a/MyTracks/AndroidManifest.xml b/MyTracks/AndroidManifest.xml
index 24126a949..0c682642a 100755
--- a/MyTracks/AndroidManifest.xml
+++ b/MyTracks/AndroidManifest.xml
@@ -293,6 +293,7 @@ limitations under the License.
+
diff --git a/MyTracks/src/com/google/android/apps/mytracks/BootReceiver.java b/MyTracks/src/com/google/android/apps/mytracks/BootReceiver.java
index 3ed021fb8..47fd14d78 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/BootReceiver.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/BootReceiver.java
@@ -19,6 +19,7 @@ import static android.content.Intent.ACTION_BOOT_COMPLETED;
import static com.google.android.apps.mytracks.Constants.RESUME_TRACK_EXTRA_NAME;
import static com.google.android.apps.mytracks.Constants.TAG;
+import com.google.android.apps.mytracks.services.RemoveTempFilesService;
import com.google.android.apps.mytracks.services.TrackRecordingService;
import android.content.BroadcastReceiver;
@@ -50,6 +51,9 @@ public class BootReceiver extends BroadcastReceiver {
Intent startIntent = new Intent(context, TrackRecordingService.class);
startIntent.putExtra(RESUME_TRACK_EXTRA_NAME, true);
context.startService(startIntent);
+
+ Intent removeTempFilesIntent = new Intent(context, RemoveTempFilesService.class);
+ context.startService(removeTempFilesIntent);
} else {
Log.w(TAG, "BootReceiver: unsupported action");
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java b/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java
index 90743a591..5e8eeb14e 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java
@@ -24,7 +24,6 @@ import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.content.WaypointsColumns;
-import com.google.android.apps.mytracks.io.file.TempFileCleaner;
import com.google.android.apps.mytracks.services.ITrackRecordingService;
import com.google.android.apps.mytracks.services.ServiceUtils;
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
@@ -256,14 +255,9 @@ public class MyTracks extends TabActivity implements OnTouchListener {
@Override
protected void onStop() {
Log.d(TAG, "MyTracks.onStop");
-
dataHub.stop();
-
tracker.dispatch();
tracker.stop();
-
- // Clean up any temporary track files.
- TempFileCleaner.clean();
super.onStop();
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracksApplication.java b/MyTracks/src/com/google/android/apps/mytracks/MyTracksApplication.java
index c2749fce9..0629f4363 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MyTracksApplication.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/MyTracksApplication.java
@@ -16,8 +16,10 @@
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.TrackDataHub;
+import com.google.android.apps.mytracks.services.RemoveTempFilesService;
import android.app.Application;
+import android.content.Intent;
/**
* MyTracksApplication for keeping global state.
@@ -28,6 +30,11 @@ public class MyTracksApplication extends Application {
private TrackDataHub trackDataHub;
+ @Override
+ public void onCreate() {
+ startService(new Intent(this, RemoveTempFilesService.class));
+ }
+
/**
* Gets the application's TrackDataHub.
*
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/TempFileCleaner.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/TempFileCleaner.java
deleted file mode 100644
index 42242fa59..000000000
--- a/MyTracks/src/com/google/android/apps/mytracks/io/file/TempFileCleaner.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.io.file;
-
-import static com.google.android.apps.mytracks.Constants.TAG;
-
-import com.google.android.apps.mytracks.util.FileUtils;
-
-import android.os.Environment;
-import android.util.Log;
-
-import java.io.File;
-
-/**
- * A class to clean up old temporary files.
- * @author Sandor Dornbush
- */
-public class TempFileCleaner {
-
- private long currentTimeMillis;
-
- public static void clean() {
- (new TempFileCleaner(System.currentTimeMillis())).cleanImpl();
- }
-
- // @VisibleForTesting
- TempFileCleaner(long time) {
- currentTimeMillis = time;
- }
-
- private void cleanImpl() {
- if (!Environment.getExternalStorageState().equals(
- Environment.MEDIA_MOUNTED)) {
- return; // Can't do anything now.
- }
- cleanTmpDirectory("csv");
- cleanTmpDirectory("gpx");
- cleanTmpDirectory("kml");
- cleanTmpDirectory("tcx");
- }
-
- private void cleanTmpDirectory(String name) {
- FileUtils fileUtils = new FileUtils();
- String dirName = fileUtils.buildExternalDirectoryPath(name, "tmp");
- cleanTmpDirectory(new File(dirName));
- }
-
- // @VisibleForTesting
- int cleanTmpDirectory(File dir) {
- if (!dir.exists()) {
- return 0;
- }
- int count = 0;
- long oldest = currentTimeMillis - 1000 * 3600;
- for (File f : dir.listFiles()) {
- if (f.lastModified() < oldest) {
- if (!f.delete()) {
- Log.w(TAG, "Failed to delete file " + f.getAbsolutePath());
- }
- count++;
- }
- }
- return count;
- }
-}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/RemoveTempFilesService.java b/MyTracks/src/com/google/android/apps/mytracks/services/RemoveTempFilesService.java
new file mode 100644
index 000000000..0a36b2e66
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/services/RemoveTempFilesService.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2012 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.services;
+
+import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
+import com.google.android.apps.mytracks.util.FileUtils;
+import com.google.common.annotations.VisibleForTesting;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Environment;
+import android.os.IBinder;
+import android.util.Log;
+
+import java.io.File;
+
+/**
+ * A service to remove My Tracks temp files older than one hour on the SD card.
+ *
+ * @author Jimmy Shih
+ */
+public class RemoveTempFilesService extends Service {
+
+ private static final String TAG = RemoveTempFilesService.class.getSimpleName();
+ private static final int ONE_HOUR_IN_MILLISECONDS = 60 * 60 * 1000;
+
+ private RemoveTempFilesAsyncTask removeTempFilesAsyncTask = null;
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+
+ // Setup an alarm to repeatedly call this service
+ Intent alarmIntent = new Intent(this, RemoveTempFilesService.class);
+ PendingIntent pendingIntent = PendingIntent.getService(
+ this, 0, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+ AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
+ alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP,
+ System.currentTimeMillis() + ONE_HOUR_IN_MILLISECONDS, AlarmManager.INTERVAL_HOUR,
+ pendingIntent);
+
+ // Invoke the AsyncTask to cleanup the temp files
+ if (removeTempFilesAsyncTask == null
+ || removeTempFilesAsyncTask.getStatus().equals(AsyncTask.Status.FINISHED)) {
+ removeTempFilesAsyncTask = new RemoveTempFilesAsyncTask();
+ removeTempFilesAsyncTask.execute((Void[]) null);
+ }
+ return START_NOT_STICKY;
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ private class RemoveTempFilesAsyncTask extends AsyncTask {
+ @Override
+ protected Void doInBackground(Void... params) {
+ if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+ // Can't do anything
+ return null;
+ }
+ cleanTempDirectory(TrackFileFormat.GPX.getExtension());
+ cleanTempDirectory(TrackFileFormat.KML.getExtension());
+ cleanTempDirectory(TrackFileFormat.CSV.getExtension());
+ cleanTempDirectory(TrackFileFormat.TCX.getExtension());
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ stopSelf();
+ }
+ }
+
+ private void cleanTempDirectory(String name) {
+ FileUtils fileUtils = new FileUtils();
+ String dirName = fileUtils.buildExternalDirectoryPath(name, "tmp");
+ File dir = new File(dirName);
+ cleanTempDirectory(dir);
+ }
+
+ /**
+ * Removes temp files in a directory older than one hour.
+ *
+ * @param dir the directory
+ * @return the number of files removed.
+ */
+ @VisibleForTesting
+ int cleanTempDirectory(File dir) {
+ if (!dir.exists()) {
+ return 0;
+ }
+ int count = 0;
+ long oneHourAgo = System.currentTimeMillis() - ONE_HOUR_IN_MILLISECONDS;
+ for (File f : dir.listFiles()) {
+ if (f.lastModified() < oneHourAgo) {
+ if (!f.delete()) {
+ Log.e(TAG, "Unable to delete file: " + f.getAbsolutePath());
+ } else {
+ count++;
+ }
+ }
+ }
+ return count;
+ }
+}
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TempFileCleanerTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TempFileCleanerTest.java
deleted file mode 100644
index cea67b571..000000000
--- a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TempFileCleanerTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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.io.file;
-
-import static com.google.android.testing.mocking.AndroidMock.expect;
-
-import com.google.android.apps.mytracks.io.file.TempFileCleaner;
-import com.google.android.testing.mocking.AndroidMock;
-import com.google.android.testing.mocking.UsesMocks;
-
-import android.test.AndroidTestCase;
-
-import java.io.File;
-
-/**
- * @author Sandor Dornbush
- */
-public class TempFileCleanerTest extends AndroidTestCase {
-
- @UsesMocks({
- File.class,
- })
-
- public void test_noDir() {
- File dir = AndroidMock.createMock(File.class, "/no_file");
- TempFileCleaner cleaner = new TempFileCleaner(0);
- expect(dir.exists()).andStubReturn(false);
- AndroidMock.replay(dir);
- assertEquals(0, cleaner.cleanTmpDirectory(dir));
- AndroidMock.verify(dir);
- }
-
- public void test_emptyDir() {
- File dir = AndroidMock.createMock(File.class, "/no_file");
- TempFileCleaner cleaner = new TempFileCleaner(0);
- expect(dir.exists()).andStubReturn(true);
- expect(dir.listFiles()).andStubReturn(new File[0]);
- AndroidMock.replay(dir);
- assertEquals(0, cleaner.cleanTmpDirectory(dir));
- AndroidMock.verify(dir);
- }
-
- public void test_newFile() {
- File dir = AndroidMock.createMock(File.class, "/no_file");
- long now = 100000000;
- TempFileCleaner cleaner = new TempFileCleaner(now);
- expect(dir.exists()).andStubReturn(true);
- File file = AndroidMock.createMock(File.class, "/no_file/foo");
- expect(file.lastModified()).andStubReturn(now);
- File[] list = { file };
- expect(dir.listFiles()).andStubReturn(list);
-
- AndroidMock.replay(dir, file);
- assertEquals(0, cleaner.cleanTmpDirectory(dir));
- AndroidMock.verify(dir, file);
- }
-
- public void test_oldFile() {
- File dir = AndroidMock.createMock(File.class, "/no_file");
- long now = 100000000;
- TempFileCleaner cleaner = new TempFileCleaner(now);
- expect(dir.exists()).andStubReturn(true);
- File file = AndroidMock.createMock(File.class, "/no_file/foo");
- expect(file.lastModified()).andStubReturn(now - 3600001);
- expect(file.delete()).andStubReturn(true);
- File[] list = { file };
- expect(dir.listFiles()).andStubReturn(list);
-
- AndroidMock.replay(dir, file);
- assertEquals(1, cleaner.cleanTmpDirectory(dir));
- AndroidMock.verify(dir, file);
- }
-}
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/services/RemoveTempFilesServiceTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/services/RemoveTempFilesServiceTest.java
new file mode 100644
index 000000000..43c9cbbcb
--- /dev/null
+++ b/MyTracksTest/src/com/google/android/apps/mytracks/services/RemoveTempFilesServiceTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.services;
+
+import static com.google.android.testing.mocking.AndroidMock.expect;
+
+import com.google.android.testing.mocking.AndroidMock;
+import com.google.android.testing.mocking.UsesMocks;
+
+import android.test.AndroidTestCase;
+
+import java.io.File;
+
+/**
+ * Tests {@link RemoveTempFilesService}.
+ *
+ * @author Sandor Dornbush
+ */
+public class RemoveTempFilesServiceTest extends AndroidTestCase {
+
+ private static final String DIR_NAME = "/tmp";
+ private static final String FILE_NAME = "foo";
+
+ private RemoveTempFilesService service;
+
+ @UsesMocks({ File.class, })
+ protected void setUp() throws Exception {
+ service = new RemoveTempFilesService();
+ };
+
+ /**
+ * Tests when the directory doesn't exists.
+ */
+ public void test_noDir() {
+ File dir = AndroidMock.createMock(File.class, DIR_NAME);
+ expect(dir.exists()).andStubReturn(false);
+ AndroidMock.replay(dir);
+
+ assertEquals(0, service.cleanTempDirectory(dir));
+ AndroidMock.verify(dir);
+ }
+
+ /**
+ * Tests when the directory is empty.
+ */
+ public void test_emptyDir() {
+ File dir = AndroidMock.createMock(File.class, DIR_NAME);
+ expect(dir.exists()).andStubReturn(true);
+ expect(dir.listFiles()).andStubReturn(new File[0]);
+ AndroidMock.replay(dir);
+
+ assertEquals(0, service.cleanTempDirectory(dir));
+ AndroidMock.verify(dir);
+ }
+
+ /**
+ * Tests when there is a new file and it shouldn't get deleted.
+ */
+ public void test_newFile() {
+ File file = AndroidMock.createMock(File.class, DIR_NAME + FILE_NAME);
+ expect(file.lastModified()).andStubReturn(System.currentTimeMillis());
+
+ File dir = AndroidMock.createMock(File.class, DIR_NAME);
+ expect(dir.exists()).andStubReturn(true);
+ expect(dir.listFiles()).andStubReturn(new File[] { file });
+ AndroidMock.replay(dir, file);
+
+ assertEquals(0, service.cleanTempDirectory(dir));
+ AndroidMock.verify(dir, file);
+ }
+
+ /**
+ * Tests when there is an old file and it should get deleted.
+ */
+ public void test_oldFile() {
+ File file = AndroidMock.createMock(File.class, DIR_NAME + FILE_NAME);
+ // qSet to one hour and 1 millisecond later than the current time
+ expect(file.lastModified()).andStubReturn(System.currentTimeMillis() - 3600001);
+ expect(file.delete()).andStubReturn(true);
+
+ File dir = AndroidMock.createMock(File.class, DIR_NAME);
+ expect(dir.exists()).andStubReturn(true);
+ expect(dir.listFiles()).andStubReturn(new File[] { file });
+ AndroidMock.replay(dir, file);
+
+ assertEquals(1, service.cleanTempDirectory(dir));
+ AndroidMock.verify(dir, file);
+ }
+}