Example usage for android.content ContentResolver notifyChange

List of usage examples for android.content ContentResolver notifyChange

Introduction

In this page you can find the example usage for android.content ContentResolver notifyChange.

Prototype

public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer) 

Source Link

Document

Notify registered observers that a row was updated and attempt to sync changes to the network.

Usage

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;
}