diff --git a/app/build.gradle b/app/build.gradle index f400c035a..788b2bad7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -25,14 +25,18 @@ dependencies { compile ('com.mapbox.mapboxsdk:mapbox-android-sdk:5.1.0@aar'){ transitive=true } + + compile 'io.reactivex.rxjava2:rxandroid:2.0.1' + // Because RxAndroid releases are few and far between, it is recommended you also + // explicitly depend on RxJava's latest version for bug fixes and new features. + compile 'io.reactivex.rxjava2:rxjava:2.1.2' + + compile 'com.facebook.fresco:fresco:1.3.0' compile 'com.facebook.stetho:stetho:1.5.0' - compile "com.google.guava:guava:${GUAVA_VERSION}" testCompile 'junit:junit:4.12' - testCompile ('org.robolectric:robolectric:3.3.2') { - exclude module: 'guava' - } + testCompile 'org.robolectric:robolectric:3.3.2' testCompile 'com.squareup.okhttp3:mockwebserver:3.8.1' androidTestCompile 'com.squareup.okhttp3:mockwebserver:3.8.1' diff --git a/app/src/main/java/fr/free/nrw/commons/concurrency/BackgroundPoolExceptionHandler.java b/app/src/main/java/fr/free/nrw/commons/concurrency/BackgroundPoolExceptionHandler.java deleted file mode 100644 index 489a45c4e..000000000 --- a/app/src/main/java/fr/free/nrw/commons/concurrency/BackgroundPoolExceptionHandler.java +++ /dev/null @@ -1,19 +0,0 @@ -package fr.free.nrw.commons.concurrency; - -import android.support.annotation.NonNull; - -import fr.free.nrw.commons.BuildConfig; - -public class BackgroundPoolExceptionHandler implements ExceptionHandler { - @Override - public void onException(@NonNull final Throwable t) { - //Crash for debug build - if (BuildConfig.DEBUG) { - Thread thread = new Thread(() -> { - throw new RuntimeException(t); - }); - thread.start(); - } - } -} - diff --git a/app/src/main/java/fr/free/nrw/commons/concurrency/ExceptionAwareThreadPoolExecutor.java b/app/src/main/java/fr/free/nrw/commons/concurrency/ExceptionAwareThreadPoolExecutor.java deleted file mode 100644 index 8196b26e7..000000000 --- a/app/src/main/java/fr/free/nrw/commons/concurrency/ExceptionAwareThreadPoolExecutor.java +++ /dev/null @@ -1,41 +0,0 @@ -package fr.free.nrw.commons.concurrency; - -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.ThreadFactory; - - -class ExceptionAwareThreadPoolExecutor extends ScheduledThreadPoolExecutor { - - private final ExceptionHandler exceptionHandler; - - public ExceptionAwareThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, - ExceptionHandler exceptionHandler) { - super(corePoolSize, threadFactory); - this.exceptionHandler = exceptionHandler; - } - - @Override - protected void afterExecute(Runnable r, Throwable t) { - super.afterExecute(r, t); - if (t == null && r instanceof Future) { - try { - Future future = (Future) r; - if (future.isDone()) future.get(); - } catch (CancellationException | InterruptedException e) { - //ignore - } catch (ExecutionException e) { - t = e.getCause() != null ? e.getCause() : e; - } catch (Exception e) { - t = e; - } - } - - if (t != null) { - exceptionHandler.onException(t); - } - } -} - diff --git a/app/src/main/java/fr/free/nrw/commons/concurrency/ExceptionHandler.java b/app/src/main/java/fr/free/nrw/commons/concurrency/ExceptionHandler.java deleted file mode 100644 index cc5a4c008..000000000 --- a/app/src/main/java/fr/free/nrw/commons/concurrency/ExceptionHandler.java +++ /dev/null @@ -1,7 +0,0 @@ -package fr.free.nrw.commons.concurrency; - -import android.support.annotation.NonNull; - -public interface ExceptionHandler { - void onException(@NonNull Throwable t); -} diff --git a/app/src/main/java/fr/free/nrw/commons/concurrency/ThreadFactoryMaker.java b/app/src/main/java/fr/free/nrw/commons/concurrency/ThreadFactoryMaker.java deleted file mode 100644 index d535fe5bd..000000000 --- a/app/src/main/java/fr/free/nrw/commons/concurrency/ThreadFactoryMaker.java +++ /dev/null @@ -1,25 +0,0 @@ -package fr.free.nrw.commons.concurrency; - -import android.os.Process; -import android.support.annotation.NonNull; - -import java.util.concurrent.ThreadFactory; - -class ThreadFactoryMaker { - public static ThreadFactory get(@NonNull final String name, final int priority) { - return new ThreadFactory() { - private int count = 0; - - @Override - public Thread newThread(@NonNull final Runnable runnable) { - count++; - Runnable wrapperRunnable = () -> { - Process.setThreadPriority(priority); - runnable.run(); - }; - return new Thread(wrapperRunnable, String.format("%s-%s", name, count)); - } - }; - } -} - diff --git a/app/src/main/java/fr/free/nrw/commons/concurrency/ThreadPoolExecutorService.java b/app/src/main/java/fr/free/nrw/commons/concurrency/ThreadPoolExecutorService.java deleted file mode 100644 index 1516d85d8..000000000 --- a/app/src/main/java/fr/free/nrw/commons/concurrency/ThreadPoolExecutorService.java +++ /dev/null @@ -1,101 +0,0 @@ -package fr.free.nrw.commons.concurrency; - -import android.os.Process; -import android.support.annotation.NonNull; - -import java.util.concurrent.Callable; -import java.util.concurrent.Executor; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -public class ThreadPoolExecutorService implements Executor { - private final ScheduledThreadPoolExecutor backgroundPool; - - private ThreadPoolExecutorService(Builder b) { - backgroundPool = new ExceptionAwareThreadPoolExecutor(b.poolSize, - ThreadFactoryMaker.get(b.name, b.priority), b.exceptionHandler); - } - - public ScheduledFuture schedule(Callable callable, long time, TimeUnit timeUnit) { - return backgroundPool.schedule(callable, time, timeUnit); - } - - public ScheduledFuture schedule(Runnable runnable) { - return schedule(runnable, 0, TimeUnit.SECONDS); - } - - public ScheduledFuture schedule(Runnable runnable, long time, TimeUnit timeUnit) { - return backgroundPool.schedule(runnable, time, timeUnit); - } - - public ScheduledFuture scheduleAtFixedRate(final Runnable task, long initialDelay, - long period, final TimeUnit timeUnit) { - return backgroundPool.scheduleAtFixedRate(task, initialDelay, period, timeUnit); - } - - public void shutdown() { - backgroundPool.shutdown(); - } - - @Override - public void execute(Runnable command) { - backgroundPool.execute(command); - } - - /** - * Builder class for {@link ThreadPoolExecutorService} - */ - public static class Builder { - //Required - private final String name; - - //Optional - private int poolSize = 1; - private int priority = Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE; - private ExceptionHandler exceptionHandler = null; - - /** - * @param name the name of the threads in the service. if there are N threads, - * the thread names will be like name-1, name-2, name-3,...,name-N - */ - public Builder(@NonNull String name) { - this.name = name; - } - - /** - * @param poolSize the number of threads to keep in the pool - * @throws IllegalArgumentException if size of pool <=0 - */ - public Builder setPoolSize(int poolSize) throws IllegalArgumentException { - if (poolSize <= 0) { - throw new IllegalArgumentException("Pool size must be grater than 0"); - } - this.poolSize = poolSize; - return this; - } - - /** - * @param priority Priority of the threads in the service. You can supply a constant from - * {@link android.os.Process} - * By default, the priority is set to a value slightly higher than the normal - * background priority - */ - public Builder setPriority(int priority) { - this.priority = priority; - return this; - } - - /** - * @param handler The handler to use to handle exceptions in the service - */ - public Builder setExceptionHandler(ExceptionHandler handler) { - this.exceptionHandler = handler; - return this; - } - - public ThreadPoolExecutorService build() { - return new ThreadPoolExecutorService(this); - } - } -} diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsActivity.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsActivity.java index f1a4adfe2..07921ce02 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsActivity.java @@ -11,7 +11,6 @@ import android.database.DataSetObserver; import android.os.Bundle; import android.os.IBinder; import android.preference.PreferenceManager; -import android.support.annotation.NonNull; import android.support.v4.app.FragmentManager; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; @@ -23,10 +22,6 @@ import android.view.View; import android.widget.Adapter; import android.widget.AdapterView; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; - import java.util.ArrayList; import butterknife.ButterKnife; @@ -38,7 +33,9 @@ import fr.free.nrw.commons.auth.AuthenticatedActivity; import fr.free.nrw.commons.media.MediaDetailPagerFragment; import fr.free.nrw.commons.settings.Prefs; import fr.free.nrw.commons.upload.UploadService; -import fr.free.nrw.commons.utils.ExecutorUtils; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.schedulers.Schedulers; import timber.log.Timber; public class ContributionsActivity @@ -68,6 +65,8 @@ public class ContributionsActivity */ private String CONTRIBUTION_SORT = Contribution.Table.COLUMN_STATE + " DESC, " + Contribution.Table.COLUMN_UPLOADED + " DESC , (" + Contribution.Table.COLUMN_TIMESTAMP + " * " + Contribution.Table.COLUMN_STATE + ")"; + private CompositeDisposable compositeDisposable = new CompositeDisposable(); + private ServiceConnection uploadServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder binder) { @@ -84,6 +83,7 @@ public class ContributionsActivity @Override protected void onDestroy() { + compositeDisposable.clear(); getSupportFragmentManager().removeOnBackStackChangedListener(this); super.onDestroy(); if(isUploadServiceConnected) { @@ -110,6 +110,8 @@ public class ContributionsActivity super.onPause(); } + + @Override protected void onAuthCookieAcquired(String authCookie) { // Do a sync everytime we get here! @@ -268,24 +270,21 @@ public class ContributionsActivity } private void setUploadCount() { - UploadCountClient uploadCountClient = new UploadCountClient(); CommonsApplication application = CommonsApplication.getInstance(); - ListenableFuture future = uploadCountClient - .getUploadCount(application.getCurrentAccount().name); - Futures.addCallback(future, new FutureCallback() { - @Override - public void onSuccess(Integer uploadCount) { - getSupportActionBar().setSubtitle(getResources() - .getQuantityString(R.plurals.contributions_subtitle, - uploadCount, - uploadCount)); - } - @Override - public void onFailure(@NonNull Throwable t) { - Timber.e(t, "Fetching upload count failed"); - } - }, ExecutorUtils.uiExecutor()); + compositeDisposable.add( + RxJava2Tasks.getUploadCount(application.getCurrentAccount().name) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + uploadCount -> + getSupportActionBar().setSubtitle(getResources() + .getQuantityString(R.plurals.contributions_subtitle, + uploadCount, + uploadCount)), + throwable -> Timber.e(throwable, "Fetching upload count failed") + ) + ); } @Override diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/RxJava2Tasks.java b/app/src/main/java/fr/free/nrw/commons/contributions/RxJava2Tasks.java new file mode 100644 index 000000000..dad47f2b0 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/contributions/RxJava2Tasks.java @@ -0,0 +1,30 @@ +package fr.free.nrw.commons.contributions; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Locale; + +import fr.free.nrw.commons.PageTitle; +import io.reactivex.Single; + +class RxJava2Tasks { + + private static final String UPLOAD_COUNT_URL_TEMPLATE = + "https://tools.wmflabs.org/urbanecmbot/uploadsbyuser/uploadsbyuser.py?user=%s"; + + static Single getUploadCount(String userName) { + return Single.fromCallable(() -> { + URL url = new URL(String.format(Locale.ENGLISH, UPLOAD_COUNT_URL_TEMPLATE, + new PageTitle(userName).getText())); + HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); + BufferedReader bufferedReader = new BufferedReader(new + InputStreamReader(urlConnection.getInputStream())); + String uploadCount = bufferedReader.readLine(); + bufferedReader.close(); + urlConnection.disconnect(); + return Integer.parseInt(uploadCount); + }); + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/UploadCountClient.java b/app/src/main/java/fr/free/nrw/commons/contributions/UploadCountClient.java deleted file mode 100644 index 4a04e3888..000000000 --- a/app/src/main/java/fr/free/nrw/commons/contributions/UploadCountClient.java +++ /dev/null @@ -1,54 +0,0 @@ -package fr.free.nrw.commons.contributions; - -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.SettableFuture; - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.Locale; - -import fr.free.nrw.commons.PageTitle; -import fr.free.nrw.commons.concurrency.BackgroundPoolExceptionHandler; -import fr.free.nrw.commons.concurrency.ThreadPoolExecutorService; -import timber.log.Timber; - -class UploadCountClient { - private ThreadPoolExecutorService threadPoolExecutor; - - UploadCountClient() { - threadPoolExecutor = new ThreadPoolExecutorService.Builder("bg-pool") - .setPoolSize(Runtime.getRuntime().availableProcessors()) - .setExceptionHandler(new BackgroundPoolExceptionHandler()) - .build(); - } - - private static final String UPLOAD_COUNT_URL_TEMPLATE = - "https://tools.wmflabs.org/urbanecmbot/uploadsbyuser/uploadsbyuser.py?user=%s"; - - ListenableFuture getUploadCount(final String userName) { - final SettableFuture future = SettableFuture.create(); - threadPoolExecutor.schedule(() -> { - URL url; - try { - url = new URL(String.format(Locale.ENGLISH, UPLOAD_COUNT_URL_TEMPLATE, - new PageTitle(userName).getText())); - HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); - try { - BufferedReader bufferedReader = new BufferedReader(new - InputStreamReader(urlConnection.getInputStream())); - String uploadCount = bufferedReader.readLine(); - bufferedReader.close(); - future.set(Integer.parseInt(uploadCount)); - } finally { - urlConnection.disconnect(); - } - } catch (Exception e) { - Timber.e("Error getting upload count Error", e); - future.setException(e); - } - }); - return future; - } -} diff --git a/gradle.properties b/gradle.properties index cf3b5a13e..b94f8fae3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,6 +12,5 @@ android.useDeprecatedNdk=true # Library dependencies BUTTERKNIFE_VERSION=8.6.0 -GUAVA_VERSION=19.0 org.gradle.jvmargs=-Xmx1536M \ No newline at end of file