List of usage examples for android.content ContentValues clear
public void clear()
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); }