forked from upstream-mirrors/OpenTracks
A lot of cleanup:
* Splitting ExternalFileBackup into UI and non-UI parts * Disabling backups while recording * Triggering cloud backups when preferences are changed
This commit is contained in:
@@ -65,6 +65,9 @@
|
|||||||
<activity android:name="com.google.android.apps.mytracks.WelcomeActivity"
|
<activity android:name="com.google.android.apps.mytracks.WelcomeActivity"
|
||||||
android:label="@string/welcome"/>
|
android:label="@string/welcome"/>
|
||||||
|
|
||||||
|
<activity android:name="com.google.android.apps.mytracks.io.backup.BackupActivity"
|
||||||
|
android:label="@string/settings_backup" />
|
||||||
|
|
||||||
<service android:name="com.google.android.apps.mytracks.services.TrackRecordingService"
|
<service android:name="com.google.android.apps.mytracks.services.TrackRecordingService"
|
||||||
android:process=":trackrecord"
|
android:process=":trackrecord"
|
||||||
android:label="Track Recording Service"
|
android:label="Track Recording Service"
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<resources>
|
<resources>
|
||||||
<!-- These are constants used internally for preferences - DO NOT TRANSLATE -->
|
<!-- Keys for application preferences - DO NOT TRANSLATE -->
|
||||||
<string name="announcement_frequency_key">announcementFrequency</string>
|
<string name="announcement_frequency_key">announcementFrequency</string>
|
||||||
<string name="bluetooth_device_key">bluetoothDevice</string>
|
<string name="bluetooth_device_key">bluetoothDevice</string>
|
||||||
<string name="bluetooth_pairing_key">bluetoothPairing</string>
|
<string name="bluetooth_pairing_key">bluetoothPairing</string>
|
||||||
@@ -28,9 +28,7 @@ limitations under the License.
|
|||||||
<string name="min_required_accuracy_key">minRequiredAccuracy</string>
|
<string name="min_required_accuracy_key">minRequiredAccuracy</string>
|
||||||
<string name="modular_stats_display_key">modularStatsDisplay</string>
|
<string name="modular_stats_display_key">modularStatsDisplay</string>
|
||||||
<string name="pick_existing_map_key">pickExistingMap</string>
|
<string name="pick_existing_map_key">pickExistingMap</string>
|
||||||
<string name="recording_track_key">recordingTrack</string>
|
|
||||||
<string name="report_speed_key">reportSpeed</string>
|
<string name="report_speed_key">reportSpeed</string>
|
||||||
<string name="selected_track_key">selectedTrack</string>
|
|
||||||
<string name="send_stats_and_points_key">sendStatsAndPoints</string>
|
<string name="send_stats_and_points_key">sendStatsAndPoints</string>
|
||||||
<string name="send_to_docs_key">sendToDocs</string>
|
<string name="send_to_docs_key">sendToDocs</string>
|
||||||
<string name="send_to_my_maps_key">sendToMyMaps</string>
|
<string name="send_to_my_maps_key">sendToMyMaps</string>
|
||||||
@@ -39,6 +37,12 @@ limitations under the License.
|
|||||||
<string name="share_url_only_key">shareUrlOnly</string>
|
<string name="share_url_only_key">shareUrlOnly</string>
|
||||||
<string name="signal_sampling_frequency_key">signalSamplingFrequency</string>
|
<string name="signal_sampling_frequency_key">signalSamplingFrequency</string>
|
||||||
<string name="split_frequency_key">splitFrequency</string>
|
<string name="split_frequency_key">splitFrequency</string>
|
||||||
|
|
||||||
|
<!-- Preference keys which keep transient state (not user preferences) - DO NOT TRANSLATE -->
|
||||||
|
<string name="recording_track_key">recordingTrack</string>
|
||||||
|
<string name="selected_track_key">selectedTrack</string>
|
||||||
|
|
||||||
|
<!-- Keys for non-persisted preferences - DO NOT TRANSLATE -->
|
||||||
<string name="backup_to_sd_key">backupToSd</string>
|
<string name="backup_to_sd_key">backupToSd</string>
|
||||||
<string name="restore_from_sd_key">restoreFromSd</string>
|
<string name="restore_from_sd_key">restoreFromSd</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -222,16 +222,17 @@ limitations under the License.
|
|||||||
<string name="settings_backup">Backup</string>
|
<string name="settings_backup">Backup</string>
|
||||||
<string name="settings_sd_backup">SD Card Backup</string>
|
<string name="settings_sd_backup">SD Card Backup</string>
|
||||||
<string name="settings_backup_to_sd">Backup now</string>
|
<string name="settings_backup_to_sd">Backup now</string>
|
||||||
<string name="settings_backup_to_sd_summary">Write a full backup of all your tracks to the SD card</string>
|
<string name="settings_backup_to_sd_summary">Write a full copy of all your tracks and settings to the SD card</string>
|
||||||
<string name="settings_restore_from_sd">Restore now</string>
|
<string name="settings_restore_from_sd">Restore now</string>
|
||||||
<string name="settings_restore_from_sd_summary">Restore a backup from the SD card</string>
|
<string name="settings_restore_from_sd_summary">Restore all tracks and settings from the SD card</string>
|
||||||
|
<string name="settings_no_backup_while_recording">Cannot manipulate backups while recording a track.</string>
|
||||||
|
|
||||||
<!-- Backups -->
|
<!-- Backups -->
|
||||||
<string name="restore_overwrites_warning">Restoring a backup from the SD card will OVERWRITE all your current tracks. Are you sure?</string>
|
<string name="restore_overwrites_warning">Restoring a backup from the SD card will OVERWRITE all your current tracks and settings. Are you sure?</string>
|
||||||
<string name="select_backup_to_restore">Select the backup to restore</string>
|
<string name="select_backup_to_restore">Select the backup to restore</string>
|
||||||
<string name="no_backups">No backups found.</string>
|
<string name="no_backups">No backups found.</string>
|
||||||
<string name="backup_write_progress_message">Writing all tracks to the SD card. This may take a while...</string>
|
<string name="backup_write_progress_message">Writing all tracks and settings to the SD card. This may take a while...</string>
|
||||||
<string name="backup_import_progress_message">Reading all tracks from the SD card. This may take a while...</string>
|
<string name="backup_import_progress_message">Reading all tracks and settings from the SD card. This may take a while...</string>
|
||||||
|
|
||||||
<!-- MyTracksSky -->
|
<!-- MyTracksSky -->
|
||||||
<string name="mytracks_sky">GPS Satellites</string>
|
<string name="mytracks_sky">GPS Satellites</string>
|
||||||
|
|||||||
@@ -15,10 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.apps.mytracks;
|
package com.google.android.apps.mytracks;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.io.backup.ExternalFileBackup;
|
import com.google.android.apps.mytracks.io.backup.BackupActivity;
|
||||||
|
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
|
||||||
import com.google.android.apps.mytracks.services.SafeStatusAnnouncerTask;
|
import com.google.android.apps.mytracks.services.SafeStatusAnnouncerTask;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.CheckBoxPreference;
|
import android.preference.CheckBoxPreference;
|
||||||
import android.preference.ListPreference;
|
import android.preference.ListPreference;
|
||||||
@@ -50,6 +53,9 @@ public class MyTracksSettings extends PreferenceActivity {
|
|||||||
public static final int DEFAULT_SPLIT_FREQUENCY = 0;
|
public static final int DEFAULT_SPLIT_FREQUENCY = 0;
|
||||||
|
|
||||||
private static boolean mTTSAvailable;
|
private static boolean mTTSAvailable;
|
||||||
|
private BackupPreferencesListener backupListener;
|
||||||
|
|
||||||
|
private SharedPreferences preferences;
|
||||||
|
|
||||||
/* establish whether the tts class is available to us */
|
/* establish whether the tts class is available to us */
|
||||||
static {
|
static {
|
||||||
@@ -72,6 +78,11 @@ public class MyTracksSettings extends PreferenceActivity {
|
|||||||
preferenceManager.setSharedPreferencesName(SETTINGS_NAME);
|
preferenceManager.setSharedPreferencesName(SETTINGS_NAME);
|
||||||
preferenceManager.setSharedPreferencesMode(0);
|
preferenceManager.setSharedPreferencesMode(0);
|
||||||
|
|
||||||
|
// Set up automatic preferences backup
|
||||||
|
backupListener = BackupPreferencesListener.create(this);
|
||||||
|
preferences = preferenceManager.getSharedPreferences();
|
||||||
|
preferences.registerOnSharedPreferenceChangeListener(backupListener);
|
||||||
|
|
||||||
// Load the preferences to be displayed
|
// Load the preferences to be displayed
|
||||||
addPreferencesFromResource(R.xml.preferences);
|
addPreferencesFromResource(R.xml.preferences);
|
||||||
|
|
||||||
@@ -101,28 +112,55 @@ public class MyTracksSettings extends PreferenceActivity {
|
|||||||
announcementFrequency.setSummary(
|
announcementFrequency.setSummary(
|
||||||
R.string.settings_announcement_not_available_summary);
|
R.string.settings_announcement_not_available_summary);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
// Add actions to the backup preferences
|
|
||||||
Preference backupNowPreference = findPreference(getString(R.string.backup_to_sd_key));
|
Preference backupNowPreference = findPreference(getString(R.string.backup_to_sd_key));
|
||||||
Preference restoreNowPreference = findPreference(getString(R.string.restore_from_sd_key));
|
Preference restoreNowPreference = findPreference(getString(R.string.restore_from_sd_key));
|
||||||
|
|
||||||
|
// If recording, disable backup/restore (we don't want to get to inconsistent states)
|
||||||
|
boolean recording = preferences.getLong(getString(R.string.recording_track_key), -1) != -1;
|
||||||
|
backupNowPreference.setEnabled(!recording);
|
||||||
|
restoreNowPreference.setEnabled(!recording);
|
||||||
|
backupNowPreference.setSummary(
|
||||||
|
recording ? R.string.settings_no_backup_while_recording
|
||||||
|
: R.string.settings_backup_to_sd_summary);
|
||||||
|
restoreNowPreference.setSummary(
|
||||||
|
recording ? R.string.settings_no_backup_while_recording
|
||||||
|
: R.string.settings_restore_from_sd_summary);
|
||||||
|
|
||||||
|
// Add actions to the backup preferences
|
||||||
backupNowPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
backupNowPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceClick(Preference preference) {
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
ExternalFileBackup helper = new ExternalFileBackup(MyTracksSettings.this);
|
Intent intent = new Intent(MyTracksSettings.this, BackupActivity.class);
|
||||||
helper.writeToDefaultFile();
|
intent.setAction(BackupActivity.BACKUP_ACTION);
|
||||||
|
startActivity(intent);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
restoreNowPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
restoreNowPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceClick(Preference preference) {
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
ExternalFileBackup helper = new ExternalFileBackup(MyTracksSettings.this);
|
Intent intent = new Intent(MyTracksSettings.this, BackupActivity.class);
|
||||||
helper.restoreFromFileList();
|
intent.setAction(BackupActivity.RESTORE_ACTION);
|
||||||
|
startActivity(intent);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
getPreferenceManager().getSharedPreferences()
|
||||||
|
.unregisterOnSharedPreferenceChangeListener(backupListener);
|
||||||
|
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates all the preferences which give options with distance units to use
|
* Updates all the preferences which give options with distance units to use
|
||||||
* the proper unit the user has selected.
|
* the proper unit the user has selected.
|
||||||
|
|||||||
@@ -0,0 +1,278 @@
|
|||||||
|
/*
|
||||||
|
* 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.MyTracks;
|
||||||
|
import com.google.android.apps.mytracks.util.FileUtils;
|
||||||
|
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.OnCancelListener;
|
||||||
|
import android.content.DialogInterface.OnClickListener;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activity which shows a UI for writing or restoring a backup,
|
||||||
|
* and calls the approriate handler for actually executing those
|
||||||
|
* operations.
|
||||||
|
*
|
||||||
|
* @author Rodrigo Damazio
|
||||||
|
*/
|
||||||
|
public class BackupActivity extends Activity {
|
||||||
|
|
||||||
|
// Since the user sees this format, we use the local timezone
|
||||||
|
private static final SimpleDateFormat DISPLAY_BACKUP_FORMAT =
|
||||||
|
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
private static final Comparator<Date> REVERSE_DATE_ORDER =
|
||||||
|
new Comparator<Date>() {
|
||||||
|
@Override
|
||||||
|
public int compare(Date s1, Date s2) {
|
||||||
|
return s2.compareTo(s1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final String BACKUP_ACTION = "backup";
|
||||||
|
public static final String RESTORE_ACTION = "restore";
|
||||||
|
|
||||||
|
private final FileUtils fileUtils = new FileUtils();
|
||||||
|
private final ExternalFileBackup backup = new ExternalFileBackup(this, fileUtils);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
Intent intent = getIntent();
|
||||||
|
if (intent != null) {
|
||||||
|
String action = intent.getAction();
|
||||||
|
if (action != null) {
|
||||||
|
if (action.equals(BACKUP_ACTION)) {
|
||||||
|
writeBackup();
|
||||||
|
} else if (action.equals(RESTORE_ACTION)) {
|
||||||
|
restoreBackup();
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unknown action: " + action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a full backup to the default file.
|
||||||
|
* This shows the results to the user.
|
||||||
|
*/
|
||||||
|
private void writeBackup() {
|
||||||
|
if (!fileUtils.isSdCardAvailable()) {
|
||||||
|
showToast(R.string.io_no_external_storage_found);
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!backup.isBackupsDirectoryAvailable(true)) {
|
||||||
|
showToast(R.string.io_create_dir_failed);
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ProgressDialog progressDialog = ProgressDialog.show(
|
||||||
|
this,
|
||||||
|
getString(R.string.progress_title),
|
||||||
|
getString(R.string.backup_write_progress_message),
|
||||||
|
true);
|
||||||
|
|
||||||
|
// Do the writing in another thread
|
||||||
|
new Thread() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
backup.writeToDefaultFile();
|
||||||
|
showToast(R.string.io_write_finished);
|
||||||
|
} catch (IOException e) {
|
||||||
|
showToast(R.string.io_write_failed);
|
||||||
|
return;
|
||||||
|
} finally {
|
||||||
|
dismissDialog(progressDialog);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.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.
|
||||||
|
*/
|
||||||
|
private void restoreBackup() {
|
||||||
|
// Get the list of existing backups
|
||||||
|
if (!fileUtils.isSdCardAvailable()) {
|
||||||
|
showToast(R.string.io_no_external_storage_found);
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!backup.isBackupsDirectoryAvailable(false)) {
|
||||||
|
showToast(R.string.no_backups);
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Date[] backupDates = backup.getAvailableBackups();
|
||||||
|
if (backupDates == null || backupDates.length == 0) {
|
||||||
|
showToast(R.string.no_backups);
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Arrays.sort(backupDates, REVERSE_DATE_ORDER);
|
||||||
|
|
||||||
|
// Show a confirmation dialog
|
||||||
|
Builder confirmationDialogBuilder = new AlertDialog.Builder(this);
|
||||||
|
confirmationDialogBuilder.setMessage(R.string.restore_overwrites_warning);
|
||||||
|
confirmationDialogBuilder.setCancelable(false);
|
||||||
|
confirmationDialogBuilder.setNegativeButton(android.R.string.no, new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
BackupActivity.this.finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
confirmationDialogBuilder.setPositiveButton(android.R.string.yes, new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
pickBackupForRestore(backupDates);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
confirmationDialogBuilder.create().show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a backup list for the user to pick, then restores it.
|
||||||
|
*
|
||||||
|
* @param backupDir the backup directory
|
||||||
|
* @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]);
|
||||||
|
finish();
|
||||||
|
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] = DISPLAY_BACKUP_FORMAT.format(backupDates[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show a dialog for the user to pick which backup to restore
|
||||||
|
Builder dialogBuilder = new AlertDialog.Builder(this);
|
||||||
|
dialogBuilder.setCancelable(true);
|
||||||
|
dialogBuilder.setTitle(R.string.select_backup_to_restore);
|
||||||
|
dialogBuilder.setItems(backupDateStrs, new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
// User picked to restore this one
|
||||||
|
restoreFromDateAsync(backupDates[which]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dialogBuilder.setOnCancelListener(new OnCancelListener() {
|
||||||
|
@Override
|
||||||
|
public void onCancel(DialogInterface dialog) {
|
||||||
|
BackupActivity.this.finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dialogBuilder.create().show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a progress dialog, then starts restoring the backup osynchronously.
|
||||||
|
*
|
||||||
|
* @param inputFile the file to restore from
|
||||||
|
*/
|
||||||
|
private void restoreFromDateAsync(final Date date) {
|
||||||
|
// Show a progress dialog
|
||||||
|
final ProgressDialog progressDialog = ProgressDialog.show(
|
||||||
|
this,
|
||||||
|
getString(R.string.progress_title),
|
||||||
|
getString(R.string.backup_import_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.io_read_finished);
|
||||||
|
} catch (IOException e) {
|
||||||
|
showToast(R.string.io_read_failed);
|
||||||
|
} finally {
|
||||||
|
dismissDialog(progressDialog);
|
||||||
|
|
||||||
|
// 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(this, MyTracks.class);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a toast with the given contents.
|
||||||
|
*/
|
||||||
|
private void showToast(final int resId) {
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Toast.makeText(BackupActivity.this, resId, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Safely dismisses the given dialog.
|
||||||
|
*/
|
||||||
|
private void dismissDialog(final Dialog dialog) {
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
+71
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* 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.MyTracksConstants;
|
||||||
|
|
||||||
|
import android.app.backup.BackupManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shared preferences listener which notifies the backup system about new data
|
||||||
|
* being available for backup.
|
||||||
|
* This class is API-version-safe and will provide a dummy implementation if
|
||||||
|
* the device doesn't support backup services.
|
||||||
|
*
|
||||||
|
* @author Rodrigo Damazio
|
||||||
|
*/
|
||||||
|
public abstract class BackupPreferencesListener implements OnSharedPreferenceChangeListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Real implementation of the listener, which calls the {@link BackupManager}.
|
||||||
|
*/
|
||||||
|
private static class BackupPreferencesListenerImpl extends BackupPreferencesListener {
|
||||||
|
private final BackupManager backupManager;
|
||||||
|
|
||||||
|
public BackupPreferencesListenerImpl(Context context) {
|
||||||
|
this.backupManager = new BackupManager(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
|
backupManager.dataChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dummy implementation of the listener which does nothing.
|
||||||
|
*/
|
||||||
|
private static class DummyBackupPreferencesListener extends BackupPreferencesListener {
|
||||||
|
@Override
|
||||||
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and returns a proper instance of the listener for this device.
|
||||||
|
*/
|
||||||
|
public static BackupPreferencesListener create(Context context) {
|
||||||
|
if (MyTracksConstants.ANDROID_API_LEVEL >= 8) {
|
||||||
|
return new BackupPreferencesListenerImpl(context);
|
||||||
|
} else {
|
||||||
|
return new DummyBackupPreferencesListener();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,34 +21,24 @@ import com.google.android.apps.mytracks.content.TrackPointsColumns;
|
|||||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||||
import com.google.android.apps.mytracks.content.WaypointsColumns;
|
import com.google.android.apps.mytracks.content.WaypointsColumns;
|
||||||
import com.google.android.apps.mytracks.util.FileUtils;
|
import com.google.android.apps.mytracks.util.FileUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.AlertDialog.Builder;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.DialogInterface.OnClickListener;
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.os.Handler;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.FilenameFilter;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Arrays;
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -56,7 +46,7 @@ import java.util.TimeZone;
|
|||||||
*
|
*
|
||||||
* @author Rodrigo Damazio
|
* @author Rodrigo Damazio
|
||||||
*/
|
*/
|
||||||
public class ExternalFileBackup {
|
class ExternalFileBackup {
|
||||||
// Filename format - in UTC
|
// Filename format - in UTC
|
||||||
private static final SimpleDateFormat BACKUP_FILENAME_FORMAT =
|
private static final SimpleDateFormat BACKUP_FILENAME_FORMAT =
|
||||||
new SimpleDateFormat("'backup-'yyyy-MM-dd_HH-mm-ss");
|
new SimpleDateFormat("'backup-'yyyy-MM-dd_HH-mm-ss");
|
||||||
@@ -64,232 +54,95 @@ public class ExternalFileBackup {
|
|||||||
BACKUP_FILENAME_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
|
BACKUP_FILENAME_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since the user sees this format, we use the local timezone
|
|
||||||
private static final SimpleDateFormat DISPLAY_BACKUP_FORMAT =
|
|
||||||
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
||||||
|
|
||||||
private static final String BACKUPS_SUBDIR = "backups";
|
private static final String BACKUPS_SUBDIR = "backups";
|
||||||
private static final int BACKUP_FILE_VERSION = 1;
|
private static final int BACKUP_FILE_VERSION = 1;
|
||||||
|
|
||||||
private static final Comparator<String> REVERSE_STRING_COMPARATOR =
|
|
||||||
new Comparator<String>() {
|
|
||||||
@Override
|
|
||||||
public int compare(String s1, String s2) {
|
|
||||||
return s2.compareTo(s1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final FileUtils fileUtils;
|
private final FileUtils fileUtils;
|
||||||
private final Handler uiThreadHandler = new Handler();
|
|
||||||
|
|
||||||
public ExternalFileBackup(Context context) {
|
public ExternalFileBackup(Context context, FileUtils fileUtils) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.fileUtils = new FileUtils();
|
this.fileUtils = fileUtils;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a full backup to the default file.
|
* Returns whether the backups directory is (or can be made) available.
|
||||||
* This shows the results to the user.
|
*
|
||||||
|
* @param create whether to try creating the directory if it doesn't exist
|
||||||
*/
|
*/
|
||||||
public void writeToDefaultFile() {
|
public boolean isBackupsDirectoryAvailable(boolean create) {
|
||||||
if (!fileUtils.isSdCardAvailable()) {
|
return getBackupsDirectory(create) != null;
|
||||||
showToast(R.string.io_no_external_storage_found);
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the backup directory, or null if not available.
|
||||||
|
*
|
||||||
|
* @param create whether to try creating the directory if it doesn't exist
|
||||||
|
*/
|
||||||
|
private File getBackupsDirectory(boolean create) {
|
||||||
String dirName = fileUtils.buildExternalDirectoryPath(BACKUPS_SUBDIR);
|
String dirName = fileUtils.buildExternalDirectoryPath(BACKUPS_SUBDIR);
|
||||||
final File dir = new File(dirName);
|
final File dir = new File(dirName);
|
||||||
if (!fileUtils.ensureDirectoryExists(dir)) {
|
Log.d(MyTracksConstants.TAG, "Dir: " + dir.getAbsolutePath());
|
||||||
showToast(R.string.io_create_dir_failed);
|
if (create) {
|
||||||
return;
|
// Try to create - if that fails, return null
|
||||||
|
return fileUtils.ensureDirectoryExists(dir) ? dir : null;
|
||||||
|
} else {
|
||||||
|
// Return it if it already exists, otherwise return null
|
||||||
|
return dir.isDirectory() ? dir : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ProgressDialog progressDialog = ProgressDialog.show(
|
|
||||||
context,
|
|
||||||
context.getString(R.string.progress_title),
|
|
||||||
context.getString(R.string.backup_write_progress_message),
|
|
||||||
true);
|
|
||||||
|
|
||||||
// Do the writing in another thread
|
|
||||||
new Thread() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
final String filename = BACKUP_FILENAME_FORMAT.format(new Date());
|
|
||||||
final File outputFile = new File(dir, filename);
|
|
||||||
|
|
||||||
Log.d(MyTracksConstants.TAG, "Writing backup to file " + filename);
|
|
||||||
writeToFile(outputFile);
|
|
||||||
showToast(R.string.io_write_finished);
|
|
||||||
} catch (IOException e) {
|
|
||||||
showToast(R.string.io_write_failed);
|
|
||||||
return;
|
|
||||||
} 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 restoreFromFileList() {
|
|
||||||
// Get the list of existing backups
|
|
||||||
if (!fileUtils.isSdCardAvailable()) {
|
|
||||||
showToast(R.string.io_no_external_storage_found);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String dirName = fileUtils.buildExternalDirectoryPath(BACKUPS_SUBDIR);
|
|
||||||
final File backupDir = new File(dirName);
|
|
||||||
if (!backupDir.isDirectory()) {
|
|
||||||
showToast(R.string.no_backups);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String[] backupFiles = getAvailableBackups(backupDir);
|
|
||||||
|
|
||||||
if (backupFiles == null || backupFiles.length == 0) {
|
|
||||||
showToast(R.string.no_backups);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show a confirmation dialog
|
|
||||||
Builder confirmationDialogBuilder = new AlertDialog.Builder(context);
|
|
||||||
confirmationDialogBuilder.setMessage(R.string.restore_overwrites_warning);
|
|
||||||
confirmationDialogBuilder.setCancelable(false);
|
|
||||||
confirmationDialogBuilder.setNegativeButton(android.R.string.no, null);
|
|
||||||
confirmationDialogBuilder.setPositiveButton(android.R.string.yes, new OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
restoreFromFileListConfirmed(backupDir, backupFiles);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
confirmationDialogBuilder.create().show();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows a backup list for the user to pick, then restores it.
|
|
||||||
*
|
|
||||||
* @param backupDir the backup directory
|
|
||||||
* @param backupFiles the list of available backup files
|
|
||||||
*/
|
|
||||||
private void restoreFromFileListConfirmed(final File backupDir, final String[] backupFiles) {
|
|
||||||
if (backupFiles.length == 1) {
|
|
||||||
// Only one choice, don't bother showing the list
|
|
||||||
File inputFile = new File(backupDir, backupFiles[0]);
|
|
||||||
restoreFromFileAsync(inputFile);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make a user-visible version of the backup filenames
|
|
||||||
final String backupFileDates[] = new String[backupFiles.length];
|
|
||||||
for (int i = 0; i < backupFiles.length; i++) {
|
|
||||||
try {
|
|
||||||
Date backupDate = BACKUP_FILENAME_FORMAT.parse(backupFiles[i]);
|
|
||||||
backupFileDates[i] = DISPLAY_BACKUP_FORMAT.format(backupDate);
|
|
||||||
} catch (ParseException e) {
|
|
||||||
throw new IllegalStateException("All filenames should be good here");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Arrays.sort(backupFileDates, REVERSE_STRING_COMPARATOR);
|
|
||||||
|
|
||||||
// Show a dialog for the user to pick which backup to restore
|
|
||||||
Builder dialogBuilder = new AlertDialog.Builder(context);
|
|
||||||
dialogBuilder.setCancelable(true);
|
|
||||||
dialogBuilder.setTitle(R.string.select_backup_to_restore);
|
|
||||||
dialogBuilder.setItems(backupFileDates, new OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
// User picked to restore this one
|
|
||||||
final String fileName = backupFiles[which];
|
|
||||||
final File inputFile = new File(backupDir, fileName);
|
|
||||||
|
|
||||||
restoreFromFileAsync(inputFile);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
dialogBuilder.create().show();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows a progress dialog, then starts restoring the backup osynchronously.
|
|
||||||
*
|
|
||||||
* @param inputFile the file to restore from
|
|
||||||
*/
|
|
||||||
private void restoreFromFileAsync(final File inputFile) {
|
|
||||||
// Show a progress dialog
|
|
||||||
final ProgressDialog progressDialog = ProgressDialog.show(
|
|
||||||
context,
|
|
||||||
context.getString(R.string.progress_title),
|
|
||||||
context.getString(R.string.backup_import_progress_message),
|
|
||||||
true);
|
|
||||||
|
|
||||||
// Do the actual importing in another thread (don't block the UI)
|
|
||||||
new Thread() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
Log.d(MyTracksConstants.TAG, "Restoring from file " + inputFile.getAbsolutePath());
|
|
||||||
restoreFromFile(inputFile);
|
|
||||||
showToast(R.string.io_read_finished);
|
|
||||||
} catch (IOException e) {
|
|
||||||
showToast(R.string.io_read_failed);
|
|
||||||
} finally {
|
|
||||||
dismissDialog(progressDialog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of available backups to be restored.
|
* Returns a list of available backups to be restored.
|
||||||
*/
|
*/
|
||||||
public String[] getAvailableBackups(File dir) {
|
public Date[] getAvailableBackups() {
|
||||||
return dir.list(new FilenameFilter() {
|
File dir = getBackupsDirectory(false);
|
||||||
@Override
|
if (dir == null) { return null; }
|
||||||
public boolean accept(File dir, String filename) {
|
String[] fileNames = dir.list();
|
||||||
try {
|
|
||||||
BACKUP_FILENAME_FORMAT.parse(filename);
|
List<Date> backupDates = new ArrayList<Date>(fileNames.length);
|
||||||
return true;
|
for (int i = 0; i < fileNames.length; i++) {
|
||||||
} catch (ParseException e) {
|
String fileName = fileNames[i];
|
||||||
return false;
|
try {
|
||||||
}
|
backupDates.add(BACKUP_FILENAME_FORMAT.parse(fileName));
|
||||||
|
} catch (ParseException e) {
|
||||||
|
// Not a backup file, ignore
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
return backupDates.toArray(new Date[backupDates.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows a toast with the given contents.
|
* Writes the backup to the default file.
|
||||||
*/
|
*/
|
||||||
private void showToast(final int resId) {
|
public void writeToDefaultFile() throws IOException {
|
||||||
uiThreadHandler.post(new Runnable() {
|
writeToFile(getFileForDate(new Date()));
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Toast.makeText(context, resId, Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Safely dismisses the given dialog.
|
* Restores the backup from the given date.
|
||||||
*/
|
*/
|
||||||
private void dismissDialog(final Dialog dialog) {
|
public void restoreFromDate(Date when) throws IOException {
|
||||||
uiThreadHandler.post(new Runnable() {
|
restoreFromFile(getFileForDate(when));
|
||||||
@Override
|
}
|
||||||
public void run() {
|
|
||||||
dialog.dismiss();
|
/**
|
||||||
}
|
* Produces the proper file descriptor for the given backup date.
|
||||||
});
|
*/
|
||||||
|
private File getFileForDate(Date when) {
|
||||||
|
File dir = getBackupsDirectory(false);
|
||||||
|
String fileName = BACKUP_FILENAME_FORMAT.format(when);
|
||||||
|
File file = new File(dir, fileName);
|
||||||
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Synchronously writes a backup to the given file.
|
* Synchronously writes a backup to the given file.
|
||||||
*/
|
*/
|
||||||
private void writeToFile(File outputFile) throws IOException {
|
private void writeToFile(File outputFile) throws IOException {
|
||||||
|
Log.d(MyTracksConstants.TAG, "Writing backup to file " + outputFile.getAbsolutePath());
|
||||||
|
|
||||||
// Create all the auxiliary classes that will do the writing
|
// Create all the auxiliary classes that will do the writing
|
||||||
PreferenceBackupHelper preferencesHelper = new PreferenceBackupHelper();
|
PreferenceBackupHelper preferencesHelper = new PreferenceBackupHelper();
|
||||||
DatabaseDumper trackDumper = new DatabaseDumper(
|
DatabaseDumper trackDumper = new DatabaseDumper(
|
||||||
@@ -313,11 +166,6 @@ public class ExternalFileBackup {
|
|||||||
// Output a version header
|
// Output a version header
|
||||||
outWriter.writeInt(BACKUP_FILE_VERSION);
|
outWriter.writeInt(BACKUP_FILE_VERSION);
|
||||||
|
|
||||||
// Dump preferences
|
|
||||||
SharedPreferences preferences =
|
|
||||||
context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
|
|
||||||
preferencesHelper.exportPreferences(preferences, outWriter);
|
|
||||||
|
|
||||||
// Dump the entire contents of each table
|
// Dump the entire contents of each table
|
||||||
ContentResolver contentResolver = context.getContentResolver();
|
ContentResolver contentResolver = context.getContentResolver();
|
||||||
Cursor tracksCursor = contentResolver.query(
|
Cursor tracksCursor = contentResolver.query(
|
||||||
@@ -343,6 +191,17 @@ public class ExternalFileBackup {
|
|||||||
} finally {
|
} finally {
|
||||||
pointsCursor.close();
|
pointsCursor.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dump preferences
|
||||||
|
SharedPreferences preferences =
|
||||||
|
context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
|
||||||
|
preferencesHelper.exportPreferences(preferences, outWriter);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// We tried to delete the partially created file, but do nothing
|
||||||
|
// if that also fails.
|
||||||
|
outputFile.delete();
|
||||||
|
|
||||||
|
throw e;
|
||||||
} finally {
|
} finally {
|
||||||
outputStream.flush();
|
outputStream.flush();
|
||||||
outputStream.close();
|
outputStream.close();
|
||||||
@@ -353,7 +212,7 @@ public class ExternalFileBackup {
|
|||||||
* Synchronously restores the backup from the given file.
|
* Synchronously restores the backup from the given file.
|
||||||
*/
|
*/
|
||||||
private void restoreFromFile(File inputFile) throws IOException {
|
private void restoreFromFile(File inputFile) throws IOException {
|
||||||
// TODO: At this point we should stop recording if we were
|
Log.d(MyTracksConstants.TAG, "Restoring from file " + inputFile.getAbsolutePath());
|
||||||
|
|
||||||
PreferenceBackupHelper preferencesHelper = new PreferenceBackupHelper();
|
PreferenceBackupHelper preferencesHelper = new PreferenceBackupHelper();
|
||||||
ContentResolver resolver = context.getContentResolver();
|
ContentResolver resolver = context.getContentResolver();
|
||||||
@@ -370,12 +229,7 @@ public class ExternalFileBackup {
|
|||||||
throw new IOException("Unknown backup file version " + backupVersion);
|
throw new IOException("Unknown backup file version " + backupVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore preferences
|
// Delete all previous contents of the tables and preferences.
|
||||||
SharedPreferences preferences =
|
|
||||||
context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
|
|
||||||
preferencesHelper.importPreferences(reader, preferences);
|
|
||||||
|
|
||||||
// Delete all previous contents of the tables.
|
|
||||||
resolver.delete(TracksColumns.CONTENT_URI, null, null);
|
resolver.delete(TracksColumns.CONTENT_URI, null, null);
|
||||||
resolver.delete(TrackPointsColumns.CONTENT_URI, null, null);
|
resolver.delete(TrackPointsColumns.CONTENT_URI, null, null);
|
||||||
resolver.delete(WaypointsColumns.CONTENT_URI, null, null);
|
resolver.delete(WaypointsColumns.CONTENT_URI, null, null);
|
||||||
@@ -384,6 +238,11 @@ public class ExternalFileBackup {
|
|||||||
trackImporter.importAllRows(reader);
|
trackImporter.importAllRows(reader);
|
||||||
waypointImporter.importAllRows(reader);
|
waypointImporter.importAllRows(reader);
|
||||||
pointImporter.importAllRows(reader);
|
pointImporter.importAllRows(reader);
|
||||||
|
|
||||||
|
// Restore preferences
|
||||||
|
SharedPreferences preferences =
|
||||||
|
context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
|
||||||
|
preferencesHelper.importPreferences(reader, preferences);
|
||||||
} finally {
|
} finally {
|
||||||
inputStream.close();
|
inputStream.close();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import java.io.ByteArrayOutputStream;
|
|||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user