diff --git a/src/org/geometerplus/android/fbreader/network/auth/ServiceNetworkContext.java b/src/org/geometerplus/android/fbreader/network/auth/ServiceNetworkContext.java index 8ac0bcbe1..0be9ab9e4 100644 --- a/src/org/geometerplus/android/fbreader/network/auth/ServiceNetworkContext.java +++ b/src/org/geometerplus/android/fbreader/network/auth/ServiceNetworkContext.java @@ -25,7 +25,7 @@ import java.util.Map; import android.app.Service; import android.content.Context; -public final class ServiceNetworkContext extends AndroidNetworkContext { +public class ServiceNetworkContext extends AndroidNetworkContext { private final Service myService; public ServiceNetworkContext(Service service) { diff --git a/src/org/geometerplus/android/fbreader/synchroniser/SynchroniserService.java b/src/org/geometerplus/android/fbreader/synchroniser/SynchroniserService.java index 15e80bd39..669b69126 100644 --- a/src/org/geometerplus/android/fbreader/synchroniser/SynchroniserService.java +++ b/src/org/geometerplus/android/fbreader/synchroniser/SynchroniserService.java @@ -24,6 +24,8 @@ import java.util.*; import android.app.Service; import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; import android.os.IBinder; import org.json.simple.JSONValue; @@ -32,6 +34,7 @@ import org.geometerplus.zlibrary.core.filesystem.ZLPhysicalFile; import org.geometerplus.zlibrary.core.network.*; import org.geometerplus.zlibrary.ui.android.network.SQLiteCookieDatabase; import org.geometerplus.fbreader.book.*; +import org.geometerplus.fbreader.fbreader.options.SyncOptions; import org.geometerplus.android.fbreader.libraryService.BookCollectionShadow; import org.geometerplus.android.fbreader.network.auth.ServiceNetworkContext; @@ -41,6 +44,7 @@ public class SynchroniserService extends Service implements IBookCollection.List Uploaded(Book.SYNCHRONIZED_LABEL), ToBeDeleted(Book.SYNC_DELETED_LABEL), Failure(Book.SYNC_FAILURE_LABEL), + SyncronizationDisabled(null), FailedPreviuousTime(null), HashNotComputed(null); @@ -58,14 +62,31 @@ public class SynchroniserService extends Service implements IBookCollection.List } } - private final ZLNetworkContext myNetworkContext = new ServiceNetworkContext(this); + private final ConnectivityManager myConnectivityManager = + (ConnectivityManager)getSystemService(CONNECTIVITY_SERVICE); + private final SyncOptions mySyncOptions = new SyncOptions(); + + private static final class SyncronizationDisabledException extends RuntimeException { + } + + private final ZLNetworkContext myNetworkContext = new ServiceNetworkContext(this) { + @Override + protected void perform(ZLNetworkRequest request, int socketTimeout, int connectionTimeout) throws ZLNetworkException { + if (!canPerformRequest()) { + throw new SyncronizationDisabledException(); + } + super.perform(request, socketTimeout, connectionTimeout); + } + }; private final BookCollectionShadow myCollection = new BookCollectionShadow(); private static volatile Thread ourSynchronizationThread; private final List myQueue = Collections.synchronizedList(new LinkedList()); private final Set myProcessed = new HashSet(); + private final Set myActualHashesFromServer = new HashSet(); private final Set myDeletedHashesFromServer = new HashSet(); + private volatile boolean myHashTablesAreInitialized = false; @Override public IBinder onBind(Intent intent) { @@ -80,6 +101,54 @@ public class SynchroniserService extends Service implements IBookCollection.List } } + private synchronized void clearHashTables() { + myActualHashesFromServer.clear(); + myDeletedHashesFromServer.clear(); + myHashTablesAreInitialized = false; + } + + private synchronized void initHashTables() { + if (myHashTablesAreInitialized) { + return; + } + + try { + myNetworkContext.perform(new PostRequest("all.hashes", null) { + @Override + public void processResponse(Object response) { + final Map> map = (Map>)response; + myActualHashesFromServer.addAll(map.get("actual")); + myDeletedHashesFromServer.addAll(map.get("deleted")); + myHashTablesAreInitialized = true; + } + }); + System.err.println(String.format("RECEIVED: %s/%s HASHES", myActualHashesFromServer.size(), myDeletedHashesFromServer.size())); + } catch (SyncronizationDisabledException e) { + throw e; + } catch (Exception e) { + e.printStackTrace(); + } + } + + private boolean canPerformRequest() { + if (!mySyncOptions.Enabled.getValue()) { + return false; + } + + switch (mySyncOptions.UploadAllBooks.getValue()) { + default: + case never: + return false; + case always: + return myConnectivityManager.getActiveNetworkInfo().isConnected(); + case viaWifi: + { + final NetworkInfo info = myConnectivityManager.getActiveNetworkInfo(); + return info.isConnected() && info.getType() == ConnectivityManager.TYPE_WIFI; + } + } + } + @Override public synchronized void run() { myCollection.addListener(this); @@ -90,23 +159,7 @@ public class SynchroniserService extends Service implements IBookCollection.List int count = 0; final Map statusCounts = new HashMap(); try { - myActualHashesFromServer.clear(); - myDeletedHashesFromServer.clear(); - try { - myNetworkContext.perform(new PostRequest("all.hashes", null) { - @Override - public void processResponse(Object response) { - final Map> map = (Map>)response; - myActualHashesFromServer.addAll(map.get("actual")); - myDeletedHashesFromServer.addAll(map.get("deleted")); - } - }); - System.err.println(String.format("RECEIVED: %s/%s HASHES", myActualHashesFromServer.size(), myDeletedHashesFromServer.size())); - } catch (Exception e) { - e.printStackTrace(); - System.err.println("DO NOT SYNCHRONIZE: ALL HASHES REQUEST FAILED"); - return; - } + clearHashTables(); for (BookQuery q = new BookQuery(new Filter.Empty(), 20);; q = q.next()) { final List books = myCollection.books(q); if (books.isEmpty()) { @@ -210,6 +263,14 @@ public class SynchroniserService extends Service implements IBookCollection.List } private SyncStatus uploadBookToServer(Book book) { + try { + return uploadBookToServerInternal(book); + } catch (SyncronizationDisabledException e) { + return SyncStatus.SyncronizationDisabled; + } + } + + private SyncStatus uploadBookToServerInternal(Book book) { final ZLPhysicalFile file = book.File.getPhysicalFile(); final String hash = myCollection.getHash(book); final boolean force = book.labels().contains(Book.SYNC_TOSYNC_LABEL); @@ -222,6 +283,9 @@ public class SynchroniserService extends Service implements IBookCollection.List } else if (!force && book.labels().contains(Book.SYNC_FAILURE_LABEL)) { return SyncStatus.FailedPreviuousTime; } + + initHashTables(); + final Map result = new HashMap(); final PostRequest verificationRequest = new PostRequest("book.status.by.hash", Collections.singletonMap("sha1", hash)) { diff --git a/src/org/geometerplus/zlibrary/core/network/ZLNetworkContext.java b/src/org/geometerplus/zlibrary/core/network/ZLNetworkContext.java index 78f907dec..7a926100c 100644 --- a/src/org/geometerplus/zlibrary/core/network/ZLNetworkContext.java +++ b/src/org/geometerplus/zlibrary/core/network/ZLNetworkContext.java @@ -59,7 +59,15 @@ public abstract class ZLNetworkContext implements ZLNetworkManager.BearerAuthent getAccountOption(host, realm).setValue(accountName != null ? accountName : ""); } - public boolean performQuietly(ZLNetworkRequest request) { + protected void perform(ZLNetworkRequest request, int socketTimeout, int connectionTimeout) throws ZLNetworkException { + myManager.perform(request, this, socketTimeout, connectionTimeout); + } + + public final void perform(ZLNetworkRequest request) throws ZLNetworkException { + perform(request, 30000, 15000); + } + + public final boolean performQuietly(ZLNetworkRequest request) { try { perform(request); return true; @@ -68,11 +76,7 @@ public abstract class ZLNetworkContext implements ZLNetworkManager.BearerAuthent } } - public void perform(ZLNetworkRequest request) throws ZLNetworkException { - myManager.perform(request, this, 30000, 15000); - } - - public void perform(List requests) throws ZLNetworkException { + public final void perform(List requests) throws ZLNetworkException { if (requests.size() == 0) { return; } @@ -107,7 +111,7 @@ public abstract class ZLNetworkContext implements ZLNetworkManager.BearerAuthent } private final void downloadToFile(String url, final File outFile, final int bufferSize) throws ZLNetworkException { - myManager.perform(new ZLNetworkRequest.Get(url) { + perform(new ZLNetworkRequest.Get(url) { public void handleStream(InputStream inputStream, int length) throws IOException, ZLNetworkException { OutputStream outStream = new FileOutputStream(outFile); try { @@ -123,7 +127,7 @@ public abstract class ZLNetworkContext implements ZLNetworkManager.BearerAuthent outStream.close(); } } - }, this, 0, 0); + }, 0, 0); } private ZLStringOption getAccountOption(String host, String realm) {