@Override public void onReceive(Context context, Intent intent) { lastSyncFromNetworkChange = Preferences.getLong(PREF_LAST_SYNC_FROM_NETWORK_CHANGE, 0L); if (DateUtilities.now() - lastSyncFromNetworkChange > DateUtilities.ONE_MINUTE * 10) { NetworkInfo info = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO); if (info != null && NetworkInfo.State.CONNECTED.equals(info.getState()) && PluginServices.getActFmPreferenceService().isLoggedIn()) { ActFmSyncThread syncThread = ActFmSyncThread.getInstance(); syncThread.repopulateQueueFromOutstandingTables(); Preferences.setLong(PREF_LAST_SYNC_FROM_NETWORK_CHANGE, DateUtilities.now()); } } }
private void sync() { try { int batchSize = 4; List<ClientToServerMessage<?>> messageBatch = new ArrayList<ClientToServerMessage<?>>(); while (true) { synchronized (monitor) { while ((pendingMessages.isEmpty() && !timeForBackgroundSync()) || !actFmPreferenceService.isLoggedIn() || !syncMigration) { try { if ((pendingMessages.isEmpty() || !actFmPreferenceService.isLoggedIn()) && notificationId >= 0) { notificationManager.cancel(notificationId); notificationId = -1; } monitor.wait(); AndroidUtilities.sleepDeep( 500L); // Wait briefly for large database operations to finish (e.g. adding a task // with several tags may trigger a message before all saves are done--fix // this?) if (!syncMigration) { syncMigration = Preferences.getBoolean(AstridNewSyncMigrator.PREF_SYNC_MIGRATION, false); } } catch (InterruptedException e) { // Ignored } } } boolean recordSyncSuccess = true; if (timeForBackgroundSync()) { repopulateQueueFromOutstandingTables(); enqueueMessage( BriefMe.instantiateBriefMeForClass( TaskListMetadata.class, NameMaps.PUSHED_AT_TASK_LIST_METADATA), DEFAULT_REFRESH_RUNNABLE); enqueueMessage( BriefMe.instantiateBriefMeForClass(Task.class, NameMaps.PUSHED_AT_TASKS), DEFAULT_REFRESH_RUNNABLE); enqueueMessage( BriefMe.instantiateBriefMeForClass(TagData.class, NameMaps.PUSHED_AT_TAGS), DEFAULT_REFRESH_RUNNABLE); enqueueMessage( BriefMe.instantiateBriefMeForClass(User.class, NameMaps.PUSHED_AT_USERS), DEFAULT_REFRESH_RUNNABLE); setTimeForBackgroundSync(false); } while (messageBatch.size() < batchSize && !pendingMessages.isEmpty()) { ClientToServerMessage<?> message = pendingMessages.remove(0); if (message != null) { messageBatch.add(message); } } if (!messageBatch.isEmpty() && checkForToken()) { JSONPayloadBuilder payload = new JSONPayloadBuilder(); MultipartEntity entity = new MultipartEntity(); boolean containsChangesHappened = false; for (int i = 0; i < messageBatch.size(); i++) { ClientToServerMessage<?> message = messageBatch.get(i); boolean success = payload.addMessage(message, entity); if (success) { if (message instanceof ChangesHappened) { containsChangesHappened = true; } } else { messageBatch.remove(i); i--; } } if (payload.getMessageCount() == 0) { messageBatch.clear(); continue; } setupNotification(); payload.addJSONObject(getClientVersion()); JSONArray errors = null; try { JSONObject response = actFmInvoker.postSync( payload.closeAndReturnString(), entity, containsChangesHappened, token); // process responses String time = response.optString("time"); JSONArray serverMessagesJson = response.optJSONArray("messages"); if (serverMessagesJson != null) { setWidgetSuppression(true); for (int i = 0; i < serverMessagesJson.length(); i++) { JSONObject serverMessageJson = serverMessagesJson.optJSONObject(i); if (serverMessageJson != null) { ServerToClientMessage serverMessage = ServerToClientMessage.instantiateMessage(serverMessageJson); if (serverMessage != null) { serverMessage.processMessage(time); } else { syncLog( "Index " + i + " unable to instantiate message " + serverMessageJson.toString()); } } } errors = response.optJSONArray("errors"); boolean errorsExist = (errors != null && errors.length() > 0); replayOutstandingChanges(errorsExist); setWidgetSuppression(false); } batchSize = Math.max(12, Math.min(batchSize, messageBatch.size()) * 2); if (recordSyncSuccess) { actFmPreferenceService.setLastError(null, null); actFmPreferenceService.recordSuccessfulSync(); } } catch (IOException e) { Log.e(ERROR_TAG, "IOException", e); batchSize = Math.max(batchSize / 2, 1); } Set<SyncMessageCallback> callbacksExecutedThisLoop = new HashSet<SyncMessageCallback>(); Map<Integer, List<JSONArray>> errorMap = buildErrorMap(errors); for (int i = 0; i < messageBatch.size(); i++) { ClientToServerMessage<?> message = messageBatch.get(i); try { SyncMessageCallback r = pendingCallbacks.remove(message); if (r != null && !callbacksExecutedThisLoop.contains(r)) { List<JSONArray> errorList = errorMap.get(i); if (errorList == null || errorList.isEmpty()) { r.runOnSuccess(); } else { r.runOnErrors(errorList); } callbacksExecutedThisLoop.add(r); } } catch (Exception e) { Log.e(ERROR_TAG, "Unexpected exception executing sync callback", e); } } messageBatch.clear(); } } } catch (Exception e) { // In the worst case, restart thread if something goes wrong Log.e(ERROR_TAG, "Unexpected sync thread exception", e); thread = null; startSyncThread(); } }