List of usage examples for android.content ContentResolver notifyChange
public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer)
From source file:com.akop.bach.parser.XboxLiveParser.java
private void parseAchievements(XboxLiveAccount account, long gameId) throws ParserException, IOException { // Find game record in local DB ContentResolver cr = mContext.getContentResolver(); String gameUid = Games.getUid(mContext, gameId); long updated = System.currentTimeMillis(); long started = System.currentTimeMillis(); String pageUrl = String.format(URL_ACHIEVEMENTS, mLocale, gameUid); String page = getResponse(pageUrl); if (App.getConfig().logToConsole()) started = displayTimeTaken("Achievement page fetch", started); Matcher m;//from w w w. j a v a 2 s .c o m if (!(m = PATTERN_ACH_JSON.matcher(page)).find()) throw new ParserException(mContext, R.string.error_achieves_retrieval); JSONObject data = getJSONObject(m.group(1), false); JSONArray players = data.optJSONArray("Players"); if (players.length() < 1) throw new ParserException(mContext, R.string.error_achieves_retrieval); JSONObject player = players.optJSONObject(0); String gamertag = player.optString("Gamertag"); List<ContentValues> cvList = new ArrayList<ContentValues>(100); JSONArray achieves = data.optJSONArray("Achievements"); for (int i = 0, n = achieves.length(); i < n; i++) { JSONObject achieve = achieves.optJSONObject(i); if (achieve == null || achieve.optString("Id") == null) continue; JSONObject progRoot = achieve.optJSONObject("EarnDates"); if (progRoot == null) continue; JSONObject prog = progRoot.optJSONObject(gamertag); String title; String description; String tileUrl; if (achieve.optBoolean("IsHidden")) { title = mContext.getString(R.string.secret_achieve_title); description = mContext.getString(R.string.secret_achieve_desc); tileUrl = URL_SECRET_ACHIEVE_TILE; } else { title = achieve.optString("Name"); description = achieve.optString("Description"); tileUrl = achieve.optString("TileUrl"); } ContentValues cv = new ContentValues(10); // TODO cv.put(Achievements.UID, achieve.optString("Id")); cv.put(Achievements.GAME_ID, gameId); cv.put(Achievements.TITLE, title); cv.put(Achievements.DESCRIPTION, description); cv.put(Achievements.ICON_URL, tileUrl); cv.put(Achievements.POINTS, achieve.optInt("Score", 0)); if (prog != null) { // Unlocked long earnedOn = 0; if (!prog.optBoolean("IsOffline")) earnedOn = parseTicks(prog.optString("EarnedOn")); cv.put(Achievements.ACQUIRED, earnedOn); cv.put(Achievements.LOCKED, 0); } else { // Locked cv.put(Achievements.ACQUIRED, 0); cv.put(Achievements.LOCKED, 1); } cvList.add(cv); } if (App.getConfig().logToConsole()) started = displayTimeTaken("New achievement parsing", started); ContentValues[] cva = new ContentValues[cvList.size()]; cvList.toArray(cva); cr.delete(Achievements.CONTENT_URI, Achievements.GAME_ID + "=" + gameId, null); // Bulk-insert new achievements cr.bulkInsert(Achievements.CONTENT_URI, cva); if (App.getConfig().logToConsole()) started = displayTimeTaken("New achievement processing", started); // Update game stats JSONObject game = data.optJSONObject("Game"); if (game != null) { ContentValues cv = new ContentValues(10); cv.put(Games.LAST_UPDATED, updated); cv.put(Games.ACHIEVEMENTS_STATUS, 0); cv.put(Games.ACHIEVEMENTS_TOTAL, game.optInt("PossibleAchievements", 0)); cv.put(Games.POINTS_TOTAL, game.optInt("PossibleScore", 0)); JSONObject progRoot = game.optJSONObject("Progress"); if (progRoot != null) { JSONObject progress = game.optJSONObject(gamertag); if (progress != null) { cv.put(Games.ACHIEVEMENTS_UNLOCKED, progress.optInt("Achievements", 0)); cv.put(Games.POINTS_ACQUIRED, progress.optInt("Score", 0)); cv.put(Games.LAST_PLAYED, parseTicks(progress.optString("LastPlayed"))); } } // Write changes cr.update(Games.CONTENT_URI, cv, Games._ID + "=" + gameId, null); } cr.notifyChange(Achievements.CONTENT_URI, null); if (App.getConfig().logToConsole()) displayTimeTaken("Updating Game", started); }
From source file:com.akop.bach.parser.PsnUsParser.java
protected void parseGames(PsnAccount account) throws ParserException, IOException { String page = getResponse(String.format(URL_GAMES, URLEncoder.encode(account.getScreenName(), "UTF-8")), true);//from ww w. j a v a2 s.c o m ContentResolver cr = mContext.getContentResolver(); boolean changed = false; long updated = System.currentTimeMillis(); Cursor c; String title; String iconUrl; String uid; int progress; int bronze; int silver; int gold; int platinum; String[] queryParams = new String[1]; final long accountId = account.getId(); ContentValues cv; List<ContentValues> newCvs = new ArrayList<ContentValues>(100); long started = System.currentTimeMillis(); Matcher m; Matcher gameMatcher = PATTERN_GAMES.matcher(page); for (int rowNo = 1; gameMatcher.find(); rowNo++) { String group = gameMatcher.group(1); if (!(m = PATTERN_GAME_UID.matcher(group)).find()) continue; uid = m.group(2); progress = 0; if ((m = PATTERN_GAME_PROGRESS.matcher(group)).find()) progress = Integer.parseInt(m.group(1)); bronze = silver = gold = platinum = 0; if ((m = PATTERN_GAME_TROPHIES.matcher(group)).find()) { bronze = Integer.parseInt(m.group(1)); if (m.find()) { silver = Integer.parseInt(m.group(1)); if (m.find()) { gold = Integer.parseInt(m.group(1)); if (m.find()) { platinum = Integer.parseInt(m.group(1)); } } } } // Check to see if we already have a record of this game queryParams[0] = uid; c = cr.query(Games.CONTENT_URI, GAMES_PROJECTION, Games.ACCOUNT_ID + "=" + accountId + " AND " + Games.UID + "=?", queryParams, null); changed = true; try { if (c == null || !c.moveToFirst()) // New game { title = ""; if ((m = PATTERN_GAME_TITLE.matcher(group)).find()) title = htmlDecode(m.group(1)); iconUrl = null; if ((m = PATTERN_GAME_ICON.matcher(group)).find()) iconUrl = getAvatarImage(m.group(1)); cv = new ContentValues(15); cv.put(Games.ACCOUNT_ID, accountId); cv.put(Games.TITLE, title); cv.put(Games.UID, uid); cv.put(Games.ICON_URL, iconUrl); cv.put(Games.PROGRESS, progress); cv.put(Games.SORT_ORDER, rowNo); cv.put(Games.UNLOCKED_PLATINUM, platinum); cv.put(Games.UNLOCKED_GOLD, gold); cv.put(Games.UNLOCKED_SILVER, silver); cv.put(Games.UNLOCKED_BRONZE, bronze); cv.put(Games.TROPHIES_DIRTY, 1); cv.put(Games.LAST_UPDATED, updated); newCvs.add(cv); } else // Existing game { boolean isDirty = false; long gameId = c.getLong(COLUMN_GAME_ID); cv = new ContentValues(15); if (c.getInt(COLUMN_GAME_PROGRESS) != progress) { isDirty = true; cv.put(Games.PROGRESS, progress); } if (c.getInt(COLUMN_GAME_BRONZE) != bronze) { isDirty = true; cv.put(Games.UNLOCKED_BRONZE, bronze); } if (c.getInt(COLUMN_GAME_SILVER) != silver) { isDirty = true; cv.put(Games.UNLOCKED_SILVER, silver); } if (c.getInt(COLUMN_GAME_GOLD) != gold) { isDirty = true; cv.put(Games.UNLOCKED_GOLD, gold); } if (c.getInt(COLUMN_GAME_PLATINUM) != platinum) { isDirty = true; cv.put(Games.UNLOCKED_PLATINUM, platinum); } if (isDirty) cv.put(Games.TROPHIES_DIRTY, 1); cv.put(Games.SORT_ORDER, rowNo); cv.put(Games.LAST_UPDATED, updated); cr.update(Games.CONTENT_URI, cv, Games._ID + "=" + gameId, null); } } finally { if (c != null) c.close(); } } if (App.getConfig().logToConsole()) started = displayTimeTaken("Game page processing", started); if (newCvs.size() > 0) { changed = true; ContentValues[] cvs = new ContentValues[newCvs.size()]; newCvs.toArray(cvs); cr.bulkInsert(Games.CONTENT_URI, cvs); if (App.getConfig().logToConsole()) displayTimeTaken("Game page insertion", started); } account.refresh(Preferences.get(mContext)); account.setLastGameUpdate(System.currentTimeMillis()); account.save(Preferences.get(mContext)); if (changed) cr.notifyChange(Games.CONTENT_URI, null); }
From source file:com.akop.bach.parser.XboxLiveParser.java
private void parseGames(XboxLiveAccount account) throws ParserException, IOException { long started = System.currentTimeMillis(); String url = String.format(URL_GAME_LIST, mLocale); String page = getResponse(url); if (App.getConfig().logToConsole()) started = displayTimeTaken("Game page fetch", started); long accountId = account.getId(); String[] queryParams = new String[1]; int rowNo = 0; boolean changed = false; Cursor c;//from ww w. j a v a2 s . c o m ContentValues cv; long updated = System.currentTimeMillis(); List<ContentValues> newCvs = new ArrayList<ContentValues>(100); ContentResolver cr = mContext.getContentResolver(); List<String> gameIds = new ArrayList<String>(50); Matcher m = PATTERN_GAME_ITEM.matcher(page); while (m.find()) { String content = m.group(1); App.logv(" *** found it: " + content); Matcher im = PATTERN_GAME_TITLE_ID.matcher(content); if (!im.find()) continue; String uid = im.group(1); String title = htmlDecode(im.group(2)); String boxArtUrl = null; int gpAcquired = 0; int achUnlocked = 0; gameIds.add(uid); im = PATTERN_GAME_BOX_ART.matcher(content); if (im.find()) boxArtUrl = im.group(1); im = PATTERN_GAME_SCORE.matcher(content); if (im.find()) { try { gpAcquired = Integer.parseInt(im.group(1)); } catch (NumberFormatException e) { } } im = PATTERN_GAME_ACHIEVEMENTS.matcher(content); if (im.find()) { try { achUnlocked = Integer.parseInt(im.group(1)); } catch (NumberFormatException e) { } } // Check to see if we already have a record of this game queryParams[0] = uid; c = cr.query(Games.CONTENT_URI, GAMES_PROJECTION, Games.ACCOUNT_ID + "=" + accountId + " AND " + Games.UID + "=?", queryParams, null); try { if (c == null || !c.moveToFirst()) // New game { cv = new ContentValues(15); cv.put(Games.ACCOUNT_ID, accountId); cv.put(Games.TITLE, title); cv.put(Games.UID, uid); cv.put(Games.BOXART_URL, boxArtUrl); cv.put(Games.LAST_PLAYED, 0); cv.put(Games.LAST_UPDATED, updated); cv.put(Games.ACHIEVEMENTS_UNLOCKED, achUnlocked); cv.put(Games.ACHIEVEMENTS_TOTAL, achUnlocked); cv.put(Games.POINTS_ACQUIRED, gpAcquired); cv.put(Games.POINTS_TOTAL, gpAcquired); cv.put(Games.GAME_URL, (String) null); cv.put(Games.INDEX, rowNo); // Games with no achievements do not need achievement refresh cv.put(Games.ACHIEVEMENTS_STATUS, 1); newCvs.add(cv); } else // Existing game { long gameId = c.getLong(COLUMN_GAME_ID); long lastPlayedTicksRec = c.getLong(COLUMN_GAME_LAST_PLAYED_DATE); cv = new ContentValues(15); boolean refreshAchievements = true; if (refreshAchievements) { cv.put(Games.ACHIEVEMENTS_UNLOCKED, achUnlocked); cv.put(Games.ACHIEVEMENTS_TOTAL, achUnlocked); cv.put(Games.POINTS_ACQUIRED, gpAcquired); cv.put(Games.POINTS_TOTAL, gpAcquired); cv.put(Games.ACHIEVEMENTS_STATUS, 1); } cv.put(Games.BEACON_SET, 0); cv.put(Games.BEACON_TEXT, (String) null); cv.put(Games.LAST_PLAYED, 0); cv.put(Games.INDEX, rowNo); cv.put(Games.LAST_UPDATED, updated); cr.update(Games.CONTENT_URI, cv, Games._ID + "=" + gameId, null); changed = true; } } finally { if (c != null) c.close(); } rowNo++; } // Remove games that are no longer present c = cr.query(Games.CONTENT_URI, GAMES_PROJECTION, Games.ACCOUNT_ID + "=" + accountId, null, null); if (c != null) { while (c.moveToNext()) { if (!gameIds.contains(c.getString(COLUMN_GAME_UID))) { // Game is no longer in list of played games; remove it cr.delete(ContentUris.withAppendedId(Games.CONTENT_URI, c.getLong(COLUMN_GAME_ID)), null, null); changed = true; } } c.close(); } if (App.getConfig().logToConsole()) started = displayTimeTaken("Game page processing", started); if (newCvs.size() > 0) { changed = true; ContentValues[] cvs = new ContentValues[newCvs.size()]; newCvs.toArray(cvs); cr.bulkInsert(Games.CONTENT_URI, cvs); if (App.getConfig().logToConsole()) displayTimeTaken("Game page insertion", started); } account.refresh(Preferences.get(mContext)); account.setLastGameUpdate(System.currentTimeMillis()); account.save(Preferences.get(mContext)); if (changed) cr.notifyChange(Games.CONTENT_URI, null); }
From source file:com.akop.bach.parser.PsnEuParser.java
@SuppressLint("DefaultLocale") @Override/*from www. j a va2s .c o m*/ protected void parseFriends(PsnAccount account) throws ParserException, IOException { synchronized (PsnEuParser.class) { ContentResolver cr = mContext.getContentResolver(); ContentValues cv; List<ContentValues> newCvs = new ArrayList<ContentValues>(100); final long accountId = account.getId(); int rowsInserted = 0; int rowsUpdated = 0; int rowsDeleted = 0; long updated = System.currentTimeMillis(); long started = updated; // Handle pending requests String page = getResponse(URL_FRIENDS); Matcher m; Matcher friendMatcher = PATTERN_FRIENDS_PENDING.matcher(page); while (friendMatcher.find()) { String onlineId = htmlDecode(friendMatcher.group(1)); Cursor c = cr.query(Friends.CONTENT_URI, FRIEND_ID_PROJECTION, Friends.ACCOUNT_ID + "=" + account.getId() + " AND " + Friends.ONLINE_ID + "=?", new String[] { onlineId }, null); long friendId = -1; try { if (c != null && c.moveToFirst()) friendId = c.getLong(0); } finally { if (c != null) c.close(); } cv = new ContentValues(15); cv.put(Friends.DELETE_MARKER, updated); cv.put(Friends.ONLINE_STATUS, PSN.STATUS_PENDING); if (friendId < 0) { // New cv.put(Friends.ONLINE_ID, onlineId); cv.put(Friends.ACCOUNT_ID, accountId); cv.put(Friends.PROGRESS, 0); cv.putNull(Friends.ICON_URL); cv.put(Friends.LEVEL, 0); cv.put(Friends.TROPHIES_PLATINUM, 0); cv.put(Friends.TROPHIES_GOLD, 0); cv.put(Friends.TROPHIES_SILVER, 0); cv.put(Friends.TROPHIES_BRONZE, 0); cv.putNull(Friends.PLAYING); cv.put(Friends.LAST_UPDATED, 0); newCvs.add(cv); } else { cr.update(ContentUris.withAppendedId(Friends.CONTENT_URI, friendId), cv, null, null); rowsUpdated++; } } // Handle rest of friends page = getResponse(URL_FRIENDS_AJAX); friendMatcher = PATTERN_FRIENDS.matcher(page); while (friendMatcher.find()) { String friendData = friendMatcher.group(1); String onlineId; if (!(m = PATTERN_FRIEND_ONLINE_ID.matcher(friendData)).find()) continue; onlineId = htmlDecode(m.group(1)); int level = 0; if ((m = PATTERN_FRIEND_LEVEL.matcher(friendData)).find()) level = Integer.parseInt(m.group(1)); String iconUrl = null; if ((m = PATTERN_FRIEND_AVATAR.matcher(friendData)).find()) iconUrl = getLargeAvatarIcon(resolveImageUrl(URL_FRIENDS_AJAX, m.group(1))); String comment = null; if ((m = PATTERN_FRIEND_COMMENT.matcher(friendData)).find()) { comment = htmlDecode(m.group(1)); if (comment != null && comment.equals("null")) comment = null; } int memberType = PSN.MEMBER_TYPE_FREE; if ((m = PATTERN_FRIEND_IS_PLUS.matcher(friendData)).find() && m.group(1).equalsIgnoreCase("true")) { memberType = PSN.MEMBER_TYPE_PLUS; } int bronze = 0; int silver = 0; int gold = 0; int platinum = 0; m = PATTERN_FRIEND_TROPHY.matcher(friendData); while (m.find()) { String type = m.group(1).toLowerCase(); if ("bronze".equals(type)) bronze = Integer.parseInt(m.group(2)); else if ("silver".equals(type)) silver = Integer.parseInt(m.group(2)); else if ("gold".equals(type)) gold = Integer.parseInt(m.group(2)); else if ("platinum".equals(type)) platinum = Integer.parseInt(m.group(2)); } boolean inGame = false; int status = PSN.STATUS_OTHER; if ((m = PATTERN_FRIEND_STATUS.matcher(friendData)).find()) { String presence = m.group(1).toLowerCase(); if (presence.equals("offline")) status = PSN.STATUS_OFFLINE; else if (presence.equals("online")) status = PSN.STATUS_ONLINE; else if (presence.equals("online-ingame")) { status = PSN.STATUS_ONLINE; inGame = true; } else if (presence.equals("online-away")) status = PSN.STATUS_AWAY; else if (presence.equals("online-ingame-away")) { status = PSN.STATUS_AWAY; inGame = true; } else if (presence.equals("pending")) status = PSN.STATUS_PENDING; } String playing = null; if ((m = PATTERN_FRIEND_PLAYING.matcher(friendData)).find()) { String activity = htmlDecode(m.group(1)).trim(); if (activity != null && activity.length() > 0) { if (inGame) playing = mContext.getString(R.string.playing_f, activity); else playing = activity; } } Cursor c = cr.query(Friends.CONTENT_URI, FRIEND_ID_PROJECTION, Friends.ACCOUNT_ID + "=" + account.getId() + " AND " + Friends.ONLINE_ID + "=?", new String[] { onlineId }, null); long friendId = -1; try { if (c != null && c.moveToFirst()) friendId = c.getLong(0); } finally { if (c != null) c.close(); } cv = new ContentValues(15); cv.put(Friends.ICON_URL, iconUrl); cv.put(Friends.LEVEL, level); cv.put(Friends.MEMBER_TYPE, memberType); cv.put(Friends.COMMENT, comment); cv.put(Friends.LEVEL, level); cv.put(Friends.ONLINE_STATUS, status); cv.put(Friends.TROPHIES_PLATINUM, platinum); cv.put(Friends.TROPHIES_GOLD, gold); cv.put(Friends.TROPHIES_SILVER, silver); cv.put(Friends.TROPHIES_BRONZE, bronze); cv.put(Friends.PLAYING, playing); cv.put(Friends.DELETE_MARKER, updated); if (friendId < 0) { // New cv.put(Friends.ONLINE_ID, onlineId); cv.put(Friends.ACCOUNT_ID, accountId); cv.put(Friends.PROGRESS, 0); cv.put(Friends.LAST_UPDATED, 0); newCvs.add(cv); } else { cr.update(ContentUris.withAppendedId(Friends.CONTENT_URI, friendId), cv, null, null); rowsUpdated++; } } // Remove friends rowsDeleted = cr.delete(Friends.CONTENT_URI, Friends.ACCOUNT_ID + "=" + accountId + " AND " + Friends.DELETE_MARKER + "!=" + updated, null); if (newCvs.size() > 0) { ContentValues[] cvs = new ContentValues[newCvs.size()]; newCvs.toArray(cvs); rowsInserted = cr.bulkInsert(Friends.CONTENT_URI, cvs); } account.refresh(Preferences.get(mContext)); account.setLastFriendUpdate(System.currentTimeMillis()); account.save(Preferences.get(mContext)); cr.notifyChange(Friends.CONTENT_URI, null); if (App.getConfig().logToConsole()) started = displayTimeTaken("Friend page processing [I:" + rowsInserted + ";U:" + rowsUpdated + ";D:" + rowsDeleted + "]", started); } }
From source file:edu.mit.mobile.android.locast.data.Sync.java
/** * Given a live cursor pointing to a data item and/or a set of contentValues loaded from the network, * attempt to sync.//w ww . jav a 2 s . c o m * Either c or cvNet can be null, but not both. * @param c A cursor pointing to the data item. Null is OK here. * @param jsonObject JSON object for the item as loaded from the network. null is OK here. * @param sync An empty JsonSyncableItem object. * @param publicPath TODO * * @return True if the item has been modified on either end. * @throws IOException */ private boolean syncItem(Uri toSync, Cursor c, JSONObject jsonObject, JsonSyncableItem sync, SyncProgressNotifier syncProgress, String publicPath) throws SyncException, IOException { boolean modified = false; boolean needToCloseCursor = false; boolean toSyncIsIndex = false; final SyncMap syncMap = sync.getSyncMap(); Uri locUri = null; final Uri origToSync = toSync; ContentValues cvNet = null; final Context context = getApplicationContext(); final ContentResolver cr = context.getContentResolver(); if (jsonObject != null) { if ("http".equals(toSync.getScheme()) || "https".equals(toSync.getScheme())) { // we successfully loaded it from the 'net, but toSync is really for local URIs. Erase it. toSync = sync.getContentUri(); if (toSync == null) { if (DEBUG) { Log.w(TAG, "cannot get local URI for " + origToSync + ". Skipping..."); } return false; } } try { cvNet = JsonSyncableItem.fromJSON(context, null, jsonObject, syncMap); } catch (final Exception e) { final SyncException se = new SyncException("Problem loading JSON object."); se.initCause(e); throw se; } } final String contentType = cr.getType(toSync); if (c != null) { if (contentType.startsWith(CONTENT_TYPE_PREFIX_DIR)) { locUri = ContentUris.withAppendedId(toSync, c.getLong(c.getColumnIndex(JsonSyncableItem._ID))) .buildUpon().query(null).build(); toSyncIsIndex = true; } else { locUri = toSync; } // skip any items already sync'd if (mLastUpdated.isUpdatedRecently(locUri)) { return false; } final int draftCol = c.getColumnIndex(TaggableItem._DRAFT); if (draftCol != -1 && c.getInt(draftCol) != 0) { if (DEBUG) { Log.d(TAG, locUri + " is marked a draft. Not syncing."); } return false; } syncMap.onPreSyncItem(cr, locUri, c); } else if (contentType.startsWith(CONTENT_TYPE_PREFIX_DIR)) { // strip any query strings toSync = toSync.buildUpon().query(null).build(); } // if (c != null){ // MediaProvider.dumpCursorToLog(c, sync.getFullProjection()); // } // when the PUBLIC_URI is null, that means it's only local final int pubUriColumn = (c != null) ? c.getColumnIndex(JsonSyncableItem._PUBLIC_URI) : -1; if (c != null && (c.isNull(pubUriColumn) || c.getString(pubUriColumn) == "")) { // new content on the local side only. Gotta publish. try { jsonObject = JsonSyncableItem.toJSON(context, locUri, c, syncMap); if (publicPath == null) { publicPath = MediaProvider.getPostPath(this, locUri); } if (DEBUG) { Log.d(TAG, "Posting " + locUri + " to " + publicPath); } // The response from a post to create a new item should be the newly created item, // which contains the public ID that we need. jsonObject = nc.postJson(publicPath, jsonObject); final ContentValues cvUpdate = JsonSyncableItem.fromJSON(context, locUri, jsonObject, syncMap); if (cr.update(locUri, cvUpdate, null, null) == 1) { // at this point, server and client should be in sync. mLastUpdated.markUpdated(locUri); if (DEBUG) { Log.i(TAG, "Hooray! " + locUri + " has been posted succesfully."); } } else { Log.e(TAG, "update of " + locUri + " failed"); } modified = true; } catch (final Exception e) { final SyncException se = new SyncException(getString(R.string.error_sync_no_post)); se.initCause(e); throw se; } // only on the remote side, so pull it in. } else if (c == null && cvNet != null) { if (DEBUG) { Log.i(TAG, "Only on the remote side, using network-provided values."); } final String[] params = { cvNet.getAsString(JsonSyncableItem._PUBLIC_URI) }; c = cr.query(toSync, sync.getFullProjection(), JsonSyncableItem._PUBLIC_URI + "=?", params, null); needToCloseCursor = true; if (!c.moveToFirst()) { locUri = cr.insert(toSync, cvNet); modified = true; } else { locUri = ContentUris.withAppendedId(toSync, c.getLong(c.getColumnIndex(JsonSyncableItem._ID))) .buildUpon().query(null).build(); syncMap.onPreSyncItem(cr, locUri, c); } } // we've now found data on both sides, so sync them. if (!modified && c != null) { publicPath = c.getString(c.getColumnIndex(JsonSyncableItem._PUBLIC_URI)); try { if (cvNet == null) { try { if (publicPath == null && toSyncIsIndex && !MediaProvider.canSync(locUri)) { // At this point, we've already checked the index and it doesn't contain the item (otherwise it would be in the syncdItems). // If we can't sync individual items, it's possible that the index is paged or the item has been deleted. if (DEBUG) { Log.w(TAG, "Asked to sync " + locUri + " but item wasn't in server index and cannot sync individual entries. Skipping and hoping it is up to date."); } return false; } else { if (mLastUpdated.isUpdatedRecently(nc.getFullUri(publicPath))) { if (DEBUG) { Log.d(TAG, "already sync'd! " + publicPath); } return false; } if (jsonObject == null) { jsonObject = nc.getObject(publicPath); } cvNet = JsonSyncableItem.fromJSON(context, locUri, jsonObject, syncMap); } } catch (final HttpResponseException hre) { if (hre.getStatusCode() == HttpStatus.SC_NOT_FOUND) { final SyncItemDeletedException side = new SyncItemDeletedException(locUri); side.initCause(hre); throw side; } } } if (cvNet == null) { Log.e(TAG, "got null values from fromJSON() on item " + locUri + ": " + (jsonObject != null ? jsonObject.toString() : "<< no json object >>")); return false; } final Date netLastModified = new Date(cvNet.getAsLong(JsonSyncableItem._MODIFIED_DATE)); final Date locLastModified = new Date(c.getLong(c.getColumnIndex(JsonSyncableItem._MODIFIED_DATE))); if (netLastModified.equals(locLastModified)) { // same! yay! We don't need to do anything. if (DEBUG) { Log.d("LocastSync", locUri + " doesn't need to sync."); } } else if (netLastModified.after(locLastModified)) { // remote is more up to date, update! cr.update(locUri, cvNet, null, null); if (DEBUG) { Log.d("LocastSync", cvNet + " is newer than " + locUri); } modified = true; } else if (netLastModified.before(locLastModified)) { // local is more up to date, propagate! jsonObject = nc.putJson(publicPath, JsonSyncableItem.toJSON(context, locUri, c, syncMap)); if (DEBUG) { Log.d("LocastSync", cvNet + " is older than " + locUri); } modified = true; } mLastUpdated.markUpdated(nc.getFullUri(publicPath)); } catch (final JSONException e) { final SyncException se = new SyncException( "Item sync error for path " + publicPath + ": invalid JSON."); se.initCause(e); throw se; } catch (final NetworkProtocolException e) { final SyncException se = new SyncException( "Item sync error for path " + publicPath + ": " + e.getHttpResponseMessage()); se.initCause(e); throw se; } finally { if (needToCloseCursor) { c.close(); needToCloseCursor = false; } } } if (needToCloseCursor) { c.close(); } if (locUri == null) { throw new RuntimeException("Never got a local URI for a sync'd item."); } // two calls are made in two different contexts. Which context you use depends on the application. syncMap.onPostSyncItem(context, locUri, jsonObject, modified); sync.onPostSyncItem(context, locUri, jsonObject, modified); mLastUpdated.markUpdated(locUri); // needed for things that may have requested a sync with a different URI than what was eventually produced. if (origToSync != locUri) { mLastUpdated.markUpdated(origToSync); cr.notifyChange(origToSync, null); } return modified; }