@Override protected void doWork(final Intent i) { final Prefs prefs = new Prefs(getBaseContext()); final Config conf; try { conf = prefs.asConfig(); } catch (final JSONException e) { LOG.w("Can not send to Hosaka: %s", e.toString()); return; } // XXX Currently this assumes only one Hosaka account. // TODO Make UI stop user adding more than one Hosaka account. final Account account = conf.firstAccountOfType(AccountProvider.HOSAKA); if (account == null) { LOG.i("Not sending to Hosaka: no account found."); return; } if (!waitForDbReady()) return; final DbInterface db = getDb(); SaveScrollNow.requestAndWaitForUiToSaveScroll(db); final Map<String, Column> hashToCol = new HashMap<String, Column>(); final Map<String, HosakaColumn> toPush = new HashMap<String, HosakaColumn>(); for (final Column col : conf.getColumns()) { if (InternalColumnType.fromColumn(col) != null) continue; // Do not sync internal columns. final String hash = HosakaColumn.columnHash(col, conf); hashToCol.put(hash, col); final ScrollState ss = db.getScroll(col.getId()); if (ss == null) continue; // In case of (new) empty columns. // Always add all columns, even if sent before new values. // - Old / regressed values will be filtered server side. // - Values sent can be used to filter response. // - Also useful as do not know state of remote DB. toPush.put( hash, new HosakaColumn( null /* ss.getItemId(); TODO ScrollState to also store sid? */, ss.getItemTime(), ss.getUnreadTime(), ss.getScrollDirection())); } final HosakaProvider prov = new HosakaProvider(); try { // Make POST even if not really sending anything new, as may be fetching new state. final long startTime = now(); final Map<String, HosakaColumn> returnedColumns = prov.sendColumns(account, toPush); final long durationMillis = TimeUnit.NANOSECONDS.toMillis(now() - startTime); LOG.i("Sent %s in %d millis: %s", account.getAccessToken(), durationMillis, toPush); final boolean syncScroll = prefs.getSharedPreferences().getBoolean(FetchingPrefFragment.KEY_SYNC_SCROLL, false); final Map<Column, ScrollState> colToNewScroll = new HashMap<Column, ScrollState>(); for (final Entry<String, HosakaColumn> e : returnedColumns.entrySet()) { final String hash = e.getKey(); final Column col = hashToCol.get(hash); final HosakaColumn before = toPush.get(hash); final HosakaColumn after = e.getValue(); if (col != null && before != null && (after.getUnreadTime() > before.getUnreadTime() || (syncScroll && before.getScrollDirection() == ScrollDirection.UP && after.getItemTime() > before.getItemTime()))) { colToNewScroll.put(col, after.toScrollState()); } } db.mergeAndStoreScrolls( colToNewScroll, syncScroll ? ScrollChangeType.UNREAD_AND_SCROLL : ScrollChangeType.UNREAD); LOG.i("Merged %s columns: %s.", colToNewScroll.size(), colToNewScroll); storeResult(db, toPush.size(), colToNewScroll.size(), null); } catch (final IOException e) { storeResult(db, toPush.size(), 0, e); } catch (final JSONException e) { storeResult(db, toPush.size(), 0, e); } finally { prov.shutdown(); } }
public static InternalColumnType fromColumn(final Column col) { for (final InternalColumnType t : InternalColumnType.values()) { if (t.matchesColumn(col)) return t; } return null; }