package com.boardgamegeek.service; import android.accounts.Account; import android.content.ContentValues; import android.content.Context; import android.support.annotation.NonNull; import com.boardgamegeek.R; import com.boardgamegeek.auth.Authenticator; import com.boardgamegeek.io.Adapter; import com.boardgamegeek.io.BggService; import com.boardgamegeek.model.PlaysResponse; import com.boardgamegeek.model.persister.PlayPersister; import com.boardgamegeek.provider.BggContract; import com.boardgamegeek.provider.BggContract.Games; import com.boardgamegeek.provider.BggContract.Plays; import com.boardgamegeek.util.SelectionBuilder; import java.io.IOException; import hugo.weaving.DebugLog; import retrofit2.Call; import retrofit2.Response; import timber.log.Timber; public class SyncGamePlays extends UpdateTask { private final int gameId; @DebugLog public SyncGamePlays(int gameId) { this.gameId = gameId; } @DebugLog @NonNull @Override public String getDescription(Context context) { if (isValid()) { return context.getString(R.string.sync_msg_game_plays_valid, String.valueOf(gameId)); } return context.getString(R.string.sync_msg_game_plays_invalid); } @DebugLog @Override public boolean isValid() { return gameId != BggContract.INVALID_ID; } @DebugLog @Override public void execute(@NonNull Context context) { Account account = Authenticator.getAccount(context); if (account == null) { return; } BggService service = Adapter.createForXml(); PlayPersister persister = new PlayPersister(context); try { final long startTime = System.currentTimeMillis(); Response<PlaysResponse> response; int page = 1; do { Call<PlaysResponse> call = service.playsByGame(account.name, gameId, page); try { response = call.execute(); if (!response.isSuccessful()) { Timber.w(String.format("Unsuccessful plays fetch with code: %s", response.code())); break; } } catch (IOException e) { Timber.w(String.format("Unsuccessful plays fetch with exception: %s", e.getLocalizedMessage())); break; } persister.save(response.body().plays, startTime); page++; } while (response.body().hasMorePages()); deleteUnupdatedPlays(context, startTime); updateGameTimestamp(context); if (SyncService.isPlaysSyncUpToDate(context)) { SyncService.calculateAndUpdateHIndex(context); } Timber.i("Synced plays for game id=" + gameId); } catch (Exception e) { // TODO bubble error up? Timber.w(e, "Problem syncing plays for game id=" + gameId); } } @DebugLog private void updateGameTimestamp(@NonNull Context context) { ContentValues values = new ContentValues(1); values.put(Games.UPDATED_PLAYS, System.currentTimeMillis()); context.getContentResolver().update(Games.buildGameUri(gameId), values, null, null); } private void deleteUnupdatedPlays(@NonNull Context context, long startTime) { int count = context.getContentResolver().delete(Plays.CONTENT_URI, Plays.SYNC_TIMESTAMP + "<? AND " + Plays.OBJECT_ID + "=? AND " + SelectionBuilder.whereZeroOrNull(Plays.UPDATE_TIMESTAMP) + " AND " + SelectionBuilder.whereZeroOrNull(Plays.DELETE_TIMESTAMP) + " AND " + SelectionBuilder.whereZeroOrNull(Plays.DIRTY_TIMESTAMP), new String[] { String.valueOf(startTime), String.valueOf(gameId) }); Timber.i("Deleted %,d unupdated play(s) of game ID=%s", count, gameId); } }