Java tutorial
/* * Copyright 2013 2016 Ricki Hirner (bitfire web engineering). * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html */ package at.bitfire.davdroid.ui; import android.accounts.Account; import android.app.Activity; import android.app.Dialog; import android.app.ProgressDialog; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.app.DialogFragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.AsyncTaskLoader; import android.support.v4.content.Loader; import org.apache.commons.lang3.BooleanUtils; import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.io.StringWriter; import java.util.logging.Level; import at.bitfire.dav4android.DavResource; import at.bitfire.dav4android.XmlUtils; import at.bitfire.dav4android.exception.HttpException; import at.bitfire.davdroid.App; import at.bitfire.davdroid.DavUtils; import at.bitfire.davdroid.HttpClient; import at.bitfire.davdroid.InvalidAccountException; import at.bitfire.davdroid.R; import at.bitfire.davdroid.model.CollectionInfo; import at.bitfire.davdroid.model.ServiceDB; import lombok.Cleanup; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; public class CreateCollectionFragment extends DialogFragment implements LoaderManager.LoaderCallbacks<Exception> { private static final String ARG_ACCOUNT = "account", ARG_COLLECTION_INFO = "collectionInfo"; protected Account account; protected CollectionInfo info; public static CreateCollectionFragment newInstance(Account account, CollectionInfo info) { CreateCollectionFragment frag = new CreateCollectionFragment(); Bundle args = new Bundle(2); args.putParcelable(ARG_ACCOUNT, account); args.putSerializable(ARG_COLLECTION_INFO, info); frag.setArguments(args); return frag; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); account = getArguments().getParcelable(ARG_ACCOUNT); info = (CollectionInfo) getArguments().getSerializable(ARG_COLLECTION_INFO); getLoaderManager().initLoader(0, null, this); } @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { ProgressDialog progress = new ProgressDialog(getContext()); progress.setTitle(R.string.create_collection_creating); progress.setMessage(getString(R.string.please_wait)); progress.setIndeterminate(true); progress.setCanceledOnTouchOutside(false); setCancelable(false); return progress; } @Override public Loader<Exception> onCreateLoader(int id, Bundle args) { return new CreateCollectionLoader(getContext(), account, info); } @Override public void onLoadFinished(Loader<Exception> loader, Exception exception) { dismissAllowingStateLoss(); Activity parent = getActivity(); if (parent != null) { if (exception != null) getFragmentManager().beginTransaction() .add(ExceptionInfoFragment.newInstance(exception, account), null).commitAllowingStateLoss(); else parent.finish(); } } @Override public void onLoaderReset(Loader<Exception> loader) { } protected static class CreateCollectionLoader extends AsyncTaskLoader<Exception> { final Account account; final CollectionInfo info; public CreateCollectionLoader(Context context, Account account, CollectionInfo info) { super(context); this.account = account; this.info = info; } @Override protected void onStartLoading() { forceLoad(); } @Override public Exception loadInBackground() { StringWriter writer = new StringWriter(); try { XmlSerializer serializer = XmlUtils.newSerializer(); serializer.setOutput(writer); serializer.startDocument("UTF-8", null); serializer.setPrefix("", XmlUtils.NS_WEBDAV); serializer.setPrefix("CAL", XmlUtils.NS_CALDAV); serializer.setPrefix("CARD", XmlUtils.NS_CARDDAV); serializer.startTag(XmlUtils.NS_WEBDAV, "mkcol"); serializer.startTag(XmlUtils.NS_WEBDAV, "set"); serializer.startTag(XmlUtils.NS_WEBDAV, "prop"); serializer.startTag(XmlUtils.NS_WEBDAV, "resourcetype"); serializer.startTag(XmlUtils.NS_WEBDAV, "collection"); serializer.endTag(XmlUtils.NS_WEBDAV, "collection"); if (info.type == CollectionInfo.Type.ADDRESS_BOOK) { serializer.startTag(XmlUtils.NS_CARDDAV, "addressbook"); serializer.endTag(XmlUtils.NS_CARDDAV, "addressbook"); } else if (info.type == CollectionInfo.Type.CALENDAR) { serializer.startTag(XmlUtils.NS_CALDAV, "calendar"); serializer.endTag(XmlUtils.NS_CALDAV, "calendar"); } serializer.endTag(XmlUtils.NS_WEBDAV, "resourcetype"); if (info.displayName != null) { serializer.startTag(XmlUtils.NS_WEBDAV, "displayname"); serializer.text(info.displayName); serializer.endTag(XmlUtils.NS_WEBDAV, "displayname"); } // addressbook-specific properties if (info.type == CollectionInfo.Type.ADDRESS_BOOK) { if (info.description != null) { serializer.startTag(XmlUtils.NS_CARDDAV, "addressbook-description"); serializer.text(info.description); serializer.endTag(XmlUtils.NS_CARDDAV, "addressbook-description"); } } // calendar-specific properties if (info.type == CollectionInfo.Type.CALENDAR) { if (info.description != null) { serializer.startTag(XmlUtils.NS_CALDAV, "calendar-description"); serializer.text(info.description); serializer.endTag(XmlUtils.NS_CALDAV, "calendar-description"); } if (info.color != null) { serializer.startTag(XmlUtils.NS_APPLE_ICAL, "calendar-color"); serializer.text(DavUtils.ARGBtoCalDAVColor(info.color)); serializer.endTag(XmlUtils.NS_APPLE_ICAL, "calendar-color"); } if (info.timeZone != null) { serializer.startTag(XmlUtils.NS_CALDAV, "calendar-timezone"); serializer.cdsect(info.timeZone); serializer.endTag(XmlUtils.NS_CALDAV, "calendar-timezone"); } serializer.startTag(XmlUtils.NS_CALDAV, "supported-calendar-component-set"); if (BooleanUtils.isTrue(info.supportsVEVENT)) { serializer.startTag(XmlUtils.NS_CALDAV, "comp"); serializer.attribute(null, "name", "VEVENT"); serializer.endTag(XmlUtils.NS_CALDAV, "comp"); } if (BooleanUtils.isTrue(info.supportsVTODO)) { serializer.startTag(XmlUtils.NS_CALDAV, "comp"); serializer.attribute(null, "name", "VTODO"); serializer.endTag(XmlUtils.NS_CALDAV, "comp"); } serializer.endTag(XmlUtils.NS_CALDAV, "supported-calendar-component-set"); } serializer.endTag(XmlUtils.NS_WEBDAV, "prop"); serializer.endTag(XmlUtils.NS_WEBDAV, "set"); serializer.endTag(XmlUtils.NS_WEBDAV, "mkcol"); serializer.endDocument(); } catch (IOException e) { App.log.log(Level.SEVERE, "Couldn't assemble Extended MKCOL request", e); } ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(getContext()); try { OkHttpClient client = HttpClient.create(getContext(), account); DavResource collection = new DavResource(client, HttpUrl.parse(info.url)); // create collection on remote server collection.mkCol(writer.toString()); // now insert collection into database: SQLiteDatabase db = dbHelper.getWritableDatabase(); // 1. find service ID String serviceType; if (info.type == CollectionInfo.Type.ADDRESS_BOOK) serviceType = ServiceDB.Services.SERVICE_CARDDAV; else if (info.type == CollectionInfo.Type.CALENDAR) serviceType = ServiceDB.Services.SERVICE_CALDAV; else throw new IllegalArgumentException("Collection must be an address book or calendar"); @Cleanup Cursor c = db.query(ServiceDB.Services._TABLE, new String[] { ServiceDB.Services.ID }, ServiceDB.Services.ACCOUNT_NAME + "=? AND " + ServiceDB.Services.SERVICE + "=?", new String[] { account.name, serviceType }, null, null, null); if (!c.moveToNext()) throw new IllegalStateException(); long serviceID = c.getLong(0); // 2. add collection to service ContentValues values = info.toDB(); values.put(ServiceDB.Collections.SERVICE_ID, serviceID); db.insert(ServiceDB.Collections._TABLE, null, values); } catch (InvalidAccountException | IOException | HttpException | IllegalStateException e) { return e; } finally { dbHelper.close(); } return null; } } }