Example usage for android.net Uri buildUpon

List of usage examples for android.net Uri buildUpon

Introduction

In this page you can find the example usage for android.net Uri buildUpon.

Prototype

public abstract Builder buildUpon();

Source Link

Document

Constructs a new builder, copying the attributes from this Uri.

Usage

From source file:com.dwdesign.tweetings.util.Utils.java

public static Uri buildQueryUri(final Uri uri, final boolean notify) {
    if (uri == null)
        return null;
    final Uri.Builder uribuilder = uri.buildUpon();
    uribuilder.appendQueryParameter(QUERY_PARAM_NOTIFY, String.valueOf(notify));
    return uribuilder.build();
}

From source file:com.android.mail.browse.ConversationCursor.java

private UnderlyingCursorWrapper doQuery(boolean withLimit) {
    Uri uri = qUri;
    if (withLimit) {
        uri = uri.buildUpon().appendQueryParameter(ConversationListQueryParameters.LIMIT,
                ConversationListQueryParameters.DEFAULT_LIMIT).build();
    }//from  ww w  . j a  v a  2s  .  com
    long time = System.currentTimeMillis();

    Utils.traceBeginSection("query");
    final Cursor result = mResolver.query(uri, qProjection, null, null, null);
    Utils.traceEndSection();
    if (result == null) {
        LogUtils.w(LOG_TAG, "doQuery returning null cursor, uri: " + uri);
    } else if (DEBUG) {
        time = System.currentTimeMillis() - time;
        LogUtils.i(LOG_TAG, "ConversationCursor query: %s, %dms, %d results", uri, time, result.getCount());
    }
    System.gc();

    return new UnderlyingCursorWrapper(result, mCachingEnabled);
}

From source file:edu.mit.mobile.android.locast.sync.SyncEngine.java

/**
 * @param toSync//  w  w w .  j ava  2s  .com
 * @param account
 * @param extras
 * @param provider
 * @param syncResult
 * @return true if the item was sync'd successfully. Soft errors will cause this to return
 *         false.
 * @throws RemoteException
 * @throws SyncException
 * @throws JSONException
 * @throws IOException
 * @throws NetworkProtocolException
 * @throws NoPublicPath
 * @throws OperationApplicationException
 * @throws InterruptedException
 */
public boolean sync(Uri toSync, Account account, Bundle extras, ContentProviderClient provider,
        SyncResult syncResult) throws RemoteException, SyncException, JSONException, IOException,
        NetworkProtocolException, NoPublicPath, OperationApplicationException, InterruptedException {

    String pubPath = null;

    //
    // Handle http or https uris separately. These require the
    // destination uri.
    //
    if ("http".equals(toSync.getScheme()) || "https".equals(toSync.getScheme())) {
        pubPath = toSync.toString();

        if (!extras.containsKey(EXTRA_DESTINATION_URI)) {
            throw new IllegalArgumentException("missing EXTRA_DESTINATION_URI when syncing HTTP URIs");
        }
        toSync = Uri.parse(extras.getString(EXTRA_DESTINATION_URI));
    }

    final String type = provider.getType(toSync);
    final boolean isDir = type.startsWith(CONTENT_TYPE_PREFIX_DIR);

    final boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);

    // skip any items already sync'd
    if (!manualSync && mLastUpdated.isUpdatedRecently(toSync)) {
        if (DEBUG) {
            Log.d(TAG, "not syncing " + toSync + " as it's been updated recently");
        }
        syncResult.stats.numSkippedEntries++;
        return false;
    }

    // the sync map will convert the json data to ContentValues
    final SyncMap syncMap = MediaProvider.getSyncMap(provider, toSync);

    final Uri toSyncWithoutQuerystring = toSync.buildUpon().query(null).build();

    final HashMap<String, SyncStatus> syncStatuses = new HashMap<String, SyncEngine.SyncStatus>();
    final ArrayList<ContentProviderOperation> cpo = new ArrayList<ContentProviderOperation>();
    final LinkedList<String> cpoPubUris = new LinkedList<String>();

    //
    // first things first, upload any content that needs to be
    // uploaded.
    //

    try {
        uploadUnpublished(toSync, account, provider, syncMap, syncStatuses, syncResult);

        if (Thread.interrupted()) {
            throw new InterruptedException();
        }

        // this should ensure that all items have a pubPath when we
        // query it below.

        if (pubPath == null) {
            // we should avoid calling this too much as it
            // can be expensive
            pubPath = MediaProvider.getPublicPath(mContext, toSync);
        }
    } catch (final NoPublicPath e) {
        // TODO this is a special case and this is probably not the best place to handle this.
        // Ideally, this should be done in such a way as to reduce any extra DB queries -
        // perhaps by doing a join with the parent.
        if (syncMap.isFlagSet(SyncMap.FLAG_PARENT_MUST_SYNC_FIRST)) {
            if (DEBUG) {
                Log.d(TAG, "skipping " + toSync + " whose parent hasn't been sync'd first");
            }
            syncResult.stats.numSkippedEntries++;
            return false;
        }

        // if it's an item, we can handle it.
        if (isDir) {
            throw e;
        }
    }

    if (pubPath == null) {

        // this should have been updated already by the initial
        // upload, so something must be wrong
        throw new SyncException("never got a public path for " + toSync);
    }

    if (DEBUG) {
        Log.d(TAG, "sync(toSync=" + toSync + ", account=" + account + ", extras=" + extras + ", manualSync="
                + manualSync + ",...)");
        Log.d(TAG, "pubPath: " + pubPath);
    }

    final long request_time = System.currentTimeMillis();

    HttpResponse hr = mNetworkClient.get(pubPath);

    final long response_time = System.currentTimeMillis();

    // the time compensation below allows a time-based synchronization to function even if the
    // local clock is entirely wrong. The server's time is extracted using the Date header and
    // all are compared relative to the respective clock reference. Any data that's stored on
    // the mobile should be stored relative to the local clock and the server will respect the
    // same.
    long serverTime;

    try {
        serverTime = getServerTime(hr);
    } catch (final DateParseException e) {
        Log.w(TAG, "could not retrieve date from server. Using local time, which may be incorrect.", e);
        serverTime = System.currentTimeMillis();
    }

    // TODO check out
    // http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
    final long response_delay = response_time - request_time;
    if (DEBUG) {
        Log.d(TAG, "request took " + response_delay + "ms");
    }
    final long localTime = request_time;

    // add this to the server time to get the local time
    final long localOffset = (localTime - serverTime);

    if (Math.abs(localOffset) > 30 * 60 * 1000) {
        Log.w(TAG, "local clock is off by " + localOffset + "ms");
    }

    if (Thread.interrupted()) {
        throw new InterruptedException();
    }

    final HttpEntity ent = hr.getEntity();

    String selection;
    String selectionInverse;
    String[] selectionArgs;

    if (isDir) {

        final JSONArray ja = new JSONArray(StreamUtils.inputStreamToString(ent.getContent()));
        ent.consumeContent();

        final int len = ja.length();
        selectionArgs = new String[len];

        // build the query to see which items are already in the
        // database
        final StringBuilder sb = new StringBuilder();

        sb.append("(");

        for (int i = 0; i < len; i++) {
            if (Thread.interrupted()) {
                throw new InterruptedException();
            }

            final SyncStatus syncStatus = loadItemFromJsonObject(ja.getJSONObject(i), syncMap, serverTime);

            syncStatuses.put(syncStatus.remote, syncStatus);

            selectionArgs[i] = syncStatus.remote;

            // add in a placeholder for the query
            sb.append('?');
            if (i != (len - 1)) {
                sb.append(',');
            }

        }
        sb.append(")");

        final String placeholders = sb.toString();
        selection = JsonSyncableItem._PUBLIC_URI + " IN " + placeholders;
        selectionInverse = JsonSyncableItem._PUBLIC_URI + " NOT IN " + placeholders;
    } else {

        final JSONObject jo = new JSONObject(StreamUtils.inputStreamToString(ent.getContent()));
        ent.consumeContent();
        final SyncStatus syncStatus = loadItemFromJsonObject(jo, syncMap, serverTime);

        syncStatuses.put(syncStatus.remote, syncStatus);

        selection = JsonSyncableItem._PUBLIC_URI + "=?";
        selectionInverse = JsonSyncableItem._PUBLIC_URI + "!=?";
        selectionArgs = new String[] { syncStatus.remote };
    }

    // first check without the querystring. This will ensure that we
    // properly mark things that we already have in the database.
    final Cursor check = provider.query(toSyncWithoutQuerystring, SYNC_PROJECTION, selection, selectionArgs,
            null);

    // these items are on both sides
    try {
        final int pubUriCol = check.getColumnIndex(JsonSyncableItem._PUBLIC_URI);
        final int idCol = check.getColumnIndex(JsonSyncableItem._ID);

        // All the items in this cursor should be found on both
        // the client and the server.
        for (check.moveToFirst(); !check.isAfterLast(); check.moveToNext()) {
            if (Thread.interrupted()) {
                throw new InterruptedException();
            }

            final long id = check.getLong(idCol);
            final Uri localUri = ContentUris.withAppendedId(toSync, id);

            final String pubUri = check.getString(pubUriCol);

            final SyncStatus itemStatus = syncStatuses.get(pubUri);

            itemStatus.state = SyncState.BOTH_UNKNOWN;

            itemStatus.local = localUri;

            // make the status searchable by both remote and
            // local uri
            syncStatuses.put(localUri.toString(), itemStatus);
        }
    } finally {
        check.close();
    }

    Cursor c = provider.query(toSync, SYNC_PROJECTION, selection, selectionArgs, null);

    // these items are on both sides
    try {
        final int pubUriCol = c.getColumnIndex(JsonSyncableItem._PUBLIC_URI);
        final int localModifiedCol = c.getColumnIndex(JsonSyncableItem._MODIFIED_DATE);
        final int serverModifiedCol = c.getColumnIndex(JsonSyncableItem._SERVER_MODIFIED_DATE);
        final int idCol = c.getColumnIndex(JsonSyncableItem._ID);

        // All the items in this cursor should be found on both
        // the client and the server.
        for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
            if (Thread.interrupted()) {
                throw new InterruptedException();
            }

            final long id = c.getLong(idCol);
            final Uri localUri = ContentUris.withAppendedId(toSync, id);

            final String pubUri = c.getString(pubUriCol);

            final SyncStatus itemStatus = syncStatuses.get(pubUri);

            if (itemStatus.state == SyncState.ALREADY_UP_TO_DATE
                    || itemStatus.state == SyncState.NOW_UP_TO_DATE) {
                if (DEBUG) {
                    Log.d(TAG, localUri + "(" + pubUri + ")" + " is already up to date.");
                }
                continue;
            }

            itemStatus.local = localUri;

            // make the status searchable by both remote and local uri
            syncStatuses.put(localUri.toString(), itemStatus);

            // last modified as stored in the DB, in phone time
            final long itemLocalModified = c.getLong(localModifiedCol);

            // last modified as stored in the DB, in server time
            final long itemServerModified = c.getLong(serverModifiedCol);
            final long localAge = localTime - itemLocalModified;

            final long remoteAge = serverTime - itemStatus.remoteModifiedTime;

            final long ageDifference = Math.abs(localAge - remoteAge);

            // up to date, as far remote -> local goes
            if (itemServerModified == itemStatus.remoteModifiedTime) {
                itemStatus.state = SyncState.ALREADY_UP_TO_DATE;
                if (DEBUG) {
                    Log.d(TAG, pubUri + " is up to date.");
                }

                // need to download
            } else if (localAge > remoteAge) {
                if (DEBUG) {
                    final long serverModified = itemStatus.remoteModifiedTime;

                    Log.d(TAG,
                            pubUri + " : local is " + ageDifference + "ms older ("
                                    + android.text.format.DateUtils.formatDateTime(mContext, itemLocalModified,
                                            FORMAT_ARGS_DEBUG)
                                    + ") than remote (" + android.text.format.DateUtils.formatDateTime(mContext,
                                            serverModified, FORMAT_ARGS_DEBUG)
                                    + "); updating local copy...");
                }

                itemStatus.state = SyncState.REMOTE_DIRTY;

                final ContentProviderOperation.Builder b = ContentProviderOperation.newUpdate(localUri);

                // update this so it's in the local timescale
                correctServerOffset(itemStatus.remoteCVs, JsonSyncableItem._CREATED_DATE,
                        JsonSyncableItem._CREATED_DATE, localOffset);
                correctServerOffset(itemStatus.remoteCVs, JsonSyncableItem._SERVER_MODIFIED_DATE,
                        JsonSyncableItem._MODIFIED_DATE, localOffset);

                b.withValues(itemStatus.remoteCVs);
                b.withExpectedCount(1);

                cpo.add(b.build());
                cpoPubUris.add(pubUri);

                syncResult.stats.numUpdates++;

                // need to upload
            } else if (localAge < remoteAge) {
                if (DEBUG) {
                    final long serverModified = itemStatus.remoteModifiedTime;

                    Log.d(TAG,
                            pubUri + " : local is " + ageDifference + "ms newer ("
                                    + android.text.format.DateUtils.formatDateTime(mContext, itemLocalModified,
                                            FORMAT_ARGS_DEBUG)
                                    + ") than remote (" + android.text.format.DateUtils.formatDateTime(mContext,
                                            serverModified, FORMAT_ARGS_DEBUG)
                                    + "); publishing to server...");
                }
                itemStatus.state = SyncState.LOCAL_DIRTY;

                mNetworkClient.putJson(pubPath, JsonSyncableItem.toJSON(mContext, localUri, c, syncMap));
            }

            mLastUpdated.markUpdated(localUri);

            syncResult.stats.numEntries++;
        } // end for
    } finally {

        c.close();
    }

    /*
     * Apply updates in bulk
     */
    if (cpo.size() > 0) {
        if (DEBUG) {
            Log.d(TAG, "applying " + cpo.size() + " bulk updates...");
        }

        final ContentProviderResult[] r = provider.applyBatch(cpo);
        if (DEBUG) {
            Log.d(TAG, "Done applying updates. Running postSync handler...");
        }

        for (int i = 0; i < r.length; i++) {
            final ContentProviderResult res = r[i];
            final SyncStatus ss = syncStatuses.get(cpoPubUris.get(i));
            if (ss == null) {
                Log.e(TAG, "can't get sync status for " + res.uri);
                continue;
            }
            syncMap.onPostSyncItem(mContext, account, ss.local, ss.remoteJson,
                    res.count != null ? res.count == 1 : true);

            ss.state = SyncState.NOW_UP_TO_DATE;
        }

        if (DEBUG) {
            Log.d(TAG, "done running postSync handler.");
        }

        cpo.clear();
        cpoPubUris.clear();
    }

    if (Thread.interrupted()) {
        throw new InterruptedException();
    }

    /*
     * Look through the SyncState.state values and find ones that need to be stored.
     */

    for (final Map.Entry<String, SyncStatus> entry : syncStatuses.entrySet()) {
        if (Thread.interrupted()) {
            throw new InterruptedException();
        }

        final String pubUri = entry.getKey();
        final SyncStatus status = entry.getValue();
        if (status.state == SyncState.REMOTE_ONLY) {
            if (DEBUG) {
                Log.d(TAG, pubUri + " is not yet stored locally, adding...");
            }

            // update this so it's in the local timescale
            correctServerOffset(status.remoteCVs, JsonSyncableItem._CREATED_DATE,
                    JsonSyncableItem._CREATED_DATE, localOffset);
            correctServerOffset(status.remoteCVs, JsonSyncableItem._SERVER_MODIFIED_DATE,
                    JsonSyncableItem._MODIFIED_DATE, localOffset);

            final ContentProviderOperation.Builder b = ContentProviderOperation.newInsert(toSync);
            b.withValues(status.remoteCVs);

            cpo.add(b.build());
            cpoPubUris.add(pubUri);
            syncResult.stats.numInserts++;

        }
    }

    /*
     * Execute the content provider operations in bulk.
     */
    if (cpo.size() > 0) {
        if (DEBUG) {
            Log.d(TAG, "bulk inserting " + cpo.size() + " items...");
        }
        final ContentProviderResult[] r = provider.applyBatch(cpo);
        if (DEBUG) {
            Log.d(TAG, "applyBatch completed. Processing results...");
        }

        int successful = 0;
        for (int i = 0; i < r.length; i++) {
            final ContentProviderResult res = r[i];
            if (res.uri == null) {
                syncResult.stats.numSkippedEntries++;
                Log.e(TAG, "result from content provider bulk operation returned null");
                continue;
            }
            final String pubUri = cpoPubUris.get(i);
            final SyncStatus ss = syncStatuses.get(pubUri);

            if (ss == null) {
                syncResult.stats.numSkippedEntries++;
                Log.e(TAG, "could not find sync status for " + cpoPubUris.get(i));
                continue;
            }

            ss.local = res.uri;
            if (DEBUG) {
                Log.d(TAG, "onPostSyncItem(" + res.uri + ", ...); pubUri: " + pubUri);
            }

            syncMap.onPostSyncItem(mContext, account, res.uri, ss.remoteJson,
                    res.count != null ? res.count == 1 : true);

            ss.state = SyncState.NOW_UP_TO_DATE;
            successful++;
        }
        if (DEBUG) {
            Log.d(TAG, successful + " batch inserts successfully applied.");
        }
    } else {
        if (DEBUG) {
            Log.d(TAG, "no updates to perform.");
        }
    }

    /**
     * Look through all the items that we didn't already find on the server side, but which
     * still have a public uri. They should be checked to make sure they're not deleted.
     */
    c = provider.query(toSync, SYNC_PROJECTION,
            ProviderUtils.addExtraWhere(selectionInverse, JsonSyncableItem._PUBLIC_URI + " NOT NULL"),
            selectionArgs, null);

    try {
        final int idCol = c.getColumnIndex(JsonSyncableItem._ID);
        final int pubUriCol = c.getColumnIndex(JsonSyncableItem._PUBLIC_URI);

        cpo.clear();

        for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
            final String pubUri = c.getString(pubUriCol);
            SyncStatus ss = syncStatuses.get(pubUri);

            final Uri item = isDir ? ContentUris.withAppendedId(toSyncWithoutQuerystring, c.getLong(idCol))
                    : toSync;

            if (ss == null) {
                ss = syncStatuses.get(item.toString());
            }

            if (DEBUG) {
                Log.d(TAG, item + " was not found in the main list of items on the server (" + pubPath
                        + "), but appears to be a child of " + toSync);

                if (ss != null) {
                    Log.d(TAG, "found sync status for " + item + ": " + ss);
                }
            }

            if (ss != null) {
                switch (ss.state) {
                case ALREADY_UP_TO_DATE:
                case NOW_UP_TO_DATE:
                    if (DEBUG) {
                        Log.d(TAG, item + " is already up to date. No need to see if it was deleted.");
                    }
                    continue;

                case BOTH_UNKNOWN:
                    if (DEBUG) {
                        Log.d(TAG,
                                item + " was found on both sides, but has an unknown sync status. Skipping...");
                    }
                    continue;

                default:

                    Log.w(TAG, "got an unexpected state for " + item + ": " + ss);
                }

            } else {
                ss = new SyncStatus(pubUri, SyncState.LOCAL_ONLY);
                ss.local = item;

                hr = mNetworkClient.head(pubUri);

                switch (hr.getStatusLine().getStatusCode()) {
                case 200:
                    if (DEBUG) {
                        Log.d(TAG, "HEAD " + pubUri + " returned 200");
                    }
                    ss.state = SyncState.BOTH_UNKNOWN;
                    break;

                case 404:
                    if (DEBUG) {
                        Log.d(TAG, "HEAD " + pubUri + " returned 404. Deleting locally...");
                    }
                    ss.state = SyncState.DELETED_REMOTELY;
                    final ContentProviderOperation deleteOp = ContentProviderOperation
                            .newDelete(ContentUris.withAppendedId(toSyncWithoutQuerystring, c.getLong(idCol)))
                            .build();
                    cpo.add(deleteOp);

                    break;

                default:
                    syncResult.stats.numIoExceptions++;
                    Log.w(TAG, "HEAD " + pubUri + " got unhandled result: " + hr.getStatusLine());
                }
            }
            syncStatuses.put(pubUri, ss);
        } // for cursor

        if (cpo.size() > 0) {
            final ContentProviderResult[] results = provider.applyBatch(cpo);

            for (final ContentProviderResult result : results) {
                if (result.count != 1) {
                    throw new SyncException("Error deleting item");
                }
            }
        }

    } finally {
        c.close();
    }

    syncStatuses.clear();

    mLastUpdated.markUpdated(toSync);

    return true;
}

From source file:de.vanita5.twittnuker.util.Utils.java

public static Uri appendQueryParameters(final Uri uri, final NameValuePair... params) {
    final Uri.Builder builder = uri.buildUpon();
    if (params != null) {
        for (final NameValuePair param : params) {
            builder.appendQueryParameter(param.getName(), param.getValue());
        }//from w w  w .  j av  a  2  s .  c  o  m
    }
    return builder.build();
}

From source file:edu.mit.mobile.android.locast.data.Sync.java

/**
 * Given a live cursor pointing to a data item and/or a set of contentValues loaded from the network,
 * attempt to sync.//from   ww  w.  j  a va 2  s. c  o m
 * Either c or cvNet can be null, but not both.
 * @param c A cursor pointing to the data item. Null is OK here.
 * @param jsonObject JSON object for the item as loaded from the network. null is OK here.
 * @param sync An empty JsonSyncableItem object.
 * @param publicPath TODO
 *
 * @return True if the item has been modified on either end.
 * @throws IOException
 */
private boolean syncItem(Uri toSync, Cursor c, JSONObject jsonObject, JsonSyncableItem sync,
        SyncProgressNotifier syncProgress, String publicPath) throws SyncException, IOException {
    boolean modified = false;
    boolean needToCloseCursor = false;
    boolean toSyncIsIndex = false;
    final SyncMap syncMap = sync.getSyncMap();

    Uri locUri = null;
    final Uri origToSync = toSync;
    ContentValues cvNet = null;

    final Context context = getApplicationContext();
    final ContentResolver cr = context.getContentResolver();
    if (jsonObject != null) {
        if ("http".equals(toSync.getScheme()) || "https".equals(toSync.getScheme())) {
            // we successfully loaded it from the 'net, but toSync is really for local URIs. Erase it.

            toSync = sync.getContentUri();
            if (toSync == null) {
                if (DEBUG) {
                    Log.w(TAG, "cannot get local URI for " + origToSync + ". Skipping...");
                }
                return false;
            }
        }
        try {
            cvNet = JsonSyncableItem.fromJSON(context, null, jsonObject, syncMap);
        } catch (final Exception e) {
            final SyncException se = new SyncException("Problem loading JSON object.");
            se.initCause(e);
            throw se;
        }
    }

    final String contentType = cr.getType(toSync);

    if (c != null) {
        if (contentType.startsWith(CONTENT_TYPE_PREFIX_DIR)) {
            locUri = ContentUris.withAppendedId(toSync, c.getLong(c.getColumnIndex(JsonSyncableItem._ID)))
                    .buildUpon().query(null).build();
            toSyncIsIndex = true;
        } else {
            locUri = toSync;
        }

        // skip any items already sync'd
        if (mLastUpdated.isUpdatedRecently(locUri)) {
            return false;
        }

        final int draftCol = c.getColumnIndex(TaggableItem._DRAFT);
        if (draftCol != -1 && c.getInt(draftCol) != 0) {
            if (DEBUG) {
                Log.d(TAG, locUri + " is marked a draft. Not syncing.");
            }
            return false;
        }

        syncMap.onPreSyncItem(cr, locUri, c);
    } else if (contentType.startsWith(CONTENT_TYPE_PREFIX_DIR)) {
        // strip any query strings
        toSync = toSync.buildUpon().query(null).build();
    }
    //      if (c != null){
    //         MediaProvider.dumpCursorToLog(c, sync.getFullProjection());
    //      }
    // when the PUBLIC_URI is null, that means it's only local
    final int pubUriColumn = (c != null) ? c.getColumnIndex(JsonSyncableItem._PUBLIC_URI) : -1;
    if (c != null && (c.isNull(pubUriColumn) || c.getString(pubUriColumn) == "")) {
        // new content on the local side only. Gotta publish.

        try {
            jsonObject = JsonSyncableItem.toJSON(context, locUri, c, syncMap);
            if (publicPath == null) {
                publicPath = MediaProvider.getPostPath(this, locUri);
            }
            if (DEBUG) {
                Log.d(TAG, "Posting " + locUri + " to " + publicPath);
            }

            // The response from a post to create a new item should be the newly created item,
            // which contains the public ID that we need.
            jsonObject = nc.postJson(publicPath, jsonObject);

            final ContentValues cvUpdate = JsonSyncableItem.fromJSON(context, locUri, jsonObject, syncMap);
            if (cr.update(locUri, cvUpdate, null, null) == 1) {
                // at this point, server and client should be in sync.
                mLastUpdated.markUpdated(locUri);
                if (DEBUG) {
                    Log.i(TAG, "Hooray! " + locUri + " has been posted succesfully.");
                }

            } else {
                Log.e(TAG, "update of " + locUri + " failed");
            }
            modified = true;

        } catch (final Exception e) {
            final SyncException se = new SyncException(getString(R.string.error_sync_no_post));
            se.initCause(e);
            throw se;
        }

        // only on the remote side, so pull it in.
    } else if (c == null && cvNet != null) {
        if (DEBUG) {
            Log.i(TAG, "Only on the remote side, using network-provided values.");
        }
        final String[] params = { cvNet.getAsString(JsonSyncableItem._PUBLIC_URI) };
        c = cr.query(toSync, sync.getFullProjection(), JsonSyncableItem._PUBLIC_URI + "=?", params, null);
        needToCloseCursor = true;

        if (!c.moveToFirst()) {
            locUri = cr.insert(toSync, cvNet);
            modified = true;
        } else {
            locUri = ContentUris.withAppendedId(toSync, c.getLong(c.getColumnIndex(JsonSyncableItem._ID)))
                    .buildUpon().query(null).build();
            syncMap.onPreSyncItem(cr, locUri, c);
        }
    }

    // we've now found data on both sides, so sync them.
    if (!modified && c != null) {

        publicPath = c.getString(c.getColumnIndex(JsonSyncableItem._PUBLIC_URI));

        try {

            if (cvNet == null) {
                try {
                    if (publicPath == null && toSyncIsIndex && !MediaProvider.canSync(locUri)) {

                        // At this point, we've already checked the index and it doesn't contain the item (otherwise it would be in the syncdItems).
                        // If we can't sync individual items, it's possible that the index is paged or the item has been deleted.
                        if (DEBUG) {
                            Log.w(TAG, "Asked to sync " + locUri
                                    + " but item wasn't in server index and cannot sync individual entries. Skipping and hoping it is up to date.");
                        }
                        return false;

                    } else {
                        if (mLastUpdated.isUpdatedRecently(nc.getFullUri(publicPath))) {
                            if (DEBUG) {
                                Log.d(TAG, "already sync'd! " + publicPath);
                            }
                            return false;
                        }
                        if (jsonObject == null) {
                            jsonObject = nc.getObject(publicPath);
                        }
                        cvNet = JsonSyncableItem.fromJSON(context, locUri, jsonObject, syncMap);

                    }
                } catch (final HttpResponseException hre) {
                    if (hre.getStatusCode() == HttpStatus.SC_NOT_FOUND) {
                        final SyncItemDeletedException side = new SyncItemDeletedException(locUri);
                        side.initCause(hre);
                        throw side;
                    }
                }
            }
            if (cvNet == null) {
                Log.e(TAG, "got null values from fromJSON() on item " + locUri + ": "
                        + (jsonObject != null ? jsonObject.toString() : "<< no json object >>"));
                return false;
            }
            final Date netLastModified = new Date(cvNet.getAsLong(JsonSyncableItem._MODIFIED_DATE));
            final Date locLastModified = new Date(c.getLong(c.getColumnIndex(JsonSyncableItem._MODIFIED_DATE)));

            if (netLastModified.equals(locLastModified)) {
                // same! yay! We don't need to do anything.
                if (DEBUG) {
                    Log.d("LocastSync", locUri + " doesn't need to sync.");
                }
            } else if (netLastModified.after(locLastModified)) {
                // remote is more up to date, update!
                cr.update(locUri, cvNet, null, null);
                if (DEBUG) {
                    Log.d("LocastSync", cvNet + " is newer than " + locUri);
                }
                modified = true;

            } else if (netLastModified.before(locLastModified)) {
                // local is more up to date, propagate!
                jsonObject = nc.putJson(publicPath, JsonSyncableItem.toJSON(context, locUri, c, syncMap));

                if (DEBUG) {
                    Log.d("LocastSync", cvNet + " is older than " + locUri);
                }
                modified = true;
            }
            mLastUpdated.markUpdated(nc.getFullUri(publicPath));
        } catch (final JSONException e) {
            final SyncException se = new SyncException(
                    "Item sync error for path " + publicPath + ": invalid JSON.");
            se.initCause(e);
            throw se;
        } catch (final NetworkProtocolException e) {
            final SyncException se = new SyncException(
                    "Item sync error for path " + publicPath + ": " + e.getHttpResponseMessage());
            se.initCause(e);
            throw se;
        } finally {
            if (needToCloseCursor) {
                c.close();
                needToCloseCursor = false;
            }
        }
    }

    if (needToCloseCursor) {
        c.close();
    }

    if (locUri == null) {
        throw new RuntimeException("Never got a local URI for a sync'd item.");
    }

    // two calls are made in two different contexts. Which context you use depends on the application.
    syncMap.onPostSyncItem(context, locUri, jsonObject, modified);
    sync.onPostSyncItem(context, locUri, jsonObject, modified);

    mLastUpdated.markUpdated(locUri);

    // needed for things that may have requested a sync with a different URI than what was eventually produced.
    if (origToSync != locUri) {
        mLastUpdated.markUpdated(origToSync);
        cr.notifyChange(origToSync, null);
    }

    return modified;
}

From source file:group.pals.android.lib.ui.filechooser.FragmentFiles.java

/**
 * Deletes a file.//from  ww  w  .ja v  a2s.c o m
 * 
 * @param position
 *            the position of item to be delete.
 */
private void deleteFile(final int position) {
    Cursor cursor = (Cursor) mFileAdapter.getItem(position);

    /*
     * The cursor can be changed if the list view is updated, so we take its
     * properties here.
     */
    final boolean isFile = BaseFileProviderUtils.isFile(cursor);
    final String filename = BaseFileProviderUtils.getFileName(cursor);

    if (!BaseFileProviderUtils.fileCanWrite(cursor)) {
        Dlg.toast(getActivity(),
                getString(R.string.afc_pmsg_cannot_delete_file,
                        isFile ? getString(R.string.afc_file) : getString(R.string.afc_folder), filename),
                Dlg.LENGTH_SHORT);
        return;
    }

    if (LocalFileContract.getAuthority(getActivity()).equals(mFileProviderAuthority)
            && !Utils.hasPermissions(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
        Dlg.toast(getActivity(), R.string.afc_msg_app_doesnot_have_permission_to_delete_files,
                Dlg.LENGTH_SHORT);
        return;
    }

    /*
     * The cursor can be changed if the list view is updated, so we take its
     * properties here.
     */
    final int id = cursor.getInt(cursor.getColumnIndex(BaseFile._ID));
    final Uri uri = BaseFileProviderUtils.getUri(cursor);

    mFileAdapter.markItemAsDeleted(id, true);

    Dlg.confirmYesno(getActivity(),
            getString(R.string.afc_pmsg_confirm_delete_file,
                    isFile ? getString(R.string.afc_file) : getString(R.string.afc_folder), filename),
            new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    new LoadingDialog<Void, Void, Boolean>(getActivity(),
                            getString(R.string.afc_pmsg_deleting_file,
                                    isFile ? getString(R.string.afc_file) : getString(R.string.afc_folder),
                                    filename),
                            true) {

                        final int taskId = EnvUtils.genId();

                        private void notifyFileDeleted() {
                            Dlg.toast(getActivity(),
                                    getString(R.string.afc_pmsg_file_has_been_deleted,
                                            isFile ? getString(R.string.afc_file)
                                                    : getString(R.string.afc_folder),
                                            filename),
                                    Dlg.LENGTH_SHORT);
                        }// notifyFileDeleted()

                        @Override
                        protected Boolean doInBackground(Void... params) {
                            getActivity().getContentResolver().delete(uri.buildUpon()
                                    .appendQueryParameter(BaseFile.PARAM_TASK_ID, Integer.toString(taskId))
                                    .build(), null, null);

                            return !BaseFileProviderUtils.fileExists(getActivity(), uri);
                        }// doInBackground()

                        @Override
                        protected void onCancelled() {
                            if (getCurrentLocation() != null)
                                BaseFileProviderUtils.cancelTask(getActivity(),
                                        getCurrentLocation().getAuthority(), taskId);

                            new LoadingDialog<Void, Void, Boolean>(getActivity(), false) {

                                @Override
                                protected Boolean doInBackground(Void... params) {
                                    return BaseFileProviderUtils.fileExists(getActivity(), uri);
                                }// doInBackground()

                                @Override
                                protected void onPostExecute(Boolean result) {
                                    super.onPostExecute(result);

                                    if (result) {
                                        mFileAdapter.markItemAsDeleted(id, false);
                                        Dlg.toast(getActivity(), R.string.afc_msg_cancelled, Dlg.LENGTH_SHORT);
                                    } else
                                        notifyFileDeleted();
                                }// onPostExecute()

                            }.execute();

                            super.onCancelled();
                        }// onCancelled()

                        @Override
                        protected void onPostExecute(Boolean result) {
                            super.onPostExecute(result);

                            if (result) {
                                notifyFileDeleted();
                            } else {
                                mFileAdapter.markItemAsDeleted(id, false);
                                Dlg.toast(getActivity(),
                                        getString(R.string.afc_pmsg_cannot_delete_file,
                                                isFile ? getString(R.string.afc_file)
                                                        : getString(R.string.afc_folder),
                                                filename),
                                        Dlg.LENGTH_SHORT);
                            }
                        }// onPostExecute()

                    }.execute();// LoadingDialog
                }// onClick()
            }, new DialogInterface.OnCancelListener() {

                @Override
                public void onCancel(DialogInterface dialog) {
                    mFileAdapter.markItemAsDeleted(id, false);
                }// onCancel()
            });
}

From source file:com.haibison.android.anhuu.FragmentFiles.java

/**
 * Deletes a file./* w ww.  j ava 2s .  co m*/
 * 
 * @param position
 *            the position of item to be delete.
 */
private void deleteFile(final int position) {
    Cursor cursor = (Cursor) mFileAdapter.getItem(position);

    /*
     * The cursor can be changed if the list view is updated, so we take its
     * properties here.
     */
    final boolean isFile = BaseFileProviderUtils.isFile(cursor);
    final String filename = BaseFileProviderUtils.getFileName(cursor);

    if (!BaseFileProviderUtils.fileCanWrite(cursor)) {
        Dlg.toast(getActivity(), getString(R.string.anhuu_f5be488d_pmsg_cannot_delete_file,
                isFile ? getString(R.string.anhuu_f5be488d_file) : getString(R.string.anhuu_f5be488d_folder),
                filename), Dlg.LENGTH_SHORT);
        return;
    }

    if (LocalFileContract.getAuthority(getActivity()).equals(mFileProviderAuthority)
            && !Utils.hasPermissions(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
        Dlg.toast(getActivity(), R.string.anhuu_f5be488d_msg_app_doesnot_have_permission_to_delete_files,
                Dlg.LENGTH_SHORT);
        return;
    }

    /*
     * The cursor can be changed if the list view is updated, so we take its
     * properties here.
     */
    final int id = cursor.getInt(cursor.getColumnIndex(BaseFile._ID));
    final Uri uri = BaseFileProviderUtils.getUri(cursor);

    mFileAdapter.markItemAsDeleted(id, true);

    Dlg.confirmYesno(getActivity(),
            getString(R.string.anhuu_f5be488d_pmsg_confirm_delete_file,
                    isFile ? getString(R.string.anhuu_f5be488d_file)
                            : getString(R.string.anhuu_f5be488d_folder),
                    filename),
            new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    new LoadingDialog<Void, Void, Boolean>(getActivity(),
                            getString(R.string.anhuu_f5be488d_pmsg_deleting_file,
                                    isFile ? getString(R.string.anhuu_f5be488d_file)
                                            : getString(R.string.anhuu_f5be488d_folder),
                                    filename),
                            true) {

                        final int taskId = EnvUtils.genId();

                        private void notifyFileDeleted() {
                            Dlg.toast(getActivity(),
                                    getString(R.string.anhuu_f5be488d_pmsg_file_has_been_deleted,
                                            isFile ? getString(R.string.anhuu_f5be488d_file)
                                                    : getString(R.string.anhuu_f5be488d_folder),
                                            filename),
                                    Dlg.LENGTH_SHORT);
                        }// notifyFileDeleted()

                        @Override
                        protected Boolean doInBackground(Void... params) {
                            getActivity().getContentResolver().delete(uri.buildUpon()
                                    .appendQueryParameter(BaseFile.PARAM_TASK_ID, Integer.toString(taskId))
                                    .build(), null, null);

                            return !BaseFileProviderUtils.fileExists(getActivity(), uri);
                        }// doInBackground()

                        @Override
                        protected void onCancelled() {
                            if (getCurrentLocation() != null)
                                BaseFileProviderUtils.cancelTask(getActivity(),
                                        getCurrentLocation().getAuthority(), taskId);

                            new LoadingDialog<Void, Void, Boolean>(getActivity(), false) {

                                @Override
                                protected Boolean doInBackground(Void... params) {
                                    return BaseFileProviderUtils.fileExists(getActivity(), uri);
                                }// doInBackground()

                                @Override
                                protected void onPostExecute(Boolean result) {
                                    super.onPostExecute(result);

                                    if (result) {
                                        mFileAdapter.markItemAsDeleted(id, false);
                                        Dlg.toast(getActivity(), R.string.anhuu_f5be488d_msg_cancelled,
                                                Dlg.LENGTH_SHORT);
                                    } else
                                        notifyFileDeleted();
                                }// onPostExecute()

                            }.execute();

                            super.onCancelled();
                        }// onCancelled()

                        @Override
                        protected void onPostExecute(Boolean result) {
                            super.onPostExecute(result);

                            if (result) {
                                notifyFileDeleted();
                            } else {
                                mFileAdapter.markItemAsDeleted(id, false);
                                Dlg.toast(getActivity(),
                                        getString(R.string.anhuu_f5be488d_pmsg_cannot_delete_file,
                                                isFile ? getString(R.string.anhuu_f5be488d_file)
                                                        : getString(R.string.anhuu_f5be488d_folder),
                                                filename),
                                        Dlg.LENGTH_SHORT);
                            }
                        }// onPostExecute()

                    }.execute();// LoadingDialog
                }// onClick()
            }, new DialogInterface.OnCancelListener() {

                @Override
                public void onCancel(DialogInterface dialog) {
                    mFileAdapter.markItemAsDeleted(id, false);
                }// onCancel()
            });
}

From source file:org.voidsink.anewjkuapp.update.ImportCalendarTask.java

@Override
public Void call() throws Exception {
    if (mProvider == null) {
        return null;
    }//from  w w w  . java2  s .co  m

    if ((ContextCompat.checkSelfPermission(mContext,
            Manifest.permission.WRITE_CALENDAR) != PackageManager.PERMISSION_GRANTED)
            || (ContextCompat.checkSelfPermission(mContext,
                    Manifest.permission.READ_CALENDAR) != PackageManager.PERMISSION_GRANTED)) {
        return null;
    }

    if (!CalendarUtils.getSyncCalendar(mContext, this.mCalendarName)) {
        return null;
    }

    if (mShowProgress) {
        mUpdateNotification = new SyncNotification(mContext, R.string.notification_sync_calendar);
        mUpdateNotification.show(mContext.getString(R.string.notification_sync_calendar_loading,
                CalendarUtils.getCalendarName(mContext, this.mCalendarName)));
    }
    CalendarChangedNotification mNotification = new CalendarChangedNotification(mContext,
            CalendarUtils.getCalendarName(mContext, this.mCalendarName));

    try {
        Log.d(TAG, "setup connection");

        updateNotify(mContext.getString(R.string.notification_sync_connect));

        if (KusssHandler.getInstance().isAvailable(mContext, AppUtils.getAccountAuthToken(mContext, mAccount),
                AppUtils.getAccountName(mContext, mAccount), AppUtils.getAccountPassword(mContext, mAccount))) {

            updateNotify(mContext.getString(R.string.notification_sync_calendar_loading,
                    CalendarUtils.getCalendarName(mContext, this.mCalendarName)));

            Log.d(TAG, "loading calendar");

            Calendar iCal;
            String kusssIdPrefix;
            // {{ Load calendar events from resource
            switch (this.mCalendarName) {
            case CalendarUtils.ARG_CALENDAR_EXAM:
                iCal = KusssHandler.getInstance().getExamIcal(mContext, mCalendarBuilder);
                kusssIdPrefix = "at-jku-kusss-exam-";
                break;
            case CalendarUtils.ARG_CALENDAR_COURSE:
                iCal = KusssHandler.getInstance().getLVAIcal(mContext, mCalendarBuilder);
                kusssIdPrefix = "at-jku-kusss-coursedate-";
                break;
            default: {
                Log.w(TAG, "calendar not found: " + this.mCalendarName);
                return null;
            }
            }
            if (iCal == null) {
                Log.w(TAG, "calendar not loaded: " + this.mCalendarName);
                mSyncResult.stats.numParseExceptions++;
                return null;
            }

            List<?> events = iCal.getComponents(Component.VEVENT);

            Log.d(TAG, String.format("got %d events", events.size()));

            updateNotify(mContext.getString(R.string.notification_sync_calendar_updating,
                    CalendarUtils.getCalendarName(mContext, this.mCalendarName)));

            ArrayList<ContentProviderOperation> batch = new ArrayList<>();

            // modify events: move courseId/term and lecturer to description
            String lineSeparator = System.getProperty("line.separator");
            if (lineSeparator == null)
                lineSeparator = ", ";

            Map<String, VEvent> eventsMap = new HashMap<>();
            for (Object e : events) {
                if (VEvent.class.isInstance(e)) {
                    VEvent ev = ((VEvent) e);

                    String summary = ev.getSummary().getValue().trim();
                    String description = ev.getDescription().getValue().trim();

                    Matcher courseIdTermMatcher = courseIdTermPattern.matcher(summary); // (courseId/term)
                    if (courseIdTermMatcher.find()) {
                        if (!description.isEmpty()) {
                            description += lineSeparator;
                            description += lineSeparator;
                        }
                        description += summary.substring(courseIdTermMatcher.start());
                        summary = summary.substring(0, courseIdTermMatcher.start());
                    } else {
                        Matcher lecturerMatcher = lecturerPattern.matcher(summary);
                        if (lecturerMatcher.find()) {
                            if (!description.isEmpty()) {
                                description += lineSeparator;
                                description += lineSeparator;
                            }
                            description += summary.substring(lecturerMatcher.start());
                            summary = summary.substring(0, lecturerMatcher.start());
                        }
                    }

                    summary = summary.trim().replaceAll("([\\r\\n]|\\\\n)+", ", ").trim();
                    description = description.trim();

                    ev.getProperty(Property.SUMMARY).setValue(summary);
                    ev.getProperty(Property.DESCRIPTION).setValue(description);
                }
            }

            // Build hash table of incoming entries
            for (Object e : events) {
                if (VEvent.class.isInstance(e)) {
                    VEvent ev = ((VEvent) e);

                    String uid = ev.getUid().getValue();
                    // compense DST
                    eventsMap.put(uid, ev);
                }
            }

            String calendarId = CalendarUtils.getCalIDByName(mContext, mAccount, mCalendarName, true);

            if (calendarId == null) {
                Log.w(TAG, "calendarId not found");
                return null;
            }

            String mCalendarAccountName = mAccount.name;
            String mCalendarAccountType = mAccount.type;

            try {
                Cursor c = mProvider.query(CalendarContractWrapper.Calendars.CONTENT_URI(),
                        CalendarUtils.CALENDAR_PROJECTION, null, null, null);
                if (c != null) {
                    while (c.moveToNext()) {
                        if (calendarId.equals(c.getString(CalendarUtils.COLUMN_CAL_ID))) {
                            mCalendarAccountName = c.getString(CalendarUtils.COLUMN_CAL_ACCOUNT_NAME);
                            mCalendarAccountType = c.getString(CalendarUtils.COLUMN_CAL_ACCOUNT_TYPE);
                            break;
                        }
                    }
                    c.close();
                }
            } catch (Exception e) {
                return null;
            }

            Log.d(TAG, "Fetching local entries for merge with: " + calendarId);

            Uri calUri = CalendarContractWrapper.Events.CONTENT_URI();

            Cursor c = CalendarUtils.loadEvent(mProvider, calUri, calendarId);

            if (c == null) {
                Log.w(TAG, "selection failed");
            } else {
                Log.d(TAG, String.format("Found %d local entries. Computing merge solution...", c.getCount()));

                // find stale data
                String eventId;
                String eventKusssId;
                String eventLocation;
                String eventTitle;
                String eventDescription;
                long eventDTStart;
                long eventDTEnd;
                boolean eventDirty;
                boolean eventDeleted;

                // calc date for notifiying only future changes
                // max update interval is 1 week
                long notifyFrom = new Date().getTime() - (DateUtils.DAY_IN_MILLIS * 7);

                while (c.moveToNext()) {
                    mSyncResult.stats.numEntries++;
                    eventId = c.getString(CalendarUtils.COLUMN_EVENT_ID);

                    //                        Log.d(TAG, "---------");
                    eventKusssId = null;

                    // get kusssId from extended properties
                    Cursor c2 = mProvider.query(CalendarContract.ExtendedProperties.CONTENT_URI,
                            CalendarUtils.EXTENDED_PROPERTIES_PROJECTION,
                            CalendarContract.ExtendedProperties.EVENT_ID + " = ?", new String[] { eventId },
                            null);

                    if (c2 != null) {
                        while (c2.moveToNext()) {

                            //                                    String extra = "";
                            //                                    for (int i = 0; i < c2.getColumnCount(); i++) {
                            //                                        extra = extra + i + "=" + c2.getString(i) + ";";
                            //                                    }
                            //                                    Log.d(TAG, "Extended: " + extra);

                            if (c2.getString(1).contains(CalendarUtils.EXTENDED_PROPERTY_NAME_KUSSS_ID)) {
                                eventKusssId = c2.getString(2);
                            }
                        }
                        c2.close();
                    }

                    if (TextUtils.isEmpty(eventKusssId)) {
                        eventKusssId = c.getString(CalendarUtils.COLUMN_EVENT_KUSSS_ID_LEGACY);
                    }

                    eventTitle = c.getString(CalendarUtils.COLUMN_EVENT_TITLE);
                    Log.d(TAG, "Title: " + eventTitle);

                    eventLocation = c.getString(CalendarUtils.COLUMN_EVENT_LOCATION);
                    eventDescription = c.getString(CalendarUtils.COLUMN_EVENT_DESCRIPTION);
                    eventDTStart = c.getLong(CalendarUtils.COLUMN_EVENT_DTSTART);
                    eventDTEnd = c.getLong(CalendarUtils.COLUMN_EVENT_DTEND);
                    eventDirty = "1".equals(c.getString(CalendarUtils.COLUMN_EVENT_DIRTY));
                    eventDeleted = "1".equals(c.getString(CalendarUtils.COLUMN_EVENT_DELETED));

                    if (eventKusssId != null && kusssIdPrefix != null
                            && eventKusssId.startsWith(kusssIdPrefix)) {
                        VEvent match = eventsMap.get(eventKusssId);
                        if (match != null && !eventDeleted) {
                            // Entry exists. Remove from entry
                            // map to prevent insert later
                            eventsMap.remove(eventKusssId);

                            // update only changes after notifiyFrom
                            if ((match.getStartDate().getDate().getTime() > notifyFrom
                                    || eventDTStart > notifyFrom) &&
                            // check to see if the entry needs to be updated
                                    ((match.getStartDate().getDate().getTime() != eventDTStart)
                                            || (match.getEndDate().getDate().getTime() != eventDTEnd)
                                            || (!match.getSummary().getValue().trim().equals(eventTitle.trim()))
                                            || (!match.getSummary().getValue().trim().equals(eventTitle.trim()))
                                            || (!match.getLocation().getValue().trim()
                                                    .equals(eventLocation.trim()))
                                            || (!match.getDescription().getValue().trim()
                                                    .equals(eventDescription.trim())))) {
                                Uri existingUri = calUri.buildUpon().appendPath(eventId).build();

                                // Update existing record
                                Log.d(TAG, "Scheduling update: " + existingUri + " dirty=" + eventDirty);

                                batch.add(ContentProviderOperation.newUpdate(existingUri)
                                        .withValues(getContentValuesFromEvent(match)).build());
                                mSyncResult.stats.numUpdates++;

                                mNotification.addUpdate(getEventString(mContext, match));
                            } else {
                                mSyncResult.stats.numSkippedEntries++;
                            }
                        } else {
                            if (eventDTStart > (mSyncFromNow - DateUtils.DAY_IN_MILLIS)) {
                                // Entry doesn't exist. Remove only newer events from the database.
                                Uri deleteUri = calUri.buildUpon().appendPath(eventId).build();
                                Log.d(TAG, "Scheduling delete: " + deleteUri);
                                // notify only future changes
                                if (eventDTStart > notifyFrom && !eventDeleted) {
                                    mNotification.addDelete(AppUtils.getEventString(mContext, eventDTStart,
                                            eventDTEnd, eventTitle, false));
                                }

                                batch.add(ContentProviderOperation.newDelete(deleteUri).build());
                                mSyncResult.stats.numDeletes++;
                            } else {
                                mSyncResult.stats.numSkippedEntries++;
                            }
                        }
                    } else {
                        Log.i(TAG, "Event UID not set, ignore event: uid=" + eventKusssId + " dirty="
                                + eventDirty + " title=" + eventTitle);
                    }
                }
                c.close();

                Log.d(TAG, String.format("Cursor closed, %d events left", eventsMap.size()));

                updateNotify(mContext.getString(R.string.notification_sync_calendar_adding,
                        CalendarUtils.getCalendarName(mContext, this.mCalendarName)));

                // Add new items
                for (VEvent v : eventsMap.values()) {

                    if (v.getUid().getValue().startsWith(kusssIdPrefix)) {
                        // notify only future changes
                        if (v.getStartDate().getDate().getTime() > notifyFrom) {
                            mNotification.addInsert(getEventString(mContext, v));
                        }

                        Builder builder = ContentProviderOperation
                                .newInsert(CalendarContractWrapper.Events.CONTENT_URI());

                        builder.withValue(CalendarContractWrapper.Events.CALENDAR_ID(), calendarId)
                                .withValues(getContentValuesFromEvent(v))
                                .withValue(CalendarContractWrapper.Events.EVENT_TIMEZONE(),
                                        TimeZone.getDefault().getID());

                        if (mCalendarName.equals(CalendarUtils.ARG_CALENDAR_EXAM)) {
                            builder.withValue(CalendarContractWrapper.Events.AVAILABILITY(),
                                    CalendarContractWrapper.Events.AVAILABILITY_BUSY());
                        } else {
                            builder.withValue(CalendarContractWrapper.Events.AVAILABILITY(),
                                    CalendarContractWrapper.Events.AVAILABILITY_FREE());
                        }

                        builder.withValue(CalendarContract.Events.STATUS,
                                CalendarContract.Events.STATUS_TENTATIVE);
                        builder.withValue(CalendarContract.Events.HAS_ALARM, "0");
                        builder.withValue(CalendarContract.Events.HAS_ATTENDEE_DATA, "0");
                        builder.withValue(CalendarContract.Events.HAS_EXTENDED_PROPERTIES, "1");

                        ContentProviderOperation op = builder.build();
                        Log.d(TAG, "Scheduling insert: " + v.getUid().getValue());
                        batch.add(op);

                        int eventIndex = batch.size() - 1;

                        // add kusssid as extendet property
                        batch.add(ContentProviderOperation
                                .newInsert(KusssContentContract.asEventSyncAdapter(
                                        CalendarContract.ExtendedProperties.CONTENT_URI, mAccount.name,
                                        mAccount.type))
                                .withValueBackReference(CalendarContract.ExtendedProperties.EVENT_ID,
                                        eventIndex)
                                .withValue(CalendarContract.ExtendedProperties.NAME,
                                        CalendarUtils.EXTENDED_PROPERTY_NAME_KUSSS_ID)
                                .withValue(CalendarContract.ExtendedProperties.VALUE, v.getUid().getValue())
                                .build());
                        // add location extra for google maps
                        batch.add(ContentProviderOperation
                                .newInsert(KusssContentContract.asEventSyncAdapter(
                                        CalendarContract.ExtendedProperties.CONTENT_URI, mAccount.name,
                                        mAccount.type))
                                .withValueBackReference(CalendarContract.ExtendedProperties.EVENT_ID,
                                        eventIndex)
                                .withValue(CalendarContract.ExtendedProperties.NAME,
                                        CalendarUtils.EXTENDED_PROPERTY_LOCATION_EXTRA)
                                .withValue(CalendarContract.ExtendedProperties.VALUE, getLocationExtra(v))
                                .build());

                        mSyncResult.stats.numInserts++;
                    } else {
                        mSyncResult.stats.numSkippedEntries++;
                    }
                }

                if (batch.size() > 0) {
                    updateNotify(mContext.getString(R.string.notification_sync_calendar_saving,
                            CalendarUtils.getCalendarName(mContext, this.mCalendarName)));

                    Log.d(TAG, "Applying batch update");
                    mProvider.applyBatch(batch);
                    Log.d(TAG, "Notify resolver");
                    mResolver.notifyChange(calUri.buildUpon().appendPath(calendarId).build(), // URI
                            // where
                            // data
                            // was
                            // modified
                            null, // No local observer
                            false); // IMPORTANT: Do not sync to
                    // network
                } else {
                    Log.w(TAG, "No batch operations found! Do nothing");
                }
            }
            KusssHandler.getInstance().logout(mContext);
        } else {
            mSyncResult.stats.numAuthExceptions++;
        }
    } catch (Exception e) {
        Analytics.sendException(mContext, e, true);
        Log.e(TAG, "import calendar failed", e);
    }

    if (mUpdateNotification != null) {
        mUpdateNotification.cancel();
    }
    mNotification.show();

    if (mReleaseProvider) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            mProvider.close();
        } else {
            mProvider.release();
        }
    }

    return null;
}