/*
* ____.____ __.____ ___ _____
* | | |/ _| | \ / _ \ ______ ______
* | | < | | / / /_\ \\____ \\____ \
* /\__| | | \| | / / | \ |_> > |_> >
* \________|____|__ \______/ \____|__ / __/| __/
* \/ \/|__| |__|
*
* Copyright (c) 2014-2015 Paul "Marunjar" Pretsch
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
package org.voidsink.anewjkuapp;
import android.content.ContentProviderClient;
import android.content.ContentProviderOperation;
import android.content.Context;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.RemoteException;
import android.util.Log;
import org.voidsink.anewjkuapp.analytics.Analytics;
import org.voidsink.anewjkuapp.notification.PoiNotification;
import org.voidsink.anewjkuapp.provider.KusssDatabaseHelper;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
public class ImportPoiTask implements Callable<Void> {
private static final String TAG = ImportPoiTask.class.getSimpleName();
private final Context mContext;
private final File mFile;
private final boolean mIsDefault;
public static final String[] POI_PROJECTION = new String[]{
PoiContentContract.Poi.COL_ROWID,
PoiContentContract.Poi.COL_NAME,
PoiContentContract.Poi.COL_LON,
PoiContentContract.Poi.COL_LAT,
PoiContentContract.Poi.COL_DESCR,
PoiContentContract.Poi.COL_IS_DEFAULT};
public static final int COLUMN_POI_ID = 0;
public static final int COLUMN_POI_NAME = 1;
public static final int COLUMN_POI_LON = 2;
public static final int COLUMN_POI_LAT = 3;
public static final int COLUMN_POI_DESCR = 4;
public static final int COLUMN_POI_IS_DEFAULT = 5;
public ImportPoiTask(Context context, File file, boolean isDefault) {
this.mContext = context;
this.mFile = file;
this.mIsDefault = isDefault;
}
@Override
public Void call() throws Exception {
ContentProviderClient mProvider = mContext.getContentResolver()
.acquireContentProviderClient(PoiContentContract.CONTENT_URI);
if (mProvider == null) {
return null;
}
Log.d(TAG, "start importing POIs");
PoiNotification mNotification = new PoiNotification(mContext);
try {
Map<String, Poi> poiMap = new HashMap<>();
try {
DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document gpx = builder.parse(mFile);
XPath xpath = XPathFactory.newInstance().newXPath();
XPathExpression wpt_path = xpath
.compile("//gpx/wpt[name][@lat][@lon]");
// XPathExpression wpt_address =
// xpath.compile("/*/extensions/gpxx:WaypointExtension/gpxx:Address");
NodeList wpts = (NodeList) wpt_path.evaluate(gpx,
XPathConstants.NODESET);
for (int i = 0; i < wpts.getLength(); i++) {
Element wpt = (Element) wpts.item(i);
double lat = Double.parseDouble(wpt.getAttribute("lat"));
double lon = Double.parseDouble(wpt.getAttribute("lon"));
NodeList names = wpt.getElementsByTagName("name");
if (names.getLength() == 1) {
String name = names.item(0).getTextContent();
Poi poi = new Poi(name, lat, lon);
if (!poiMap.containsKey(poi.getName())) {
Log.d(TAG, "poi found: " + poi.getName());
poiMap.put(poi.getName(), poi);
poi.parse(wpt);
}
}
}
} catch (ParserConfigurationException | SAXException | IOException
| XPathExpressionException e) {
poiMap.clear();
Log.e(TAG, "parse failed", e);
Analytics.sendException(mContext, e, true);
}
if (!poiMap.isEmpty()) {
Log.i(TAG, String.format("got %s pois", poiMap.size()));
ArrayList<ContentProviderOperation> batch = new ArrayList<>();
Uri poiUri = PoiContentContract.Poi.CONTENT_URI;
Cursor c = mProvider.query(poiUri, POI_PROJECTION, null, null,
null);
if (c != null) {
Log.d(TAG, "Found " + c.getCount()
+ " local entries. Computing merge solution...");
int poiId;
String poiName;
boolean poiIsDefault;
// TODO
while (c.moveToNext()) {
poiId = c.getInt(COLUMN_POI_ID);
poiName = c.getString(COLUMN_POI_NAME);
poiIsDefault = KusssDatabaseHelper.toBool(c
.getInt(COLUMN_POI_IS_DEFAULT));
Poi poi = poiMap.get(poiName);
if (poi != null) {
poiMap.remove(poiName);
if (mIsDefault || !poiIsDefault) {
// Check to see if the entry needs to be updated
Uri existingUri = poiUri.buildUpon()
.appendPath(Integer.toString(poiId))
.build();
Log.d(TAG, String.format("Scheduling update: %s (%s)", poiName, existingUri));
batch.add(ContentProviderOperation
.newUpdate(existingUri)
// PoiContentContract
// .asEventSyncAdapter(
// existingUri,
// mAccount.name,
// mAccount.type))
.withValue(
PoiContentContract.Poi.COL_ROWID,
Integer.toString(poiId))
.withValues(
poi.getContentValues(
poiIsDefault,
mIsDefault)).build());
// mSyncResult.stats.numUpdates++;
}
} else {
if (poiIsDefault && mIsDefault) {
// Entry doesn't exist.
Uri deleteUri = poiUri.buildUpon()
.appendPath(Integer.toString(poiId))
.build();
Log.d(TAG, String.format("Scheduling delete: %s (%s)", poiName, deleteUri));
batch.add(ContentProviderOperation.newDelete(
deleteUri)
// PoiContentContract
// .asEventSyncAdapter(
// deleteUri,
// mAccount.name,
// mAccount.type))
.build());
// mSyncResult.stats.numDeletes++;
}
}
}
c.close();
for (Poi poi : poiMap.values()) {
batch.add(ContentProviderOperation
.newInsert(poiUri)
// PoiContentContract
// .asEventSyncAdapter(poiUri,
// mAccount.name,
// mAccount.type))
.withValues(poi.getContentValues(mIsDefault))
.build());
Log.d(TAG, "Scheduling insert: " + poi.getName());
// mSyncResult.stats.numInserts++;
}
if (batch.size() > 0) {
// mSyncNotification.update("LVAs werden gespeichert");
Log.d(TAG, "Applying batch update");
mProvider.applyBatch(batch);
Log.d(TAG, "Notify resolver");
mContext.getContentResolver().notifyChange(
PoiContentContract.Poi.CONTENT_URI, null, // No
// local
// observer
false); // IMPORTANT: Do not sync to network
} else {
Log.w(TAG, "No batch operations found! Do nothing");
}
} else {
Log.w(TAG, "selection failed");
}
}
} catch (RemoteException | OperationApplicationException e) {
Analytics.sendException(mContext, e, true);
} finally {
mNotification.show();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mProvider.close();
} else {
mProvider.release();
}
return null;
}
}