mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-18 08:43:07 +02:00
sync from main
This commit is contained in:
@@ -158,17 +158,26 @@ limitations under the License.
|
|||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.app.default_searchable"
|
android:name="android.app.default_searchable"
|
||||||
android:value="com.google.android.apps.mytracks.SearchActivity" />
|
android:value="com.google.android.apps.mytracks.SearchActivity" />
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity android:name="com.google.android.apps.mytracks.ExportAllActivity"/>
|
||||||
<activity
|
<activity
|
||||||
android:name="com.google.android.apps.mytracks.DeleteTrack"
|
android:label="@string/my_tracks_importer"
|
||||||
|
android:name="com.google.android.apps.mytracks.ImportActivity"
|
||||||
android:noHistory="true"
|
android:noHistory="true"
|
||||||
android:theme="@android:style/Theme.Translucent.NoTitleBar" >
|
android:theme="@android:style/Theme.Translucent.NoTitleBar" >
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.DELETE" />
|
|
||||||
|
|
||||||
|
<action android:name="android.intent.action.ATTACH_DATA" />
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
|
||||||
<data android:mimeType="vnd.android.cursor.item/vnd.google.track" />
|
<data android:mimeType="application/gpx" />
|
||||||
|
<data android:mimeType="application/gpx+xml" />
|
||||||
|
<data android:mimeType="application/vnd.google-earth.gpx" />
|
||||||
|
<data android:mimeType="application/vnd.google-earth.gpx+xml" />
|
||||||
|
<data android:scheme="file" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
@@ -274,26 +283,10 @@ limitations under the License.
|
|||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:label="@string/welcome_title"
|
android:label="@string/welcome_title"
|
||||||
android:name="com.google.android.apps.mytracks.WelcomeActivity" />
|
android:name="com.google.android.apps.mytracks.WelcomeActivity" />
|
||||||
|
<activity android:name="com.google.android.apps.mytracks.io.backup.BackupActivity"/>
|
||||||
|
<activity android:name="com.google.android.apps.mytracks.io.backup.RestoreActivity"/>
|
||||||
|
<activity android:name="com.google.android.apps.mytracks.io.backup.RestoreChooserActivity"/>
|
||||||
<activity android:name="com.google.android.apps.mytracks.io.docs.SendDocsActivity" />
|
<activity android:name="com.google.android.apps.mytracks.io.docs.SendDocsActivity" />
|
||||||
<activity
|
|
||||||
android:label="@string/my_tracks_importer"
|
|
||||||
android:name="com.google.android.apps.mytracks.io.file.ImportActivity"
|
|
||||||
android:noHistory="true"
|
|
||||||
android:theme="@android:style/Theme.Translucent.NoTitleBar" >
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.ATTACH_DATA" />
|
|
||||||
<action android:name="android.intent.action.VIEW" />
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
|
|
||||||
<data android:mimeType="application/gpx" />
|
|
||||||
<data android:mimeType="application/gpx+xml" />
|
|
||||||
<data android:mimeType="application/vnd.google-earth.gpx" />
|
|
||||||
<data android:mimeType="application/vnd.google-earth.gpx+xml" />
|
|
||||||
<data android:scheme="file" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
<activity
|
<activity
|
||||||
android:name="com.google.android.apps.mytracks.io.file.SaveActivity"
|
android:name="com.google.android.apps.mytracks.io.file.SaveActivity"
|
||||||
android:noHistory="true"
|
android:noHistory="true"
|
||||||
@@ -312,7 +305,7 @@ limitations under the License.
|
|||||||
<activity android:name="com.google.android.apps.mytracks.io.sendtogoogle.AccountChooserActivity" />
|
<activity android:name="com.google.android.apps.mytracks.io.sendtogoogle.AccountChooserActivity" />
|
||||||
<activity android:name="com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity" />
|
<activity android:name="com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity" />
|
||||||
<activity android:name="com.google.android.apps.mytracks.io.sendtogoogle.UploadServiceChooserActivity" />
|
<activity android:name="com.google.android.apps.mytracks.io.sendtogoogle.UploadServiceChooserActivity" />
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:name="com.google.android.apps.mytracks.services.ControlRecordingService" />
|
android:name="com.google.android.apps.mytracks.services.ControlRecordingService" />
|
||||||
|
|||||||
@@ -1537,8 +1537,7 @@ limitations under the License.
|
|||||||
and it will overwrite all the current tracks and settings.
|
and it will overwrite all the current tracks and settings.
|
||||||
|
|
||||||
Screenshot: settings_backup_restore_confirm_message.png">
|
Screenshot: settings_backup_restore_confirm_message.png">
|
||||||
Restoring a backup from the SD card will overwrite all your current tracks and settings. Are you
|
Restoring a backup from the SD card will overwrite all your current tracks and settings.
|
||||||
sure?
|
|
||||||
</string>
|
</string>
|
||||||
<string name="settings_backup_restore_no_backup"
|
<string name="settings_backup_restore_no_backup"
|
||||||
translation_description="In the 'Backup' settings, after pressing the 'Restore now' option, the
|
translation_description="In the 'Backup' settings, after pressing the 'Restore now' option, the
|
||||||
|
|||||||
@@ -1,83 +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;
|
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks with the user if he prefers the metric units or the imperial units.
|
|
||||||
*
|
|
||||||
* @author Sandor Dornbush
|
|
||||||
*/
|
|
||||||
class CheckUnits {
|
|
||||||
private static final String CHECK_UNITS_PREFERENCE_FILE = "checkunits";
|
|
||||||
private static final String CHECK_UNITS_PREFERENCE_KEY = "checkunits.checked";
|
|
||||||
private static boolean metric = true;
|
|
||||||
|
|
||||||
public static void check(final Context context) {
|
|
||||||
final SharedPreferences checkUnitsSharedPreferences = context.getSharedPreferences(
|
|
||||||
CHECK_UNITS_PREFERENCE_FILE, Context.MODE_PRIVATE);
|
|
||||||
if (checkUnitsSharedPreferences.getBoolean(CHECK_UNITS_PREFERENCE_KEY, false)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
|
||||||
builder.setTitle(context.getString(R.string.preferred_units_title));
|
|
||||||
CharSequence[] items = { context.getString(R.string.preferred_units_metric),
|
|
||||||
context.getString(R.string.preferred_units_imperial) };
|
|
||||||
builder.setSingleChoiceItems(items, 0, new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
if (which == 0) {
|
|
||||||
metric = true;
|
|
||||||
} else {
|
|
||||||
metric = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
builder.setCancelable(true);
|
|
||||||
builder.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
recordCheckPerformed(checkUnitsSharedPreferences);
|
|
||||||
SharedPreferences useMetricPreferences = context.getSharedPreferences(
|
|
||||||
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
|
||||||
SharedPreferences.Editor editor = useMetricPreferences.edit();
|
|
||||||
String key = context.getString(R.string.metric_units_key);
|
|
||||||
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor.putBoolean(key, metric));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
|
||||||
public void onCancel(DialogInterface dialog) {
|
|
||||||
recordCheckPerformed(checkUnitsSharedPreferences);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
builder.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void recordCheckPerformed(SharedPreferences preferences) {
|
|
||||||
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(
|
|
||||||
preferences.edit().putBoolean(CHECK_UNITS_PREFERENCE_KEY, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
private CheckUnits() {}
|
|
||||||
}
|
|
||||||
@@ -37,16 +37,8 @@ public abstract class Constants {
|
|||||||
* onActivityResult request codes:
|
* onActivityResult request codes:
|
||||||
*/
|
*/
|
||||||
public static final int SHOW_TRACK = 0;
|
public static final int SHOW_TRACK = 0;
|
||||||
public static final int SHARE_GPX_FILE = 1;
|
public static final int SHOW_WAYPOINT = 1;
|
||||||
public static final int SHARE_KML_FILE = 2;
|
public static final int WELCOME = 2;
|
||||||
public static final int SHARE_CSV_FILE = 3;
|
|
||||||
public static final int SHARE_TCX_FILE = 4;
|
|
||||||
public static final int SAVE_GPX_FILE = 5;
|
|
||||||
public static final int SAVE_KML_FILE = 6;
|
|
||||||
public static final int SAVE_CSV_FILE = 7;
|
|
||||||
public static final int SAVE_TCX_FILE = 8;
|
|
||||||
public static final int SHOW_WAYPOINT = 9;
|
|
||||||
public static final int WELCOME = 10;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Context menu ids. Sorted alphabetically.
|
* Context menu ids. Sorted alphabetically.
|
||||||
@@ -168,29 +160,6 @@ public abstract class Constants {
|
|||||||
public static final String RESUME_TRACK_EXTRA_NAME =
|
public static final String RESUME_TRACK_EXTRA_NAME =
|
||||||
"com.google.android.apps.mytracks.RESUME_TRACK";
|
"com.google.android.apps.mytracks.RESUME_TRACK";
|
||||||
|
|
||||||
public static int getActionFromMenuId(int menuId) {
|
|
||||||
switch (menuId) {
|
|
||||||
case Constants.MENU_SHARE_KML_FILE:
|
|
||||||
return Constants.SHARE_KML_FILE;
|
|
||||||
case Constants.MENU_SHARE_GPX_FILE:
|
|
||||||
return Constants.SHARE_GPX_FILE;
|
|
||||||
case Constants.MENU_SHARE_CSV_FILE:
|
|
||||||
return Constants.SHARE_CSV_FILE;
|
|
||||||
case Constants.MENU_SHARE_TCX_FILE:
|
|
||||||
return Constants.SHARE_TCX_FILE;
|
|
||||||
case Constants.MENU_SAVE_GPX_FILE:
|
|
||||||
return Constants.SAVE_GPX_FILE;
|
|
||||||
case Constants.MENU_SAVE_KML_FILE:
|
|
||||||
return Constants.SAVE_KML_FILE;
|
|
||||||
case Constants.MENU_SAVE_CSV_FILE:
|
|
||||||
return Constants.SAVE_CSV_FILE;
|
|
||||||
case Constants.MENU_SAVE_TCX_FILE:
|
|
||||||
return Constants.SAVE_TCX_FILE;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String MAPSHOP_BASE_URL =
|
public static final String MAPSHOP_BASE_URL =
|
||||||
"https://maps.google.com/maps/ms";
|
"https://maps.google.com/maps/ms";
|
||||||
|
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2008 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;
|
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
|
||||||
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.SharedPreferences.Editor;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A utility class that can be used to delete all tracks and track points
|
|
||||||
* from the provider, including asking for confirmation from the user via
|
|
||||||
* a dialog.
|
|
||||||
*
|
|
||||||
* @author Leif Hendrik Wilden
|
|
||||||
*/
|
|
||||||
public class DeleteAllTracks extends Handler {
|
|
||||||
|
|
||||||
private final Context context;
|
|
||||||
private final Runnable done;
|
|
||||||
|
|
||||||
public DeleteAllTracks(Context context, Runnable done) {
|
|
||||||
this.context = context;
|
|
||||||
this.done = done;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message msg) {
|
|
||||||
super.handleMessage(msg);
|
|
||||||
|
|
||||||
AlertDialog dialog = null;
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
|
||||||
builder.setMessage(
|
|
||||||
context.getString(R.string.track_list_delete_all_confirm_message));
|
|
||||||
builder.setTitle(context.getString(R.string.generic_confirm_title));
|
|
||||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
|
||||||
builder.setPositiveButton(context.getString(R.string.generic_yes),
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialogInterface, int i) {
|
|
||||||
dialogInterface.dismiss();
|
|
||||||
Log.w(Constants.TAG, "deleting all!");
|
|
||||||
MyTracksProviderUtils.Factory.get(context).deleteAllTracks();
|
|
||||||
SharedPreferences prefs = context.getSharedPreferences(
|
|
||||||
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
|
||||||
Editor editor = prefs.edit();
|
|
||||||
// TODO: Go through data manager
|
|
||||||
editor.putLong(context.getString(R.string.selected_track_key), -1);
|
|
||||||
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
|
||||||
if (done != null) {
|
|
||||||
Handler h = new Handler();
|
|
||||||
h.post(done);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
builder.setNegativeButton(context.getString(R.string.generic_no),
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialogInterface, int i) {
|
|
||||||
dialogInterface.dismiss();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
dialog = builder.create();
|
|
||||||
dialog.show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011 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;
|
|
||||||
|
|
||||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
|
||||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
|
||||||
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
|
||||||
import com.google.android.apps.mytracks.util.UriUtils;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.ContentUris;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.DialogInterface.OnCancelListener;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.SharedPreferences.Editor;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Activity used to delete a track.
|
|
||||||
*
|
|
||||||
* @author Rodrigo Damazio
|
|
||||||
*/
|
|
||||||
public class DeleteTrack extends Activity
|
|
||||||
implements DialogInterface.OnClickListener, OnCancelListener {
|
|
||||||
private static final int CONFIRM_DIALOG = 1;
|
|
||||||
|
|
||||||
private MyTracksProviderUtils providerUtils;
|
|
||||||
|
|
||||||
private long deleteTrackId;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
providerUtils = MyTracksProviderUtils.Factory.get(this);
|
|
||||||
|
|
||||||
Intent intent = getIntent();
|
|
||||||
String action = intent.getAction();
|
|
||||||
Uri data = intent.getData();
|
|
||||||
if (!Intent.ACTION_DELETE.equals(action) ||
|
|
||||||
!UriUtils.matchesContentUri(data, TracksColumns.CONTENT_URI)) {
|
|
||||||
Log.e(TAG, "Got bad delete intent: " + intent);
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteTrackId = ContentUris.parseId(data);
|
|
||||||
|
|
||||||
showDialog(CONFIRM_DIALOG);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Dialog onCreateDialog(int id) {
|
|
||||||
if (id != CONFIRM_DIALOG) {
|
|
||||||
Log.e(TAG, "Unknown dialog " + id);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
||||||
builder.setMessage(getString(R.string.track_list_delete_track_confirm_message));
|
|
||||||
builder.setTitle(getString(R.string.generic_confirm_title));
|
|
||||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
|
||||||
builder.setPositiveButton(getString(R.string.generic_yes), this);
|
|
||||||
builder.setNegativeButton(getString(R.string.generic_no), this);
|
|
||||||
builder.setOnCancelListener(this);
|
|
||||||
return builder.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialogInterface, int which) {
|
|
||||||
dialogInterface.dismiss();
|
|
||||||
if (which == DialogInterface.BUTTON_POSITIVE) {
|
|
||||||
deleteTrack();
|
|
||||||
}
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCancel(DialogInterface dialog) {
|
|
||||||
onClick(dialog, DialogInterface.BUTTON_NEGATIVE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteTrack() {
|
|
||||||
providerUtils.deleteTrack(deleteTrackId);
|
|
||||||
|
|
||||||
// If the track we just deleted was selected, unselect it.
|
|
||||||
String selectedKey = getString(R.string.selected_track_key);
|
|
||||||
SharedPreferences preferences = getSharedPreferences(
|
|
||||||
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
|
||||||
if (preferences.getLong(selectedKey, -1) == deleteTrackId) {
|
|
||||||
Editor editor = preferences.edit().putLong(selectedKey, -1);
|
|
||||||
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 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;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An activity to export all the tracks to the SD card.
|
||||||
|
*
|
||||||
|
* @author Sandor Dornbush
|
||||||
|
*/
|
||||||
|
public class ExportAllActivity extends Activity {
|
||||||
|
|
||||||
|
public static final String EXTRA_TRACK_FILE_FORMAT = "track_file_format";
|
||||||
|
|
||||||
|
private static final int DIALOG_PROGRESS_ID = 0;
|
||||||
|
|
||||||
|
private ExportAllAsyncTask exportAllAsyncTask;
|
||||||
|
private ProgressDialog progressDialog;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
Object retained = getLastNonConfigurationInstance();
|
||||||
|
if (retained instanceof ExportAllAsyncTask) {
|
||||||
|
exportAllAsyncTask = (ExportAllAsyncTask) retained;
|
||||||
|
exportAllAsyncTask.setActivity(this);
|
||||||
|
} else {
|
||||||
|
Intent intent = getIntent();
|
||||||
|
TrackFileFormat trackFileFormat = intent.getParcelableExtra(EXTRA_TRACK_FILE_FORMAT);
|
||||||
|
|
||||||
|
exportAllAsyncTask = new ExportAllAsyncTask(this, trackFileFormat);
|
||||||
|
exportAllAsyncTask.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object onRetainNonConfigurationInstance() {
|
||||||
|
exportAllAsyncTask.setActivity(null);
|
||||||
|
return exportAllAsyncTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Dialog onCreateDialog(int id) {
|
||||||
|
switch (id) {
|
||||||
|
case DIALOG_PROGRESS_ID:
|
||||||
|
progressDialog = new ProgressDialog(this);
|
||||||
|
progressDialog.setCancelable(true);
|
||||||
|
progressDialog.setIcon(android.R.drawable.ic_dialog_info);
|
||||||
|
progressDialog.setIndeterminate(true);
|
||||||
|
progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||||
|
@Override
|
||||||
|
public void onCancel(DialogInterface dialog) {
|
||||||
|
exportAllAsyncTask.cancel(true);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||||
|
progressDialog.setTitle(R.string.track_list_export_all);
|
||||||
|
return progressDialog;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes when the associated AsyncTask completes.
|
||||||
|
*
|
||||||
|
* @param success true if the AsyncTask is successful
|
||||||
|
* @param messageId message id to display to user
|
||||||
|
*/
|
||||||
|
public void onAsyncTaskCompleted(boolean success, int messageId) {
|
||||||
|
removeDialog(DIALOG_PROGRESS_ID);
|
||||||
|
Toast.makeText(this, messageId, success ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG).show();
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the progress dialog.
|
||||||
|
*/
|
||||||
|
public void showProgressDialog() {
|
||||||
|
showDialog(DIALOG_PROGRESS_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the progress dialog value.
|
||||||
|
*
|
||||||
|
* @param number the number of tracks exported
|
||||||
|
* @param max the maximum number of tracks
|
||||||
|
*/
|
||||||
|
public void setProgressDialogValue(int number, int max) {
|
||||||
|
if (progressDialog != null) {
|
||||||
|
progressDialog.setIndeterminate(false);
|
||||||
|
progressDialog.setMax(max);
|
||||||
|
progressDialog.setProgress(Math.min(number, max));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||||
|
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||||
|
import com.google.android.apps.mytracks.io.file.TrackWriter;
|
||||||
|
import com.google.android.apps.mytracks.io.file.TrackWriterFactory;
|
||||||
|
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
|
||||||
|
import com.google.android.apps.mytracks.util.SystemUtils;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.PowerManager.WakeLock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AsyncTask to export all the tracks to the SD card.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public class ExportAllAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||||
|
|
||||||
|
private ExportAllActivity exportAllActivity;
|
||||||
|
private final TrackFileFormat trackFileFormat;
|
||||||
|
private final Context context;
|
||||||
|
private final MyTracksProviderUtils myTracksProviderUtils;
|
||||||
|
private WakeLock wakeLock;
|
||||||
|
private TrackWriter trackWriter;
|
||||||
|
|
||||||
|
// true if the AsyncTask result is success
|
||||||
|
private boolean success;
|
||||||
|
|
||||||
|
// true if the AsyncTask has completed
|
||||||
|
private boolean completed;
|
||||||
|
|
||||||
|
// message id to return to the activity
|
||||||
|
private int messageId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an AsyncTask.
|
||||||
|
*
|
||||||
|
* @param exportAllActivity the activity currently associated with this
|
||||||
|
* AsyncTask
|
||||||
|
* @param trackFileFormat the track file format
|
||||||
|
*/
|
||||||
|
public ExportAllAsyncTask(ExportAllActivity exportAllActivity, TrackFileFormat trackFileFormat) {
|
||||||
|
this.exportAllActivity = exportAllActivity;
|
||||||
|
this.trackFileFormat = trackFileFormat;
|
||||||
|
context = exportAllActivity.getApplicationContext();
|
||||||
|
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(exportAllActivity);
|
||||||
|
|
||||||
|
SharedPreferences sharedPreferences = exportAllActivity.getSharedPreferences(
|
||||||
|
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
||||||
|
long recordingTrackId = sharedPreferences.getLong(
|
||||||
|
exportAllActivity.getString(R.string.recording_track_key), -1L);
|
||||||
|
|
||||||
|
// Get the wake lock if not recording
|
||||||
|
if (recordingTrackId == -1L) {
|
||||||
|
wakeLock = SystemUtils.acquireWakeLock(exportAllActivity, wakeLock);
|
||||||
|
}
|
||||||
|
success = false;
|
||||||
|
completed = false;
|
||||||
|
messageId = R.string.export_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current {@link ExportAllActivity} associated with this AyncTask.
|
||||||
|
*
|
||||||
|
* @param exportAllActivity the current {@link ExportAllActivity}, can be null
|
||||||
|
*/
|
||||||
|
public void setActivity(ExportAllActivity exportAllActivity) {
|
||||||
|
this.exportAllActivity = exportAllActivity;
|
||||||
|
if (completed && exportAllActivity != null) {
|
||||||
|
exportAllActivity.onAsyncTaskCompleted(success, messageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute() {
|
||||||
|
if (exportAllActivity != null) {
|
||||||
|
exportAllActivity.showProgressDialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boolean doInBackground(Void... params) {
|
||||||
|
Cursor cursor = null;
|
||||||
|
try {
|
||||||
|
cursor = myTracksProviderUtils.getTracksCursor(null, null, TracksColumns._ID);
|
||||||
|
if (cursor == null) {
|
||||||
|
messageId = R.string.export_success;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int count = cursor.getCount();
|
||||||
|
int idIndex = cursor.getColumnIndexOrThrow(TracksColumns._ID);
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
if (isCancelled()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cursor.moveToPosition(i);
|
||||||
|
long id = cursor.getLong(idIndex);
|
||||||
|
trackWriter = TrackWriterFactory.newWriter(
|
||||||
|
context, myTracksProviderUtils, id, trackFileFormat);
|
||||||
|
if (trackWriter == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
trackWriter.writeTrack();
|
||||||
|
|
||||||
|
if (!trackWriter.wasSuccess()) {
|
||||||
|
messageId = trackWriter.getErrorMessage();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
publishProgress(i + 1, count);
|
||||||
|
}
|
||||||
|
messageId = R.string.export_success;
|
||||||
|
return true;
|
||||||
|
} finally {
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
// Release the wake lock if obtained
|
||||||
|
if (wakeLock != null && wakeLock.isHeld()) {
|
||||||
|
wakeLock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onProgressUpdate(Integer... values) {
|
||||||
|
if (exportAllActivity != null) {
|
||||||
|
exportAllActivity.setProgressDialogValue(values[0], values[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Boolean result) {
|
||||||
|
success = result;
|
||||||
|
completed = true;
|
||||||
|
if (exportAllActivity != null) {
|
||||||
|
exportAllActivity.onAsyncTaskCompleted(success, messageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCancelled() {
|
||||||
|
if (trackWriter != null) {
|
||||||
|
trackWriter.stopWriteTrack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,229 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2009 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;
|
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
|
||||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
|
||||||
import com.google.android.apps.mytracks.io.file.TrackWriter;
|
|
||||||
import com.google.android.apps.mytracks.io.file.TrackWriterFactory;
|
|
||||||
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
|
|
||||||
import com.google.android.apps.mytracks.util.SystemUtils;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.os.PowerManager.WakeLock;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class that will export all tracks to the sd card.
|
|
||||||
*
|
|
||||||
* @author Sandor Dornbush
|
|
||||||
*/
|
|
||||||
public class ExportAllTracks {
|
|
||||||
// These must line up with the index in the array.
|
|
||||||
public static final int GPX_OPTION_INDEX = 0;
|
|
||||||
public static final int KML_OPTION_INDEX = 1;
|
|
||||||
public static final int CSV_OPTION_INDEX = 2;
|
|
||||||
public static final int TCX_OPTION_INDEX = 3;
|
|
||||||
|
|
||||||
private final Activity activity;
|
|
||||||
private WakeLock wakeLock;
|
|
||||||
private ProgressDialog progress;
|
|
||||||
|
|
||||||
private TrackFileFormat format = TrackFileFormat.GPX;
|
|
||||||
|
|
||||||
private final DialogInterface.OnClickListener itemClick =
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
switch (which) {
|
|
||||||
case GPX_OPTION_INDEX:
|
|
||||||
format = TrackFileFormat.GPX;
|
|
||||||
break;
|
|
||||||
case KML_OPTION_INDEX:
|
|
||||||
format = TrackFileFormat.KML;
|
|
||||||
break;
|
|
||||||
case CSV_OPTION_INDEX:
|
|
||||||
format = TrackFileFormat.CSV;
|
|
||||||
break;
|
|
||||||
case TCX_OPTION_INDEX:
|
|
||||||
format = TrackFileFormat.TCX;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Log.w(Constants.TAG, "Unknown export format: " + which);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public ExportAllTracks(Activity activity) {
|
|
||||||
this.activity = activity;
|
|
||||||
Log.i(Constants.TAG, "ExportAllTracks: Starting");
|
|
||||||
|
|
||||||
String exportFileFormat = activity.getString(R.string.track_list_export_file);
|
|
||||||
String fileTypes[] = activity.getResources().getStringArray(R.array.file_types);
|
|
||||||
|
|
||||||
String[] choices = new String[fileTypes.length];
|
|
||||||
for (int i = 0; i < fileTypes.length; i++) {
|
|
||||||
choices[i] = String.format(exportFileFormat, fileTypes[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
|
||||||
builder.setTitle(R.string.track_list_export_all);
|
|
||||||
builder.setSingleChoiceItems(choices, 0, itemClick);
|
|
||||||
builder.setPositiveButton(R.string.generic_ok, positiveClick);
|
|
||||||
builder.setNegativeButton(R.string.generic_cancel, null);
|
|
||||||
builder.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private final DialogInterface.OnClickListener positiveClick =
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
new Thread(runner, "ExportAllTracks").start();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final Runnable runner = new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
aquireLocksAndExport();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes sure that we keep the phone from sleeping.
|
|
||||||
* See if there is a current track. Aquire a wake lock if there is no
|
|
||||||
* current track.
|
|
||||||
*/
|
|
||||||
private void aquireLocksAndExport() {
|
|
||||||
SharedPreferences prefs = activity.getSharedPreferences(
|
|
||||||
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
|
||||||
long recordingTrackId = -1;
|
|
||||||
if (prefs != null) {
|
|
||||||
recordingTrackId =
|
|
||||||
prefs.getLong(activity.getString(R.string.recording_track_key), -1);
|
|
||||||
}
|
|
||||||
if (recordingTrackId != -1) {
|
|
||||||
wakeLock = SystemUtils.acquireWakeLock(activity, wakeLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now we can safely export everything.
|
|
||||||
exportAll();
|
|
||||||
|
|
||||||
// Release the wake lock if we recorded one.
|
|
||||||
// TODO check what happens if we started recording after getting this lock.
|
|
||||||
if (wakeLock != null && wakeLock.isHeld()) {
|
|
||||||
wakeLock.release();
|
|
||||||
Log.i(Constants.TAG, "ExportAllTracks: Releasing wake lock.");
|
|
||||||
}
|
|
||||||
Log.i(Constants.TAG, "ExportAllTracks: Done");
|
|
||||||
showToast(R.string.export_success, Toast.LENGTH_SHORT);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void makeProgressDialog(final int trackCount) {
|
|
||||||
String exportMsg = activity.getString(R.string.track_list_export_all);
|
|
||||||
progress = new ProgressDialog(activity);
|
|
||||||
progress.setIcon(android.R.drawable.ic_dialog_info);
|
|
||||||
progress.setTitle(exportMsg);
|
|
||||||
progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
|
||||||
progress.setMax(trackCount);
|
|
||||||
progress.setProgress(0);
|
|
||||||
progress.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Actually export the tracks.
|
|
||||||
* This should be called after the wake locks have been aquired.
|
|
||||||
*/
|
|
||||||
private void exportAll() {
|
|
||||||
// Get a cursor over all tracks.
|
|
||||||
Cursor cursor = null;
|
|
||||||
try {
|
|
||||||
MyTracksProviderUtils providerUtils =
|
|
||||||
MyTracksProviderUtils.Factory.get(activity);
|
|
||||||
cursor = providerUtils.getTracksCursor(null, null, TracksColumns._ID);
|
|
||||||
if (cursor == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int trackCount = cursor.getCount();
|
|
||||||
Log.i(Constants.TAG,
|
|
||||||
"ExportAllTracks: Exporting: " + cursor.getCount() + " tracks.");
|
|
||||||
int idxTrackId = cursor.getColumnIndexOrThrow(TracksColumns._ID);
|
|
||||||
activity.runOnUiThread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
makeProgressDialog(trackCount);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
for (int i = 0; cursor.moveToNext(); i++) {
|
|
||||||
final int status = i;
|
|
||||||
activity.runOnUiThread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
synchronized (this) {
|
|
||||||
if (progress == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
progress.setProgress(status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
long id = cursor.getLong(idxTrackId);
|
|
||||||
Log.i(Constants.TAG, "ExportAllTracks: exporting: " + id);
|
|
||||||
TrackWriter writer =
|
|
||||||
TrackWriterFactory.newWriter(activity, providerUtils, id, format);
|
|
||||||
if (writer == null) {
|
|
||||||
showToast(R.string.export_error, Toast.LENGTH_LONG);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.writeTrack();
|
|
||||||
|
|
||||||
if (!writer.wasSuccess()) {
|
|
||||||
// Abort the whole export on the first error.
|
|
||||||
showToast(writer.getErrorMessage(), Toast.LENGTH_LONG);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (cursor != null) {
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
if (progress != null) {
|
|
||||||
synchronized (this) {
|
|
||||||
progress.dismiss();
|
|
||||||
progress = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showToast(final int messageId, final int length) {
|
|
||||||
activity.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Toast.makeText(activity, messageId, length).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,207 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011 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;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||||
|
import com.google.android.apps.mytracks.util.FileUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.UriUtils;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.content.ContentUris;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An activity to import GPX files from the SD card. Optionally to import one
|
||||||
|
* GPX file and display it in My Tracks.
|
||||||
|
*
|
||||||
|
* @author Rodrigo Damazio
|
||||||
|
*/
|
||||||
|
public class ImportActivity extends Activity {
|
||||||
|
|
||||||
|
public static final String EXTRA_IMPORT_ALL = "import_all";
|
||||||
|
|
||||||
|
private static final String TAG = ImportActivity.class.getSimpleName();
|
||||||
|
|
||||||
|
private static final int DIALOG_PROGRESS_ID = 0;
|
||||||
|
private static final int DIALOG_RESULT_ID = 1;
|
||||||
|
|
||||||
|
private ImportAsyncTask importAsyncTask;
|
||||||
|
private ProgressDialog progressDialog;
|
||||||
|
|
||||||
|
private boolean importAll;
|
||||||
|
|
||||||
|
// path on the SD card to import
|
||||||
|
private String path;
|
||||||
|
|
||||||
|
// number of succesfully imported files
|
||||||
|
private int successCount;
|
||||||
|
|
||||||
|
// number of files to import
|
||||||
|
private int totalCount;
|
||||||
|
|
||||||
|
// last successfully imported track id
|
||||||
|
private long trackId;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
Intent intent = getIntent();
|
||||||
|
importAll = intent.getBooleanExtra(EXTRA_IMPORT_ALL, false);
|
||||||
|
if (importAll) {
|
||||||
|
path = new FileUtils().buildExternalDirectoryPath("gpx");
|
||||||
|
} else {
|
||||||
|
String action = intent.getAction();
|
||||||
|
if (!(Intent.ACTION_ATTACH_DATA.equals(action) || Intent.ACTION_VIEW.equals(action))) {
|
||||||
|
Log.d(TAG, "Invalid action: " + intent);
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uri data = intent.getData();
|
||||||
|
if (!UriUtils.isFileUri(data)) {
|
||||||
|
Log.d(TAG, "Invalid data: " + intent);
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
path = data.getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
Object retained = getLastNonConfigurationInstance();
|
||||||
|
if (retained instanceof ImportAsyncTask) {
|
||||||
|
importAsyncTask = (ImportAsyncTask) retained;
|
||||||
|
importAsyncTask.setActivity(this);
|
||||||
|
} else {
|
||||||
|
importAsyncTask = new ImportAsyncTask(this, importAll, path);
|
||||||
|
importAsyncTask.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object onRetainNonConfigurationInstance() {
|
||||||
|
importAsyncTask.setActivity(null);
|
||||||
|
return importAsyncTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Dialog onCreateDialog(int id) {
|
||||||
|
switch (id) {
|
||||||
|
case DIALOG_PROGRESS_ID:
|
||||||
|
progressDialog = new ProgressDialog(this);
|
||||||
|
progressDialog.setCancelable(true);
|
||||||
|
progressDialog.setIcon(android.R.drawable.ic_dialog_info);
|
||||||
|
progressDialog.setIndeterminate(true);
|
||||||
|
progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||||
|
@Override
|
||||||
|
public void onCancel(DialogInterface dialog) {
|
||||||
|
importAsyncTask.cancel(true);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||||
|
progressDialog.setTitle(R.string.track_list_import_all);
|
||||||
|
return progressDialog;
|
||||||
|
case DIALOG_RESULT_ID:
|
||||||
|
String message;
|
||||||
|
if (successCount == 0) {
|
||||||
|
message = getString(R.string.import_no_file, path);
|
||||||
|
} else {
|
||||||
|
String totalFiles = getResources()
|
||||||
|
.getQuantityString(R.plurals.importGpxFiles, totalCount, totalCount);
|
||||||
|
message = getString(R.string.import_success, successCount, totalFiles, path);
|
||||||
|
}
|
||||||
|
return new AlertDialog.Builder(this).setCancelable(true)
|
||||||
|
.setCancelable(true)
|
||||||
|
.setMessage(message)
|
||||||
|
.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||||
|
@Override
|
||||||
|
public void onCancel(DialogInterface dialog) {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
if (!importAll && trackId != -1L) {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
intent.setDataAndType(
|
||||||
|
ContentUris.withAppendedId(TracksColumns.CONTENT_URI, trackId),
|
||||||
|
TracksColumns.CONTENT_ITEMTYPE);
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.create();
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes when the associated AsyncTask completes.
|
||||||
|
*
|
||||||
|
* @param success true if the AsyncTask is successful
|
||||||
|
* @param imported the number of files successfully imported
|
||||||
|
* @param total the total number of files to import
|
||||||
|
* @param id the last successfully imported track id
|
||||||
|
*/
|
||||||
|
public void onAsyncTaskCompleted(boolean success, int imported, int total, long id) {
|
||||||
|
successCount = imported;
|
||||||
|
totalCount = total;
|
||||||
|
trackId = id;
|
||||||
|
removeDialog(DIALOG_PROGRESS_ID);
|
||||||
|
if (success) {
|
||||||
|
showDialog(DIALOG_RESULT_ID);
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this, getString(R.string.import_error, path), Toast.LENGTH_LONG).show();
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the progress dialog.
|
||||||
|
*/
|
||||||
|
public void showProgressDialog() {
|
||||||
|
showDialog(DIALOG_PROGRESS_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the progress dialog value.
|
||||||
|
*
|
||||||
|
* @param number the number of files imported
|
||||||
|
* @param max the maximum number of files
|
||||||
|
*/
|
||||||
|
public void setProgressDialogValue(int number, int max) {
|
||||||
|
if (progressDialog != null) {
|
||||||
|
progressDialog.setIndeterminate(false);
|
||||||
|
progressDialog.setMax(max);
|
||||||
|
progressDialog.setProgress(Math.min(number, max));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,269 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011 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;
|
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
|
||||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
|
||||||
import com.google.android.apps.mytracks.io.file.GpxImporter;
|
|
||||||
import com.google.android.apps.mytracks.util.FileUtils;
|
|
||||||
import com.google.android.apps.mytracks.util.SystemUtils;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.ContentUris;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.PowerManager.WakeLock;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class that will import all GPX tracks in /sdcard/MyTracks/gpx/
|
|
||||||
*
|
|
||||||
* @author David Piggott
|
|
||||||
*/
|
|
||||||
public class ImportAllTracks {
|
|
||||||
|
|
||||||
private final Activity activity;
|
|
||||||
private FileUtils fileUtils;
|
|
||||||
private boolean singleTrackSelected;
|
|
||||||
private String gpxPath;
|
|
||||||
private WakeLock wakeLock;
|
|
||||||
private ProgressDialog progress;
|
|
||||||
private int gpxFileCount;
|
|
||||||
private int importSuccessCount;
|
|
||||||
private long importedTrackIds[];
|
|
||||||
|
|
||||||
public ImportAllTracks(Activity activity) {
|
|
||||||
this(activity, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor to import tracks.
|
|
||||||
*
|
|
||||||
* @param activity the activity
|
|
||||||
* @param path path of the gpx file to import and display. If null, then just
|
|
||||||
* import all the gpx files under MyTracks/gpx and do not display any
|
|
||||||
* track.
|
|
||||||
*/
|
|
||||||
public ImportAllTracks(Activity activity, String path) {
|
|
||||||
Log.i(Constants.TAG, "ImportAllTracks: Starting");
|
|
||||||
this.activity = activity;
|
|
||||||
fileUtils = new FileUtils();
|
|
||||||
singleTrackSelected = path != null;
|
|
||||||
gpxPath = path == null ? fileUtils.buildExternalDirectoryPath("gpx") : path;
|
|
||||||
new Thread(runner).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Runnable runner = new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
aquireLocksAndImport();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes sure that we keep the phone from sleeping. See if there is a current
|
|
||||||
* track. Acquire a wake lock if there is no current track.
|
|
||||||
*/
|
|
||||||
private void aquireLocksAndImport() {
|
|
||||||
SharedPreferences prefs = activity.getSharedPreferences(
|
|
||||||
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
|
||||||
long recordingTrackId = -1;
|
|
||||||
if (prefs != null) {
|
|
||||||
recordingTrackId = prefs.getLong(activity.getString(R.string.recording_track_key), -1);
|
|
||||||
}
|
|
||||||
if (recordingTrackId == -1) {
|
|
||||||
wakeLock = SystemUtils.acquireWakeLock(activity, wakeLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now we can safely import everything.
|
|
||||||
importAll();
|
|
||||||
|
|
||||||
// Release the wake lock if we acquired one.
|
|
||||||
// TODO check what happens if we started recording after getting this lock.
|
|
||||||
if (wakeLock != null && wakeLock.isHeld()) {
|
|
||||||
wakeLock.release();
|
|
||||||
Log.i(Constants.TAG, "ImportAllTracks: Releasing wake lock.");
|
|
||||||
}
|
|
||||||
|
|
||||||
activity.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
showDoneDialog();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showDoneDialog() {
|
|
||||||
Log.i(Constants.TAG, "ImportAllTracks: Done");
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
|
||||||
if (gpxFileCount == 0) {
|
|
||||||
builder.setMessage(activity.getString(R.string.import_no_file, gpxPath));
|
|
||||||
} else {
|
|
||||||
String totalFiles = activity.getResources().getQuantityString(
|
|
||||||
R.plurals.importGpxFiles, gpxFileCount, gpxFileCount);
|
|
||||||
builder.setMessage(
|
|
||||||
activity.getString(R.string.import_success, importSuccessCount, totalFiles, gpxPath));
|
|
||||||
}
|
|
||||||
builder.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
if (singleTrackSelected) {
|
|
||||||
long lastTrackId = importedTrackIds[importedTrackIds.length - 1];
|
|
||||||
Uri trackUri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, lastTrackId);
|
|
||||||
|
|
||||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
|
||||||
intent.setDataAndType(trackUri, TracksColumns.CONTENT_ITEMTYPE);
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
|
||||||
activity.startActivity(intent);
|
|
||||||
activity.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
builder.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void makeProgressDialog(final int trackCount) {
|
|
||||||
String importMsg = activity.getString(R.string.track_list_import_all);
|
|
||||||
progress = new ProgressDialog(activity);
|
|
||||||
progress.setIcon(android.R.drawable.ic_dialog_info);
|
|
||||||
progress.setTitle(importMsg);
|
|
||||||
progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
|
||||||
progress.setMax(trackCount);
|
|
||||||
progress.setProgress(0);
|
|
||||||
progress.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Actually import the tracks. This should be called after the wake locks have
|
|
||||||
* been acquired.
|
|
||||||
*/
|
|
||||||
private void importAll() {
|
|
||||||
MyTracksProviderUtils providerUtils = MyTracksProviderUtils.Factory.get(activity);
|
|
||||||
|
|
||||||
if (!fileUtils.isSdCardAvailable()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<File> gpxFiles = getGpxFiles();
|
|
||||||
gpxFileCount = gpxFiles.size();
|
|
||||||
if (gpxFileCount == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.i(Constants.TAG, "ImportAllTracks: Importing: " + gpxFileCount + " tracks.");
|
|
||||||
activity.runOnUiThread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
makeProgressDialog(gpxFileCount);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Iterator<File> gpxFilesIterator = gpxFiles.iterator();
|
|
||||||
for (int currentFileNumber = 0; gpxFilesIterator.hasNext(); currentFileNumber++) {
|
|
||||||
File currentFile = gpxFilesIterator.next();
|
|
||||||
final int status = currentFileNumber;
|
|
||||||
activity.runOnUiThread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
synchronized (this) {
|
|
||||||
if (progress == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
progress.setProgress(status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (importFile(currentFile, providerUtils)) {
|
|
||||||
importSuccessCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (progress != null) {
|
|
||||||
synchronized (this) {
|
|
||||||
progress.dismiss();
|
|
||||||
progress = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempts to import a GPX file. Returns true on success, issues error
|
|
||||||
* notifications and returns false on failure.
|
|
||||||
*/
|
|
||||||
private boolean importFile(final File gpxFile, MyTracksProviderUtils providerUtils) {
|
|
||||||
Log.i(Constants.TAG, "ImportAllTracks: importing: " + gpxFile.getName());
|
|
||||||
try {
|
|
||||||
importedTrackIds = GpxImporter.importGPXFile(new FileInputStream(gpxFile), providerUtils);
|
|
||||||
return true;
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
Log.w(Constants.TAG, "GPX file wasn't found/went missing: "
|
|
||||||
+ gpxFile.getAbsolutePath(), e);
|
|
||||||
} catch (ParserConfigurationException e) {
|
|
||||||
Log.w(Constants.TAG, "Error parsing file: " + gpxFile.getAbsolutePath(), e);
|
|
||||||
} catch (SAXException e) {
|
|
||||||
Log.w(Constants.TAG, "Error parsing file: " + gpxFile.getAbsolutePath(), e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.w(Constants.TAG, "Error reading file: " + gpxFile.getAbsolutePath(), e);
|
|
||||||
}
|
|
||||||
activity.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Toast.makeText(activity, activity.getString(R.string.import_error, gpxFile.getName()),
|
|
||||||
Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a list of the GPX files. If singleTrackSelected is true, returns a
|
|
||||||
* list containing just the gpxPath file. If singleTrackSelected is false,
|
|
||||||
* returns a list of GPX files under the gpxPath directory.
|
|
||||||
*/
|
|
||||||
private List<File> getGpxFiles() {
|
|
||||||
List<File> gpxFiles = new LinkedList<File>();
|
|
||||||
File file = new File(gpxPath);
|
|
||||||
if (singleTrackSelected) {
|
|
||||||
gpxFiles.add(file);
|
|
||||||
} else {
|
|
||||||
File[] gpxFileCandidates = file.listFiles();
|
|
||||||
if (gpxFileCandidates != null) {
|
|
||||||
for (File candidate : gpxFileCandidates) {
|
|
||||||
if (!candidate.isDirectory() && candidate.getName().endsWith(".gpx")) {
|
|
||||||
gpxFiles.add(candidate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return gpxFiles;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,221 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||||
|
import com.google.android.apps.mytracks.io.file.GpxImporter;
|
||||||
|
import com.google.android.apps.mytracks.util.FileUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.SystemUtils;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.PowerManager.WakeLock;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AsyncTask to import GPX files from the SD card.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public class ImportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||||
|
|
||||||
|
private static final String TAG = ImportAsyncTask.class.getSimpleName();
|
||||||
|
|
||||||
|
private ImportActivity importActivity;
|
||||||
|
private final boolean importAll;
|
||||||
|
private final String path;
|
||||||
|
private final MyTracksProviderUtils myTracksProviderUtils;
|
||||||
|
private WakeLock wakeLock;
|
||||||
|
|
||||||
|
// true if the AsyncTask result is success
|
||||||
|
private boolean success;
|
||||||
|
|
||||||
|
// true if the AsyncTask has completed
|
||||||
|
private boolean completed;
|
||||||
|
|
||||||
|
// number of files successfully imported
|
||||||
|
private int successCount;
|
||||||
|
|
||||||
|
// number of files to import
|
||||||
|
private int totalCount;
|
||||||
|
|
||||||
|
// the last successfully imported track id
|
||||||
|
private long trackId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an AsyncTask.
|
||||||
|
*
|
||||||
|
* @param importActivity the activity currently associated with this AsyncTask
|
||||||
|
* @param importAll true to import all GPX files
|
||||||
|
* @param path path to import GPX files
|
||||||
|
*/
|
||||||
|
public ImportAsyncTask(ImportActivity importActivity, boolean importAll, String path) {
|
||||||
|
this.importActivity = importActivity;
|
||||||
|
this.importAll = importAll;
|
||||||
|
this.path = path;
|
||||||
|
|
||||||
|
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(importActivity);
|
||||||
|
SharedPreferences sharedPreferences = importActivity.getSharedPreferences(
|
||||||
|
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
||||||
|
long recordingTrackId = sharedPreferences.getLong(
|
||||||
|
importActivity.getString(R.string.recording_track_key), -1L);
|
||||||
|
|
||||||
|
// Get the wake lock if not recording
|
||||||
|
if (recordingTrackId == -1L) {
|
||||||
|
wakeLock = SystemUtils.acquireWakeLock(importActivity, wakeLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
success = false;
|
||||||
|
completed = false;
|
||||||
|
successCount = 0;
|
||||||
|
totalCount = 0;
|
||||||
|
trackId = -1L;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current {@link ImportActivity} associated with this AyncTask.
|
||||||
|
*
|
||||||
|
* @param importActivity the current {@link ImportActivity}, can be null
|
||||||
|
*/
|
||||||
|
public void setActivity(ImportActivity importActivity) {
|
||||||
|
this.importActivity = importActivity;
|
||||||
|
if (completed && importActivity != null) {
|
||||||
|
importActivity.onAsyncTaskCompleted(success, successCount, totalCount, trackId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute() {
|
||||||
|
if (importActivity != null) {
|
||||||
|
importActivity.showProgressDialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boolean doInBackground(Void... params) {
|
||||||
|
try {
|
||||||
|
FileUtils fileUtils = new FileUtils();
|
||||||
|
if (!fileUtils.isSdCardAvailable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<File> files = getFiles();
|
||||||
|
totalCount = files.size();
|
||||||
|
if (totalCount == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < totalCount; i++) {
|
||||||
|
if (isCancelled()) {
|
||||||
|
// If cancelled, return true to show the number of files imported
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
File file = files.get(i);
|
||||||
|
if (importFile(file)) {
|
||||||
|
successCount++;
|
||||||
|
}
|
||||||
|
publishProgress(i + 1, totalCount);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} finally {
|
||||||
|
// Release the wake lock if obtained
|
||||||
|
if (wakeLock != null && wakeLock.isHeld()) {
|
||||||
|
wakeLock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onProgressUpdate(Integer... values) {
|
||||||
|
if (importActivity != null) {
|
||||||
|
importActivity.setProgressDialogValue(values[0], values[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Boolean result) {
|
||||||
|
success = result;
|
||||||
|
completed = true;
|
||||||
|
if (importActivity != null) {
|
||||||
|
importActivity.onAsyncTaskCompleted(success, successCount, totalCount, trackId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Imports a GPX file.
|
||||||
|
*
|
||||||
|
* @param file the file
|
||||||
|
*/
|
||||||
|
private boolean importFile(final File file) {
|
||||||
|
try {
|
||||||
|
long trackIds[] = GpxImporter.importGPXFile(new FileInputStream(file), myTracksProviderUtils);
|
||||||
|
int length = trackIds.length;
|
||||||
|
if (length > 0) {
|
||||||
|
trackId = trackIds[length - 1];
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
Log.d(TAG, "file: " + file.getAbsolutePath(), e);
|
||||||
|
return false;
|
||||||
|
} catch (ParserConfigurationException e) {
|
||||||
|
Log.d(TAG, "file: " + file.getAbsolutePath(), e);
|
||||||
|
return false;
|
||||||
|
} catch (SAXException e) {
|
||||||
|
Log.d(TAG, "file: " + file.getAbsolutePath(), e);
|
||||||
|
return false;
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(TAG, "file: " + file.getAbsolutePath(), e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a list of GPX files. If importAll is true, returns a list of GPX files
|
||||||
|
* under the path directory. If importAll is false, returns a list containing
|
||||||
|
* just the path file.
|
||||||
|
*/
|
||||||
|
private List<File> getFiles() {
|
||||||
|
List<File> files = new ArrayList<File>();
|
||||||
|
File file = new File(path);
|
||||||
|
if (importAll) {
|
||||||
|
File[] candidates = file.listFiles();
|
||||||
|
if (candidates != null) {
|
||||||
|
for (File candidate : candidates) {
|
||||||
|
if (!candidate.isDirectory() && candidate.getName().endsWith(".gpx")) {
|
||||||
|
files.add(candidate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
files.add(file);
|
||||||
|
}
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,13 +22,14 @@ import com.google.android.apps.mytracks.content.Track;
|
|||||||
import com.google.android.apps.mytracks.content.TrackDataHub;
|
import com.google.android.apps.mytracks.content.TrackDataHub;
|
||||||
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
|
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
|
||||||
import com.google.android.apps.mytracks.content.TrackDataListener;
|
import com.google.android.apps.mytracks.content.TrackDataListener;
|
||||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
import com.google.android.apps.mytracks.io.file.SaveActivity;
|
import com.google.android.apps.mytracks.io.file.SaveActivity;
|
||||||
|
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
|
||||||
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
|
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
|
||||||
import com.google.android.apps.mytracks.io.sendtogoogle.UploadServiceChooserActivity;
|
import com.google.android.apps.mytracks.io.sendtogoogle.UploadServiceChooserActivity;
|
||||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||||
|
import com.google.android.apps.mytracks.util.DialogUtils;
|
||||||
import com.google.android.apps.mytracks.util.GeoRect;
|
import com.google.android.apps.mytracks.util.GeoRect;
|
||||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||||
import com.google.android.apps.mytracks.util.PlayTrackUtils;
|
import com.google.android.apps.mytracks.util.PlayTrackUtils;
|
||||||
@@ -38,11 +39,14 @@ import com.google.android.maps.MapView;
|
|||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.ContentUris;
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.SharedPreferences.Editor;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Parcelable;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.speech.tts.TextToSpeech;
|
import android.speech.tts.TextToSpeech;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -72,7 +76,8 @@ public class MapActivity extends com.google.android.maps.MapActivity
|
|||||||
implements View.OnTouchListener, View.OnClickListener,
|
implements View.OnTouchListener, View.OnClickListener,
|
||||||
TrackDataListener {
|
TrackDataListener {
|
||||||
|
|
||||||
private static final int DIALOG_INSTALL_EARTH = 0;
|
private static final int DIALOG_INSTALL_EARTH_ID = 0;
|
||||||
|
private static final int DIALOG_DELETE_CURRENT_ID = 1;
|
||||||
|
|
||||||
// Saved instance state keys:
|
// Saved instance state keys:
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
@@ -241,8 +246,26 @@ public class MapActivity extends com.google.android.maps.MapActivity
|
|||||||
@Override
|
@Override
|
||||||
protected Dialog onCreateDialog(int id) {
|
protected Dialog onCreateDialog(int id) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case DIALOG_INSTALL_EARTH:
|
case DIALOG_INSTALL_EARTH_ID:
|
||||||
return PlayTrackUtils.createInstallEarthDialog(this);
|
return PlayTrackUtils.createInstallEarthDialog(this);
|
||||||
|
case DIALOG_DELETE_CURRENT_ID:
|
||||||
|
return DialogUtils.createConfirmationDialog(this,
|
||||||
|
R.string.track_list_delete_track_confirm_message,
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
long trackId = dataHub.getSelectedTrackId();
|
||||||
|
MyTracksProviderUtils.Factory.get(MapActivity.this).deleteTrack(trackId);
|
||||||
|
// If the deleted track was selected, unselect it.
|
||||||
|
String selectedTrackKey = getString(R.string.selected_track_key);
|
||||||
|
SharedPreferences sharedPreferences = getSharedPreferences(
|
||||||
|
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
||||||
|
if (sharedPreferences.getLong(selectedTrackKey, -1L) == trackId) {
|
||||||
|
Editor editor = sharedPreferences.edit().putLong(selectedTrackKey, -1L);
|
||||||
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -508,7 +531,7 @@ public class MapActivity extends com.google.android.maps.MapActivity
|
|||||||
PlayTrackUtils.playTrack(this, trackId);
|
PlayTrackUtils.playTrack(this, trackId);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
showDialog(DIALOG_INSTALL_EARTH);
|
showDialog(DIALOG_INSTALL_EARTH_ID);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case Constants.MENU_SEND_TO_GOOGLE:
|
case Constants.MENU_SEND_TO_GOOGLE:
|
||||||
@@ -527,29 +550,56 @@ public class MapActivity extends com.google.android.maps.MapActivity
|
|||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
return true;
|
return true;
|
||||||
case Constants.MENU_SHARE_GPX_FILE:
|
case Constants.MENU_SHARE_GPX_FILE:
|
||||||
case Constants.MENU_SHARE_KML_FILE:
|
startSaveActivity(trackId, TrackFileFormat.GPX, true);
|
||||||
case Constants.MENU_SHARE_CSV_FILE:
|
|
||||||
case Constants.MENU_SHARE_TCX_FILE:
|
|
||||||
case Constants.MENU_SAVE_GPX_FILE:
|
|
||||||
case Constants.MENU_SAVE_KML_FILE:
|
|
||||||
case Constants.MENU_SAVE_CSV_FILE:
|
|
||||||
case Constants.MENU_SAVE_TCX_FILE:
|
|
||||||
SaveActivity.handleExportTrackAction(
|
|
||||||
this, trackId, Constants.getActionFromMenuId(item.getItemId()));
|
|
||||||
return true;
|
return true;
|
||||||
|
case Constants.MENU_SHARE_KML_FILE:
|
||||||
|
startSaveActivity(trackId, TrackFileFormat.KML, true);
|
||||||
|
return true;
|
||||||
|
case Constants.MENU_SHARE_CSV_FILE:
|
||||||
|
startSaveActivity(trackId, TrackFileFormat.CSV, true);
|
||||||
|
return true;
|
||||||
|
case Constants.MENU_SHARE_TCX_FILE:
|
||||||
|
startSaveActivity(trackId, TrackFileFormat.TCX, true);
|
||||||
|
return true;
|
||||||
|
case Constants.MENU_SAVE_GPX_FILE:
|
||||||
|
startSaveActivity(trackId, TrackFileFormat.GPX, false);
|
||||||
|
return true;
|
||||||
|
case Constants.MENU_SAVE_KML_FILE:
|
||||||
|
startSaveActivity(trackId, TrackFileFormat.KML, false);
|
||||||
|
return true;
|
||||||
|
case Constants.MENU_SAVE_CSV_FILE:
|
||||||
|
startSaveActivity(trackId, TrackFileFormat.CSV, false);
|
||||||
|
return true;
|
||||||
|
case Constants.MENU_SAVE_TCX_FILE:
|
||||||
|
startSaveActivity(trackId, TrackFileFormat.TCX, false);
|
||||||
|
return true;
|
||||||
case Constants.MENU_CLEAR_MAP:
|
case Constants.MENU_CLEAR_MAP:
|
||||||
dataHub.unloadCurrentTrack();
|
dataHub.unloadCurrentTrack();
|
||||||
return true;
|
return true;
|
||||||
case Constants.MENU_DELETE:
|
case Constants.MENU_DELETE:
|
||||||
Uri uri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, trackId);
|
showDialog(DIALOG_DELETE_CURRENT_ID);
|
||||||
intent = new Intent(Intent.ACTION_DELETE, uri);
|
|
||||||
startActivity(intent);
|
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return super.onMenuItemSelected(featureId, item);
|
return super.onMenuItemSelected(featureId, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the {@link SaveActivity} to save a track.
|
||||||
|
*
|
||||||
|
* @param trackId the track id
|
||||||
|
* @param trackFileFormat the track file format
|
||||||
|
* @param shareTrack true to share the track after saving
|
||||||
|
*/
|
||||||
|
private void startSaveActivity(
|
||||||
|
long trackId, TrackFileFormat trackFileFormat, boolean shareTrack) {
|
||||||
|
Intent intent = new Intent(this, SaveActivity.class)
|
||||||
|
.putExtra(SaveActivity.EXTRA_TRACK_ID, trackId)
|
||||||
|
.putExtra(SaveActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) trackFileFormat)
|
||||||
|
.putExtra(SaveActivity.EXTRA_SHARE_TRACK, shareTrack);
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the map is currently in satellite view mode.
|
* Returns whether the map is currently in satellite view mode.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -70,7 +70,10 @@ import android.widget.Toast;
|
|||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public class MyTracks extends TabActivity implements OnTouchListener {
|
public class MyTracks extends TabActivity implements OnTouchListener {
|
||||||
private static final int DIALOG_EULA_ID = 0;
|
private static final int DIALOG_EULA_ID = 0;
|
||||||
|
private static final int DIALOG_CHECK_UNITS_ID = 1;
|
||||||
|
private static final String CHECK_UNITS_PREFERENCE_FILE = "checkunits";
|
||||||
|
private static final String CHECK_UNITS_PREFERENCE_KEY = "checkunits.checked";
|
||||||
|
|
||||||
private TrackDataHub dataHub;
|
private TrackDataHub dataHub;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -262,31 +265,59 @@ public class MyTracks extends TabActivity implements OnTouchListener {
|
|||||||
protected Dialog onCreateDialog(int id) {
|
protected Dialog onCreateDialog(int id) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case DIALOG_EULA_ID:
|
case DIALOG_EULA_ID:
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
return new AlertDialog.Builder(this)
|
||||||
builder.setTitle(R.string.eula_title);
|
.setCancelable(true)
|
||||||
builder.setMessage(EulaUtils.getEulaMessage(this));
|
.setMessage(EulaUtils.getEulaMessage(this))
|
||||||
builder.setPositiveButton(R.string.eula_accept, new DialogInterface.OnClickListener() {
|
.setNegativeButton(R.string.eula_decline, new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
EulaUtils.setEulaValue(MyTracks.this);
|
finish();
|
||||||
Intent startIntent = new Intent(MyTracks.this, WelcomeActivity.class);
|
}
|
||||||
startActivityForResult(startIntent, Constants.WELCOME);
|
})
|
||||||
}
|
.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||||
});
|
@Override
|
||||||
builder.setNegativeButton(R.string.eula_decline, new DialogInterface.OnClickListener() {
|
public void onCancel(DialogInterface dialog) {
|
||||||
@Override
|
finish();
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
}
|
||||||
finish();
|
})
|
||||||
}
|
.setPositiveButton(R.string.eula_accept, new DialogInterface.OnClickListener() {
|
||||||
});
|
@Override
|
||||||
builder.setCancelable(true);
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
EulaUtils.setEulaValue(MyTracks.this);
|
||||||
@Override
|
Intent startIntent = new Intent(MyTracks.this, WelcomeActivity.class);
|
||||||
public void onCancel(DialogInterface dialog) {
|
startActivityForResult(startIntent, Constants.WELCOME);
|
||||||
finish();
|
}
|
||||||
}
|
})
|
||||||
});
|
.setTitle(R.string.eula_title)
|
||||||
return builder.create();
|
.create();
|
||||||
|
case DIALOG_CHECK_UNITS_ID:
|
||||||
|
return new AlertDialog.Builder(this)
|
||||||
|
.setCancelable(true)
|
||||||
|
.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||||
|
public void onCancel(DialogInterface dialog) {
|
||||||
|
SharedPreferences sharedPreferences = getSharedPreferences(
|
||||||
|
CHECK_UNITS_PREFERENCE_FILE, Context.MODE_PRIVATE);
|
||||||
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(
|
||||||
|
sharedPreferences.edit().putBoolean(CHECK_UNITS_PREFERENCE_KEY, true));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
SharedPreferences sharedPreferences = getSharedPreferences(
|
||||||
|
CHECK_UNITS_PREFERENCE_FILE, Context.MODE_PRIVATE);
|
||||||
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(
|
||||||
|
sharedPreferences.edit().putBoolean(CHECK_UNITS_PREFERENCE_KEY, true));
|
||||||
|
|
||||||
|
int position = ((AlertDialog) dialog).getListView().getSelectedItemPosition();
|
||||||
|
SharedPreferences.Editor editor = preferences.edit();
|
||||||
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(
|
||||||
|
editor.putBoolean(getString(R.string.metric_units_key), position == 0));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setSingleChoiceItems(new CharSequence[] { getString(R.string.preferred_units_metric),
|
||||||
|
getString(R.string.preferred_units_imperial) }, 0, null)
|
||||||
|
.setTitle(R.string.preferred_units_title)
|
||||||
|
.create();
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -380,7 +411,11 @@ public class MyTracks extends TabActivity implements OnTouchListener {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Constants.WELCOME: {
|
case Constants.WELCOME: {
|
||||||
CheckUnits.check(this);
|
SharedPreferences sharedPreferences = getSharedPreferences(
|
||||||
|
CHECK_UNITS_PREFERENCE_FILE, Context.MODE_PRIVATE);
|
||||||
|
if (!sharedPreferences.getBoolean(CHECK_UNITS_PREFERENCE_KEY, false)) {
|
||||||
|
showDialog(DIALOG_CHECK_UNITS_ID);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,9 @@ package com.google.android.apps.mytracks;
|
|||||||
|
|
||||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.io.backup.BackupActivityHelper;
|
import com.google.android.apps.mytracks.io.backup.BackupActivity;
|
||||||
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
|
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
|
||||||
|
import com.google.android.apps.mytracks.io.backup.RestoreChooserActivity;
|
||||||
import com.google.android.apps.mytracks.services.sensors.ant.AntUtils;
|
import com.google.android.apps.mytracks.services.sensors.ant.AntUtils;
|
||||||
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||||
import com.google.android.apps.mytracks.util.BluetoothDeviceUtils;
|
import com.google.android.apps.mytracks.util.BluetoothDeviceUtils;
|
||||||
@@ -62,8 +63,9 @@ import java.util.Set;
|
|||||||
*/
|
*/
|
||||||
public class SettingsActivity extends PreferenceActivity {
|
public class SettingsActivity extends PreferenceActivity {
|
||||||
|
|
||||||
private static final int DIALOG_CONFIRM_RESET = 0;
|
private static final int DIALOG_CONFIRM_RESET_ID = 0;
|
||||||
private static final int DIALOG_CONFIRM_ACCESS = 1;
|
private static final int DIALOG_CONFIRM_ACCESS_ID = 1;
|
||||||
|
private static final int DIALOG_CONFIRM_RESTORE_ID = 2;
|
||||||
|
|
||||||
// Value when the task frequency is off.
|
// Value when the task frequency is off.
|
||||||
private static final String TASK_FREQUENCY_OFF = "0";
|
private static final String TASK_FREQUENCY_OFF = "0";
|
||||||
@@ -150,7 +152,7 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
resetPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
resetPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceClick(Preference arg0) {
|
public boolean onPreferenceClick(Preference arg0) {
|
||||||
showDialog(DIALOG_CONFIRM_RESET);
|
showDialog(DIALOG_CONFIRM_RESET_ID);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -162,7 +164,7 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
if ((Boolean) newValue) {
|
if ((Boolean) newValue) {
|
||||||
showDialog(DIALOG_CONFIRM_ACCESS);
|
showDialog(DIALOG_CONFIRM_ACCESS_ID);
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
@@ -174,7 +176,7 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
@Override
|
@Override
|
||||||
protected Dialog onCreateDialog(int id) {
|
protected Dialog onCreateDialog(int id) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case DIALOG_CONFIRM_RESET:
|
case DIALOG_CONFIRM_RESET_ID:
|
||||||
return DialogUtils.createConfirmationDialog(
|
return DialogUtils.createConfirmationDialog(
|
||||||
this, R.string.settings_reset_confirm_message, new OnClickListener() {
|
this, R.string.settings_reset_confirm_message, new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -182,7 +184,7 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
onResetPreferencesConfirmed();
|
onResetPreferencesConfirmed();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
case DIALOG_CONFIRM_ACCESS:
|
case DIALOG_CONFIRM_ACCESS_ID:
|
||||||
return DialogUtils.createConfirmationDialog(
|
return DialogUtils.createConfirmationDialog(
|
||||||
this, R.string.settings_sharing_allow_access_confirm_message, new OnClickListener() {
|
this, R.string.settings_sharing_allow_access_confirm_message, new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -192,6 +194,14 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
pref.setChecked(true);
|
pref.setChecked(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
case DIALOG_CONFIRM_RESTORE_ID:
|
||||||
|
return DialogUtils.createConfirmationDialog(
|
||||||
|
this, R.string.settings_backup_restore_confirm_message, new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
startActivity(new Intent(SettingsActivity.this, RestoreChooserActivity.class));
|
||||||
|
}
|
||||||
|
});
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -354,9 +364,7 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
new OnPreferenceClickListener() {
|
new OnPreferenceClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceClick(Preference preference) {
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
BackupActivityHelper backupHelper =
|
startActivity(new Intent(SettingsActivity.this, BackupActivity.class));
|
||||||
new BackupActivityHelper(SettingsActivity.this);
|
|
||||||
backupHelper.writeBackup();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -364,9 +372,7 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
new OnPreferenceClickListener() {
|
new OnPreferenceClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceClick(Preference preference) {
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
BackupActivityHelper backupHelper =
|
showDialog(DIALOG_CONFIRM_RESTORE_ID);
|
||||||
new BackupActivityHelper(SettingsActivity.this);
|
|
||||||
backupHelper.restoreBackup();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -17,26 +17,31 @@ package com.google.android.apps.mytracks;
|
|||||||
|
|
||||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||||
import com.google.android.apps.mytracks.io.file.SaveActivity;
|
import com.google.android.apps.mytracks.io.file.SaveActivity;
|
||||||
|
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
|
||||||
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
|
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
|
||||||
import com.google.android.apps.mytracks.io.sendtogoogle.UploadServiceChooserActivity;
|
import com.google.android.apps.mytracks.io.sendtogoogle.UploadServiceChooserActivity;
|
||||||
import com.google.android.apps.mytracks.services.ServiceUtils;
|
import com.google.android.apps.mytracks.services.ServiceUtils;
|
||||||
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
||||||
|
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||||
|
import com.google.android.apps.mytracks.util.DialogUtils;
|
||||||
import com.google.android.apps.mytracks.util.PlayTrackUtils;
|
import com.google.android.apps.mytracks.util.PlayTrackUtils;
|
||||||
import com.google.android.apps.mytracks.util.StringUtils;
|
import com.google.android.apps.mytracks.util.StringUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.ListActivity;
|
import android.app.ListActivity;
|
||||||
import android.content.ContentUris;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.SharedPreferences.Editor;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Parcelable;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
import android.view.ContextMenu.ContextMenuInfo;
|
import android.view.ContextMenu.ContextMenuInfo;
|
||||||
@@ -62,7 +67,10 @@ public class TrackList extends ListActivity
|
|||||||
implements SharedPreferences.OnSharedPreferenceChangeListener,
|
implements SharedPreferences.OnSharedPreferenceChangeListener,
|
||||||
View.OnClickListener {
|
View.OnClickListener {
|
||||||
|
|
||||||
private static final int DIALOG_INSTALL_EARTH = 0;
|
private static final int DIALOG_INSTALL_EARTH_ID = 0;
|
||||||
|
private static final int DIALOG_EXPORT_ALL_ID = 1;
|
||||||
|
private static final int DIALOG_DELETE_ALL_ID = 2;
|
||||||
|
private static final int DIALOG_DELETE_CURRENT_ID = 3;
|
||||||
|
|
||||||
private int contextPosition = -1;
|
private int contextPosition = -1;
|
||||||
private long trackId = -1;
|
private long trackId = -1;
|
||||||
@@ -178,7 +186,7 @@ public class TrackList extends ListActivity
|
|||||||
PlayTrackUtils.playTrack(this, trackId);
|
PlayTrackUtils.playTrack(this, trackId);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
showDialog(DIALOG_INSTALL_EARTH);
|
showDialog(DIALOG_INSTALL_EARTH_ID);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case Constants.MENU_SEND_TO_GOOGLE:
|
case Constants.MENU_SEND_TO_GOOGLE:
|
||||||
@@ -197,21 +205,31 @@ public class TrackList extends ListActivity
|
|||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
return true;
|
return true;
|
||||||
case Constants.MENU_SHARE_GPX_FILE:
|
case Constants.MENU_SHARE_GPX_FILE:
|
||||||
case Constants.MENU_SHARE_KML_FILE:
|
startSaveActivity(TrackFileFormat.GPX, true);
|
||||||
case Constants.MENU_SHARE_CSV_FILE:
|
|
||||||
case Constants.MENU_SHARE_TCX_FILE:
|
|
||||||
case Constants.MENU_SAVE_GPX_FILE:
|
|
||||||
case Constants.MENU_SAVE_KML_FILE:
|
|
||||||
case Constants.MENU_SAVE_CSV_FILE:
|
|
||||||
case Constants.MENU_SAVE_TCX_FILE:
|
|
||||||
SaveActivity.handleExportTrackAction(
|
|
||||||
this, trackId, Constants.getActionFromMenuId(item.getItemId()));
|
|
||||||
return true;
|
return true;
|
||||||
|
case Constants.MENU_SHARE_KML_FILE:
|
||||||
|
startSaveActivity(TrackFileFormat.KML, true);
|
||||||
|
return true;
|
||||||
|
case Constants.MENU_SHARE_CSV_FILE:
|
||||||
|
startSaveActivity(TrackFileFormat.CSV, true);
|
||||||
|
return true;
|
||||||
|
case Constants.MENU_SHARE_TCX_FILE:
|
||||||
|
startSaveActivity(TrackFileFormat.TCX, true);
|
||||||
|
return true;
|
||||||
|
case Constants.MENU_SAVE_GPX_FILE:
|
||||||
|
startSaveActivity(TrackFileFormat.GPX, false);
|
||||||
|
return true;
|
||||||
|
case Constants.MENU_SAVE_KML_FILE:
|
||||||
|
startSaveActivity(TrackFileFormat.KML, false);
|
||||||
|
return true;
|
||||||
|
case Constants.MENU_SAVE_CSV_FILE:
|
||||||
|
startSaveActivity(TrackFileFormat.CSV, false);
|
||||||
|
return true;
|
||||||
|
case Constants.MENU_SAVE_TCX_FILE:
|
||||||
|
startSaveActivity(TrackFileFormat.TCX, false);
|
||||||
|
return true;
|
||||||
case Constants.MENU_DELETE:
|
case Constants.MENU_DELETE:
|
||||||
Uri uri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, trackId);
|
showDialog(DIALOG_DELETE_CURRENT_ID);
|
||||||
intent = new Intent(Intent.ACTION_DELETE)
|
|
||||||
.setDataAndType(uri, TracksColumns.CONTENT_ITEMTYPE);
|
|
||||||
startActivity(intent);
|
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
Log.w(TAG, "Unknown menu item: " + item.getItemId() + "(" + item.getTitle() + ")");
|
Log.w(TAG, "Unknown menu item: " + item.getItemId() + "(" + item.getTitle() + ")");
|
||||||
@@ -219,22 +237,34 @@ public class TrackList extends ListActivity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the {@link SaveActivity} to save trackId.
|
||||||
|
*
|
||||||
|
* @param trackFileFormat the track file format
|
||||||
|
* @param shareTrack true to share the track after saving
|
||||||
|
*/
|
||||||
|
private void startSaveActivity(TrackFileFormat trackFileFormat, boolean shareTrack) {
|
||||||
|
Intent intent = new Intent(this, SaveActivity.class)
|
||||||
|
.putExtra(SaveActivity.EXTRA_TRACK_ID, trackId)
|
||||||
|
.putExtra(SaveActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) trackFileFormat)
|
||||||
|
.putExtra(SaveActivity.EXTRA_SHARE_TRACK, shareTrack);
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
switch (v.getId()) {
|
switch (v.getId()) {
|
||||||
case R.id.tracklist_btn_delete_all: {
|
case R.id.tracklist_btn_delete_all:
|
||||||
Handler h = new DeleteAllTracks(this, null);
|
showDialog(DIALOG_DELETE_ALL_ID);
|
||||||
h.handleMessage(null);
|
|
||||||
break;
|
break;
|
||||||
}
|
case R.id.tracklist_btn_export_all:
|
||||||
case R.id.tracklist_btn_export_all: {
|
showDialog(DIALOG_EXPORT_ALL_ID);
|
||||||
new ExportAllTracks(this);
|
|
||||||
break;
|
break;
|
||||||
}
|
case R.id.tracklist_btn_import_all:
|
||||||
case R.id.tracklist_btn_import_all: {
|
Intent intent = new Intent(this, ImportActivity.class)
|
||||||
new ImportAllTracks(this);
|
.putExtra(ImportActivity.EXTRA_IMPORT_ALL, true);
|
||||||
break;
|
startActivity(intent);
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,8 +328,60 @@ public class TrackList extends ListActivity
|
|||||||
@Override
|
@Override
|
||||||
protected Dialog onCreateDialog(int id) {
|
protected Dialog onCreateDialog(int id) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case DIALOG_INSTALL_EARTH:
|
case DIALOG_INSTALL_EARTH_ID:
|
||||||
return PlayTrackUtils.createInstallEarthDialog(this);
|
return PlayTrackUtils.createInstallEarthDialog(this);
|
||||||
|
case DIALOG_EXPORT_ALL_ID:
|
||||||
|
String exportFileFormat = getString(R.string.track_list_export_file);
|
||||||
|
String fileTypes[] = getResources().getStringArray(R.array.file_types);
|
||||||
|
String[] choices = new String[fileTypes.length];
|
||||||
|
for (int i = 0; i < fileTypes.length; i++) {
|
||||||
|
choices[i] = String.format(exportFileFormat, fileTypes[i]);
|
||||||
|
}
|
||||||
|
return new AlertDialog.Builder(this)
|
||||||
|
.setNegativeButton(R.string.generic_cancel, null)
|
||||||
|
.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
int index = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
||||||
|
Intent intent = new Intent(TrackList.this, ExportAllActivity.class);
|
||||||
|
intent.putExtra(ExportAllActivity.EXTRA_TRACK_FILE_FORMAT,
|
||||||
|
(Parcelable) TrackFileFormat.values()[index]);
|
||||||
|
TrackList.this.startActivity(intent);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setSingleChoiceItems(choices, 0, null)
|
||||||
|
.setTitle(R.string.track_list_export_all)
|
||||||
|
.create();
|
||||||
|
case DIALOG_DELETE_ALL_ID:
|
||||||
|
return DialogUtils.createConfirmationDialog(this,
|
||||||
|
R.string.track_list_delete_all_confirm_message, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
MyTracksProviderUtils.Factory.get(TrackList.this).deleteAllTracks();
|
||||||
|
SharedPreferences sharedPreferences = getSharedPreferences(
|
||||||
|
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
||||||
|
Editor editor = sharedPreferences.edit();
|
||||||
|
// TODO: Go through data manager
|
||||||
|
editor.putLong(getString(R.string.selected_track_key), -1L);
|
||||||
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
case DIALOG_DELETE_CURRENT_ID:
|
||||||
|
return DialogUtils.createConfirmationDialog(this,
|
||||||
|
R.string.track_list_delete_track_confirm_message, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
MyTracksProviderUtils.Factory.get(TrackList.this).deleteTrack(trackId);
|
||||||
|
// If the deleted track was selected, unselect it.
|
||||||
|
String selectedTrackKey = getString(R.string.selected_track_key);
|
||||||
|
SharedPreferences sharedPreferences = getSharedPreferences(
|
||||||
|
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
||||||
|
if (sharedPreferences.getLong(selectedTrackKey, -1L) == trackId) {
|
||||||
|
Editor editor = sharedPreferences.edit().putLong(selectedTrackKey, -1L);
|
||||||
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,10 +24,11 @@ import com.google.android.apps.mytracks.content.WaypointCreationRequest;
|
|||||||
import com.google.android.apps.mytracks.content.WaypointsColumns;
|
import com.google.android.apps.mytracks.content.WaypointsColumns;
|
||||||
import com.google.android.apps.mytracks.services.ITrackRecordingService;
|
import com.google.android.apps.mytracks.services.ITrackRecordingService;
|
||||||
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
||||||
|
import com.google.android.apps.mytracks.util.DialogUtils;
|
||||||
import com.google.android.apps.mytracks.util.StringUtils;
|
import com.google.android.apps.mytracks.util.StringUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.Dialog;
|
||||||
import android.app.ListActivity;
|
import android.app.ListActivity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
@@ -57,9 +58,10 @@ import android.widget.Toast;
|
|||||||
*
|
*
|
||||||
* @author Leif Hendrik Wilden
|
* @author Leif Hendrik Wilden
|
||||||
*/
|
*/
|
||||||
public class WaypointsList extends ListActivity
|
public class WaypointsList extends ListActivity implements View.OnClickListener {
|
||||||
implements View.OnClickListener {
|
|
||||||
|
|
||||||
|
private static final int DIALOG_DELETE_CURRENT_ID = 0;
|
||||||
|
|
||||||
private int contextPosition = -1;
|
private int contextPosition = -1;
|
||||||
private long trackId = -1;
|
private long trackId = -1;
|
||||||
private long selectedWaypointId = -1;
|
private long selectedWaypointId = -1;
|
||||||
@@ -119,7 +121,7 @@ public class WaypointsList extends ListActivity
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case Constants.MENU_DELETE: {
|
case Constants.MENU_DELETE: {
|
||||||
deleteWaypoint(selectedWaypointId);
|
showDialog(DIALOG_DELETE_CURRENT_ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -199,6 +201,24 @@ public class WaypointsList extends ListActivity
|
|||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Dialog onCreateDialog(int id) {
|
||||||
|
switch (id) {
|
||||||
|
case DIALOG_DELETE_CURRENT_ID:
|
||||||
|
return DialogUtils.createConfirmationDialog(this,
|
||||||
|
R.string.marker_list_delete_marker_confirm_message,
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
providerUtils.deleteWaypoint(
|
||||||
|
selectedWaypointId, new DescriptionGeneratorImpl(WaypointsList.this));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
getMenuInflater().inflate(R.menu.search_only, menu);
|
getMenuInflater().inflate(R.menu.search_only, menu);
|
||||||
@@ -303,34 +323,4 @@ public class WaypointsList extends ListActivity
|
|||||||
});
|
});
|
||||||
setListAdapter(adapter);
|
setListAdapter(adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes the way point with the given id.
|
|
||||||
* Prompts the user if he want to really delete it.
|
|
||||||
*/
|
|
||||||
public void deleteWaypoint(final long waypointId) {
|
|
||||||
AlertDialog dialog = null;
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
||||||
builder.setMessage(getString(R.string.marker_list_delete_marker_confirm_message));
|
|
||||||
builder.setTitle(getString(R.string.generic_confirm_title));
|
|
||||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
|
||||||
builder.setPositiveButton(getString(R.string.generic_yes),
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialogInterface, int i) {
|
|
||||||
dialogInterface.dismiss();
|
|
||||||
providerUtils.deleteWaypoint(waypointId,
|
|
||||||
new DescriptionGeneratorImpl(WaypointsList.this));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
builder.setNegativeButton(getString(R.string.generic_no),
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialogInterface, int i) {
|
|
||||||
dialogInterface.dismiss();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
dialog = builder.create();
|
|
||||||
dialog.show();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* 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.io.backup;
|
||||||
|
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activity to backup data to the SD card.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public class BackupActivity extends Activity {
|
||||||
|
|
||||||
|
private static final int DIALOG_PROGRESS_ID = 0;
|
||||||
|
|
||||||
|
private BackupAsyncTask backupAsyncTask;
|
||||||
|
private ProgressDialog progressDialog;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
Object retained = getLastNonConfigurationInstance();
|
||||||
|
if (retained instanceof BackupAsyncTask) {
|
||||||
|
backupAsyncTask = (BackupAsyncTask) retained;
|
||||||
|
backupAsyncTask.setActivity(this);
|
||||||
|
} else {
|
||||||
|
backupAsyncTask = new BackupAsyncTask(this);
|
||||||
|
backupAsyncTask.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object onRetainNonConfigurationInstance() {
|
||||||
|
backupAsyncTask.setActivity(null);
|
||||||
|
return backupAsyncTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Dialog onCreateDialog(int id) {
|
||||||
|
switch (id) {
|
||||||
|
case DIALOG_PROGRESS_ID:
|
||||||
|
progressDialog = new ProgressDialog(this);
|
||||||
|
progressDialog.setCancelable(true);
|
||||||
|
progressDialog.setIcon(android.R.drawable.ic_dialog_info);
|
||||||
|
progressDialog.setIndeterminate(true);
|
||||||
|
progressDialog.setMessage(getString(R.string.settings_backup_now_progress_message));
|
||||||
|
progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||||
|
@Override
|
||||||
|
public void onCancel(DialogInterface dialog) {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||||
|
progressDialog.setTitle(R.string.generic_progress_title);
|
||||||
|
return progressDialog;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes when the associated AsyncTask completes.
|
||||||
|
*
|
||||||
|
* @param success true if the AsyncTask is successful
|
||||||
|
* @param messageId message id to display to user
|
||||||
|
*/
|
||||||
|
public void onAsyncTaskCompleted(boolean success, int messageId) {
|
||||||
|
removeDialog(DIALOG_PROGRESS_ID);
|
||||||
|
Toast.makeText(this, messageId, success ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG).show();
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the progress dialog.
|
||||||
|
*/
|
||||||
|
public void showProgressDialog() {
|
||||||
|
showDialog(DIALOG_PROGRESS_ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,240 +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.backup;
|
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
|
||||||
import com.google.android.apps.mytracks.MyTracks;
|
|
||||||
import com.google.android.apps.mytracks.util.FileUtils;
|
|
||||||
import com.google.android.apps.mytracks.util.StringUtils;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.AlertDialog.Builder;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.DialogInterface.OnClickListener;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper which shows a UI for writing or restoring a backup,
|
|
||||||
* and calls the appropriate handler for actually executing those
|
|
||||||
* operations.
|
|
||||||
*
|
|
||||||
* @author Rodrigo Damazio
|
|
||||||
*/
|
|
||||||
public class BackupActivityHelper {
|
|
||||||
|
|
||||||
private static final Comparator<Date> REVERSE_DATE_ORDER =
|
|
||||||
new Comparator<Date>() {
|
|
||||||
@Override
|
|
||||||
public int compare(Date s1, Date s2) {
|
|
||||||
return s2.compareTo(s1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final FileUtils fileUtils;
|
|
||||||
private final ExternalFileBackup backup;
|
|
||||||
private final Activity activity;
|
|
||||||
|
|
||||||
public BackupActivityHelper(Activity activity) {
|
|
||||||
this.activity = activity;
|
|
||||||
this.fileUtils = new FileUtils();
|
|
||||||
this.backup = new ExternalFileBackup(activity, fileUtils);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a full backup to the default file.
|
|
||||||
* This shows the results to the user.
|
|
||||||
*/
|
|
||||||
public void writeBackup() {
|
|
||||||
if (!fileUtils.isSdCardAvailable()) {
|
|
||||||
showToast(R.string.sd_card_error_no_storage);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!backup.isBackupsDirectoryAvailable(true)) {
|
|
||||||
showToast(R.string.sd_card_error_create_dir);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final ProgressDialog progressDialog = ProgressDialog.show(
|
|
||||||
activity,
|
|
||||||
activity.getString(R.string.generic_progress_title),
|
|
||||||
activity.getString(R.string.settings_backup_now_progress_message),
|
|
||||||
true);
|
|
||||||
|
|
||||||
// Do the writing in another thread
|
|
||||||
new Thread() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
backup.writeToDefaultFile();
|
|
||||||
showToast(R.string.sd_card_success_write_file);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(Constants.TAG, "Failed to write backup", e);
|
|
||||||
showToast(R.string.sd_card_error_write_file);
|
|
||||||
} finally {
|
|
||||||
dismissDialog(progressDialog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Restores a full backup from the SD card.
|
|
||||||
* The user will be given a choice of which backup to restore as well as a
|
|
||||||
* confirmation dialog.
|
|
||||||
*/
|
|
||||||
public void restoreBackup() {
|
|
||||||
// Get the list of existing backups
|
|
||||||
if (!fileUtils.isSdCardAvailable()) {
|
|
||||||
showToast(R.string.sd_card_error_no_storage);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!backup.isBackupsDirectoryAvailable(false)) {
|
|
||||||
showToast(R.string.settings_backup_restore_no_backup);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Date[] backupDates = backup.getAvailableBackups();
|
|
||||||
if (backupDates == null || backupDates.length == 0) {
|
|
||||||
showToast(R.string.settings_backup_restore_no_backup);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Arrays.sort(backupDates, REVERSE_DATE_ORDER);
|
|
||||||
|
|
||||||
// Show a confirmation dialog
|
|
||||||
Builder confirmationDialogBuilder = new AlertDialog.Builder(activity);
|
|
||||||
confirmationDialogBuilder.setMessage(R.string.settings_backup_restore_confirm_message);
|
|
||||||
confirmationDialogBuilder.setCancelable(true);
|
|
||||||
confirmationDialogBuilder.setPositiveButton(android.R.string.yes,
|
|
||||||
new OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
pickBackupForRestore(backupDates);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
confirmationDialogBuilder.setNegativeButton(android.R.string.no, null);
|
|
||||||
confirmationDialogBuilder.create().show();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows a backup list for the user to pick, then restores it.
|
|
||||||
*
|
|
||||||
* @param backupDates the list of available backup files
|
|
||||||
*/
|
|
||||||
private void pickBackupForRestore(final Date[] backupDates) {
|
|
||||||
if (backupDates.length == 1) {
|
|
||||||
// Only one choice, don't bother showing the list
|
|
||||||
restoreFromDateAsync(backupDates[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make a user-visible version of the backup filenames
|
|
||||||
final String backupDateStrs[] = new String[backupDates.length];
|
|
||||||
for (int i = 0; i < backupDates.length; i++) {
|
|
||||||
backupDateStrs[i] = StringUtils.formatDateTime(activity, backupDates[i].getTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show a dialog for the user to pick which backup to restore
|
|
||||||
Builder dialogBuilder = new AlertDialog.Builder(activity);
|
|
||||||
dialogBuilder.setCancelable(true);
|
|
||||||
dialogBuilder.setTitle(R.string.settings_backup_restore_select_title);
|
|
||||||
dialogBuilder.setItems(backupDateStrs, new OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
// User picked to restore this one
|
|
||||||
restoreFromDateAsync(backupDates[which]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
dialogBuilder.create().show();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows a progress dialog, then starts restoring the backup asynchronously.
|
|
||||||
*
|
|
||||||
* @param date the date
|
|
||||||
*/
|
|
||||||
private void restoreFromDateAsync(final Date date) {
|
|
||||||
// Show a progress dialog
|
|
||||||
ProgressDialog.show(
|
|
||||||
activity,
|
|
||||||
activity.getString(R.string.generic_progress_title),
|
|
||||||
activity.getString(R.string.settings_backup_restore_progress_message),
|
|
||||||
true);
|
|
||||||
|
|
||||||
// Do the actual importing in another thread (don't block the UI)
|
|
||||||
new Thread() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
backup.restoreFromDate(date);
|
|
||||||
showToast(R.string.sd_card_success_read_file);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(Constants.TAG, "Failed to restore backup", e);
|
|
||||||
showToast(R.string.sd_card_error_read_file);
|
|
||||||
} finally {
|
|
||||||
// Data may have been restored, "reboot" the app to catch it
|
|
||||||
restartApplication();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Restarts My Tracks completely.
|
|
||||||
* This forces any modified data to be re-read.
|
|
||||||
*/
|
|
||||||
private void restartApplication() {
|
|
||||||
Intent intent = new Intent(activity, MyTracks.class);
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
|
||||||
activity.startActivity(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows a toast with the given contents.
|
|
||||||
*/
|
|
||||||
private void showToast(final int resId) {
|
|
||||||
activity.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Toast.makeText(activity, resId, Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Safely dismisses the given dialog.
|
|
||||||
*/
|
|
||||||
private void dismissDialog(final Dialog dialog) {
|
|
||||||
activity.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
dialog.dismiss();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* 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.io.backup;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.util.FileUtils;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AsyncTask to backup data to the SD card.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public class BackupAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||||
|
|
||||||
|
private static final String TAG = BackupAsyncTask.class.getSimpleName();
|
||||||
|
|
||||||
|
private BackupActivity backupActivity;
|
||||||
|
private final ExternalFileBackup externalFileBackup;
|
||||||
|
|
||||||
|
// true if the AsyncTask result is success
|
||||||
|
private boolean success;
|
||||||
|
|
||||||
|
// true if the AsyncTask has completed
|
||||||
|
private boolean completed;
|
||||||
|
|
||||||
|
// message id to return to the activity
|
||||||
|
private int messageId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an AsyncTask.
|
||||||
|
*
|
||||||
|
* @param backupActivity the activity currently associated with this
|
||||||
|
* AsyncTask
|
||||||
|
*/
|
||||||
|
public BackupAsyncTask(BackupActivity backupActivity) {
|
||||||
|
this.backupActivity = backupActivity;
|
||||||
|
this.externalFileBackup = new ExternalFileBackup(backupActivity, new FileUtils());
|
||||||
|
success = false;
|
||||||
|
completed = false;
|
||||||
|
messageId = R.string.sd_card_error_write_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current {@link BackupActivity} associated with this AyncTask.
|
||||||
|
*
|
||||||
|
* @param activity the current {@link BackupActivity}, can be null
|
||||||
|
*/
|
||||||
|
public void setActivity(BackupActivity activity) {
|
||||||
|
this.backupActivity = activity;
|
||||||
|
if (completed && backupActivity != null) {
|
||||||
|
backupActivity.onAsyncTaskCompleted(success, messageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute() {
|
||||||
|
if (backupActivity != null) {
|
||||||
|
backupActivity.showProgressDialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boolean doInBackground(Void... params) {
|
||||||
|
FileUtils fileUtils = new FileUtils();
|
||||||
|
|
||||||
|
if (!fileUtils.isSdCardAvailable()) {
|
||||||
|
messageId = R.string.sd_card_error_no_storage;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!externalFileBackup.isBackupsDirectoryAvailable(true)) {
|
||||||
|
messageId = R.string.sd_card_error_create_dir;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
externalFileBackup.writeToDefaultFile();
|
||||||
|
messageId = R.string.sd_card_success_write_file;
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(TAG, "IO exception", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Boolean result) {
|
||||||
|
success = result;
|
||||||
|
completed = true;
|
||||||
|
if (backupActivity != null) {
|
||||||
|
backupActivity.onAsyncTaskCompleted(success, messageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* 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.io.backup;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.MyTracks;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An activity to restore data from the SD card.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public class RestoreActivity extends Activity {
|
||||||
|
|
||||||
|
public static final String EXTRA_DATE = "date";
|
||||||
|
|
||||||
|
private static final String TAG = RestoreActivity.class.getSimpleName();
|
||||||
|
private static final int DIALOG_PROGRESS_ID = 0;
|
||||||
|
|
||||||
|
private RestoreAsyncTask restoreAsyncTask;
|
||||||
|
private ProgressDialog progressDialog;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
Object retained = getLastNonConfigurationInstance();
|
||||||
|
if (retained instanceof RestoreAsyncTask) {
|
||||||
|
restoreAsyncTask = (RestoreAsyncTask) retained;
|
||||||
|
restoreAsyncTask.setActivity(this);
|
||||||
|
} else {
|
||||||
|
long date = getIntent().getLongExtra(EXTRA_DATE, -1L);
|
||||||
|
if (date == -1L) {
|
||||||
|
Log.d(TAG, "Invalid date");
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
restoreAsyncTask = new RestoreAsyncTask(this, new Date(date));
|
||||||
|
restoreAsyncTask.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object onRetainNonConfigurationInstance() {
|
||||||
|
restoreAsyncTask.setActivity(null);
|
||||||
|
return restoreAsyncTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Dialog onCreateDialog(int id) {
|
||||||
|
switch (id) {
|
||||||
|
case DIALOG_PROGRESS_ID:
|
||||||
|
progressDialog = new ProgressDialog(this);
|
||||||
|
progressDialog.setCancelable(true);
|
||||||
|
progressDialog.setIcon(android.R.drawable.ic_dialog_info);
|
||||||
|
progressDialog.setIndeterminate(true);
|
||||||
|
progressDialog.setMessage(getString(R.string.settings_backup_restore_progress_message));
|
||||||
|
progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||||
|
@Override
|
||||||
|
public void onCancel(DialogInterface dialog) {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||||
|
progressDialog.setTitle(R.string.generic_progress_title);
|
||||||
|
return progressDialog;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes when the associated AsyncTask completes.
|
||||||
|
*
|
||||||
|
* @param success true if the AsyncTask is successful
|
||||||
|
* @param messageId message id to display to user
|
||||||
|
*/
|
||||||
|
public void onAsyncTaskCompleted(boolean success, int messageId) {
|
||||||
|
removeDialog(DIALOG_PROGRESS_ID);
|
||||||
|
Toast.makeText(this, messageId, success ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG).show();
|
||||||
|
startActivity(new Intent(this, MyTracks.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the progress dialog.
|
||||||
|
*/
|
||||||
|
public void showProgressDialog() {
|
||||||
|
showDialog(DIALOG_PROGRESS_ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* 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.io.backup;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.util.FileUtils;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AsyncTask to restore data from the SD card.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public class RestoreAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||||
|
|
||||||
|
private static final String TAG = RestoreAsyncTask.class.getSimpleName();
|
||||||
|
|
||||||
|
private RestoreActivity restoreActivity;
|
||||||
|
private final Date date;
|
||||||
|
private final ExternalFileBackup externalFileBackup;
|
||||||
|
|
||||||
|
// true if the AsyncTask result is success
|
||||||
|
private boolean success;
|
||||||
|
|
||||||
|
// true if the AsyncTask has completed
|
||||||
|
private boolean completed;
|
||||||
|
|
||||||
|
// message id to return to the activity
|
||||||
|
private int messageId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an AsyncTask.
|
||||||
|
*
|
||||||
|
* @param restoreActivity the activity currently associated with this
|
||||||
|
* AsyncTask
|
||||||
|
* @param date the date to retore from
|
||||||
|
*/
|
||||||
|
public RestoreAsyncTask(RestoreActivity restoreActivity, Date date) {
|
||||||
|
this.restoreActivity = restoreActivity;
|
||||||
|
this.date = date;
|
||||||
|
this.externalFileBackup = new ExternalFileBackup(restoreActivity, new FileUtils());
|
||||||
|
success = false;
|
||||||
|
completed = false;
|
||||||
|
messageId = R.string.sd_card_error_read_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current {@link RestoreActivity} associated with this AyncTask.
|
||||||
|
*
|
||||||
|
* @param activity the current {@link RestoreActivity}, can be null
|
||||||
|
*/
|
||||||
|
public void setActivity(RestoreActivity activity) {
|
||||||
|
this.restoreActivity = activity;
|
||||||
|
if (completed && restoreActivity != null) {
|
||||||
|
restoreActivity.onAsyncTaskCompleted(success, messageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute() {
|
||||||
|
if (restoreActivity != null) {
|
||||||
|
restoreActivity.showProgressDialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boolean doInBackground(Void... params) {
|
||||||
|
try {
|
||||||
|
externalFileBackup.restoreFromDate(date);
|
||||||
|
messageId = R.string.sd_card_success_read_file;
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(TAG, "IO exception", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Boolean result) {
|
||||||
|
success = result;
|
||||||
|
completed = true;
|
||||||
|
if (restoreActivity != null) {
|
||||||
|
restoreActivity.onAsyncTaskCompleted(success, messageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* 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.io.backup;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.util.FileUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.StringUtils;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.DialogInterface.OnCancelListener;
|
||||||
|
import android.content.DialogInterface.OnClickListener;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An activity to choose a date to restore from.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public class RestoreChooserActivity extends Activity {
|
||||||
|
|
||||||
|
private static final Comparator<Date> REVERSE_DATE_ORDER = new Comparator<Date>() {
|
||||||
|
@Override
|
||||||
|
public int compare(Date s1, Date s2) {
|
||||||
|
return s2.compareTo(s1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private static final int DIALOG_CHOOSER_ID = 0;
|
||||||
|
|
||||||
|
private Date[] backupDates;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
FileUtils fileUtils = new FileUtils();
|
||||||
|
ExternalFileBackup externalFileBackup = new ExternalFileBackup(this, fileUtils);
|
||||||
|
|
||||||
|
// Get the list of existing backups
|
||||||
|
if (!fileUtils.isSdCardAvailable()) {
|
||||||
|
Toast.makeText(this, R.string.sd_card_error_no_storage, Toast.LENGTH_LONG).show();
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!externalFileBackup.isBackupsDirectoryAvailable(false)) {
|
||||||
|
Toast.makeText(this, R.string.settings_backup_restore_no_backup, Toast.LENGTH_LONG).show();
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
backupDates = externalFileBackup.getAvailableBackups();
|
||||||
|
if (backupDates == null || backupDates.length == 0) {
|
||||||
|
Toast.makeText(this, R.string.settings_backup_restore_no_backup, Toast.LENGTH_LONG).show();
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backupDates.length == 1) {
|
||||||
|
startActivity(new Intent(this, RestoreActivity.class)
|
||||||
|
.putExtra(RestoreActivity.EXTRA_DATE, backupDates[0].getTime()));
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Arrays.sort(backupDates, REVERSE_DATE_ORDER);
|
||||||
|
showDialog(DIALOG_CHOOSER_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Dialog onCreateDialog(int id) {
|
||||||
|
switch (id) {
|
||||||
|
case DIALOG_CHOOSER_ID:
|
||||||
|
String items[] = new String[backupDates.length];
|
||||||
|
for (int i = 0; i < backupDates.length; i++) {
|
||||||
|
items[i] = StringUtils.formatDateTime(this, backupDates[i].getTime());
|
||||||
|
}
|
||||||
|
return new AlertDialog.Builder(this)
|
||||||
|
.setCancelable(true)
|
||||||
|
.setItems(items, new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
startActivity(new Intent(RestoreChooserActivity.this, RestoreActivity.class)
|
||||||
|
.putExtra(RestoreActivity.EXTRA_DATE, backupDates[which].getTime()));
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setOnCancelListener(new OnCancelListener() {
|
||||||
|
@Override
|
||||||
|
public void onCancel(DialogInterface dialog) {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setTitle(R.string.settings_backup_restore_select_title)
|
||||||
|
.create();
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011 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.ImportAllTracks;
|
|
||||||
import com.google.android.apps.mytracks.util.UriUtils;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An activity that imports a track from a file and displays the track in My Tracks.
|
|
||||||
*
|
|
||||||
* @author Rodrigo Damazio
|
|
||||||
*/
|
|
||||||
public class ImportActivity extends Activity {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
|
|
||||||
Intent intent = getIntent();
|
|
||||||
String action = intent.getAction();
|
|
||||||
Uri data = intent.getData();
|
|
||||||
if (!(Intent.ACTION_VIEW.equals(action) || Intent.ACTION_ATTACH_DATA.equals(action))) {
|
|
||||||
Log.e(TAG, "Received an intent with unsupported action: " + intent);
|
|
||||||
finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!UriUtils.isFileUri(data)) {
|
|
||||||
Log.e(TAG, "Received an intent with unsupported data: " + intent);
|
|
||||||
finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String path = data.getPath();
|
|
||||||
Log.i(TAG, "Importing GPX file at " + path);
|
|
||||||
new ImportAllTracks(this, path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -13,24 +13,19 @@
|
|||||||
* License for the specific language governing permissions and limitations under
|
* License for the specific language governing permissions and limitations under
|
||||||
* the License.
|
* the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.google.android.apps.mytracks.io.file;
|
package com.google.android.apps.mytracks.io.file;
|
||||||
|
|
||||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
|
||||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
|
||||||
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
|
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
|
||||||
import com.google.android.apps.mytracks.util.FileUtils;
|
import com.google.android.apps.mytracks.util.FileUtils;
|
||||||
import com.google.android.apps.mytracks.util.PlayTrackUtils;
|
import com.google.android.apps.mytracks.util.PlayTrackUtils;
|
||||||
import com.google.android.apps.mytracks.util.UriUtils;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.ContentUris;
|
import android.app.ProgressDialog;
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.DialogInterface.OnCancelListener;
|
import android.content.DialogInterface.OnCancelListener;
|
||||||
import android.content.DialogInterface.OnClickListener;
|
import android.content.DialogInterface.OnClickListener;
|
||||||
@@ -42,208 +37,190 @@ import android.util.Log;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activity for saving a track to a file (and optionally sending that file).
|
* Activity for saving a track to the SD card, and optionally share or play the
|
||||||
|
* track.
|
||||||
*
|
*
|
||||||
* @author Rodrigo Damazio
|
* @author Rodrigo Damazio
|
||||||
*/
|
*/
|
||||||
public class SaveActivity extends Activity {
|
public class SaveActivity extends Activity {
|
||||||
public static final String EXTRA_FILE_FORMAT = "file_format";
|
|
||||||
public static final String EXTRA_SHARE_FILE = "share_file";
|
|
||||||
public static final String EXTRA_PLAY_FILE = "play_file";
|
|
||||||
|
|
||||||
private static final int RESULT_DIALOG = 1;
|
public static final String EXTRA_TRACK_ID = "track_id";
|
||||||
/* VisibleForTesting */
|
public static final String EXTRA_TRACK_FILE_FORMAT = "track_file_format";
|
||||||
static final int PROGRESS_DIALOG = 2;
|
public static final String EXTRA_SHARE_TRACK = "share_track";
|
||||||
|
public static final String EXTRA_PLAY_TRACK = "play_track";
|
||||||
|
|
||||||
|
private static final String TAG = SaveActivity.class.getSimpleName();
|
||||||
|
|
||||||
|
private static final int DIALOG_PROGRESS_ID = 0;
|
||||||
|
private static final int DIALOG_RESULT_ID = 1;
|
||||||
|
|
||||||
private MyTracksProviderUtils providerUtils;
|
|
||||||
private long trackId;
|
private long trackId;
|
||||||
private TrackWriter writer;
|
private TrackFileFormat trackFileFormat;
|
||||||
private boolean shareFile;
|
private boolean shareTrack;
|
||||||
private boolean playFile;
|
private boolean playTrack;
|
||||||
private TrackFileFormat format;
|
|
||||||
private WriteProgressController controller;
|
private SaveAsyncTask saveAsyncTask;
|
||||||
|
private ProgressDialog progressDialog;
|
||||||
|
|
||||||
|
// result from the AsyncTask
|
||||||
|
private boolean success;
|
||||||
|
|
||||||
|
// message id from the AsyncTask
|
||||||
|
private int messageId;
|
||||||
|
|
||||||
|
// path of the saved file
|
||||||
|
private String filePath;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
providerUtils = MyTracksProviderUtils.Factory.get(this);
|
Intent intent = getIntent();
|
||||||
|
trackId = intent.getLongExtra(EXTRA_TRACK_ID, -1L);
|
||||||
|
if (trackId < 0) {
|
||||||
|
Log.d(TAG, "Invalid track id");
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
trackFileFormat = intent.getParcelableExtra(EXTRA_TRACK_FILE_FORMAT);
|
||||||
|
shareTrack = intent.getBooleanExtra(EXTRA_SHARE_TRACK, false);
|
||||||
|
playTrack = intent.getBooleanExtra(EXTRA_PLAY_TRACK, false);
|
||||||
|
|
||||||
|
Object retained = getLastNonConfigurationInstance();
|
||||||
|
if (retained instanceof SaveAsyncTask) {
|
||||||
|
saveAsyncTask = (SaveAsyncTask) retained;
|
||||||
|
saveAsyncTask.setActivity(this);
|
||||||
|
} else {
|
||||||
|
TrackWriter trackWriter = TrackWriterFactory.newWriter(
|
||||||
|
this, MyTracksProviderUtils.Factory.get(this), trackId, trackFileFormat);
|
||||||
|
if (trackWriter == null) {
|
||||||
|
Log.e(TAG, "Track writer is null");
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (shareTrack || playTrack) {
|
||||||
|
// Save to the temp directory
|
||||||
|
String dirName = new FileUtils().buildExternalDirectoryPath(
|
||||||
|
trackFileFormat.getExtension(), "tmp");
|
||||||
|
trackWriter.setDirectory(new File(dirName));
|
||||||
|
}
|
||||||
|
saveAsyncTask = new SaveAsyncTask(this, trackWriter);
|
||||||
|
saveAsyncTask.execute();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStart() {
|
public Object onRetainNonConfigurationInstance() {
|
||||||
super.onStart();
|
saveAsyncTask.setActivity(null);
|
||||||
|
return saveAsyncTask;
|
||||||
|
}
|
||||||
|
|
||||||
Intent intent = getIntent();
|
@Override
|
||||||
String action = intent.getAction();
|
protected Dialog onCreateDialog(int id) {
|
||||||
String type = intent.getType();
|
switch (id) {
|
||||||
Uri data = intent.getData();
|
case DIALOG_PROGRESS_ID:
|
||||||
if (!getString(R.string.track_action_save).equals(action)
|
progressDialog = new ProgressDialog(this);
|
||||||
|| !TracksColumns.CONTENT_ITEMTYPE.equals(type)
|
progressDialog.setCancelable(true);
|
||||||
|| !UriUtils.matchesContentUri(data, TracksColumns.CONTENT_URI)) {
|
progressDialog.setIcon(android.R.drawable.ic_dialog_info);
|
||||||
Log.e(TAG, "Got bad save intent: " + intent);
|
progressDialog.setIndeterminate(true);
|
||||||
finish();
|
progressDialog.setMessage(getString(R.string.sd_card_progress_write_file));
|
||||||
return;
|
progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||||
|
@Override
|
||||||
|
public void onCancel(DialogInterface dialog) {
|
||||||
|
saveAsyncTask.cancel(true);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||||
|
progressDialog.setTitle(R.string.generic_progress_title);
|
||||||
|
return progressDialog;
|
||||||
|
case DIALOG_RESULT_ID:
|
||||||
|
return new AlertDialog.Builder(this)
|
||||||
|
.setCancelable(true)
|
||||||
|
.setIcon(success
|
||||||
|
? android.R.drawable.ic_dialog_info : android.R.drawable.ic_dialog_alert)
|
||||||
|
.setMessage(messageId)
|
||||||
|
.setOnCancelListener(new OnCancelListener() {
|
||||||
|
@Override
|
||||||
|
public void onCancel(DialogInterface dialog) {
|
||||||
|
dialog.dismiss();
|
||||||
|
onPostResultDialog();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setPositiveButton(R.string.generic_ok, new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int arg1) {
|
||||||
|
dialog.dismiss();
|
||||||
|
onPostResultDialog();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setTitle(success ? R.string.generic_success_title : R.string.generic_error_title)
|
||||||
|
.create();
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
trackId = ContentUris.parseId(data);
|
/**
|
||||||
|
* Invokes when the associated AsyncTask completes.
|
||||||
|
*
|
||||||
|
* @param isSuccess true if the AsyncTask is successful
|
||||||
|
* @param aMessageId the id of the AsyncTask message
|
||||||
|
* @param aPath the path of the saved file
|
||||||
|
*/
|
||||||
|
public void onAsyncTaskCompleted(boolean isSuccess, int aMessageId, String aPath) {
|
||||||
|
this.success = isSuccess;
|
||||||
|
this.messageId = aMessageId;
|
||||||
|
this.filePath = aPath;
|
||||||
|
removeDialog(DIALOG_PROGRESS_ID);
|
||||||
|
showDialog(DIALOG_RESULT_ID);
|
||||||
|
}
|
||||||
|
|
||||||
int formatIdx = intent.getIntExtra(EXTRA_FILE_FORMAT, -1);
|
/**
|
||||||
format = TrackFileFormat.values()[formatIdx];
|
* Shows the progress dialog.
|
||||||
shareFile = intent.getBooleanExtra(EXTRA_SHARE_FILE, false);
|
*/
|
||||||
playFile = intent.getBooleanExtra(EXTRA_PLAY_FILE, false);
|
public void showProgressDialog() {
|
||||||
|
showDialog(DIALOG_PROGRESS_ID);
|
||||||
writer = TrackWriterFactory.newWriter(this, providerUtils, trackId, format);
|
}
|
||||||
if (writer == null) {
|
|
||||||
Log.e(TAG, "Unable to build writer");
|
/**
|
||||||
finish();
|
* Sets the progress dialog value.
|
||||||
return;
|
*
|
||||||
|
* @param number the number of points saved
|
||||||
|
* @param max the maximum number of points
|
||||||
|
*/
|
||||||
|
public void setProgressDialogValue(int number, int max) {
|
||||||
|
if (progressDialog != null) {
|
||||||
|
progressDialog.setIndeterminate(false);
|
||||||
|
progressDialog.setMax(max);
|
||||||
|
progressDialog.setProgress(Math.min(number, max));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shareFile || playFile) {
|
|
||||||
// If the file is for sending, save it to a temporary location instead.
|
|
||||||
FileUtils fileUtils = new FileUtils();
|
|
||||||
String extension = format.getExtension();
|
|
||||||
String dirName = fileUtils.buildExternalDirectoryPath(extension, "tmp");
|
|
||||||
|
|
||||||
File dir = new File(dirName);
|
|
||||||
writer.setDirectory(dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
controller = new WriteProgressController(this, writer, PROGRESS_DIALOG);
|
|
||||||
controller.setOnCompletionListener(new WriteProgressController.OnCompletionListener() {
|
|
||||||
@Override
|
|
||||||
public void onComplete() {
|
|
||||||
showDialog(RESULT_DIALOG);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
controller.startWrite();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To be invoked after showing the result dialog.
|
* To be invoked after showing the result dialog.
|
||||||
*/
|
*/
|
||||||
private void onPostResultDialog() {
|
private void onPostResultDialog() {
|
||||||
if (writer.wasSuccess()) {
|
if (success) {
|
||||||
if (shareFile) {
|
if (shareTrack) {
|
||||||
shareWrittenFile();
|
Intent intent = new Intent(Intent.ACTION_SEND)
|
||||||
} else if (playFile) {
|
.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(filePath)))
|
||||||
playWrittenFile();
|
.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_track_subject))
|
||||||
|
.putExtra(Intent.EXTRA_TEXT, getString(R.string.share_track_file_body_format))
|
||||||
|
.putExtra(getString(R.string.track_id_broadcast_extra), trackId)
|
||||||
|
.setType(trackFileFormat.getMimeType());
|
||||||
|
startActivity(Intent.createChooser(intent, getString(R.string.share_track_picker_title)));
|
||||||
|
} else if (playTrack) {
|
||||||
|
Intent intent = new Intent()
|
||||||
|
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||||
|
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
.putExtra(PlayTrackUtils.TOUR_FEATURE_ID, KmlTrackWriter.TOUR_FEATURE_ID)
|
||||||
|
.setClassName(PlayTrackUtils.GOOGLE_EARTH_PACKAGE, PlayTrackUtils.GOOGLE_EARTH_CLASS)
|
||||||
|
.setDataAndType(Uri.fromFile(new File(filePath)), PlayTrackUtils.KML_MIME_TYPE);
|
||||||
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void shareWrittenFile() {
|
|
||||||
// Share the file.
|
|
||||||
Intent shareIntent = new Intent(Intent.ACTION_SEND);
|
|
||||||
shareIntent.putExtra(Intent.EXTRA_SUBJECT,
|
|
||||||
getResources().getText(R.string.share_track_subject).toString());
|
|
||||||
shareIntent.putExtra(Intent.EXTRA_TEXT,
|
|
||||||
getResources().getText(R.string.share_track_file_body_format)
|
|
||||||
.toString());
|
|
||||||
shareIntent.setType(format.getMimeType());
|
|
||||||
Uri u = Uri.fromFile(new File(writer.getAbsolutePath()));
|
|
||||||
shareIntent.putExtra(Intent.EXTRA_STREAM, u);
|
|
||||||
shareIntent.putExtra(getString(R.string.track_id_broadcast_extra), trackId);
|
|
||||||
startActivity(Intent.createChooser(shareIntent,
|
|
||||||
getResources().getText(R.string.share_track_picker_title).toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void playWrittenFile() {
|
|
||||||
Uri uri = Uri.fromFile(new File(writer.getAbsolutePath()));
|
|
||||||
Intent intent = new Intent()
|
|
||||||
.setClassName(PlayTrackUtils.GOOGLE_EARTH_PACKAGE, PlayTrackUtils.GOOGLE_EARTH_CLASS)
|
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
.setDataAndType(uri, PlayTrackUtils.KML_MIME_TYPE)
|
|
||||||
.putExtra(PlayTrackUtils.TOUR_FEATURE_ID, KmlTrackWriter.TOUR_FEATURE_ID);
|
|
||||||
startActivity(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Dialog onCreateDialog(int id) {
|
|
||||||
switch (id) {
|
|
||||||
case RESULT_DIALOG:
|
|
||||||
return createResultDialog();
|
|
||||||
case PROGRESS_DIALOG:
|
|
||||||
if (controller != null) {
|
|
||||||
return controller.createProgressDialog();
|
|
||||||
}
|
|
||||||
//$FALL-THROUGH$
|
|
||||||
default:
|
|
||||||
return super.onCreateDialog(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Dialog createResultDialog() {
|
|
||||||
boolean success = writer.wasSuccess();
|
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
||||||
builder.setMessage(writer.getErrorMessage());
|
|
||||||
builder.setPositiveButton(R.string.generic_ok, new OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int arg1) {
|
|
||||||
dialog.dismiss();
|
|
||||||
onPostResultDialog();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
builder.setOnCancelListener(new OnCancelListener() {
|
|
||||||
@Override
|
|
||||||
public void onCancel(DialogInterface dialog) {
|
|
||||||
dialog.dismiss();
|
|
||||||
onPostResultDialog();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
builder.setIcon(success ? android.R.drawable.ic_dialog_info :
|
|
||||||
android.R.drawable.ic_dialog_alert);
|
|
||||||
builder.setTitle(success ? R.string.generic_success_title : R.string.generic_error_title);
|
|
||||||
return builder.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void handleExportTrackAction(Context ctx, long trackId, int actionCode) {
|
|
||||||
if (trackId < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TrackFileFormat exportFormat = null;
|
|
||||||
switch (actionCode) {
|
|
||||||
case Constants.SAVE_GPX_FILE:
|
|
||||||
case Constants.SHARE_GPX_FILE:
|
|
||||||
exportFormat = TrackFileFormat.GPX;
|
|
||||||
break;
|
|
||||||
case Constants.SAVE_KML_FILE:
|
|
||||||
case Constants.SHARE_KML_FILE:
|
|
||||||
exportFormat = TrackFileFormat.KML;
|
|
||||||
break;
|
|
||||||
case Constants.SAVE_CSV_FILE:
|
|
||||||
case Constants.SHARE_CSV_FILE:
|
|
||||||
exportFormat = TrackFileFormat.CSV;
|
|
||||||
break;
|
|
||||||
case Constants.SAVE_TCX_FILE:
|
|
||||||
case Constants.SHARE_TCX_FILE:
|
|
||||||
exportFormat = TrackFileFormat.TCX;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Warning unhandled action code: " + actionCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean shareFile = false;
|
|
||||||
switch (actionCode) {
|
|
||||||
case Constants.SHARE_GPX_FILE:
|
|
||||||
case Constants.SHARE_KML_FILE:
|
|
||||||
case Constants.SHARE_CSV_FILE:
|
|
||||||
case Constants.SHARE_TCX_FILE:
|
|
||||||
shareFile = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Uri uri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, trackId);
|
|
||||||
|
|
||||||
Intent intent = new Intent(ctx, SaveActivity.class);
|
|
||||||
intent.setAction(ctx.getString(R.string.track_action_save));
|
|
||||||
intent.setDataAndType(uri, TracksColumns.CONTENT_ITEMTYPE);
|
|
||||||
intent.putExtra(EXTRA_FILE_FORMAT, exportFormat.ordinal());
|
|
||||||
intent.putExtra(EXTRA_SHARE_FILE, shareFile);
|
|
||||||
ctx.startActivity(intent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* 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.io.file;
|
||||||
|
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Async Task to save a track to the SD card.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||||
|
|
||||||
|
private SaveActivity saveActivity;
|
||||||
|
private final TrackWriter trackWriter;
|
||||||
|
|
||||||
|
// true if the AsyncTask result is success
|
||||||
|
private boolean success;
|
||||||
|
|
||||||
|
// true if the AsyncTask has completed
|
||||||
|
private boolean completed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an AsyncTask.
|
||||||
|
*
|
||||||
|
* @param saveActivity the {@link SaveActivity} currently associated with this
|
||||||
|
* AsyncTask
|
||||||
|
* @param trackWriter the track writer
|
||||||
|
*/
|
||||||
|
public SaveAsyncTask(SaveActivity saveActivity, TrackWriter trackWriter) {
|
||||||
|
this.saveActivity = saveActivity;
|
||||||
|
this.trackWriter = trackWriter;
|
||||||
|
success = false;
|
||||||
|
completed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current {@link SaveActivity} associated with this AyncTask.
|
||||||
|
*
|
||||||
|
* @param saveActivity the current {@link SaveActivity}, can be null
|
||||||
|
*/
|
||||||
|
public void setActivity(SaveActivity saveActivity) {
|
||||||
|
this.saveActivity = saveActivity;
|
||||||
|
if (completed && saveActivity != null) {
|
||||||
|
saveActivity.onAsyncTaskCompleted(
|
||||||
|
success, trackWriter.getErrorMessage(), trackWriter.getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute() {
|
||||||
|
if (saveActivity != null) {
|
||||||
|
saveActivity.showProgressDialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boolean doInBackground(Void... params) {
|
||||||
|
trackWriter.setOnWriteListener(new TrackWriter.OnWriteListener() {
|
||||||
|
@Override
|
||||||
|
public void onWrite(int number, int max) {
|
||||||
|
// Update the progress dialog once every 500 points
|
||||||
|
if (number % 500 == 0) {
|
||||||
|
publishProgress(number, max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
trackWriter.writeTrack();
|
||||||
|
return trackWriter.wasSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onProgressUpdate(Integer... values) {
|
||||||
|
if (saveActivity != null) {
|
||||||
|
saveActivity.setProgressDialogValue(values[0], values[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Boolean result) {
|
||||||
|
success = result;
|
||||||
|
completed = true;
|
||||||
|
if (saveActivity != null) {
|
||||||
|
saveActivity.onAsyncTaskCompleted(
|
||||||
|
success, trackWriter.getErrorMessage(), trackWriter.getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCancelled() {
|
||||||
|
trackWriter.stopWriteTrack();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,10 +27,6 @@ import java.io.File;
|
|||||||
* @author Rodrigo Damazio
|
* @author Rodrigo Damazio
|
||||||
*/
|
*/
|
||||||
public interface TrackWriter {
|
public interface TrackWriter {
|
||||||
/** This listener is used to signal completion of track write */
|
|
||||||
public interface OnCompletionListener {
|
|
||||||
public void onComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** This listener is used to signal track writes. */
|
/** This listener is used to signal track writes. */
|
||||||
public interface OnWriteListener {
|
public interface OnWriteListener {
|
||||||
@@ -43,11 +39,6 @@ public interface TrackWriter {
|
|||||||
public void onWrite(int number, int max);
|
public void onWrite(int number, int max);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets listener to be invoked when the writer has finished.
|
|
||||||
*/
|
|
||||||
void setOnCompletionListener(OnCompletionListener onCompletionListener);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a listener to be invoked for each location writer.
|
* Sets a listener to be invoked for each location writer.
|
||||||
*/
|
*/
|
||||||
@@ -63,12 +54,6 @@ public interface TrackWriter {
|
|||||||
*/
|
*/
|
||||||
String getAbsolutePath();
|
String getAbsolutePath();
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes the given track id to the SD card.
|
|
||||||
* This is non-blocking.
|
|
||||||
*/
|
|
||||||
void writeTrackAsync();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the given track id to the SD card.
|
* Writes the given track id to the SD card.
|
||||||
* This is blocking.
|
* This is blocking.
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
|||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,7 +36,7 @@ public class TrackWriterFactory {
|
|||||||
/**
|
/**
|
||||||
* Definition of all possible track formats.
|
* Definition of all possible track formats.
|
||||||
*/
|
*/
|
||||||
public enum TrackFileFormat {
|
public enum TrackFileFormat implements Parcelable {
|
||||||
GPX {
|
GPX {
|
||||||
@Override
|
@Override
|
||||||
TrackFormatWriter newFormatWriter(Context context) {
|
TrackFormatWriter newFormatWriter(Context context) {
|
||||||
@@ -60,6 +62,28 @@ public class TrackWriterFactory {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(final Parcel dest, final int flags) {
|
||||||
|
dest.writeInt(ordinal());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Creator<TrackFileFormat> CREATOR = new Creator<TrackFileFormat>() {
|
||||||
|
@Override
|
||||||
|
public TrackFileFormat createFromParcel(final Parcel source) {
|
||||||
|
return TrackFileFormat.values()[source.readInt()];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TrackFileFormat[] newArray(final int size) {
|
||||||
|
return new TrackFileFormat[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and returns a new format writer for each format.
|
* Creates and returns a new format writer for each format.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ class TrackWriterImpl implements TrackWriter {
|
|||||||
private int errorMessage = -1;
|
private int errorMessage = -1;
|
||||||
private File directory = null;
|
private File directory = null;
|
||||||
private File file = null;
|
private File file = null;
|
||||||
private OnCompletionListener onCompletionListener;
|
|
||||||
private OnWriteListener onWriteListener;
|
private OnWriteListener onWriteListener;
|
||||||
private Thread writeThread;
|
private Thread writeThread;
|
||||||
|
|
||||||
@@ -70,11 +69,6 @@ class TrackWriterImpl implements TrackWriter {
|
|||||||
this.fileUtils = new FileUtils();
|
this.fileUtils = new FileUtils();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setOnCompletionListener(OnCompletionListener onCompletionListener) {
|
|
||||||
this.onCompletionListener = onCompletionListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setOnWriteListener(OnWriteListener onWriteListener) {
|
public void setOnWriteListener(OnWriteListener onWriteListener) {
|
||||||
this.onWriteListener = onWriteListener;
|
this.onWriteListener = onWriteListener;
|
||||||
@@ -90,8 +84,7 @@ class TrackWriterImpl implements TrackWriter {
|
|||||||
return file.getAbsolutePath();
|
return file.getAbsolutePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void writeTrackAsync() {
|
||||||
public void writeTrackAsync() {
|
|
||||||
writeThread = new Thread() {
|
writeThread = new Thread() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -131,7 +124,6 @@ class TrackWriterImpl implements TrackWriter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finished();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopWriteTrack() {
|
public void stopWriteTrack() {
|
||||||
@@ -163,18 +155,6 @@ class TrackWriterImpl implements TrackWriter {
|
|||||||
* ===============
|
* ===============
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private void finished() {
|
|
||||||
if (onCompletionListener != null) {
|
|
||||||
runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
onCompletionListener.onComplete();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs the given runnable in the UI thread.
|
* Runs the given runnable in the UI thread.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,132 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011 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 com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a {@link TrackWriter}, this class manages the process of writing the
|
|
||||||
* data in the track represented by the writer. This includes the display of
|
|
||||||
* a progress dialog, updating the progress bar in said dialog, and notifying
|
|
||||||
* interested parties when the write completes.
|
|
||||||
*
|
|
||||||
* @author Matthew Simmons
|
|
||||||
*/
|
|
||||||
class WriteProgressController {
|
|
||||||
/**
|
|
||||||
* This listener is used to notify interested parties when the write has
|
|
||||||
* completed.
|
|
||||||
*/
|
|
||||||
public interface OnCompletionListener {
|
|
||||||
/**
|
|
||||||
* When this method is invoked, the write has completed, and the progress
|
|
||||||
* dialog has been dismissed. Whether the write succeeded can be
|
|
||||||
* determined by examining the {@link TrackWriter}.
|
|
||||||
*/
|
|
||||||
public void onComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Activity activity;
|
|
||||||
private final TrackWriter writer;
|
|
||||||
private ProgressDialog dialog;
|
|
||||||
|
|
||||||
private OnCompletionListener onCompletionListener;
|
|
||||||
private final int progressDialogId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param activity the activity associated with this write
|
|
||||||
* @param writer the writer which writes the track to disk. Note that this
|
|
||||||
* class will use the writer's completion listener. If callers are
|
|
||||||
* interested in notification upon completion of the write, they should
|
|
||||||
* use {@link #setOnCompletionListener}.
|
|
||||||
*/
|
|
||||||
public WriteProgressController(Activity activity, TrackWriter writer, int progressDialogId) {
|
|
||||||
this.activity = activity;
|
|
||||||
this.writer = writer;
|
|
||||||
this.progressDialogId = progressDialogId;
|
|
||||||
|
|
||||||
writer.setOnCompletionListener(writerCompleteListener);
|
|
||||||
writer.setOnWriteListener(writerWriteListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set a listener to be invoked when the write completes. */
|
|
||||||
public void setOnCompletionListener(OnCompletionListener onCompletionListener) {
|
|
||||||
this.onCompletionListener = onCompletionListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For testing purpose
|
|
||||||
OnCompletionListener getOnCompletionListener() {
|
|
||||||
return onCompletionListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProgressDialog createProgressDialog() {
|
|
||||||
dialog = new ProgressDialog(activity);
|
|
||||||
dialog.setIcon(android.R.drawable.ic_dialog_info);
|
|
||||||
dialog.setTitle(activity.getString(R.string.generic_progress_title));
|
|
||||||
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
|
||||||
dialog.setMessage(activity.getString(R.string.sd_card_progress_write_file));
|
|
||||||
dialog.setIndeterminate(true);
|
|
||||||
dialog.setOnCancelListener(dialogCancelListener);
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Initiate an asynchronous write. */
|
|
||||||
public void startWrite() {
|
|
||||||
activity.showDialog(progressDialogId);
|
|
||||||
writer.writeTrackAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** VisibleForTesting */
|
|
||||||
ProgressDialog getDialog() {
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final DialogInterface.OnCancelListener dialogCancelListener =
|
|
||||||
new DialogInterface.OnCancelListener() {
|
|
||||||
@Override
|
|
||||||
public void onCancel(DialogInterface dialogInterface) {
|
|
||||||
writer.stopWriteTrack();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final TrackWriter.OnCompletionListener writerCompleteListener =
|
|
||||||
new TrackWriter.OnCompletionListener() {
|
|
||||||
@Override
|
|
||||||
public void onComplete() {
|
|
||||||
activity.dismissDialog(progressDialogId);
|
|
||||||
|
|
||||||
if (onCompletionListener != null) {
|
|
||||||
onCompletionListener.onComplete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final TrackWriter.OnWriteListener writerWriteListener =
|
|
||||||
new TrackWriter.OnWriteListener() {
|
|
||||||
@Override
|
|
||||||
public void onWrite(int number, int max) {
|
|
||||||
if (number % 500 == 0) {
|
|
||||||
dialog.setIndeterminate(false);
|
|
||||||
dialog.setMax(max);
|
|
||||||
dialog.setProgress(Math.min(number, max));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -16,14 +16,12 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.util;
|
package com.google.android.apps.mytracks.util;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
|
||||||
import com.google.android.apps.mytracks.io.file.SaveActivity;
|
import com.google.android.apps.mytracks.io.file.SaveActivity;
|
||||||
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
|
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.ContentUris;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.DialogInterface.OnClickListener;
|
import android.content.DialogInterface.OnClickListener;
|
||||||
@@ -31,6 +29,7 @@ import android.content.Intent;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -80,12 +79,10 @@ public class PlayTrackUtils {
|
|||||||
public static void playTrack(Context context, long trackId) {
|
public static void playTrack(Context context, long trackId) {
|
||||||
AnalyticsUtils.sendPageViews(context, "/action/play");
|
AnalyticsUtils.sendPageViews(context, "/action/play");
|
||||||
|
|
||||||
Uri uri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, trackId);
|
|
||||||
Intent intent = new Intent(context, SaveActivity.class)
|
Intent intent = new Intent(context, SaveActivity.class)
|
||||||
.putExtra(SaveActivity.EXTRA_FILE_FORMAT, TrackFileFormat.KML.ordinal())
|
.putExtra(SaveActivity.EXTRA_TRACK_ID, trackId)
|
||||||
.putExtra(SaveActivity.EXTRA_PLAY_FILE, true)
|
.putExtra(SaveActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) TrackFileFormat.KML)
|
||||||
.setAction(context.getString(R.string.track_action_save))
|
.putExtra(SaveActivity.EXTRA_PLAY_TRACK, true);
|
||||||
.setDataAndType(uri, TracksColumns.CONTENT_ITEMTYPE);
|
|
||||||
context.startActivity(intent);
|
context.startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,21 +19,14 @@ import java.io.File;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple, fake {@link TrackWriter} subclass with all methods mocked out.
|
* A simple, fake {@link TrackWriter} subclass with all methods mocked out.
|
||||||
* Tests are expected to override {@link #writeTrack} and/or
|
* Tests are expected to override {@link #writeTrack}.
|
||||||
* {@link #writeTrackAsync}, at the very least.
|
|
||||||
*
|
*
|
||||||
* @author Matthew Simmons
|
* @author Matthew Simmons
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class MockTrackWriter implements TrackWriter {
|
public class MockTrackWriter implements TrackWriter {
|
||||||
public OnCompletionListener onCompletionListener;
|
|
||||||
public OnWriteListener onWriteListener;
|
public OnWriteListener onWriteListener;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setOnCompletionListener(OnCompletionListener onCompletionListener) {
|
|
||||||
this.onCompletionListener = onCompletionListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setOnWriteListener(OnWriteListener onWriteListener) {
|
public void setOnWriteListener(OnWriteListener onWriteListener) {
|
||||||
this.onWriteListener = onWriteListener;
|
this.onWriteListener = onWriteListener;
|
||||||
@@ -49,11 +42,6 @@ public class MockTrackWriter implements TrackWriter {
|
|||||||
throw new UnsupportedOperationException("not implemented");
|
throw new UnsupportedOperationException("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeTrackAsync() {
|
|
||||||
throw new UnsupportedOperationException("not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeTrack() {
|
public void writeTrack() {
|
||||||
throw new UnsupportedOperationException("not implemented");
|
throw new UnsupportedOperationException("not implemented");
|
||||||
|
|||||||
@@ -169,13 +169,7 @@ public class TrackWriterTest extends AndroidTestCase {
|
|||||||
writer = new WriteTracksTrackWriter(getContext(), providerUtils, track,
|
writer = new WriteTracksTrackWriter(getContext(), providerUtils, track,
|
||||||
formatWriter, true);
|
formatWriter, true);
|
||||||
|
|
||||||
// Expect the completion listener to be run
|
|
||||||
TrackWriter.OnCompletionListener completionListener
|
|
||||||
= mocksControl.createMock(TrackWriter.OnCompletionListener.class);
|
|
||||||
completionListener.onComplete();
|
|
||||||
|
|
||||||
mocksControl.replay();
|
mocksControl.replay();
|
||||||
writer.setOnCompletionListener(completionListener);
|
|
||||||
writer.writeTrack();
|
writer.writeTrack();
|
||||||
|
|
||||||
assertEquals(1, writeDocumentCalls);
|
assertEquals(1, writeDocumentCalls);
|
||||||
@@ -187,13 +181,7 @@ public class TrackWriterTest extends AndroidTestCase {
|
|||||||
writer = new WriteTracksTrackWriter(getContext(), providerUtils, track,
|
writer = new WriteTracksTrackWriter(getContext(), providerUtils, track,
|
||||||
formatWriter, false);
|
formatWriter, false);
|
||||||
|
|
||||||
// Expect the completion listener to be run
|
|
||||||
TrackWriter.OnCompletionListener completionListener
|
|
||||||
= mocksControl.createMock(TrackWriter.OnCompletionListener.class);
|
|
||||||
completionListener.onComplete();
|
|
||||||
|
|
||||||
mocksControl.replay();
|
mocksControl.replay();
|
||||||
writer.setOnCompletionListener(completionListener);
|
|
||||||
writer.writeTrack();
|
writer.writeTrack();
|
||||||
|
|
||||||
assertEquals(0, writeDocumentCalls);
|
assertEquals(0, writeDocumentCalls);
|
||||||
|
|||||||
-90
@@ -1,90 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011 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 android.app.ProgressDialog;
|
|
||||||
import android.test.ActivityInstrumentationTestCase2;
|
|
||||||
|
|
||||||
import java.util.concurrent.Semaphore;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link WriteProgressController}.
|
|
||||||
*
|
|
||||||
* @author Matthew Simmons
|
|
||||||
*/
|
|
||||||
public class WriteProgressControllerTest extends ActivityInstrumentationTestCase2<SaveActivity> {
|
|
||||||
public WriteProgressControllerTest() {
|
|
||||||
super(SaveActivity.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void assertProgress(ProgressDialog dialog, int expectedProgress,
|
|
||||||
int expectedMax) {
|
|
||||||
assertEquals(expectedProgress, dialog.getProgress());
|
|
||||||
assertEquals(expectedMax, dialog.getMax());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testSimple() throws Exception {
|
|
||||||
final AtomicReference<ProgressDialog> dialogRef = new AtomicReference<ProgressDialog>();
|
|
||||||
final AtomicReference<Boolean> controllerDoneRef = new AtomicReference<Boolean>();
|
|
||||||
final Semaphore writerDone = new Semaphore(0);
|
|
||||||
|
|
||||||
TrackWriter mockWriter = new MockTrackWriter() {
|
|
||||||
@Override
|
|
||||||
public void writeTrackAsync() {
|
|
||||||
onWriteListener.onWrite(1000, 10000);
|
|
||||||
assertProgress(dialogRef.get(), 1000, 10000);
|
|
||||||
|
|
||||||
onCompletionListener.onComplete();
|
|
||||||
writerDone.release();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
final WriteProgressController controller = new WriteProgressController(
|
|
||||||
getActivity(), mockWriter, SaveActivity.PROGRESS_DIALOG);
|
|
||||||
controller.setOnCompletionListener(new WriteProgressController.OnCompletionListener() {
|
|
||||||
@Override
|
|
||||||
public void onComplete() {
|
|
||||||
controllerDoneRef.set(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The WriteProgressController constructor calls the mockWriter's
|
|
||||||
* setOnCompletionListener method with a listener that dismisses the
|
|
||||||
* progress dialog. However, this unit test only tests the
|
|
||||||
* WriteProgressController and doesn't actually show any progress dialog.
|
|
||||||
* Thus after the WriteProgressController is setup, we need to call the
|
|
||||||
* mockWriter's setOnCompletionListener method again with an listener that
|
|
||||||
* doesn't dismiss dialog.
|
|
||||||
*/
|
|
||||||
mockWriter.setOnCompletionListener(new TrackWriter.OnCompletionListener() {
|
|
||||||
@Override
|
|
||||||
public void onComplete() {
|
|
||||||
controller.getOnCompletionListener().onComplete();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
dialogRef.set(controller.createProgressDialog());
|
|
||||||
|
|
||||||
controller.startWrite();
|
|
||||||
|
|
||||||
// wait for the writer to finish
|
|
||||||
writerDone.acquire();
|
|
||||||
|
|
||||||
assertTrue(controllerDoneRef.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user