/*
* Copyright (c) 2015 Jonas Kalderstam.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nononsenseapps.notepad.data.service.gtasks;
import android.accounts.Account;
import android.content.AbstractThreadedSyncAdapter;
import android.content.ContentProviderClient;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SyncResult;
import android.os.Bundle;
import android.preference.PreferenceManager;
import com.nononsenseapps.notepad.ui.settings.SyncPrefs;
import com.nononsenseapps.notepad.data.remote.gtasks.GoogleTaskSync;
/**
* This adapter syncs with GoogleTasks API. Each sync is an incremental sync
* from our last sync. This is accomplished with a combinatinon of etags and
* last updated time stamp. The API returns a "global" e-tag (hash-value of all
* content). If this is the same as the etag we have, then nothing has changed
* on server. Hence, we can know that there is nothing to download. If the etag
* has changed, the adapter requests, for all lists, all tasks which have been
* updated since the latest synced task in the database.
*
* Before any changes are committed either way, we should have two DISJOINT
* sets:
*
* TasksFromServer and TasksToServer.
*
* Due to the conflict resolution, no task should exist in both sets. We then
* upload TasksToServer. For each upload the server will return the current
* state of the task with some fields updated. These changes we want to save of
* course, so we add them to TasksFromServer. Which means that after uploading
* we have a single set:
*
* TasksFromServer
*
* Which now contains all tasks that were modified either locally or remotely.
* In other words, this set is now the union of the two initially disjoint sets,
* with some fields updated by the server.
*
* These tasks are then committed to the database in a single transaction.
*/
public class SyncAdapter extends AbstractThreadedSyncAdapter {
public static final String SYNC_STARTED = "com.nononsenseapps.notepad.sync.SYNC_STARTED";
public static final String SYNC_FINISHED = "com.nononsenseapps.notepad.sync.SYNC_FINISHED";
public static final String SYNC_RESULT = "com.nononsenseapps.notepad.sync.SYNC_RESULT";
public static final int SUCCESS = 0;
public static final int LOGIN_FAIL = 1;
public static final int ERROR = 2;
private final Context mContext;
public SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
mContext = context;
}
@Override
public void onPerformSync(Account account, Bundle extras, String authority,
ContentProviderClient provider, SyncResult syncResult) {
final SharedPreferences settings = PreferenceManager
.getDefaultSharedPreferences(mContext);
/*
* Only sync if it has been enabled by the user, and account is selected
* Issue on reinstall where account approval is remembered by system
* Also only sync if APIKEY has no spaces in it. A space in the key
* means that the app has been built from the open source code, for
* which the api key is naturally not included. A space also causes the
* app to crash since that is entirely invalid. So don't sync if there
* is a space in the api key.
*/
Intent doneIntent = new Intent(SYNC_FINISHED);
doneIntent.putExtra(SYNC_RESULT, ERROR);
try {
// Gtasks first
// Dummy key has a space in it. Only builds using real api keys
// should not have spaces
if (com.nononsenseapps.build.Config.getGtasksApiKey(mContext) !=
null && !com.nononsenseapps.build.Config
.getGtasksApiKey(mContext).contains(" ")) {
if (settings.getBoolean(SyncPrefs.KEY_SYNC_ENABLE, false)
&& !settings.getString(SyncPrefs.KEY_ACCOUNT, "")
.isEmpty()
&& account.name.equals(settings.getString(
SyncPrefs.KEY_ACCOUNT, ""))) {
mContext.sendBroadcast(new Intent(SYNC_STARTED));
if (GoogleTaskSync.fullSync(mContext,
account, extras, authority, provider, syncResult)) {
// Success
doneIntent.putExtra(SYNC_RESULT, SUCCESS);
}
}
}
}
finally {
mContext.sendBroadcast(doneIntent);
}
}
}