use of bolts.Continuation in project facebook-android-sdk by facebook.
the class FacebookAppLinkResolverTests method executeResolverOnBlockerThread.
public void executeResolverOnBlockerThread(final FacebookAppLinkResolver resolver, final Uri testUrl) {
final TestBlocker blocker = getTestBlocker();
Runnable runnable = new Runnable() {
public void run() {
try {
resolveTask = resolver.getAppLinkFromUrlInBackground(testUrl);
resolveTask.continueWith(new Continuation() {
@Override
public Object then(Task task) throws Exception {
// Once the task is complete, unblock the test thread, so it can inspect for errors/results.
blocker.signal();
return null;
}
});
} catch (Exception e) {
// Get back to the test case if there was an uncaught exception
blocker.signal();
}
}
};
Handler handler = new Handler(blocker.getLooper());
handler.post(runnable);
}
use of bolts.Continuation in project Parse-SDK-Android by ParsePlatform.
the class ParseCommandCache method maybeRunAllCommandsNow.
/**
* Attempts to run every command in the disk queue in order, synchronously. If there is no network
* connection, returns immediately without doing anything. If there is supposedly a connection,
* but parse can't be reached, waits timeoutRetryWaitSeconds before retrying up to
* retriesRemaining times. Blocks until either there's a connection, or the retries are exhausted.
* If any command fails, just deletes it and moves on to the next one.
*/
private void maybeRunAllCommandsNow(int retriesRemaining) {
synchronized (lock) {
unprocessedCommandsExist = false;
if (!isConnected()) {
// There's no way to do work when there's no network connection.
return;
}
String[] fileNames = cachePath.list();
if (fileNames == null || fileNames.length == 0) {
return;
}
Arrays.sort(fileNames);
for (String fileName : fileNames) {
final File file = new File(cachePath, fileName);
// Read one command from the cache.
JSONObject json;
try {
json = ParseFileUtils.readFileToJSONObject(file);
} catch (FileNotFoundException e) {
// This shouldn't really be possible.
if (Parse.LOG_LEVEL_ERROR >= Parse.getLogLevel()) {
log.log(Level.SEVERE, "File disappeared from cache while being read.", e);
}
continue;
} catch (IOException e) {
if (Parse.LOG_LEVEL_ERROR >= Parse.getLogLevel()) {
log.log(Level.SEVERE, "Unable to read contents of file in cache.", e);
}
removeFile(file);
continue;
} catch (JSONException e) {
if (Parse.LOG_LEVEL_ERROR >= Parse.getLogLevel()) {
log.log(Level.SEVERE, "Error parsing JSON found in cache.", e);
}
removeFile(file);
continue;
}
// Convert the command from a string.
final ParseRESTCommand command;
final TaskCompletionSource<JSONObject> tcs = pendingTasks.containsKey(file) ? pendingTasks.get(file) : null;
try {
command = commandFromJSON(json);
} catch (JSONException e) {
if (Parse.LOG_LEVEL_ERROR >= Parse.getLogLevel()) {
log.log(Level.SEVERE, "Unable to create ParseCommand from JSON.", e);
}
removeFile(file);
continue;
}
try {
Task<JSONObject> commandTask;
if (command == null) {
commandTask = Task.forResult(null);
if (tcs != null) {
tcs.setResult(null);
}
notifyTestHelper(TestHelper.COMMAND_OLD_FORMAT_DISCARDED);
} else {
commandTask = command.executeAsync(httpClient).continueWithTask(new Continuation<JSONObject, Task<JSONObject>>() {
@Override
public Task<JSONObject> then(Task<JSONObject> task) throws Exception {
String localId = command.getLocalId();
Exception error = task.getError();
if (error != null) {
if (error instanceof ParseException && ((ParseException) error).getCode() == ParseException.CONNECTION_FAILED) {
// do nothing
} else {
if (tcs != null) {
tcs.setError(error);
}
}
return task;
}
JSONObject json = task.getResult();
if (tcs != null) {
tcs.setResult(json);
} else if (localId != null) {
// If this command created a new objectId, add it to the map.
String objectId = json.optString("objectId", null);
if (objectId != null) {
ParseCorePlugins.getInstance().getLocalIdManager().setObjectId(localId, objectId);
}
}
return task;
}
});
}
waitForTaskWithoutLock(commandTask);
if (tcs != null) {
waitForTaskWithoutLock(tcs.getTask());
}
// The command succeeded. Remove it from the cache.
removeFile(file);
notifyTestHelper(TestHelper.COMMAND_SUCCESSFUL);
} catch (ParseException e) {
if (e.getCode() == ParseException.CONNECTION_FAILED) {
if (retriesRemaining > 0) {
// Parse. Wait N minutes, or until we get signaled again before doing anything else.
if (Parse.LOG_LEVEL_INFO >= Parse.getLogLevel()) {
log.info("Network timeout in command cache. Waiting for " + timeoutRetryWaitSeconds + " seconds and then retrying " + retriesRemaining + " times.");
}
long currentTime = System.currentTimeMillis();
long waitUntil = currentTime + (long) (timeoutRetryWaitSeconds * 1000);
while (currentTime < waitUntil) {
// or should stop, just quit.
if (!isConnected() || shouldStop) {
if (Parse.LOG_LEVEL_INFO >= Parse.getLogLevel()) {
log.info("Aborting wait because runEventually thread should stop.");
}
return;
}
try {
lock.wait(waitUntil - currentTime);
} catch (InterruptedException ie) {
shouldStop = true;
}
currentTime = System.currentTimeMillis();
if (currentTime < (waitUntil - (long) (timeoutRetryWaitSeconds * 1000))) {
// This situation should be impossible, so it must mean the clock changed.
currentTime = (waitUntil - (long) (timeoutRetryWaitSeconds * 1000));
}
}
maybeRunAllCommandsNow(retriesRemaining - 1);
} else {
setConnected(false);
notifyTestHelper(TestHelper.NETWORK_DOWN);
}
} else {
if (Parse.LOG_LEVEL_ERROR >= Parse.getLogLevel()) {
log.log(Level.SEVERE, "Failed to run command.", e);
}
// Delete the command from the cache, even though it failed.
// Otherwise, we'll just keep trying it forever.
removeFile(file);
notifyTestHelper(TestHelper.COMMAND_FAILED, e);
}
}
}
}
}
use of bolts.Continuation in project Parse-SDK-Android by ParsePlatform.
the class OfflineStore method saveLocallyAsync.
/**
* Stores a single object in the local database. If the object is a pointer, isn't dirty, and has
* an objectId already, it may not be saved, since it would provide no useful data.
*
* @param object
* The object to save.
* @param db
* A database connection to use.
*/
private Task<Void> saveLocallyAsync(final String key, final ParseObject object, final ParseSQLiteDatabase db) {
// If this is just a clean, unfetched pointer known to Parse, then there is nothing to save.
if (object.getObjectId() != null && !object.isDataAvailable() && !object.hasChanges() && !object.hasOutstandingOperations()) {
return Task.forResult(null);
}
final Capture<String> uuidCapture = new Capture<>();
// Make sure we have a UUID for the object to be saved.
return getOrCreateUUIDAsync(object, db).onSuccessTask(new Continuation<String, Task<Void>>() {
@Override
public Task<Void> then(Task<String> task) throws Exception {
String uuid = task.getResult();
uuidCapture.set(uuid);
return updateDataForObjectAsync(uuid, object, db);
}
}).onSuccessTask(new Continuation<Void, Task<Void>>() {
@Override
public Task<Void> then(Task<Void> task) throws Exception {
final ContentValues values = new ContentValues();
values.put(OfflineSQLiteOpenHelper.KEY_KEY, key);
values.put(OfflineSQLiteOpenHelper.KEY_UUID, uuidCapture.get());
return db.insertWithOnConflict(OfflineSQLiteOpenHelper.TABLE_DEPENDENCIES, values, SQLiteDatabase.CONFLICT_IGNORE);
}
});
}
use of bolts.Continuation in project Parse-SDK-Android by ParsePlatform.
the class OfflineStore method getOrCreateUUIDAsync.
/**
* Gets the UUID for the given object, if it has one. Otherwise, creates a new UUID for the object
* and adds a new row to the database for the object with no data.
*/
private Task<String> getOrCreateUUIDAsync(final ParseObject object, ParseSQLiteDatabase db) {
final String newUUID = UUID.randomUUID().toString();
final TaskCompletionSource<String> tcs = new TaskCompletionSource<>();
synchronized (lock) {
Task<String> uuidTask = objectToUuidMap.get(object);
if (uuidTask != null) {
return uuidTask;
}
// The object doesn't have a UUID yet, so we're gonna have to make one.
objectToUuidMap.put(object, tcs.getTask());
uuidToObjectMap.put(newUUID, object);
fetchedObjects.put(object, tcs.getTask().onSuccess(new Continuation<String, ParseObject>() {
@Override
public ParseObject then(Task<String> task) throws Exception {
return object;
}
}));
}
/*
* We need to put a placeholder row in the database so that later on, the save can just be an
* update. This could be a pointer to an object that itself never gets saved offline, in which
* case the consumer will just have to deal with that.
*/
ContentValues values = new ContentValues();
values.put(OfflineSQLiteOpenHelper.KEY_UUID, newUUID);
values.put(OfflineSQLiteOpenHelper.KEY_CLASS_NAME, object.getClassName());
db.insertOrThrowAsync(OfflineSQLiteOpenHelper.TABLE_OBJECTS, values).continueWith(new Continuation<Void, Void>() {
@Override
public Void then(Task<Void> task) throws Exception {
// This will signal that the UUID does represent a row in the database.
tcs.setResult(newUUID);
return null;
}
});
return tcs.getTask();
}
use of bolts.Continuation in project Parse-SDK-Android by ParsePlatform.
the class Parse method initialize.
public static void initialize(Configuration configuration) {
// NOTE (richardross): We will need this here, as ParsePlugins uses the return value of
// isLocalDataStoreEnabled() to perform additional behavior.
isLocalDatastoreEnabled = configuration.localDataStoreEnabled;
ParsePlugins.Android.initialize(configuration.context, configuration.applicationId, configuration.clientKey);
try {
ParseRESTCommand.server = new URL(configuration.server);
} catch (MalformedURLException ex) {
throw new RuntimeException(ex);
}
Context applicationContext = configuration.context.getApplicationContext();
ParseHttpClient.setKeepAlive(true);
ParseHttpClient.setMaxConnections(20);
// If we have interceptors in list, we have to initialize all http clients and add interceptors
if (configuration.interceptors != null && configuration.interceptors.size() > 0) {
initializeParseHttpClientsWithParseNetworkInterceptors(configuration.interceptors);
}
ParseObject.registerParseSubclasses();
if (configuration.localDataStoreEnabled) {
offlineStore = new OfflineStore(configuration.context);
} else {
ParseKeyValueCache.initialize(configuration.context);
}
// Make sure the data on disk for Parse is for the current
// application.
checkCacheApplicationId();
final Context context = configuration.context;
Task.callInBackground(new Callable<Void>() {
@Override
public Void call() throws Exception {
getEventuallyQueue(context);
return null;
}
});
ParseFieldOperations.registerDefaultDecoders();
if (!allParsePushIntentReceiversInternal()) {
throw new SecurityException("To prevent external tampering to your app's notifications, " + "all receivers registered to handle the following actions must have " + "their exported attributes set to false: com.parse.push.intent.RECEIVE, " + "com.parse.push.intent.OPEN, com.parse.push.intent.DELETE");
}
// May need to update GCM registration ID if app version has changed.
// This also primes current installation.
GcmRegistrar.getInstance().registerAsync().continueWithTask(new Continuation<Void, Task<Void>>() {
@Override
public Task<Void> then(Task<Void> task) throws Exception {
// Prime current user in the background
return ParseUser.getCurrentUserAsync().makeVoid();
}
}).continueWith(new Continuation<Void, Void>() {
@Override
public Void then(Task<Void> task) throws Exception {
// Prime config in the background
ParseConfig.getCurrentConfig();
return null;
}
}, Task.BACKGROUND_EXECUTOR);
if (ManifestInfo.getPushType() == PushType.PPNS) {
PushService.startServiceIfRequired(applicationContext);
}
dispatchOnParseInitialized();
// FYI we probably don't want to do this if we ever add other callbacks.
synchronized (MUTEX_CALLBACKS) {
Parse.callbacks = null;
}
}
Aggregations