You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tasks/app/src/main/java/com/todoroo/astrid/backup/TasksXmlImporter.java

334 lines
10 KiB
Java

/*
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.backup;
import static org.tasks.data.Place.newPlace;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Handler;
import android.text.TextUtils;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.inject.Inject;
import org.tasks.LocalBroadcastManager;
import org.tasks.R;
import org.tasks.backup.XmlReader;
import org.tasks.data.Alarm;
import org.tasks.data.AlarmDao;
import org.tasks.data.Geofence;
import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskDao;
import org.tasks.data.LocationDao;
import org.tasks.data.Place;
import org.tasks.data.Tag;
import org.tasks.data.TagDao;
import org.tasks.data.TagData;
import org.tasks.data.TagDataDao;
import org.tasks.data.UserActivity;
import org.tasks.data.UserActivityDao;
import org.tasks.dialogs.DialogBuilder;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import timber.log.Timber;
public class TasksXmlImporter {
private static final String FORMAT2 = "2"; // $NON-NLS-1$
private static final String FORMAT3 = "3"; // $NON-NLS-1$
private final TagDataDao tagDataDao;
private final UserActivityDao userActivityDao;
private final DialogBuilder dialogBuilder;
private final TaskDao taskDao;
private final LocalBroadcastManager localBroadcastManager;
private final AlarmDao alarmDao;
private final TagDao tagDao;
private final GoogleTaskDao googleTaskDao;
private final LocationDao locationDao;
private Activity activity;
private Handler handler;
private int taskCount;
private int importCount = 0;
private int skipCount = 0;
private int errorCount = 0;
private ProgressDialog progressDialog;
private Uri input;
@Inject
public TasksXmlImporter(
TagDataDao tagDataDao,
UserActivityDao userActivityDao,
DialogBuilder dialogBuilder,
TaskDao taskDao,
LocationDao locationDao,
LocalBroadcastManager localBroadcastManager,
AlarmDao alarmDao,
TagDao tagDao,
GoogleTaskDao googleTaskDao) {
this.tagDataDao = tagDataDao;
this.userActivityDao = userActivityDao;
this.dialogBuilder = dialogBuilder;
this.taskDao = taskDao;
this.locationDao = locationDao;
this.localBroadcastManager = localBroadcastManager;
this.alarmDao = alarmDao;
this.tagDao = tagDao;
this.googleTaskDao = googleTaskDao;
}
private void setProgressMessage(final String message) {
handler.post(() -> progressDialog.setMessage(message));
}
public void importTasks(Activity activity, Uri input, ProgressDialog progressDialog) {
this.activity = activity;
this.input = input;
this.progressDialog = progressDialog;
handler = new Handler();
new Thread(
() -> {
try {
performImport();
} catch (IOException | XmlPullParserException e) {
Timber.e(e);
}
})
.start();
}
// --- importers
// =============================================================== FORMAT2
private void performImport() throws IOException, XmlPullParserException {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xpp = factory.newPullParser();
InputStream inputStream = activity.getContentResolver().openInputStream(input);
InputStreamReader reader = new InputStreamReader(inputStream);
xpp.setInput(reader);
try {
while (xpp.next() != XmlPullParser.END_DOCUMENT) {
String tag = xpp.getName();
if (xpp.getEventType() == XmlPullParser.END_TAG) {
// Ignore end tags
continue;
}
if (tag != null) {
// Process <astrid ... >
if (tag.equals(BackupConstants.ASTRID_TAG)) {
String format = xpp.getAttributeValue(null, BackupConstants.ASTRID_ATTR_FORMAT);
if (TextUtils.equals(format, FORMAT2)) {
new Format2TaskImporter(xpp);
} else if (TextUtils.equals(format, FORMAT3)) {
new Format3TaskImporter(xpp);
} else {
throw new UnsupportedOperationException(
"Did not know how to import tasks with xml format '" + format + "'");
}
}
}
}
} finally {
reader.close();
inputStream.close();
localBroadcastManager.broadcastRefresh();
handler.post(
() -> {
if (progressDialog.isShowing()) {
DialogUtilities.dismissDialog(activity, progressDialog);
showSummary();
}
});
}
}
private void showSummary() {
Resources r = activity.getResources();
dialogBuilder
.newDialog()
.setTitle(R.string.import_summary_title)
.setMessage(
activity.getString(
R.string.import_summary_message,
"",
r.getQuantityString(R.plurals.Ntasks, taskCount, taskCount),
r.getQuantityString(R.plurals.Ntasks, importCount, importCount),
r.getQuantityString(R.plurals.Ntasks, skipCount, skipCount),
r.getQuantityString(R.plurals.Ntasks, errorCount, errorCount)))
.setPositiveButton(android.R.string.ok, (dialog, id) -> dialog.dismiss())
.show();
}
// =============================================================== FORMAT3
private class Format2TaskImporter {
XmlPullParser xpp;
Task currentTask;
Format2TaskImporter() {}
Format2TaskImporter(XmlPullParser xpp) throws XmlPullParserException, IOException {
this.xpp = xpp;
while (xpp.next() != XmlPullParser.END_DOCUMENT) {
String tag = xpp.getName();
if (tag == null || xpp.getEventType() == XmlPullParser.END_TAG) {
continue;
}
try {
switch (tag) {
case BackupConstants.TASK_TAG:
parseTask();
break;
case BackupConstants.COMMENT_TAG:
parseComment();
break;
case BackupConstants.METADATA_TAG:
parseMetadata(2);
break;
}
} catch (Exception e) {
errorCount++;
Timber.e(e);
}
}
}
void parseTask() {
taskCount++;
setProgressMessage(activity.getString(R.string.import_progress_read, taskCount));
currentTask = new Task(new XmlReader(xpp));
Task existingTask = taskDao.fetch(currentTask.getUuid());
if (existingTask == null) {
taskDao.createNew(currentTask);
importCount++;
} else {
skipCount++;
}
}
/** Imports a comment from the XML we're reading. taken from EditNoteActivity.addComment() */
void parseComment() {
if (!currentTask.isSaved()) {
return;
}
UserActivity userActivity = new UserActivity(new XmlReader(xpp));
userActivityDao.createNew(userActivity);
}
void parseMetadata(int format) {
if (!currentTask.isSaved()) {
return;
}
XmlReader xml = new XmlReader(xpp);
String key = xml.readString("key");
if ("alarm".equals(key)) {
Alarm alarm = new Alarm();
alarm.setTask(currentTask.getId());
alarm.setTime(xml.readLong("value"));
alarmDao.insert(alarm);
} else if ("geofence".equals(key)) {
Place place = newPlace();
place.setName(xml.readString("value"));
place.setLatitude(xml.readDouble("value2"));
place.setLongitude(xml.readDouble("value3"));
locationDao.insert(place);
Geofence geofence = new Geofence();
geofence.setTask(currentTask.getId());
geofence.setPlace(place.getUid());
geofence.setRadius(xml.readInteger("value4"));
geofence.setArrival(true);
locationDao.insert(geofence);
} else if ("tags-tag".equals(key)) {
String name = xml.readString("value");
String tagUid = xml.readString("value2");
if (tagDao.getTagByTaskAndTagUid(currentTask.getId(), tagUid) == null) {
tagDao.insert(new Tag(currentTask.getId(), currentTask.getUuid(), name, tagUid));
}
// Construct the TagData from Metadata
// Fix for failed backup, Version before 4.6.10
if (format == 2) {
TagData tagData = tagDataDao.getByUuid(tagUid);
if (tagData == null) {
tagData = new TagData();
tagData.setRemoteId(tagUid);
tagData.setName(name);
tagDataDao.createNew(tagData);
}
}
} else if ("gtasks".equals(key)) {
GoogleTask googleTask = new GoogleTask();
googleTask.setTask(currentTask.getId());
googleTask.setRemoteId(xml.readString("value"));
googleTask.setListId(xml.readString("value2"));
googleTask.setParent(xml.readLong("value3"));
googleTask.setOrder(xml.readLong("value5"));
googleTask.setRemoteOrder(xml.readLong("value6"));
googleTask.setLastSync(xml.readLong("value7"));
googleTask.setDeleted(xml.readLong("deleted"));
googleTaskDao.insert(googleTask);
}
}
}
private class Format3TaskImporter extends Format2TaskImporter {
Format3TaskImporter(XmlPullParser xpp) throws XmlPullParserException, IOException {
this.xpp = xpp;
while (xpp.next() != XmlPullParser.END_DOCUMENT) {
String tag = xpp.getName();
if (tag == null || xpp.getEventType() == XmlPullParser.END_TAG) {
continue;
}
try {
switch (tag) {
case BackupConstants.TASK_TAG:
parseTask();
break;
case BackupConstants.METADATA_TAG:
parseMetadata(3);
break;
case BackupConstants.COMMENT_TAG:
parseComment();
break;
case BackupConstants.TAGDATA_TAG:
parseTagdata();
break;
}
} catch (Exception e) {
errorCount++;
Timber.e(e);
}
}
}
private void parseTagdata() {
TagData tagData = new TagData(new XmlReader(xpp));
if (tagDataDao.getByUuid(tagData.getRemoteId()) == null) {
tagDataDao.createNew(tagData);
}
}
}
}