Example usage for android.content ContentValues clear

List of usage examples for android.content ContentValues clear

Introduction

In this page you can find the example usage for android.content ContentValues clear.

Prototype

public void clear() 

Source Link

Document

Removes all values.

Usage

From source file:com.chen.emailcommon.utility.AttachmentUtilities.java

/**
 * Save the attachment to its final resting place (cache or sd card)
 *///from   ww  w. j a va  2  s . c o m
public static void saveAttachment(Context context, InputStream in, Attachment attachment) {
    Uri uri = ContentUris.withAppendedId(Attachment.CONTENT_URI, attachment.mId);
    ContentValues cv = new ContentValues();
    long attachmentId = attachment.mId;
    long accountId = attachment.mAccountKey;
    String contentUri = null;
    long size;
    try {
        ContentResolver resolver = context.getContentResolver();
        if (attachment.mUiDestination == UIProvider.AttachmentDestination.CACHE) {
            Uri attUri = getAttachmentUri(accountId, attachmentId);
            size = copyFile(in, resolver.openOutputStream(attUri));
            contentUri = attUri.toString();
        } else if (Utility.isExternalStorageMounted()) {
            File downloads = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
            downloads.mkdirs();
            File file = Utility.createUniqueFile(downloads, attachment.mFileName);
            size = copyFile(in, new FileOutputStream(file));
            String absolutePath = file.getAbsolutePath();

            // Although the download manager can scan media files, scanning only happens
            // after the user clicks on the item in the Downloads app. So, we run the
            // attachment through the media scanner ourselves so it gets added to
            // gallery / music immediately.
            MediaScannerConnection.scanFile(context, new String[] { absolutePath }, null, null);

            DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
            long id = dm.addCompletedDownload(attachment.mFileName, attachment.mFileName,
                    false /* do not use media scanner */, attachment.mMimeType, absolutePath, size,
                    true /* show notification */);
            contentUri = dm.getUriForDownloadedFile(id).toString();

        } else {
            LogUtils.w(Logging.LOG_TAG, "Trying to save an attachment without external storage?");
            throw new IOException();
        }

        // Update the attachment
        cv.put(AttachmentColumns.SIZE, size);
        cv.put(AttachmentColumns.CONTENT_URI, contentUri);
        cv.put(AttachmentColumns.UI_STATE, UIProvider.AttachmentState.SAVED);
    } catch (IOException e) {
        // Handle failures here...
        cv.put(AttachmentColumns.UI_STATE, UIProvider.AttachmentState.FAILED);
    }
    context.getContentResolver().update(uri, cv, null, null);

    // If this is an inline attachment, update the body
    if (contentUri != null && attachment.mContentId != null) {
        Body body = Body.restoreBodyWithMessageId(context, attachment.mMessageKey);
        if (body != null && body.mHtmlContent != null) {
            cv.clear();
            String html = body.mHtmlContent;
            String contentIdRe = "\\s+(?i)src=\"cid(?-i):\\Q" + attachment.mContentId + "\\E\"";
            String srcContentUri = " src=\"" + contentUri + "\"";
            html = html.replaceAll(contentIdRe, srcContentUri);
            cv.put(BodyColumns.HTML_CONTENT, html);
            context.getContentResolver().update(ContentUris.withAppendedId(Body.CONTENT_URI, body.mId), cv,
                    null, null);
        }
    }
}

From source file:com.spit.matrix15.CategoriesActivity.java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //initRecyclerView();
    //initFab();/*from  ww  w.j  a  v  a2  s  .c  om*/
    initToolbar();
    setupDrawerLayout();

    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction ft = fragmentManager.beginTransaction();
    ft.replace(R.id.fragment_container, new CategoriesFragment());
    ft.commit();

    if (funItems.isEmpty() || preItems.isEmpty() || litItems.isEmpty() || codingItems.isEmpty()) {
        List<Event> funEvents = Event.find(Event.class, "event_category = ?", "Fun and Games");
        for (Event event : funEvents) {
            funItems.add(new ViewModel(event.eventName,
                    "http://matrixthefest.org/app_posters/" + event.eventPoster));
        }

        List<Event> codingEvents = Event.find(Event.class, "event_category = ?", "Coding");
        for (Event event : codingEvents) {
            codingItems.add(new ViewModel(event.eventName,
                    "http://matrixthefest.org/app_posters/" + event.eventPoster));
        }
        List<Event> preEvents = Event.find(Event.class, "event_category = ?", "Pre-Fest");
        for (Event event : preEvents) {
            preItems.add(new ViewModel(event.eventName,
                    "http://matrixthefest.org/app_posters/" + event.eventPoster));
        }
        List<Event> litEvents = Event.find(Event.class, "event_category = ?", "Literary");
        for (Event event : litEvents) {
            litItems.add(new ViewModel(event.eventName,
                    "http://matrixthefest.org/app_posters/" + event.eventPoster));
        }

        if (!reminderAdded) {
            Calendar beginTime = Calendar.getInstance();
            beginTime.set(2015, 9, 9, 9, 00);
            Calendar endTime = Calendar.getInstance();
            endTime.set(2015, 9, 9, 5, 00);
            long startInMillis = beginTime.getTimeInMillis();
            long endInMillis = endTime.getTimeInMillis();
            ContentValues eventValues = new ContentValues();
            eventValues.put(CalendarContract.Events.DTSTART, startInMillis);
            eventValues.put(CalendarContract.Events.DTEND, endInMillis);
            eventValues.put(CalendarContract.Events.TITLE, "Matrix 2015");
            eventValues.put(CalendarContract.Events.DESCRIPTION,
                    "The official Techfest of Sardar Patel Institute of Technology");
            eventValues.put(CalendarContract.Events.CALENDAR_ID, calID);
            eventValues.put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().getID());
            AddReminderAsyncHandler eventAdder = new AddReminderAsyncHandler(getContentResolver());
            eventAdder.startInsert(1, null, CalendarContract.Events.CONTENT_URI, eventValues);
            Uri uri = getContentResolver().insert(CalendarContract.Events.CONTENT_URI, eventValues);
            long eventID = Long.parseLong(uri.getLastPathSegment());
            ContentValues reminderValues = new ContentValues();
            reminderValues.put(CalendarContract.Reminders.MINUTES, 60);
            reminderValues.put(CalendarContract.Reminders.EVENT_ID, eventID);
            reminderValues.put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT);
            AddReminderAsyncHandler reminderAdder = new AddReminderAsyncHandler(getContentResolver());
            reminderAdder.startInsert(2, null, CalendarContract.Reminders.CONTENT_URI, reminderValues);
            beginTime.set(2015, 9, 10, 9, 00);
            endTime.set(2015, 9, 10, 5, 00);
            startInMillis = beginTime.getTimeInMillis();
            endInMillis = endTime.getTimeInMillis();
            eventValues.clear();
            eventValues.put(CalendarContract.Events.DTSTART, startInMillis);
            eventValues.put(CalendarContract.Events.DTEND, endInMillis);
            eventValues.put(CalendarContract.Events.TITLE, "Matrix 2015");
            eventValues.put(CalendarContract.Events.DESCRIPTION,
                    "The official Techfest of Sardar Patel Institute of Technology");
            eventValues.put(CalendarContract.Events.CALENDAR_ID, calID);
            eventValues.put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().getID());
            eventAdder.startInsert(3, null, CalendarContract.Events.CONTENT_URI, eventValues);
            uri = getContentResolver().insert(CalendarContract.Events.CONTENT_URI, eventValues);
            eventID = Long.parseLong(uri.getLastPathSegment());
            reminderValues.clear();
            reminderValues.put(CalendarContract.Reminders.MINUTES, 60);
            reminderValues.put(CalendarContract.Reminders.EVENT_ID, eventID);
            reminderValues.put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT);
            reminderAdder.startInsert(4, null, CalendarContract.Reminders.CONTENT_URI, reminderValues);
            reminderAdded = true;
        }
    }
    //
    //        mTabLayout = (TabLayout) findViewById(R.id.tab_layout);
    //        mAdapter = new YourPagerAdapter(getSupportFragmentManager());
    //        mPager = (ViewPager) findViewById(R.id.view_pager);
    //        mPager.setAdapter(mAdapter);
    //        //Notice how the Tab Layout links with the Pager Adapter
    //        mTabLayout.setTabsFromPagerAdapter(mAdapter);
    //
    //        //Notice how The Tab Layout adn View Pager object are linked
    //        mTabLayout.setupWithViewPager(mPager);
    //        mPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mTabLayout));
    //
    //
    //
    //        content = findViewById(R.id.content);
    //
    //        final ImageView avatar = (ImageView) findViewById(R.id.avatar);
    //        Picasso.with(this).load(AVATAR_URL).transform(new CircleTransform()).into(avatar);
}

From source file:org.tomahawk.libtomahawk.database.DatabaseHelper.java

/**
 * Store the given {@link Playlist}//  ww  w . j  a  v a  2 s.c  o m
 *
 * @param playlist       the given {@link Playlist}
 * @param reverseEntries set to true, if the order of the entries should be reversed before
 *                       storing in the database
 */
public void storePlaylist(final Playlist playlist, final boolean reverseEntries) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (this) {
                ContentValues values = new ContentValues();
                values.put(TomahawkSQLiteHelper.PLAYLISTS_COLUMN_NAME, playlist.getName());
                values.put(TomahawkSQLiteHelper.PLAYLISTS_COLUMN_CURRENTREVISION,
                        playlist.getCurrentRevision());
                values.put(TomahawkSQLiteHelper.PLAYLISTS_COLUMN_ID, playlist.getId());
                values.put(TomahawkSQLiteHelper.PLAYLISTS_COLUMN_HATCHETID, playlist.getHatchetId());

                mDatabase.beginTransaction();
                mDatabase.insertWithOnConflict(TomahawkSQLiteHelper.TABLE_PLAYLISTS, null, values,
                        SQLiteDatabase.CONFLICT_REPLACE);
                // Delete every already associated Track entry
                mDatabase.delete(TomahawkSQLiteHelper.TABLE_TRACKS,
                        TomahawkSQLiteHelper.TRACKS_COLUMN_PLAYLISTID + " = ?",
                        new String[] { playlist.getId() });

                // Store every single Track in the database and store the relationship
                // by storing the playlists's id with it
                ArrayList<PlaylistEntry> entries = playlist.getEntries();
                for (int i = 0; i < entries.size(); i++) {
                    PlaylistEntry entry;
                    if (reverseEntries) {
                        entry = entries.get(entries.size() - 1 - i);
                    } else {
                        entry = entries.get(i);
                    }
                    values.clear();
                    values.put(TomahawkSQLiteHelper.TRACKS_COLUMN_PLAYLISTID, playlist.getId());
                    values.put(TomahawkSQLiteHelper.TRACKS_COLUMN_TRACKNAME,
                            entry.getQuery().getBasicTrack().getName());
                    values.put(TomahawkSQLiteHelper.TRACKS_COLUMN_ARTISTNAME,
                            entry.getQuery().getBasicTrack().getArtist().getName());
                    values.put(TomahawkSQLiteHelper.TRACKS_COLUMN_ALBUMNAME,
                            entry.getQuery().getBasicTrack().getAlbum().getName());
                    values.put(TomahawkSQLiteHelper.TRACKS_COLUMN_RESULTHINT,
                            entry.getQuery().getTopTrackResultKey());
                    values.put(TomahawkSQLiteHelper.TRACKS_COLUMN_PLAYLISTENTRYINDEX, i);
                    if (entry.getQuery().isFetchedViaHatchet()) {
                        values.put(TomahawkSQLiteHelper.TRACKS_COLUMN_ISFETCHEDVIAHATCHET, TRUE);
                    } else {
                        values.put(TomahawkSQLiteHelper.TRACKS_COLUMN_ISFETCHEDVIAHATCHET, FALSE);
                    }
                    values.put(TomahawkSQLiteHelper.TRACKS_COLUMN_PLAYLISTENTRYID, entry.getId());
                    mDatabase.insert(TomahawkSQLiteHelper.TABLE_TRACKS, null, values);
                }
                mDatabase.setTransactionSuccessful();
                mDatabase.endTransaction();
                sendReportResultsBroadcast(playlist.getId());
            }
        }
    }).start();
}

From source file:com.indeema.emailcommon.utility.AttachmentUtilities.java

/**
 * Save the attachment to its final resting place (cache or sd card)
 *//*w ww  .jav  a  2 s.c  om*/
public static void saveAttachment(Context context, InputStream in, Attachment attachment) {
    Uri uri = ContentUris.withAppendedId(Attachment.CONTENT_URI, attachment.mId);
    ContentValues cv = new ContentValues();
    long attachmentId = attachment.mId;
    long accountId = attachment.mAccountKey;
    String contentUri = null;
    long size;
    try {
        ContentResolver resolver = context.getContentResolver();
        if (attachment.mUiDestination == UIProvider.AttachmentDestination.CACHE) {
            Uri attUri = getAttachmentUri(accountId, attachmentId);
            size = copyFile(in, resolver.openOutputStream(attUri));
            contentUri = attUri.toString();
        } else if (Utility.isExternalStorageMounted()) {
            if (attachment.mFileName == null) {
                // TODO: This will prevent a crash but does not surface the underlying problem
                // to the user correctly.
                LogUtils.w(Logging.LOG_TAG, "Trying to save an attachment with no name: %d", attachmentId);
                throw new IOException("Can't save an attachment with no name");
            }
            File downloads = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
            downloads.mkdirs();
            File file = Utility.createUniqueFile(downloads, attachment.mFileName);
            size = copyFile(in, new FileOutputStream(file));
            String absolutePath = file.getAbsolutePath();

            // Although the download manager can scan media files, scanning only happens
            // after the user clicks on the item in the Downloads app. So, we run the
            // attachment through the media scanner ourselves so it gets added to
            // gallery / music immediately.
            MediaScannerConnection.scanFile(context, new String[] { absolutePath }, null, null);

            DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
            long id = dm.addCompletedDownload(attachment.mFileName, attachment.mFileName,
                    false /* do not use media scanner */, attachment.mMimeType, absolutePath, size,
                    true /* show notification */);
            contentUri = dm.getUriForDownloadedFile(id).toString();

        } else {
            LogUtils.w(Logging.LOG_TAG, "Trying to save an attachment without external storage?");
            throw new IOException();
        }

        // Update the attachment
        cv.put(AttachmentColumns.SIZE, size);
        cv.put(AttachmentColumns.CONTENT_URI, contentUri);
        cv.put(AttachmentColumns.UI_STATE, UIProvider.AttachmentState.SAVED);
    } catch (IOException e) {
        // Handle failures here...
        cv.put(AttachmentColumns.UI_STATE, UIProvider.AttachmentState.FAILED);
    }
    context.getContentResolver().update(uri, cv, null, null);

    // If this is an inline attachment, update the body
    if (contentUri != null && attachment.mContentId != null) {
        Body body = Body.restoreBodyWithMessageId(context, attachment.mMessageKey);
        if (body != null && body.mHtmlContent != null) {
            cv.clear();
            String html = body.mHtmlContent;
            String contentIdRe = "\\s+(?i)src=\"cid(?-i):\\Q" + attachment.mContentId + "\\E\"";
            String srcContentUri = " src=\"" + contentUri + "\"";
            html = html.replaceAll(contentIdRe, srcContentUri);
            cv.put(BodyColumns.HTML_CONTENT, html);
            context.getContentResolver().update(ContentUris.withAppendedId(Body.CONTENT_URI, body.mId), cv,
                    null, null);
        }
    }
}

From source file:com.google.samples.apps.iosched.service.SessionCalendarService.java

/**
 * Adds or removes a single session to/from the specified Google Calendar.
 *///from   www .  j  a va  2s .  com
private ArrayList<ContentProviderOperation> processSessionCalendar(final ContentResolver resolver,
        final long calendarId, final boolean isAddEvent, final Uri sessionUri, final long sessionBlockStart,
        final long sessionBlockEnd, final String sessionTitle, final String sessionRoom) {
    ArrayList<ContentProviderOperation> batch = new ArrayList<ContentProviderOperation>();

    // Unable to find the Calendar associated with the user or permissions were revoked.
    if (calendarId == INVALID_CALENDAR_ID || !permissionsAlreadyGranted()) {
        return batch;
    }

    final String calendarEventTitle = makeCalendarEventTitle(sessionTitle);

    Cursor cursor;
    ContentValues values = new ContentValues();

    // Add Calendar event.
    if (isAddEvent) {
        if (sessionBlockStart == 0L || sessionBlockEnd == 0L || sessionTitle == null) {
            LOGW(TAG, "Unable to add a Calendar event due to insufficient input parameters.");
            return batch;
        }

        // Check if the calendar event exists first.  If it does, we don't want to add a
        // duplicate one.
        //noinspection MissingPermission
        cursor = resolver.query(CalendarContract.Events.CONTENT_URI, // URI
                new String[] { CalendarContract.Events._ID }, // Projection
                CalendarContract.Events.CALENDAR_ID + "=? and " // Selection
                        + CalendarContract.Events.TITLE + "=? and " + CalendarContract.Events.DTSTART
                        + ">=? and " + CalendarContract.Events.DTEND + "<=?",
                new String[] { // Selection args
                        Long.valueOf(calendarId).toString(), calendarEventTitle,
                        Long.toString(Config.CONFERENCE_START_MILLIS),
                        Long.toString(Config.CONFERENCE_END_MILLIS) },
                null);

        long newEventId = -1;

        if (cursor != null && cursor.moveToFirst()) {
            // Calendar event already exists for this session.
            newEventId = cursor.getLong(0);
            cursor.close();

            // Data fix (workaround):
            batch.add(ContentProviderOperation.newUpdate(CalendarContract.Events.CONTENT_URI)
                    .withValue(CalendarContract.Events.EVENT_TIMEZONE, Config.CONFERENCE_TIMEZONE.getID())
                    .withSelection(CalendarContract.Events._ID + "=?",
                            new String[] { Long.valueOf(newEventId).toString() })
                    .build());
            // End data fix.

        } else {
            // Calendar event doesn't exist, create it.

            // NOTE: we can't use batch processing here because we need the result of
            // the insert.
            values.clear();
            values.put(CalendarContract.Events.DTSTART, sessionBlockStart);
            values.put(CalendarContract.Events.DTEND, sessionBlockEnd);
            values.put(CalendarContract.Events.EVENT_LOCATION, sessionRoom);
            values.put(CalendarContract.Events.TITLE, calendarEventTitle);
            values.put(CalendarContract.Events.CALENDAR_ID, calendarId);
            values.put(CalendarContract.Events.EVENT_TIMEZONE, Config.CONFERENCE_TIMEZONE.getID());
            @SuppressWarnings("MissingPermission")
            Uri eventUri = resolver.insert(CalendarContract.Events.CONTENT_URI, values);
            String eventId = eventUri.getLastPathSegment();
            if (eventId == null) {
                return batch; // Should be empty at this point
            }

            newEventId = Long.valueOf(eventId);
            // Since we're adding session reminder to system notification, we're not creating
            // Calendar event reminders.  If we were to create Calendar event reminders, this
            // is how we would do it.
            //values.put(CalendarContract.Reminders.EVENT_ID, Integer.valueOf(eventId));
            //values.put(CalendarContract.Reminders.MINUTES, 10);
            //values.put(CalendarContract.Reminders.METHOD,
            //        CalendarContract.Reminders.METHOD_ALERT); // Or default?
            //cr.insert(CalendarContract.Reminders.CONTENT_URI, values);
            //values.clear();
        }

        // Update the session in our own provider with the newly created calendar event ID.
        values.clear();
        values.put(ScheduleContract.Sessions.SESSION_CAL_EVENT_ID, newEventId);
        resolver.update(sessionUri, values, null, null);

    } else {
        // Remove Calendar event, if exists.

        // Get the event calendar id.
        cursor = resolver.query(sessionUri, new String[] { ScheduleContract.Sessions.SESSION_CAL_EVENT_ID },
                null, null, null);
        long calendarEventId = -1;
        if (cursor != null && cursor.moveToFirst()) {
            calendarEventId = cursor.getLong(0);
            cursor.close();
        }

        // Try to remove the Calendar Event based on key.  If successful, move on;
        // otherwise, remove the event based on Event title.
        int affectedRows = 0;
        if (calendarEventId != -1) {
            //noinspection MissingPermission
            affectedRows = resolver.delete(CalendarContract.Events.CONTENT_URI,
                    CalendarContract.Events._ID + "=?",
                    new String[] { Long.valueOf(calendarEventId).toString() });
        }

        if (affectedRows == 0) {
            //noinspection MissingPermission
            resolver.delete(CalendarContract.Events.CONTENT_URI,
                    String.format("%s=? and %s=? and %s=? and %s=?", CalendarContract.Events.CALENDAR_ID,
                            CalendarContract.Events.TITLE, CalendarContract.Events.DTSTART,
                            CalendarContract.Events.DTEND),
                    new String[] { Long.valueOf(calendarId).toString(), calendarEventTitle,
                            Long.valueOf(sessionBlockStart).toString(),
                            Long.valueOf(sessionBlockEnd).toString() });
        }

        // Remove the session and calendar event association.
        values.clear();
        values.put(ScheduleContract.Sessions.SESSION_CAL_EVENT_ID, (Long) null);
        resolver.update(sessionUri, values, null, null);
    }

    return batch;
}

From source file:com.android.exchange.EasAccountService.java

/**
 * Performs FolderSync/*from  w  w  w  .  j  a  v a  2  s  .  c om*/
 *
 * @throws IOException
 * @throws EasParserException
 */
public void sync() throws IOException, EasParserException {
    // Check that the account's mailboxes are consistent
    MailboxUtilities.checkMailboxConsistency(mContext, mAccount.mId);
    // Initialize exit status to success
    try {
        if (mAccount.mSyncKey == null) {
            mAccount.mSyncKey = "0";
            userLog("Account syncKey INIT to 0");
            ContentValues cv = new ContentValues();
            cv.put(AccountColumns.SYNC_KEY, mAccount.mSyncKey);
            mAccount.update(mContext, cv);
        }

        boolean firstSync = mAccount.mSyncKey.equals("0");
        if (firstSync) {
            userLog("Initial FolderSync");
        }

        // When we first start up, change all mailboxes to push.
        ContentValues cv = new ContentValues();
        cv.put(Mailbox.SYNC_INTERVAL, Mailbox.CHECK_INTERVAL_PUSH);
        if (mContentResolver.update(Mailbox.CONTENT_URI, cv, WHERE_ACCOUNT_AND_SYNC_INTERVAL_PING,
                new String[] { Long.toString(mAccount.mId) }) > 0) {
            ExchangeService.kick("change ping boxes to push");
        }

        // Determine our protocol version, if we haven't already and save it in the Account
        // Also re-check protocol version at least once a day (in case of upgrade)
        if (mAccount.mProtocolVersion == null || firstSync
                || ((System.currentTimeMillis() - mMailbox.mSyncTime) > DateUtils.DAY_IN_MILLIS)) {
            userLog("Determine EAS protocol version");
            EasResponse resp = sendHttpClientOptions();
            try {
                int code = resp.getStatus();
                userLog("OPTIONS response: ", code);
                if (code == HttpStatus.SC_OK) {
                    Header header = resp.getHeader("MS-ASProtocolCommands");
                    userLog(header.getValue());
                    header = resp.getHeader("ms-asprotocolversions");
                    try {
                        setupProtocolVersion(this, header);
                    } catch (MessagingException e) {
                        // Since we've already validated, this can't really happen
                        // But if it does, we'll rethrow this...
                        throw new IOException(e);
                    }
                    // Save the protocol version
                    cv.clear();
                    // Save the protocol version in the account; if we're using 12.0 or greater,
                    // set the flag for support of SmartForward
                    cv.put(Account.PROTOCOL_VERSION, mProtocolVersion);
                    if (mProtocolVersionDouble >= 12.0) {
                        cv.put(Account.FLAGS, mAccount.mFlags | Account.FLAGS_SUPPORTS_SMART_FORWARD
                                | Account.FLAGS_SUPPORTS_SEARCH | Account.FLAGS_SUPPORTS_GLOBAL_SEARCH);
                    }
                    mAccount.update(mContext, cv);
                    cv.clear();
                    // Save the sync time of the account mailbox to current time
                    cv.put(Mailbox.SYNC_TIME, System.currentTimeMillis());
                    mMailbox.update(mContext, cv);
                } else if (code == EAS_REDIRECT_CODE && canHandleAccountMailboxRedirect(resp)) {
                    // Cause this to re-run
                    throw new IOException("Will retry after a brief hold...");
                } else if (resp.isProvisionError()) {
                    throw new CommandStatusException(CommandStatus.NEEDS_PROVISIONING);
                } else if (resp.isAuthError()) {
                    mExitStatus = EasSyncService.EXIT_LOGIN_FAILURE;
                    return;
                } else {
                    errorLog("OPTIONS command failed; throwing IOException");
                    throw new IOException();
                }
            } finally {
                resp.close();
            }
        }

        // Change all pushable boxes to push when we start the account mailbox
        if (mAccount.mSyncInterval == Account.CHECK_INTERVAL_PUSH) {
            cv.clear();
            cv.put(Mailbox.SYNC_INTERVAL, Mailbox.CHECK_INTERVAL_PUSH);
            if (mContentResolver.update(Mailbox.CONTENT_URI, cv, WHERE_IN_ACCOUNT_AND_PUSHABLE,
                    new String[] { Long.toString(mAccount.mId) }) > 0) {
                userLog("Push account; set pushable boxes to push...");
            }
        }

        while (!isStopped()) {
            // If we're not allowed to sync (e.g. roaming policy), leave now
            if (!ExchangeService.canAutoSync(mAccount)) {
                if (ExchangeService.onSecurityHold(mAccount)) {
                    mExitStatus = EasSyncService.EXIT_SECURITY_FAILURE;
                } else {
                    // Use backoff rules, etc.
                    mExitStatus = EasSyncService.EXIT_IO_ERROR;
                }
                return;
            }
            userLog("Sending Account syncKey: ", mAccount.mSyncKey);
            Serializer s = new Serializer();
            s.start(Tags.FOLDER_FOLDER_SYNC).start(Tags.FOLDER_SYNC_KEY).text(mAccount.mSyncKey).end().end()
                    .done();
            EasResponse resp = sendHttpClientPost("FolderSync", s.toByteArray());
            try {
                if (isStopped())
                    break;
                int code = resp.getStatus();
                if (code == HttpStatus.SC_OK) {
                    if (!resp.isEmpty()) {
                        InputStream is = resp.getInputStream();
                        // Returns true if we need to sync again
                        if (new FolderSyncParser(is, new AccountSyncAdapter(this)).parse()) {
                            continue;
                        }
                    }
                } else if (resp.isProvisionError()) {
                    throw new CommandStatusException(CommandStatus.NEEDS_PROVISIONING);
                } else if (resp.isAuthError()) {
                    mExitStatus = EasSyncService.EXIT_LOGIN_FAILURE;
                    return;
                } else if (code == EAS_REDIRECT_CODE && canHandleAccountMailboxRedirect(resp)) {
                    // This will cause a retry of the FolderSync
                    continue;
                } else {
                    userLog("FolderSync response error: ", code);
                }
            } finally {
                resp.close();
            }

            // Change all push/hold boxes to push
            cv.clear();
            cv.put(Mailbox.SYNC_INTERVAL, Account.CHECK_INTERVAL_PUSH);
            if (mContentResolver.update(Mailbox.CONTENT_URI, cv, WHERE_PUSH_HOLD_NOT_ACCOUNT_MAILBOX,
                    new String[] { Long.toString(mAccount.mId) }) > 0) {
                userLog("Set push/hold boxes to push...");
            }

            // Before each run of the pingLoop, if this Account has a PolicySet, make sure it's
            // active; otherwise, clear out the key/flag.  This should cause a provisioning
            // error on the next POST, and start the security sequence over again
            String key = mAccount.mSecuritySyncKey;
            if (!TextUtils.isEmpty(key)) {
                Policy policy = Policy.restorePolicyWithId(mContext, mAccount.mPolicyKey);
                if ((policy != null) && !PolicyServiceProxy.isActive(mContext, policy)) {
                    resetSecurityPolicies();
                }
            }

            // Wait for push notifications.
            String threadName = Thread.currentThread().getName();
            try {
                runPingLoop();
            } catch (StaleFolderListException e) {
                // We break out if we get told about a stale folder list
                userLog("Ping interrupted; folder list requires sync...");
            } catch (IllegalHeartbeatException e) {
                // If we're sending an illegal heartbeat, reset either the min or the max to
                // that heartbeat
                resetHeartbeats(e.mLegalHeartbeat);
            } finally {
                Thread.currentThread().setName(threadName);
            }
        }
    } catch (CommandStatusException e) {
        // If the sync error is a provisioning failure (perhaps policies changed),
        // let's try the provisioning procedure
        // Provisioning must only be attempted for the account mailbox - trying to
        // provision any other mailbox may result in race conditions and the
        // creation of multiple policy keys.
        int status = e.mStatus;
        if (CommandStatus.isNeedsProvisioning(status)) {
            if (!tryProvision(this)) {
                // Set the appropriate failure status
                mExitStatus = EasSyncService.EXIT_SECURITY_FAILURE;
                return;
            }
        } else if (CommandStatus.isDeniedAccess(status)) {
            mExitStatus = EasSyncService.EXIT_ACCESS_DENIED;
            return;
        } else {
            userLog("Unexpected status: " + CommandStatus.toString(status));
            mExitStatus = EasSyncService.EXIT_EXCEPTION;
        }
    }
}

From source file:net.sf.diningout.content.SyncAdapter.java

/**
 * Insert new system contacts, delete orphaned app contacts, and synchronise any changes to
 * existing.//from   ww  w  .  java 2s. c om
 */
private void refreshContacts(Context context, ContentProviderClient cp) throws RemoteException {
    /* get system contacts */
    String[] proj = { Email.ADDRESS, ContactsContract.Contacts.LOOKUP_KEY, RawContacts.CONTACT_ID,
            ContactsContract.Contacts.DISPLAY_NAME };
    String sel = Email.IN_VISIBLE_GROUP + " = 1 AND " + Email.ADDRESS + " <> ?";
    String[] args = { Accounts.selected().name };
    EasyCursor sys = new EasyCursor(cr().query(Email.CONTENT_URI, proj, sel, args, Email.ADDRESS));
    /* get app contacts */
    proj = new String[] { Contacts.EMAIL, Contacts.ANDROID_LOOKUP_KEY, Contacts.ANDROID_ID, Contacts.NAME, _ID,
            Contacts.FOLLOWING, Contacts.STATUS_ID };
    sel = Contacts.EMAIL + " IS NOT NULL";
    EasyCursor app = new EasyCursor(cp.query(CONTACTS_URI, proj, sel, null, Contacts.EMAIL));
    /* compare and sync */
    ContentValues vals = new ContentValues();
    for (CursorJoiner.Result result : new CursorJoiner(sys, new String[] { Email.ADDRESS }, app,
            new String[] { Contacts.EMAIL })) {
        switch (result) {
        case LEFT: // new system contact, insert into app contacts
            String email = sys.getString(Email.ADDRESS);
            String hash = BaseEncoding.base64()
                    .encode(Hashing.sha512().hashString(email.toLowerCase(ENGLISH), UTF_8).asBytes());
            long id = Contacts.idForHash(hash); // do we have this contact and not know it?
            /* insert or update values */
            vals.put(Contacts.ANDROID_LOOKUP_KEY, sys.getString(ContactsContract.Contacts.LOOKUP_KEY));
            vals.put(Contacts.ANDROID_ID, sys.getLong(RawContacts.CONTACT_ID));
            String name = sys.getString(ContactsContract.Contacts.DISPLAY_NAME);
            vals.put(Contacts.NAME, name);
            vals.put(Contacts.NORMALISED_NAME, SQLite.normalise(name));
            vals.put(Contacts.EMAIL, email);
            if (id <= 0) {
                vals.put(Contacts.EMAIL_HASH, hash);
                vals.put(Contacts.COLOR, Contacts.defaultColor());
                id = ContentUris.parseId(cp.insert(CONTACTS_URI, vals));
            } else {
                cp.update(ContentUris.withAppendedId(CONTACTS_URI, id), vals, null, null);
            }
            if (id > 0) {
                context.startService(new Intent(context, FriendColorService.class)
                        .putExtra(FriendColorService.EXTRA_ID, id));
            }
            break;
        case RIGHT: // orphaned app contact, delete unless user is following
            if (app.getInt(Contacts.FOLLOWING) == 0 && app.getInt(Contacts.STATUS_ID) == ACTIVE.id) {
                vals.put(Contacts.STATUS_ID, DELETED.id);
                vals.put(Contacts.DIRTY, 1);
                cp.update(Uris.appendId(CONTACTS_URI, app), vals, null, null);
            }
            break;
        case BOTH: // matching contacts, update details in app if needed
            String s = sys.getString(ContactsContract.Contacts.LOOKUP_KEY);
            if (!s.equals(app.getString(Contacts.ANDROID_LOOKUP_KEY))) {
                vals.put(Contacts.ANDROID_LOOKUP_KEY, s);
            }
            long l = sys.getLong(RawContacts.CONTACT_ID);
            if (l != app.getLong(Contacts.ANDROID_ID)) {
                vals.put(Contacts.ANDROID_ID, l);
            }
            s = sys.getString(ContactsContract.Contacts.DISPLAY_NAME);
            if (!s.equals(app.getString(Contacts.NAME))) {
                vals.put(Contacts.NAME, s);
                vals.put(Contacts.NORMALISED_NAME, SQLite.normalise(s));
            }
            if (app.getInt(Contacts.STATUS_ID) == DELETED.id) {
                vals.put(Contacts.STATUS_ID, ACTIVE.id);
                vals.put(Contacts.DIRTY, 1);
            }
            if (vals.size() > 0) {
                cp.update(Uris.appendId(CONTACTS_URI, app), vals, null, null);
                context.startService(new Intent(context, FriendColorService.class)
                        .putExtra(FriendColorService.EXTRA_ID, app.getLong(_ID)));
            }
            break;
        }
        vals.clear();
    }
    sys.close();
    app.close();
}

From source file:com.android.exchange.EasSyncService.java

/**
 * Performs FolderSync/*from ww  w. j av a2  s  . c  om*/
 *
 * @throws IOException
 * @throws EasParserException
 */
public void runAccountMailbox() throws IOException, EasParserException {
    // Initialize exit status to success
    mExitStatus = EmailServiceStatus.SUCCESS;
    try {
        try {
            SyncManager.callback().syncMailboxListStatus(mAccount.mId, EmailServiceStatus.IN_PROGRESS, 0);
        } catch (RemoteException e1) {
            // Don't care if this fails
        }

        if (mAccount.mSyncKey == null) {
            mAccount.mSyncKey = "0";
            userLog("Account syncKey INIT to 0");
            ContentValues cv = new ContentValues();
            cv.put(AccountColumns.SYNC_KEY, mAccount.mSyncKey);
            mAccount.update(mContext, cv);
        }

        boolean firstSync = mAccount.mSyncKey.equals("0");
        if (firstSync) {
            userLog("Initial FolderSync");
        }

        // When we first start up, change all mailboxes to push.
        ContentValues cv = new ContentValues();
        cv.put(Mailbox.SYNC_INTERVAL, Mailbox.CHECK_INTERVAL_PUSH);
        if (mContentResolver.update(Mailbox.CONTENT_URI, cv, WHERE_ACCOUNT_AND_SYNC_INTERVAL_PING,
                new String[] { Long.toString(mAccount.mId) }) > 0) {
            SyncManager.kick("change ping boxes to push");
        }

        // Determine our protocol version, if we haven't already and save it in the Account
        // Also re-check protocol version at least once a day (in case of upgrade)
        if (mAccount.mProtocolVersion == null || ((System.currentTimeMillis() - mMailbox.mSyncTime) > DAYS)) {
            userLog("Determine EAS protocol version");
            HttpResponse resp = sendHttpClientOptions();
            int code = resp.getStatusLine().getStatusCode();
            userLog("OPTIONS response: ", code);
            if (code == HttpStatus.SC_OK) {
                Header header = resp.getFirstHeader("MS-ASProtocolCommands");
                userLog(header.getValue());
                header = resp.getFirstHeader("ms-asprotocolversions");
                try {
                    setupProtocolVersion(this, header);
                } catch (MessagingException e) {
                    // Since we've already validated, this can't really happen
                    // But if it does, we'll rethrow this...
                    throw new IOException();
                }
                // Save the protocol version
                cv.clear();
                // Save the protocol version in the account
                cv.put(Account.PROTOCOL_VERSION, mProtocolVersion);
                mAccount.update(mContext, cv);
                cv.clear();
                // Save the sync time of the account mailbox to current time
                cv.put(Mailbox.SYNC_TIME, System.currentTimeMillis());
                mMailbox.update(mContext, cv);
            } else {
                errorLog("OPTIONS command failed; throwing IOException");
                throw new IOException();
            }
        }

        // Change all pushable boxes to push when we start the account mailbox
        if (mAccount.mSyncInterval == Account.CHECK_INTERVAL_PUSH) {
            cv.clear();
            cv.put(Mailbox.SYNC_INTERVAL, Mailbox.CHECK_INTERVAL_PUSH);
            if (mContentResolver.update(Mailbox.CONTENT_URI, cv, SyncManager.WHERE_IN_ACCOUNT_AND_PUSHABLE,
                    new String[] { Long.toString(mAccount.mId) }) > 0) {
                userLog("Push account; set pushable boxes to push...");
            }
        }

        while (!mStop) {
            userLog("Sending Account syncKey: ", mAccount.mSyncKey);
            Serializer s = new Serializer();
            s.start(Tags.FOLDER_FOLDER_SYNC).start(Tags.FOLDER_SYNC_KEY).text(mAccount.mSyncKey).end().end()
                    .done();
            HttpResponse resp = sendHttpClientPost("FolderSync", s.toByteArray());
            if (mStop)
                break;
            int code = resp.getStatusLine().getStatusCode();
            if (code == HttpStatus.SC_OK) {
                HttpEntity entity = resp.getEntity();
                int len = (int) entity.getContentLength();
                if (len != 0) {
                    InputStream is = entity.getContent();
                    // Returns true if we need to sync again
                    if (new FolderSyncParser(is, new AccountSyncAdapter(mMailbox, this)).parse()) {
                        continue;
                    }
                }
            } else if (isProvisionError(code)) {
                // If the sync error is a provisioning failure (perhaps the policies changed),
                // let's try the provisioning procedure
                // Provisioning must only be attempted for the account mailbox - trying to
                // provision any other mailbox may result in race conditions and the creation
                // of multiple policy keys.
                if (!tryProvision()) {
                    // Set the appropriate failure status
                    mExitStatus = EXIT_SECURITY_FAILURE;
                    return;
                } else {
                    // If we succeeded, try again...
                    continue;
                }
            } else if (isAuthError(code)) {
                mExitStatus = EXIT_LOGIN_FAILURE;
                return;
            } else {
                userLog("FolderSync response error: ", code);
            }

            // Change all push/hold boxes to push
            cv.clear();
            cv.put(Mailbox.SYNC_INTERVAL, Account.CHECK_INTERVAL_PUSH);
            if (mContentResolver.update(Mailbox.CONTENT_URI, cv, WHERE_PUSH_HOLD_NOT_ACCOUNT_MAILBOX,
                    new String[] { Long.toString(mAccount.mId) }) > 0) {
                userLog("Set push/hold boxes to push...");
            }

            try {
                SyncManager.callback().syncMailboxListStatus(mAccount.mId, mExitStatus, 0);
            } catch (RemoteException e1) {
                // Don't care if this fails
            }

            // Before each run of the pingLoop, if this Account has a PolicySet, make sure it's
            // active; otherwise, clear out the key/flag.  This should cause a provisioning
            // error on the next POST, and start the security sequence over again
            String key = mAccount.mSecuritySyncKey;
            if (!TextUtils.isEmpty(key)) {
                PolicySet ps = new PolicySet(mAccount);
                SecurityPolicy sp = SecurityPolicy.getInstance(mContext);
                if (!sp.isActive(ps)) {
                    cv.clear();
                    cv.put(AccountColumns.SECURITY_FLAGS, 0);
                    cv.putNull(AccountColumns.SECURITY_SYNC_KEY);
                    long accountId = mAccount.mId;
                    mContentResolver.update(ContentUris.withAppendedId(Account.CONTENT_URI, accountId), cv,
                            null, null);
                    sp.policiesRequired(accountId);
                }
            }

            // Wait for push notifications.
            String threadName = Thread.currentThread().getName();
            try {
                runPingLoop();
            } catch (StaleFolderListException e) {
                // We break out if we get told about a stale folder list
                userLog("Ping interrupted; folder list requires sync...");
            } catch (IllegalHeartbeatException e) {
                // If we're sending an illegal heartbeat, reset either the min or the max to
                // that heartbeat
                resetHeartbeats(e.mLegalHeartbeat);
            } finally {
                Thread.currentThread().setName(threadName);
            }
        }
    } catch (IOException e) {
        // We catch this here to send the folder sync status callback
        // A folder sync failed callback will get sent from run()
        try {
            if (!mStop) {
                SyncManager.callback().syncMailboxListStatus(mAccount.mId, EmailServiceStatus.CONNECTION_ERROR,
                        0);
            }
        } catch (RemoteException e1) {
            // Don't care if this fails
        }
        throw e;
    }
}

From source file:org.pixmob.freemobile.netstat.SyncService.java

private void run(Intent intent, final SQLiteDatabase db) throws Exception {
    final long now = dateAtMidnight(System.currentTimeMillis());

    Log.i(TAG, "Initializing statistics before uploading");

    final LongSparseArray<DailyStat> stats = new LongSparseArray<DailyStat>(15);
    final Set<Long> uploadedStats = new HashSet<Long>(15);
    final long statTimestampStart = now - 7 * DAY_IN_MILLISECONDS;

    // Get pending uploads.
    Cursor c = db.query("daily_stat", new String[] { "stat_timestamp", "orange", "free_mobile", "sync" },
            "stat_timestamp>=? AND stat_timestamp<?",
            new String[] { String.valueOf(statTimestampStart), String.valueOf(now) }, null, null, null);
    try {/*from w  ww.j  av  a2s . c o  m*/
        while (c.moveToNext()) {
            final long d = c.getLong(0);
            final int sync = c.getInt(3);
            if (SYNC_UPLOADED == sync) {
                uploadedStats.add(d);
            } else if (SYNC_PENDING == sync) {
                final DailyStat s = new DailyStat();
                s.orange = c.getInt(1);
                s.freeMobile = c.getInt(2);
                stats.put(d, s);
            }
        }
    } finally {
        c.close();
    }

    // Compute missing uploads.
    final ContentValues cv = new ContentValues();
    db.beginTransaction();
    try {
        for (long d = statTimestampStart; d < now; d += DAY_IN_MILLISECONDS) {
            if (stats.get(d) == null && !uploadedStats.contains(d)) {
                final DailyStat s = computeDailyStat(d);
                cv.put("stat_timestamp", d);
                cv.put("orange", s.orange);
                cv.put("free_mobile", s.freeMobile);
                cv.put("sync", SYNC_PENDING);
                db.insertOrThrow("daily_stat", null, cv);
                stats.put(d, s);
            }
        }
        db.setTransactionSuccessful();
    } finally {
        db.endTransaction();
    }

    // Delete old statistics.
    if (DEBUG) {
        Log.d(TAG, "Cleaning up upload database");
    }
    db.delete("daily_stat", "stat_timestamp<?", new String[] { String.valueOf(statTimestampStart) });

    // Check if there are any statistics to upload.
    final int statsLen = stats.size();
    if (statsLen == 0) {
        Log.i(TAG, "Nothing to upload");
        return;
    }

    // Check if the remote server is up.
    final HttpClient client = createHttpClient();
    try {
        client.head(createServerUrl(null)).execute();
    } catch (HttpClientException e) {
        Log.w(TAG, "Remote server is not available: cannot upload statistics", e);
        return;
    }

    // Upload statistics.
    Log.i(TAG, "Uploading statistics");
    final JSONObject json = new JSONObject();
    final String deviceId = getDeviceId();
    final boolean deviceWasRegistered = intent.getBooleanExtra(EXTRA_DEVICE_REG, false);
    for (int i = 0; i < statsLen; ++i) {
        final long d = stats.keyAt(i);
        final DailyStat s = stats.get(d);

        try {
            json.put("timeOnOrange", s.orange);
            json.put("timeOnFreeMobile", s.freeMobile);
        } catch (JSONException e) {
            final IOException ioe = new IOException("Failed to prepare statistics upload");
            ioe.initCause(e);
            throw ioe;
        }

        final String url = createServerUrl(
                "/device/" + deviceId + "/daily/" + DateFormat.format("yyyyMMdd", d));
        if (DEBUG) {
            Log.d(TAG, "Uploading statistics for " + DateUtils.formatDate(d) + " to: " + url);
        }

        final byte[] rawJson = json.toString().getBytes("UTF-8");
        try {
            client.post(url).content(rawJson, "application/json")
                    .expect(HttpURLConnection.HTTP_OK, HttpURLConnection.HTTP_NOT_FOUND)
                    .to(new HttpResponseHandler() {
                        @Override
                        public void onResponse(HttpResponse response) throws Exception {
                            final int sc = response.getStatusCode();
                            if (HttpURLConnection.HTTP_NOT_FOUND == sc) {
                                // Check if the device has just been
                                // registered.
                                if (deviceWasRegistered) {
                                    throw new IOException("Failed to upload statistics");
                                } else {
                                    // Got 404: the device does not exist.
                                    // We need to register this device.
                                    registerDevice(deviceId);

                                    // Restart this service.
                                    startService(new Intent(getApplicationContext(), SyncService.class)
                                            .putExtra(EXTRA_DEVICE_REG, true));
                                }
                            } else if (HttpURLConnection.HTTP_OK == sc) {
                                // Update upload database.
                                cv.clear();
                                cv.put("sync", SYNC_UPLOADED);
                                db.update("daily_stat", cv, "stat_timestamp=?",
                                        new String[] { String.valueOf(d) });

                                if (DEBUG) {
                                    Log.d(TAG, "Upload done for " + DateUtils.formatDate(d));
                                }
                            }
                        }
                    }).execute();
        } catch (HttpClientException e) {
            final IOException ioe = new IOException("Failed to send request with statistics");
            ioe.initCause(e);
            throw ioe;
        }
    }
}

From source file:org.pixmob.droidlink.sync.SyncAdapter.java

private void doPerformSync(NetworkClient client, SharedPreferences prefs, ContentProviderClient provider,
        SyncResult syncResult, boolean fullSync) {
    // Prepare the query.
    final String selection = DEVICE_ID + "=? AND " + STATE + "=? OR " + STATE + "=?";
    final String[] selectionArgs = { client.getDeviceId(), String.valueOf(EventsContract.PENDING_UPLOAD_STATE),
            String.valueOf(EventsContract.PENDING_DELETE_STATE) };

    // Get local data to sync.
    final Map<String, JSONObject> eventsToUpload = new HashMap<String, JSONObject>(8);
    final Set<String> eventsToDelete = new HashSet<String>(4);
    Cursor c = null;//ww  w.  j  a v  a  2s .c om
    try {
        c = provider.query(EventsContract.CONTENT_URI, PROJECTION, selection, selectionArgs, null);

        final int idIdx = c.getColumnIndexOrThrow(_ID);
        final int typeIdx = c.getColumnIndexOrThrow(TYPE);
        final int createdIdx = c.getColumnIndexOrThrow(CREATED);
        final int numberIdx = c.getColumnIndexOrThrow(NUMBER);
        final int nameIdx = c.getColumnIndexOrThrow(NAME);
        final int messageIdx = c.getColumnIndexOrThrow(MESSAGE);
        final int stateIdx = c.getColumnIndexOrThrow(STATE);

        while (c.moveToNext()) {
            final String eventId = c.getString(idIdx);
            final int eventState = c.getInt(stateIdx);

            if (EventsContract.PENDING_UPLOAD_STATE == eventState) {
                // This is a newly created event.
                final JSONObject event = new JSONObject();
                try {
                    event.put("deviceId", client.getDeviceId());
                    event.put("created", c.getLong(createdIdx));
                    event.put("type", c.getInt(typeIdx));
                    event.put("number", c.getString(numberIdx));
                    event.put("name", c.getString(nameIdx));
                    event.put("message", c.getString(messageIdx));
                } catch (JSONException e) {
                    Log.w(TAG, "Invalid event " + eventId + ": cannot sync", e);
                    syncResult.stats.numSkippedEntries++;
                    continue;
                }
                eventsToUpload.put(eventId, event);
            } else if (EventsContract.PENDING_DELETE_STATE == eventState) {
                // The user wants this event to be deleted.
                eventsToDelete.add(eventId);
            }
        }
    } catch (RemoteException e) {
        Log.e(TAG, "Failed to get events: cannot sync", e);
        syncResult.stats.numIoExceptions++;
    } finally {
        if (c != null) {
            c.close();
            c = null;
        }
    }

    final ArrayList<ContentProviderOperation> batch = new ArrayList<ContentProviderOperation>(32);
    final ContentValues values = new ContentValues(8);

    if (eventsToDelete.isEmpty()) {
        Log.i(TAG, "No events to delete");
    } else {
        Log.i(TAG, "Found " + eventsToDelete.size() + " event(s) to delete");
    }

    // Delete events on the remote server.
    for (final String eventId : eventsToDelete) {
        if (DEVELOPER_MODE) {
            Log.d(TAG, "Deleting event: " + eventId);
        }

        try {
            client.delete("/events/" + eventId);

            if (DEVELOPER_MODE) {
                Log.d(TAG, "Deleting event in local database: " + eventId);
            }
            batch.add(ContentProviderOperation
                    .newDelete(Uri.withAppendedPath(EventsContract.CONTENT_URI, eventId)).build());
            syncResult.stats.numDeletes++;
        } catch (IOException e) {
            Log.e(TAG, "Event deletion error: cannot sync", e);
            syncResult.stats.numIoExceptions++;
            return;
        } catch (AppEngineAuthenticationException e) {
            Log.e(TAG, "Authentication error: cannot sync", e);
            syncResult.stats.numAuthExceptions++;
            return;
        }
    }

    try {
        provider.applyBatch(batch);
    } catch (Exception e) {
        Log.w(TAG, "Database error: cannot sync", e);
        syncResult.stats.numIoExceptions++;
        return;
    }
    batch.clear();

    if (fullSync) {
        // Get all events from the remote server.
        final JSONArray events;
        if (DEVELOPER_MODE) {
            Log.d(TAG, "Fetching events from the remote server");
        }
        try {
            events = client.getAsArray("/events");
        } catch (IOException e) {
            Log.e(TAG, "Event listing error: cannot sync", e);
            syncResult.stats.numIoExceptions++;
            return;
        } catch (AppEngineAuthenticationException e) {
            Log.e(TAG, "Authentication error: cannot sync", e);
            syncResult.stats.numAuthExceptions++;
            return;
        }

        final int eventsLen = events != null ? events.length() : 0;
        if (eventsLen == 0) {
            Log.i(TAG, "No events from the remote server");
        } else {
            Log.i(TAG, "Found " + eventsLen + " event(s) from the remote server");
        }

        // Build a collection with local event identifiers.
        // This collection will be used to identify which events have
        // been deleted on the remote server.
        final Set<String> localEventIds;
        try {
            c = provider.query(EventsContract.CONTENT_URI, PROJECTION_ID, STATE + "=?",
                    new String[] { String.valueOf(EventsContract.UPLOADED_STATE) }, null);
            localEventIds = new HashSet<String>(c.getCount());

            final int idIdx = c.getColumnIndexOrThrow(_ID);
            while (c.moveToNext()) {
                final String eventId = c.getString(idIdx);
                localEventIds.add(eventId);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to get events from local database", e);
            syncResult.stats.numIoExceptions++;
            return;
        } finally {
            if (c != null) {
                c.close();
                c = null;
            }
        }

        String newEventId = null;
        int newEventCount = 0;

        // Reconcile remote events with local events.
        for (int i = 0; i < eventsLen; ++i) {
            String eventId = null;
            try {
                final JSONObject event = events.getJSONObject(i);
                eventId = event.getString("id");

                // Check if this event exists in the local database.
                if (localEventIds.contains(eventId)) {
                    // Found the event: update it.
                    values.clear();
                    values.put(NUMBER, trimToNull(event.getString("number")));
                    values.put(NAME, trimToNull(event.getString("name")));
                    values.put(MESSAGE, trimToNull(event.getString("message")));

                    if (DEVELOPER_MODE) {
                        Log.d(TAG, "Updating event in local database: " + eventId);
                    }
                    batch.add(ContentProviderOperation
                            .newUpdate(Uri.withAppendedPath(EventsContract.CONTENT_URI, eventId))
                            .withExpectedCount(1).withValues(values).build());
                    syncResult.stats.numUpdates++;
                } else {
                    // The event was not found: insert it.
                    values.clear();
                    values.put(_ID, eventId);
                    values.put(DEVICE_ID, event.getString("deviceId"));
                    values.put(CREATED, event.getLong("created"));
                    values.put(TYPE, event.getInt("type"));
                    values.put(NUMBER, trimToNull(event.getString("number")));
                    values.put(NAME, trimToNull(event.getString("name")));
                    values.put(MESSAGE, trimToNull(event.getString("message")));
                    values.put(STATE, EventsContract.UPLOADED_STATE);

                    if (DEVELOPER_MODE) {
                        Log.d(TAG, "Adding event to local database: " + eventId);
                    }
                    batch.add(ContentProviderOperation
                            .newInsert(Uri.withAppendedPath(EventsContract.CONTENT_URI, eventId))
                            .withValues(values).build());
                    syncResult.stats.numInserts++;

                    ++newEventCount;
                    if (newEventId == null) {
                        newEventId = eventId;
                    }
                }

                // This event now exists in the local database:
                // remove its identifier from this collection as we
                // don't want to delete it.
                localEventIds.remove(eventId);
            } catch (JSONException e) {
                Log.w(TAG, "Invalid event at index " + i + ": cannot sync", e);
                syncResult.stats.numSkippedEntries++;
                continue;
            }
        }

        // The remaining event identifiers was removed on the remote
        // server: there are still present in the local database. These
        // events are now being deleted.
        for (final String eventId : localEventIds) {
            if (DEVELOPER_MODE) {
                Log.d(TAG, "Deleting event in local database: " + eventId);
            }
            batch.add(ContentProviderOperation
                    .newDelete(Uri.withAppendedPath(EventsContract.CONTENT_URI, eventId)).build());
            syncResult.stats.numDeletes++;
        }

        try {
            provider.applyBatch(batch);
        } catch (Exception e) {
            Log.e(TAG, "Database error: cannot sync", e);
            syncResult.stats.numIoExceptions++;
            return;
        }
        batch.clear();

        if (newEventCount > 1) {
            newEventId = null;
        }
        if (newEventCount != 0) {
            startSyncNotificationService(newEventCount, newEventId);
        }
    }

    final int numEventsToUpload = eventsToUpload.size();
    if (numEventsToUpload == 0) {
        Log.i(TAG, "No events to upload");
    } else {
        Log.i(TAG, "Found " + numEventsToUpload + " event(s) to upload");
    }

    // Send local events to the remote server.
    for (final Map.Entry<String, JSONObject> entry : eventsToUpload.entrySet()) {
        final String eventId = entry.getKey();

        if (DEVELOPER_MODE) {
            Log.d(TAG, "Uploading event: " + eventId);
        }

        final JSONObject event = entry.getValue();
        try {
            client.put("/events/" + eventId, event);

            if (DEVELOPER_MODE) {
                Log.d(TAG, "Updating event state to UPLOADED: " + eventId);
            }
            values.clear();
            values.put(STATE, EventsContract.UPLOADED_STATE);
            batch.add(ContentProviderOperation
                    .newUpdate(Uri.withAppendedPath(EventsContract.CONTENT_URI, eventId)).withValues(values)
                    .withExpectedCount(1).build());
            syncResult.stats.numUpdates++;

            Log.i(TAG, "Event upload successful: " + eventId);
        } catch (NetworkClientException e) {
            if (e.getStatusCode() == 404) {
                Log.e(TAG, "Device not found: cannot sync", e);
                registerDevice();
            } else {
                Log.e(TAG, "Network error: cannot sync", e);
            }
            syncResult.stats.numIoExceptions++;
            return;
        } catch (IOException e) {
            Log.e(TAG, "Event upload error: cannot sync", e);
            syncResult.stats.numIoExceptions++;
            return;
        } catch (AppEngineAuthenticationException e) {
            Log.e(TAG, "Authentication error: cannot sync", e);
            syncResult.stats.numAuthExceptions++;
            return;
        }
    }

    try {
        provider.applyBatch(batch);
    } catch (Exception e) {
        Log.w(TAG, "Database error: cannot sync", e);
        syncResult.stats.numIoExceptions++;
        return;
    }
    batch.clear();

    final SharedPreferences.Editor prefsEditor = prefs.edit();
    final boolean syncRequired = !eventsToDelete.isEmpty() || !eventsToUpload.isEmpty();
    if (syncRequired) {
        // Generate an unique sync token: the server will send this token to
        // every devices. If this token is received on this device, the sync
        // will not start.
        final String syncToken = UUID.randomUUID().toString();
        prefsEditor.putString(SP_KEY_SYNC_TOKEN, syncToken);
        Features.getFeature(SharedPreferencesSaverFeature.class).save(prefsEditor);

        // Sync user devices.
        try {
            final JSONObject data = new JSONObject();
            data.put("token", syncToken);
            client.post("/devices/" + client.getDeviceId() + "/sync", data);
        } catch (NetworkClientException e) {
            if (e.getStatusCode() == 404) {
                registerDevice();
            }
        } catch (IOException e) {
            Log.e(TAG, "Device sync error: cannot sync", e);
            syncResult.stats.numIoExceptions++;
            return;
        } catch (AppEngineAuthenticationException e) {
            Log.e(TAG, "Authentication error: cannot sync", e);
            syncResult.stats.numAuthExceptions++;
            return;
        } catch (JSONException e) {
            Log.w(TAG, "Invalid sync token " + syncToken + ": cannot sync", e);
            syncResult.stats.numIoExceptions++;
            return;
        }
    }

    // Store sync time.
    prefsEditor.putLong(SP_KEY_LAST_SYNC, System.currentTimeMillis());
    Features.getFeature(SharedPreferencesSaverFeature.class).save(prefsEditor);
}