Example usage for android.content ContentProviderClient release

List of usage examples for android.content ContentProviderClient release

Introduction

In this page you can find the example usage for android.content ContentProviderClient release.

Prototype

@Deprecated
public boolean release() 

Source Link

Usage

From source file:fr.free.nrw.commons.contributions.ContributionDao.java

public void delete(Contribution contribution) {
    ContentProviderClient db = clientProvider.get();
    try {/*from w w w  .ja  v  a 2 s. co m*/
        if (contribution.getContentUri() == null) {
            // noooo
            throw new RuntimeException("tried to delete item with no content URI");
        } else {
            db.delete(contribution.getContentUri(), null, null);
        }
    } catch (RemoteException e) {
        throw new RuntimeException(e);
    } finally {
        db.release();
    }
}

From source file:fr.free.nrw.commons.contributions.ContributionDao.java

public void save(Contribution contribution) {
    ContentProviderClient db = clientProvider.get();
    try {//ww  w . ja va  2  s.co  m
        if (contribution.getContentUri() == null) {
            contribution.setContentUri(db.insert(BASE_URI, toContentValues(contribution)));
        } else {
            db.update(contribution.getContentUri(), toContentValues(contribution), null, null);
        }
    } catch (RemoteException e) {
        throw new RuntimeException(e);
    } finally {
        db.release();
    }
}

From source file:org.kontalk.sync.SyncAdapter.java

@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider,
        SyncResult syncResult) {//from w  ww. jav  a  2s  .c o m

    try {
        // broadcast sync start
        mBroadcastManager.sendBroadcast(new Intent(ACTION_SYNC_START));

        final long startTime = SystemClock.elapsedRealtime();
        boolean force = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);

        // do not start if offline
        if (Preferences.getOfflineMode()) {
            Log.d(TAG, "not requesting sync - offline mode");
            return;
        }

        // do not start if no server available (limbo state)
        if (Preferences.getEndpointServer(mContext) == null) {
            Log.d(TAG, "no server available - aborting");
            return;
        }

        if (!force) {
            if (isThrottling()) {
                Log.d(TAG, "not starting sync - throttling");
                // TEST do not delay - syncResult.delayUntil = (long) diff;
                return;
            }
        }

        Log.i(TAG, "sync started (authority=" + authority + ")");
        // avoid other syncs to get scheduled in the meanwhile
        Preferences.setLastSyncTimestamp(System.currentTimeMillis());

        ContentProviderClient usersProvider = getContext().getContentResolver()
                .acquireContentProviderClient(UsersProvider.AUTHORITY);

        try {
            // hold a reference to the message center while syncing
            MessageCenterService.hold(mContext, true);
            // start sync
            mSyncer = new Syncer(mContext);
            mSyncer.performSync(mContext, account, authority, provider, usersProvider, syncResult);
        } catch (OperationCanceledException e) {
            Log.w(TAG, "sync canceled!", e);
        } finally {
            // release the message center
            MessageCenterService.release(mContext);
            // release user provider
            usersProvider.release();

            Preferences.setLastSyncTimestamp(System.currentTimeMillis());
            // some stats :)
            long endTime = SystemClock.elapsedRealtime();
            Log.d(TAG, String.format("sync took %.5f seconds", ((float) (endTime - startTime)) / 1000));
        }
    } finally {
        // broadcast sync finish
        mBroadcastManager.sendBroadcast(new Intent(ACTION_SYNC_FINISH));
    }
}

From source file:edu.stanford.mobisocial.dungbeetle.DBHelper.java

public static DBHelper getGlobal(Context context) {
    ContentProviderClient cpc = context.getContentResolver()
            .acquireContentProviderClient(DungBeetleContentProvider.CONTENT_URI);
    try {//  w ww .  j  a va  2s  .c  o  m
        DungBeetleContentProvider dbcp = (DungBeetleContentProvider) cpc.getLocalContentProvider();
        return dbcp.getDBHelper();
    } finally {
        cpc.release();
    }
}

From source file:com.microsoft.onedrive.apiexplorer.ItemFragment.java

@Override
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
    final BaseApplication application = (BaseApplication) getActivity().getApplication();
    final IOneDriveClient oneDriveClient = application.getOneDriveClient();

    if (requestCode == REQUEST_CODE_SIMPLE_UPLOAD && data != null && data.getData() != null
            && data.getData().getScheme().equalsIgnoreCase(SCHEME_CONTENT)) {

        final ProgressDialog dialog = new ProgressDialog(getActivity());
        dialog.setTitle(R.string.upload_in_progress_title);
        dialog.setMessage(getString(R.string.upload_in_progress_message));
        dialog.setIndeterminate(false);//from  w w  w .j  a v a 2 s  .co m
        dialog.setCancelable(false);
        dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        dialog.setProgressNumberFormat(getString(R.string.upload_in_progress_number_format));
        dialog.show();
        final AsyncTask<Void, Void, Void> uploadFile = new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(final Void... params) {
                try {
                    final ContentResolver contentResolver = getActivity().getContentResolver();
                    final ContentProviderClient contentProvider = contentResolver
                            .acquireContentProviderClient(data.getData());
                    final byte[] fileInMemory = FileContent.getFileBytes(contentProvider, data.getData());
                    contentProvider.release();

                    // Fix up the file name (needed for camera roll photos, etc)
                    final String filename = FileContent.getValidFileName(contentResolver, data.getData());
                    final Option option = new QueryOption("@name.conflictBehavior", "fail");
                    oneDriveClient.getDrive().getItems(mItemId).getChildren().byId(filename).getContent()
                            .buildRequest(Collections.singletonList(option))
                            .put(fileInMemory, new IProgressCallback<Item>() {
                                @Override
                                public void success(final Item item) {
                                    dialog.dismiss();
                                    Toast.makeText(getActivity(),
                                            application.getString(R.string.upload_complete, item.name),
                                            Toast.LENGTH_LONG).show();
                                    refresh();
                                }

                                @Override
                                public void failure(final ClientException error) {
                                    dialog.dismiss();
                                    if (error.isError(OneDriveErrorCodes.NameAlreadyExists)) {
                                        Toast.makeText(getActivity(), R.string.upload_failed_name_conflict,
                                                Toast.LENGTH_LONG).show();
                                    } else {
                                        Toast.makeText(getActivity(),
                                                application.getString(R.string.upload_failed, filename),
                                                Toast.LENGTH_LONG).show();
                                    }
                                }

                                @Override
                                public void progress(final long current, final long max) {
                                    dialog.setProgress((int) current);
                                    dialog.setMax((int) max);
                                }
                            });
                } catch (final Exception e) {
                    Log.e(getClass().getSimpleName(), e.getMessage());
                    Log.e(getClass().getSimpleName(), e.toString());
                }
                return null;
            }
        };
        uploadFile.execute();
    }
}

From source file:com.renard.ocr.OCRActivity.java

private Uri saveDocumentToDB(File imageFile, String hocr, String plainText) throws RemoteException {
    ContentProviderClient client = null;
    try {/* ww w.  j  a v a2s. c om*/
        ContentValues v = null;
        if (imageFile != null) {
            v = new ContentValues();
            v.put(com.renard.ocr.DocumentContentProvider.Columns.PHOTO_PATH, imageFile.getPath());
        }
        if (hocr != null) {
            v.put(Columns.HOCR_TEXT, hocr);
        }
        if (plainText != null) {
            v.put(Columns.OCR_TEXT, plainText);
        }

        if (mParentId > -1) {
            v.put(Columns.PARENT_ID, mParentId);
        }
        client = getContentResolver().acquireContentProviderClient(DocumentContentProvider.CONTENT_URI);
        return client.insert(DocumentContentProvider.CONTENT_URI, v);
    } finally {
        if (client != null) {
            client.release();
        }
    }
}

From source file:at.bitfire.davdroid.AccountSettings.java

@SuppressWarnings({ "Recycle", "unused" })
private void update_2_3() {
    // Don't show a warning for Android updates anymore
    accountManager.setUserData(account, "last_android_version", null);

    Long serviceCardDAV = null, serviceCalDAV = null;

    ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(context);
    try {/*from   www. ja  v  a 2s  . co m*/
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        // we have to create the WebDAV Service database only from the old address book, calendar and task list URLs

        // CardDAV: migrate address books
        ContentProviderClient client = context.getContentResolver()
                .acquireContentProviderClient(ContactsContract.AUTHORITY);
        if (client != null)
            try {
                LocalAddressBook addrBook = new LocalAddressBook(account, client);
                String url = addrBook.getURL();
                if (url != null) {
                    App.log.fine("Migrating address book " + url);

                    // insert CardDAV service
                    ContentValues values = new ContentValues();
                    values.put(Services.ACCOUNT_NAME, account.name);
                    values.put(Services.SERVICE, Services.SERVICE_CARDDAV);
                    serviceCardDAV = db.insert(Services._TABLE, null, values);

                    // insert address book
                    values.clear();
                    values.put(Collections.SERVICE_ID, serviceCardDAV);
                    values.put(Collections.URL, url);
                    values.put(Collections.SYNC, 1);
                    db.insert(Collections._TABLE, null, values);

                    // insert home set
                    HttpUrl homeSet = HttpUrl.parse(url).resolve("../");
                    values.clear();
                    values.put(HomeSets.SERVICE_ID, serviceCardDAV);
                    values.put(HomeSets.URL, homeSet.toString());
                    db.insert(HomeSets._TABLE, null, values);
                }

            } catch (ContactsStorageException e) {
                App.log.log(Level.SEVERE, "Couldn't migrate address book", e);
            } finally {
                client.release();
            }

        // CalDAV: migrate calendars + task lists
        Set<String> collections = new HashSet<>();
        Set<HttpUrl> homeSets = new HashSet<>();

        client = context.getContentResolver().acquireContentProviderClient(CalendarContract.AUTHORITY);
        if (client != null)
            try {
                LocalCalendar calendars[] = (LocalCalendar[]) LocalCalendar.find(account, client,
                        LocalCalendar.Factory.INSTANCE, null, null);
                for (LocalCalendar calendar : calendars) {
                    String url = calendar.getName();
                    App.log.fine("Migrating calendar " + url);
                    collections.add(url);
                    homeSets.add(HttpUrl.parse(url).resolve("../"));
                }
            } catch (CalendarStorageException e) {
                App.log.log(Level.SEVERE, "Couldn't migrate calendars", e);
            } finally {
                client.release();
            }

        TaskProvider provider = LocalTaskList.acquireTaskProvider(context.getContentResolver());
        if (provider != null)
            try {
                LocalTaskList[] taskLists = (LocalTaskList[]) LocalTaskList.find(account, provider,
                        LocalTaskList.Factory.INSTANCE, null, null);
                for (LocalTaskList taskList : taskLists) {
                    String url = taskList.getSyncId();
                    App.log.fine("Migrating task list " + url);
                    collections.add(url);
                    homeSets.add(HttpUrl.parse(url).resolve("../"));
                }
            } catch (CalendarStorageException e) {
                App.log.log(Level.SEVERE, "Couldn't migrate task lists", e);
            } finally {
                provider.close();
            }

        if (!collections.isEmpty()) {
            // insert CalDAV service
            ContentValues values = new ContentValues();
            values.put(Services.ACCOUNT_NAME, account.name);
            values.put(Services.SERVICE, Services.SERVICE_CALDAV);
            serviceCalDAV = db.insert(Services._TABLE, null, values);

            // insert collections
            for (String url : collections) {
                values.clear();
                values.put(Collections.SERVICE_ID, serviceCalDAV);
                values.put(Collections.URL, url);
                values.put(Collections.SYNC, 1);
                db.insert(Collections._TABLE, null, values);
            }

            // insert home sets
            for (HttpUrl homeSet : homeSets) {
                values.clear();
                values.put(HomeSets.SERVICE_ID, serviceCalDAV);
                values.put(HomeSets.URL, homeSet.toString());
                db.insert(HomeSets._TABLE, null, values);
            }
        }
    } finally {
        dbHelper.close();
    }

    // initiate service detection (refresh) to get display names, colors etc.
    Intent refresh = new Intent(context, DavService.class);
    refresh.setAction(DavService.ACTION_REFRESH_COLLECTIONS);
    if (serviceCardDAV != null) {
        refresh.putExtra(DavService.EXTRA_DAV_SERVICE_ID, serviceCardDAV);
        context.startService(refresh);
    }
    if (serviceCalDAV != null) {
        refresh.putExtra(DavService.EXTRA_DAV_SERVICE_ID, serviceCalDAV);
        context.startService(refresh);
    }
}

From source file:com.android.example.leanback.fastlane.RecommendationsService.java

@Override
protected void onHandleIntent(Intent intent) {
    ContentProviderClient client = getContentResolver()
            .acquireContentProviderClient(VideoItemContract.VideoItem.buildDirUri());
    try {/*ww w .  j a v a 2  s .  c  om*/
        Cursor cursor = client.query(VideoItemContract.VideoItem.buildDirUri(), VideoDataManager.PROJECTION,
                null, null, VideoItemContract.VideoItem.DEFAULT_SORT);

        VideoDataManager.VideoItemMapper mapper = new VideoDataManager.VideoItemMapper();
        mapper.bindColumns(cursor);

        NotificationManager mNotificationManager = (NotificationManager) getApplicationContext()
                .getSystemService(Context.NOTIFICATION_SERVICE);

        Log.d(TAG, mNotificationManager == null ? "It's null" : mNotificationManager.toString());

        int count = 1;

        while (cursor.moveToNext() && count <= MAX_RECOMMENDATIONS) {

            Video video = mapper.bind(cursor);
            PendingIntent pendingIntent = buildPendingIntent(video);
            Bundle extras = new Bundle();
            extras.putString(EXTRA_BACKGROUND_IMAGE_URL, video.getThumbUrl());

            Bitmap image = Picasso.with(getApplicationContext()).load(video.getThumbUrl())
                    .resize(VideoDetailsFragment.dpToPx(DETAIL_THUMB_WIDTH, getApplicationContext()),
                            VideoDetailsFragment.dpToPx(DETAIL_THUMB_HEIGHT, getApplicationContext()))
                    .get();

            Notification notification = new NotificationCompat.BigPictureStyle(
                    new NotificationCompat.Builder(getApplicationContext()).setContentTitle(video.getTitle())
                            .setContentText(video.getDescription()).setPriority(4).setLocalOnly(true)
                            .setOngoing(true)
                            .setColor(getApplicationContext().getResources().getColor(R.color.primary))
                            // .setCategory(Notification.CATEGORY_RECOMMENDATION)
                            .setCategory("recommendation").setLargeIcon(image)
                            .setSmallIcon(R.drawable.ic_stat_f).setContentIntent(pendingIntent)
                            .setExtras(extras)).build();

            mNotificationManager.notify(count, notification);
            count++;
        }

        cursor.close();
    } catch (RemoteException re) {
        Log.e(TAG, "Cannot query VideoItems", re);
    } catch (IOException re) {
        Log.e(TAG, "Cannot download thumbnail", re);
    } finally {
        client.release();
    }
}

From source file:org.voidsink.anewjkuapp.calendar.CalendarUtils.java

private static boolean deleteKusssEvents(Context context, String calId) {
    if (calId != null) {
        ContentProviderClient provider = context.getContentResolver()
                .acquireContentProviderClient(CalendarContractWrapper.Events.CONTENT_URI());

        if (provider == null) {
            return false;
        }/*  w ww.  j a  va  2  s . c  o m*/

        try {
            Uri calUri = CalendarContractWrapper.Events.CONTENT_URI();

            Cursor c = loadEvent(provider, calUri, calId);
            if (c != null) {
                try {
                    ArrayList<ContentProviderOperation> batch = new ArrayList<>();
                    long deleteFrom = new Date().getTime() - DateUtils.DAY_IN_MILLIS;
                    while (c.moveToNext()) {
                        long eventDTStart = c.getLong(CalendarUtils.COLUMN_EVENT_DTSTART);
                        if (eventDTStart > deleteFrom) {
                            String eventId = c.getString(COLUMN_EVENT_ID);
                            //                        Log.d(TAG, "---------");
                            String eventKusssId = null;

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

                            if (c2 != null) {
                                while (c2.moveToNext()) {
                                    if (c2.getString(1).contains(EXTENDED_PROPERTY_NAME_KUSSS_ID)) {
                                        eventKusssId = c2.getString(2);
                                    }
                                }
                                c2.close();
                            }

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

                            if (!TextUtils.isEmpty(eventKusssId)) {
                                if (eventKusssId.startsWith("at-jku-kusss-exam-")
                                        || eventKusssId.startsWith("at-jku-kusss-coursedate-")) {
                                    Uri deleteUri = calUri.buildUpon().appendPath(eventId).build();
                                    Log.d(TAG, "Scheduling delete: " + deleteUri);
                                    batch.add(ContentProviderOperation.newDelete(deleteUri).build());
                                }
                            }
                        }
                    }
                    if (batch.size() > 0) {
                        Log.d(TAG, "Applying batch update");
                        provider.applyBatch(batch);
                        Log.d(TAG, "Notify resolver");
                    } else {
                        Log.w(TAG, "No batch operations found! Do nothing");
                    }
                } catch (RemoteException | OperationApplicationException e) {
                    Analytics.sendException(context, e, true);
                    return false;
                }
            }
        } finally {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                provider.close();
            } else {
                provider.release();
            }
        }
        return false;
    }
    return true;
}

From source file:com.example.jumpnote.android.SyncAdapter.java

@Override
public void onPerformSync(final Account account, Bundle extras, String authority,
        final ContentProviderClient provider, final SyncResult syncResult) {
    TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
    String clientDeviceId = tm.getDeviceId();

    final long newSyncTime = System.currentTimeMillis();

    final boolean uploadOnly = extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false);
    final boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
    final boolean initialize = extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false);

    C2DMReceiver.refreshAppC2DMRegistrationState(mContext);

    Log.i(TAG, "Beginning " + (uploadOnly ? "upload-only" : "full") + " sync for account " + account.name);

    // Read this account's sync metadata
    final SharedPreferences syncMeta = mContext.getSharedPreferences("sync:" + account.name, 0);
    long lastSyncTime = syncMeta.getLong(LAST_SYNC, 0);
    long lastServerSyncTime = syncMeta.getLong(SERVER_LAST_SYNC, 0);

    // Check for changes in either app-wide auto sync registration information, or changes in
    // the user's preferences for auto sync on this account; if either changes, piggy back the
    // new registration information in this sync.
    long lastRegistrationChangeTime = C2DMessaging.getLastRegistrationChange(mContext);

    boolean autoSyncDesired = ContentResolver.getMasterSyncAutomatically()
            && ContentResolver.getSyncAutomatically(account, JumpNoteContract.AUTHORITY);
    boolean autoSyncEnabled = syncMeta.getBoolean(DM_REGISTERED, false);

    // Will be 0 for no change, -1 for unregister, 1 for register.
    final int deviceRegChange;
    JsonRpcClient.Call deviceRegCall = null;
    if (autoSyncDesired != autoSyncEnabled || lastRegistrationChangeTime > lastSyncTime || initialize
            || manualSync) {//from   w  w w.  ja v a  2s. c om

        String registrationId = C2DMessaging.getRegistrationId(mContext);
        deviceRegChange = (autoSyncDesired && registrationId != null) ? 1 : -1;

        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG,
                    "Auto sync selection or registration information has changed, "
                            + (deviceRegChange == 1 ? "registering" : "unregistering")
                            + " messaging for this device, for account " + account.name);
        }

        try {
            if (deviceRegChange == 1) {
                // Register device for auto sync on this account.
                deviceRegCall = new JsonRpcClient.Call(JumpNoteProtocol.DevicesRegister.METHOD);
                JSONObject params = new JSONObject();

                DeviceRegistration device = new DeviceRegistration(clientDeviceId, DEVICE_TYPE, registrationId);
                params.put(JumpNoteProtocol.DevicesRegister.ARG_DEVICE, device.toJSON());
                deviceRegCall.setParams(params);
            } else {
                // Unregister device for auto sync on this account.
                deviceRegCall = new JsonRpcClient.Call(JumpNoteProtocol.DevicesUnregister.METHOD);
                JSONObject params = new JSONObject();
                params.put(JumpNoteProtocol.DevicesUnregister.ARG_DEVICE_ID, clientDeviceId);
                deviceRegCall.setParams(params);
            }
        } catch (JSONException e) {
            logErrorMessage("Error generating device registration remote RPC parameters.", manualSync);
            e.printStackTrace();
            return;
        }
    } else {
        deviceRegChange = 0;
    }

    // Get the list of locally changed notes. If this is an upload-only sync and there were
    // no local changes, cancel the sync.
    List<ModelJava.Note> locallyChangedNotes = null;
    try {
        locallyChangedNotes = getLocallyChangedNotes(provider, account, new Date(lastSyncTime));
    } catch (RemoteException e) {
        logErrorMessage("Remote exception accessing content provider: " + e.getMessage(), manualSync);
        e.printStackTrace();
        syncResult.stats.numIoExceptions++;
        return;
    }

    if (uploadOnly && locallyChangedNotes.isEmpty() && deviceRegCall == null) {
        Log.i(TAG, "No local changes; upload-only sync canceled.");
        return;
    }

    // Set up the RPC sync calls
    final AuthenticatedJsonRpcJavaClient jsonRpcClient = new AuthenticatedJsonRpcJavaClient(mContext,
            Config.SERVER_AUTH_URL_TEMPLATE, Config.SERVER_RPC_URL);
    try {
        jsonRpcClient.blockingAuthenticateAccount(account,
                manualSync ? AuthenticatedJsonRpcJavaClient.NEED_AUTH_INTENT
                        : AuthenticatedJsonRpcJavaClient.NEED_AUTH_NOTIFICATION,
                false);
    } catch (AuthenticationException e) {
        logErrorMessage("Authentication exception when attempting to sync.", manualSync);
        e.printStackTrace();
        syncResult.stats.numAuthExceptions++;
        return;
    } catch (OperationCanceledException e) {
        Log.i(TAG, "Sync for account " + account.name + " manually canceled.");
        return;
    } catch (RequestedUserAuthenticationException e) {
        syncResult.stats.numAuthExceptions++;
        return;
    } catch (InvalidAuthTokenException e) {
        logErrorMessage("Invalid auth token provided by AccountManager when attempting to " + "sync.",
                manualSync);
        e.printStackTrace();
        syncResult.stats.numAuthExceptions++;
        return;
    }

    // Set up the notes sync call.
    JsonRpcClient.Call notesSyncCall = new JsonRpcClient.Call(JumpNoteProtocol.NotesSync.METHOD);
    try {
        JSONObject params = new JSONObject();
        params.put(JumpNoteProtocol.ARG_CLIENT_DEVICE_ID, clientDeviceId);
        params.put(JumpNoteProtocol.NotesSync.ARG_SINCE_DATE,
                Util.formatDateISO8601(new Date(lastServerSyncTime)));

        JSONArray locallyChangedNotesJson = new JSONArray();
        for (ModelJava.Note locallyChangedNote : locallyChangedNotes) {
            locallyChangedNotesJson.put(locallyChangedNote.toJSON());
        }

        params.put(JumpNoteProtocol.NotesSync.ARG_LOCAL_NOTES, locallyChangedNotesJson);
        notesSyncCall.setParams(params);
    } catch (JSONException e) {
        logErrorMessage("Error generating sync remote RPC parameters.", manualSync);
        e.printStackTrace();
        syncResult.stats.numParseExceptions++;
        return;
    }

    List<JsonRpcClient.Call> jsonRpcCalls = new ArrayList<JsonRpcClient.Call>();
    jsonRpcCalls.add(notesSyncCall);
    if (deviceRegChange != 0)
        jsonRpcCalls.add(deviceRegCall);

    jsonRpcClient.callBatch(jsonRpcCalls, new JsonRpcClient.BatchCallback() {
        public void onData(Object[] data) {
            if (data[0] != null) {
                // Read notes sync data.
                JSONObject dataJson = (JSONObject) data[0];
                try {
                    List<ModelJava.Note> changedNotes = new ArrayList<ModelJava.Note>();
                    JSONArray notesJson = dataJson.getJSONArray(JumpNoteProtocol.NotesSync.RET_NOTES);
                    for (int i = 0; i < notesJson.length(); i++) {
                        changedNotes.add(new ModelJava.Note(notesJson.getJSONObject(i)));
                    }

                    reconcileSyncedNotes(provider, account, changedNotes, syncResult.stats);

                    // If sync is successful (no exceptions thrown), update sync metadata
                    long newServerSyncTime = Util
                            .parseDateISO8601(dataJson.getString(JumpNoteProtocol.NotesSync.RET_NEW_SINCE_DATE))
                            .getTime();
                    syncMeta.edit().putLong(LAST_SYNC, newSyncTime).commit();
                    syncMeta.edit().putLong(SERVER_LAST_SYNC, newServerSyncTime).commit();
                    Log.i(TAG, "Sync complete, setting last sync time to " + Long.toString(newSyncTime));
                } catch (JSONException e) {
                    logErrorMessage("Error parsing note sync RPC response", manualSync);
                    e.printStackTrace();
                    syncResult.stats.numParseExceptions++;
                    return;
                } catch (ParseException e) {
                    logErrorMessage("Error parsing note sync RPC response", manualSync);
                    e.printStackTrace();
                    syncResult.stats.numParseExceptions++;
                    return;
                } catch (RemoteException e) {
                    logErrorMessage("RemoteException in reconcileSyncedNotes: " + e.getMessage(), manualSync);
                    e.printStackTrace();
                    return;
                } catch (OperationApplicationException e) {
                    logErrorMessage("Could not apply batch operations to content provider: " + e.getMessage(),
                            manualSync);
                    e.printStackTrace();
                    return;
                } finally {
                    provider.release();
                }
            }

            // Read device reg data.
            if (deviceRegChange != 0) {
                // data[1] will be null in case of an error (successful unregisters
                // will have an empty JSONObject, not null).
                boolean registered = (data[1] != null && deviceRegChange == 1);
                syncMeta.edit().putBoolean(DM_REGISTERED, registered).commit();
                if (Log.isLoggable(TAG, Log.DEBUG)) {
                    Log.d(TAG, "Stored account auto sync registration state: " + Boolean.toString(registered));
                }
            }
        }

        public void onError(int callIndex, JsonRpcException e) {
            if (e.getHttpCode() == 403) {
                Log.w(TAG, "Got a 403 response, invalidating App Engine ACSID token");
                jsonRpcClient.invalidateAccountAcsidToken(account);
            }

            provider.release();
            logErrorMessage("Error calling remote note sync RPC", manualSync);
            e.printStackTrace();
        }
    });
}