package com.boardgamegeek.service; import android.app.IntentService; import android.content.Context; import android.content.Intent; import android.support.annotation.NonNull; import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat.Builder; import android.text.TextUtils; import com.boardgamegeek.R; import com.boardgamegeek.events.UpdateCompleteEvent; import com.boardgamegeek.events.UpdateErrorEvent; import com.boardgamegeek.events.UpdateEvent; import com.boardgamegeek.provider.BggContract; import com.boardgamegeek.util.NetworkUtils; import com.boardgamegeek.util.NotificationUtils; import com.boardgamegeek.util.PreferencesUtils; import org.greenrobot.eventbus.EventBus; import timber.log.Timber; public class UpdateService extends IntentService { private static final String KEY_SYNC_TYPE = "KEY_SYNC_TYPE"; private static final String KEY_SYNC_ID = "KEY_SYNC_ID"; private static final String KEY_SYNC_KEY = "KEY_SYNC_KEY"; public static final int SYNC_TYPE_GAME = 1; public static final int SYNC_TYPE_GAME_PLAYS = 2; public static final int SYNC_TYPE_GAME_COLLECTION = 3; public static final int SYNC_TYPE_BUDDY = 4; public static final int SYNC_TYPE_BUDDY_SELF = 5; public static final int SYNC_TYPE_DESIGNER = 10; public static final int SYNC_TYPE_ARTIST = 11; public static final int SYNC_TYPE_PUBLISHER = 12; public static final int SYNC_TYPE_PLAYS_DATE = 20; private static final int SYNC_TYPE_UNKNOWN = 0; public static void start(@NonNull Context context, int type, int id) { context.startService(new Intent(Intent.ACTION_SYNC, null, context, UpdateService.class) .putExtra(KEY_SYNC_TYPE, type) .putExtra(KEY_SYNC_ID, id)); } public static void start(@NonNull Context context, int type, String key) { context.startService(new Intent(Intent.ACTION_SYNC, null, context, UpdateService.class) .putExtra(KEY_SYNC_TYPE, type) .putExtra(KEY_SYNC_KEY, key)); } public UpdateService() { super("BGG-UpdateService"); } @Override protected void onHandleIntent(Intent intent) { if (intent == null) { Timber.i("Null intent"); return; } Timber.d("onHandleIntent(intent=%s)", intent); if (!Intent.ACTION_SYNC.equals(intent.getAction())) { Timber.w("Invalid intent action: %s", intent.getAction()); return; } if (NetworkUtils.isOffline(getApplicationContext())) { Timber.i("Skipping update; offline"); return; } int syncType = intent.getIntExtra(KEY_SYNC_TYPE, SYNC_TYPE_UNKNOWN); int syncId = intent.getIntExtra(KEY_SYNC_ID, BggContract.INVALID_ID); String syncKey = intent.getStringExtra(KEY_SYNC_KEY); UpdateTask task = createUpdateTask(syncType, syncId, syncKey); if (task.isValid()) { executeTask(syncType, task); } else { postError(getString(R.string.sync_msg_invalid, task.getDescription(getApplicationContext()))); } } private void executeTask(int syncType, @NonNull UpdateTask task) { final long startTime = signalStart(syncType); try { task.execute(this); } catch (Exception e) { Timber.e(e, "Error executing task"); String message = createErrorMessage(task, e); maybeShowNotification(message); postError(message); } finally { signalEnd(startTime); } } private long signalStart(int syncType) { EventBus.getDefault().postSticky(new UpdateEvent(syncType)); return System.currentTimeMillis(); } private void signalEnd(long startTime) { Timber.d("Sync took %,d ms", System.currentTimeMillis() - startTime); EventBus.getDefault().removeStickyEvent(UpdateEvent.class); EventBus.getDefault().post(new UpdateCompleteEvent()); } @NonNull private UpdateTask createUpdateTask(int syncType, int syncId, String syncKey) { UpdateTask task = new InvalidUpdateTask(syncType); switch (syncType) { case SYNC_TYPE_GAME: task = new SyncGame(syncId); break; case SYNC_TYPE_GAME_PLAYS: task = new SyncGamePlays(syncId); break; case SYNC_TYPE_GAME_COLLECTION: task = new SyncGameCollection(syncId); break; case SYNC_TYPE_BUDDY: task = new SyncBuddy(syncKey); break; case SYNC_TYPE_BUDDY_SELF: task = new SyncBuddySelf(); break; case SYNC_TYPE_DESIGNER: task = new SyncDesigner(syncId); break; case SYNC_TYPE_ARTIST: task = new SyncArtist(syncId); break; case SYNC_TYPE_PUBLISHER: task = new SyncPublisher(syncId); break; case SYNC_TYPE_PLAYS_DATE: task = new SyncPlaysByDate(syncKey); break; } return task; } @NonNull private String createErrorMessage(@NonNull UpdateTask task, @NonNull Exception e) { String message = getString(R.string.sync_msg_error, task.getDescription(getApplicationContext())); String error = e.getLocalizedMessage(); if (!TextUtils.isEmpty(error)) { message += "\n" + error; } return message; } private void maybeShowNotification(String message) { if (PreferencesUtils.getSyncShowNotifications(this)) { Builder builder = NotificationUtils .createNotificationBuilder(getApplicationContext(), R.string.title_error) .setCategory(NotificationCompat.CATEGORY_ERROR); builder.setContentText(message).setStyle(new NotificationCompat.BigTextStyle().bigText(message)); NotificationUtils.notify(getApplicationContext(), NotificationUtils.TAG_UPDATE_ERROR, 0, builder); } } private void postError(String message) { Timber.w(message); EventBus.getDefault().post(new UpdateErrorEvent(message)); } }