Consolidate the networking libraries - drop volley in favor of OkHttp

This commit is contained in:
Paul Hawke 2017-12-09 23:01:47 -06:00
parent 2255bd9a56
commit 32cb8df9ae
8 changed files with 194 additions and 262 deletions

View file

@ -11,7 +11,6 @@ dependencies {
implementation 'fr.avianey.com.viewpagerindicator:library:2.4.1.1@aar'
implementation 'in.yuvi:http.fluent:1.3'
implementation 'com.github.chrisbanes:PhotoView:2.0.0'
implementation 'com.android.volley:volley:1.0.0'
implementation 'ch.acra:acra:4.9.2'
implementation 'org.mediawiki:api:1.3'
implementation 'commons-codec:commons-codec:1.10'

View file

@ -1,5 +1,5 @@
-dontobfuscate
-keep class org.apache.http.** { *; }
-dontwarn org.apache.http.**
-keep class fr.free.nrw.commons.upload.MwVolleyApi$Page {*;}
-keep class fr.free.nrw.commons.upload.CategoryApi$Page {*;}
-keep class android.support.v7.widget.ShareActionProvider { *; }

View file

@ -7,7 +7,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import fr.free.nrw.commons.upload.MwVolleyApi;
import fr.free.nrw.commons.upload.CategoryApi;
import timber.log.Timber;
public class CacheController {
@ -31,8 +31,8 @@ public class CacheController {
public void cacheCategory() {
List<String> pointCatList = new ArrayList<>();
if (MwVolleyApi.GpsCatExists.getGpsCatExists()) {
pointCatList.addAll(MwVolleyApi.getGpsCat());
if (CategoryApi.GpsCatExists.getGpsCatExists()) {
pointCatList.addAll(CategoryApi.getGpsCat());
Timber.d("Categories being cached: %s", pointCatList);
} else {
Timber.d("No categories found, so no categories cached");

View file

@ -39,7 +39,7 @@ import butterknife.ButterKnife;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.mwapi.MediaWikiApi;
import fr.free.nrw.commons.upload.MwVolleyApi;
import fr.free.nrw.commons.upload.CategoryApi;
import fr.free.nrw.commons.utils.StringSortingUtils;
import fr.free.nrw.commons.utils.ViewUtil;
import io.reactivex.Observable;
@ -288,8 +288,8 @@ public class CategorizationFragment extends CommonsDaggerSupportFragment {
private Observable<CategoryItem> gpsCategories() {
return Observable.fromIterable(
MwVolleyApi.GpsCatExists.getGpsCatExists()
? MwVolleyApi.getGpsCat() : new ArrayList<>())
CategoryApi.GpsCatExists.getGpsCatExists()
? CategoryApi.getGpsCat() : new ArrayList<>())
.map(name -> new CategoryItem(name, false));
}

View file

@ -4,9 +4,11 @@ import android.content.ContentProviderClient;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.v4.util.LruCache;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import javax.inject.Named;
import javax.inject.Singleton;
@ -14,7 +16,6 @@ import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.auth.AccountUtil;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.caching.CacheController;
@ -24,6 +25,8 @@ import fr.free.nrw.commons.mwapi.ApacheHttpClientMediaWikiApi;
import fr.free.nrw.commons.mwapi.MediaWikiApi;
import fr.free.nrw.commons.nearby.NearbyPlaces;
import fr.free.nrw.commons.upload.UploadController;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import static android.content.Context.MODE_PRIVATE;
import static fr.free.nrw.commons.contributions.ContributionsContentProvider.CONTRIBUTION_AUTHORITY;
@ -69,6 +72,12 @@ public class CommonsApplicationModule {
return context.getContentResolver().acquireContentProviderClient(MODIFICATIONS_AUTHORITY);
}
@Provides
@Singleton
public OkHttpClient provideOkHttpClient() {
return new OkHttpClient.Builder().build();
}
@Provides
@Named("application_preferences")
public SharedPreferences providesApplicationSharedPreferences(Context context) {
@ -126,6 +135,14 @@ public class CommonsApplicationModule {
return new ApacheHttpClientMediaWikiApi(context, BuildConfig.WIKIMEDIA_API_HOST, defaultPreferences, categoryPrefs, gson);
}
@Provides
@Named("commons_mediawiki_url")
@NonNull
@SuppressWarnings("ConstantConditions")
public HttpUrl provideMwUrl() {
return HttpUrl.parse("https://commons.wikimedia.org/");
}
@Provides
@Singleton
public LocationServiceManager provideLocationServiceManager(Context context) {
@ -139,7 +156,7 @@ public class CommonsApplicationModule {
@Provides
@Singleton
public Gson provideGson() {
return new Gson();
return new GsonBuilder().create();
}
@Provides

View file

@ -0,0 +1,165 @@
package fr.free.nrw.commons.upload;
import android.support.annotation.NonNull;
import com.google.gson.Gson;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.ResponseBody;
import timber.log.Timber;
/**
* Uses the OkHttp library to implement asynchronous calls to the Commons MediaWiki API to match
* GPS coordinates with nearby Commons categories. Parses the results using GSON to obtain a list
* of relevant categories.
*/
public class CategoryApi {
private static Set<String> categorySet;
private static List<String> categoryList;
private final OkHttpClient okHttpClient;
private final HttpUrl mwUrl;
private final Gson gson;
@Inject
public CategoryApi(OkHttpClient okHttpClient, @Named("commons_mediawiki_url") HttpUrl mwUrl, Gson gson) {
this.okHttpClient = okHttpClient;
this.mwUrl = mwUrl;
this.gson = gson;
categorySet = new HashSet<>();
}
public static List<String> getGpsCat() {
return categoryList;
}
public static void setGpsCat(List<String> cachedList) {
categoryList = new ArrayList<>();
categoryList.addAll(cachedList);
Timber.d("Setting GPS cats from cache: %s", categoryList);
}
public void request(String coords) {
String apiUrl = buildUrl(coords);
Timber.d("URL: %s", apiUrl);
Call call = okHttpClient.newCall(new Request.Builder().get().url(apiUrl).build());
call.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
Timber.e(e);
GpsCatExists.setGpsCatExists(false);
}
@Override
public void onResponse(@NonNull Call call, @NonNull okhttp3.Response response) {
categoryList = new ArrayList<>();
categorySet = new HashSet<>();
ResponseBody body = response.body();
if (body == null) {
return;
}
QueryResponse queryResponse = gson.fromJson(body.charStream(), QueryResponse.class);
if (queryResponse != null && queryResponse.query != null && queryResponse.query.pages != null) {
for (Page page : queryResponse.query.pages) {
if (page.categories != null) {
for (Category category : page.categories) {
String categoryString = category.title.replace("Category:", "");
categorySet.add(categoryString);
}
categoryList = new ArrayList<>(categorySet);
}
}
}
GpsCatExists.setGpsCatExists(!categorySet.isEmpty());
}
});
}
/**
* Builds URL with image coords for MediaWiki API calls
* Example URL: https://commons.wikimedia.org/w/api.php?action=query&prop=categories|coordinates|pageprops&format=json&clshow=!hidden&coprop=type|name|dim|country|region|globe&codistancefrompoint=38.11386944444445|13.356263888888888&generator=geosearch&redirects=&ggscoord=38.11386944444445|1.356263888888888&ggsradius=100&ggslimit=10&ggsnamespace=6&ggsprop=type|name|dim|country|region|globe&ggsprimary=all&formatversion=2
*
* @param coords Coordinates to build query with
* @return URL for API query
*/
private String buildUrl(String coords) {
return mwUrl.newBuilder()
.addPathSegment("w")
.addPathSegment("api.php")
.addQueryParameter("action", "query")
.addQueryParameter("prop", "categories|coordinates|pageprops")
.addQueryParameter("format", "json")
.addQueryParameter("clshow", "!hidden")
.addQueryParameter("coprop", "type|name|dim|country|region|globe")
.addQueryParameter("codistancefrompoint", coords)
.addQueryParameter("generator", "geosearch")
.addQueryParameter("ggscoord", coords)
.addQueryParameter("ggsradius", "10000")
.addQueryParameter("ggslimit", "10")
.addQueryParameter("ggsnamespace", "6")
.addQueryParameter("ggsprop", "type|name|dim|country|region|globe")
.addQueryParameter("ggsprimary", "all")
.addQueryParameter("formatversion", "2")
.build().toString();
}
public static class GpsCatExists {
private static boolean gpsCatExists;
public static void setGpsCatExists(boolean gpsCat) {
gpsCatExists = gpsCat;
}
public static boolean getGpsCatExists() {
return gpsCatExists;
}
}
private static class QueryResponse {
public Query query;
public QueryResponse() {
}
}
private static class Query {
public Page[] pages;
public Query() {
pages = new Page[0];
}
}
private static class Page {
public String title;
public Category[] categories;
public Category category;
public Page() {
}
}
private static class Category {
public String title;
public Category() {
}
}
}

View file

@ -1,249 +0,0 @@
package fr.free.nrw.commons.upload;
import android.content.Context;
import android.net.Uri;
import com.android.volley.Cache;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.HttpHeaderParser;
import com.android.volley.toolbox.JsonRequest;
import com.android.volley.toolbox.Volley;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import timber.log.Timber;
/**
* Uses the Volley library to implement asynchronous calls to the Commons MediaWiki API to match
* GPS coordinates with nearby Commons categories. Parses the results using GSON to obtain a list
* of relevant categories.
*/
public class MwVolleyApi {
private static RequestQueue REQUEST_QUEUE;
private static final Gson GSON = new GsonBuilder().create();
private static Set<String> categorySet;
private static List<String> categoryList;
private static final String MWURL = "https://commons.wikimedia.org/";
private final Context context;
public MwVolleyApi(Context context) {
this.context = context;
categorySet = new HashSet<>();
}
public static List<String> getGpsCat() {
return categoryList;
}
public static void setGpsCat(List<String> cachedList) {
categoryList = new ArrayList<>();
categoryList.addAll(cachedList);
Timber.d("Setting GPS cats from cache: %s", categoryList);
}
public void request(String coords) {
String apiUrl = buildUrl(coords);
Timber.d("URL: %s", apiUrl);
JsonRequest<QueryResponse> request = new QueryRequest(apiUrl,
new LogResponseListener<>(), new LogResponseErrorListener());
getQueue().add(request);
}
/**
* Builds URL with image coords for MediaWiki API calls
* Example URL: https://commons.wikimedia.org/w/api.php?action=query&prop=categories|coordinates|pageprops&format=json&clshow=!hidden&coprop=type|name|dim|country|region|globe&codistancefrompoint=38.11386944444445|13.356263888888888&generator=geosearch&redirects=&ggscoord=38.11386944444445|1.356263888888888&ggsradius=100&ggslimit=10&ggsnamespace=6&ggsprop=type|name|dim|country|region|globe&ggsprimary=all&formatversion=2
* @param coords Coordinates to build query with
* @return URL for API query
*/
private String buildUrl(String coords) {
Uri.Builder builder = Uri.parse(MWURL).buildUpon();
builder.appendPath("w")
.appendPath("api.php")
.appendQueryParameter("action", "query")
.appendQueryParameter("prop", "categories|coordinates|pageprops")
.appendQueryParameter("format", "json")
.appendQueryParameter("clshow", "!hidden")
.appendQueryParameter("coprop", "type|name|dim|country|region|globe")
.appendQueryParameter("codistancefrompoint", coords)
.appendQueryParameter("generator", "geosearch")
.appendQueryParameter("ggscoord", coords)
.appendQueryParameter("ggsradius", "10000")
.appendQueryParameter("ggslimit", "10")
.appendQueryParameter("ggsnamespace", "6")
.appendQueryParameter("ggsprop", "type|name|dim|country|region|globe")
.appendQueryParameter("ggsprimary", "all")
.appendQueryParameter("formatversion", "2");
return builder.toString();
}
private synchronized RequestQueue getQueue() {
if (REQUEST_QUEUE == null) {
REQUEST_QUEUE = Volley.newRequestQueue(context);
}
return REQUEST_QUEUE;
}
private static class LogResponseListener<T> implements Response.Listener<T> {
@Override
public void onResponse(T response) {
Timber.d(response.toString());
}
}
private static class LogResponseErrorListener implements Response.ErrorListener {
@Override
public void onErrorResponse(VolleyError error) {
Timber.e(error.toString());
}
}
private static class QueryRequest extends JsonRequest<QueryResponse> {
public QueryRequest(String url,
Response.Listener<QueryResponse> listener,
Response.ErrorListener errorListener) {
super(Request.Method.GET, url, null, listener, errorListener);
}
@Override
protected Response<QueryResponse> parseNetworkResponse(NetworkResponse response) {
String json = parseString(response);
QueryResponse queryResponse = GSON.fromJson(json, QueryResponse.class);
return Response.success(queryResponse, cacheEntry(response));
}
private Cache.Entry cacheEntry(NetworkResponse response) {
return HttpHeaderParser.parseCacheHeaders(response);
}
private String parseString(NetworkResponse response) {
try {
return new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException e) {
return new String(response.data);
}
}
}
public static class GpsCatExists {
private static boolean gpsCatExists;
public static void setGpsCatExists(boolean gpsCat) {
gpsCatExists = gpsCat;
}
public static boolean getGpsCatExists() {
return gpsCatExists;
}
}
private static class QueryResponse {
private Query query = new Query();
private String printSet() {
if (categorySet == null || categorySet.isEmpty()) {
GpsCatExists.setGpsCatExists(false);
Timber.d("gpsCatExists=%b", GpsCatExists.getGpsCatExists());
return "No collection of categories";
} else {
GpsCatExists.setGpsCatExists(true);
Timber.d("gpsCatExists=%b", GpsCatExists.getGpsCatExists());
return "CATEGORIES FOUND" + categorySet.toString();
}
}
@Override
public String toString() {
if (query != null) {
return "query=" + query.toString() + "\n" + printSet();
} else {
return "No pages found";
}
}
}
private static class Query {
private Page [] pages;
@Override
public String toString() {
StringBuilder builder = new StringBuilder("pages=" + "\n");
if (pages != null) {
for (Page page : pages) {
builder.append(page.toString());
builder.append("\n");
}
builder.replace(builder.length() - 1, builder.length(), "");
return builder.toString();
} else {
return "No pages found";
}
}
}
public static class Page {
private int pageid;
private int ns;
private String title;
private Category[] categories;
private Category category;
public Page() {
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder("PAGEID=" + pageid + " ns=" + ns + " title=" + title + "\n" + " CATEGORIES= ");
if (categories == null || categories.length == 0) {
builder.append("no categories exist\n");
} else {
for (Category category : categories) {
builder.append(category.toString());
builder.append("\n");
if (category != null) {
String categoryString = category.toString().replace("Category:", "");
categorySet.add(categoryString);
}
}
}
categoryList = new ArrayList<>(categorySet);
builder.replace(builder.length() - 1, builder.length(), "");
return builder.toString();
}
}
private static class Category {
private String title;
@Override
public String toString() {
return title;
}
}
}

View file

@ -123,6 +123,8 @@ public class ShareActivity
@Inject
ModifierSequenceDao modifierSequenceDao;
@Inject
CategoryApi apiCall;
@Inject
@Named("default_preferences")
SharedPreferences prefs;
@ -699,8 +701,6 @@ public class ShareActivity
cacheController.setQtPoint(decLongitude, decLatitude);
}
MwVolleyApi apiCall = new MwVolleyApi(this);
List<String> displayCatList = cacheController.findCategory();
boolean catListEmpty = displayCatList.isEmpty();
@ -712,7 +712,7 @@ public class ShareActivity
} else {
cacheFound = true;
Timber.d("Cache found, setting categoryList in MwVolleyApi to %s", displayCatList);
MwVolleyApi.setGpsCat(displayCatList);
CategoryApi.setGpsCat(displayCatList);
}
}else{
Timber.d("EXIF: no coords");