aboutsummaryrefslogtreecommitdiff
path: root/libs/networking
diff options
context:
space:
mode:
Diffstat (limited to 'libs/networking')
-rw-r--r--libs/networking/.gitignore23
-rw-r--r--libs/networking/WordPressNetworking/build.gradle49
-rw-r--r--libs/networking/WordPressNetworking/gradle.properties-example2
-rw-r--r--libs/networking/WordPressNetworking/src/main/AndroidManifest.xml3
-rw-r--r--libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/Authenticator.java13
-rw-r--r--libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/AuthenticatorRequest.java96
-rw-r--r--libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/RestClientFactory.java19
-rw-r--r--libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/RestClientFactoryAbstract.java9
-rw-r--r--libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/RestClientFactoryDefault.java14
-rw-r--r--libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/RestClientUtils.java475
-rw-r--r--libs/networking/build.gradle0
-rw-r--r--libs/networking/gradle/wrapper/gradle-wrapper.jarbin0 -> 49896 bytes
-rw-r--r--libs/networking/gradle/wrapper/gradle-wrapper.properties6
-rwxr-xr-xlibs/networking/gradlew164
-rw-r--r--libs/networking/gradlew.bat90
-rw-r--r--libs/networking/settings.gradle1
16 files changed, 964 insertions, 0 deletions
diff --git a/libs/networking/.gitignore b/libs/networking/.gitignore
new file mode 100644
index 000000000..df914c258
--- /dev/null
+++ b/libs/networking/.gitignore
@@ -0,0 +1,23 @@
+# generated files
+build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+tools/deploy-mvn-artifact.conf
+
+# Intellij project files
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# Gradle
+.gradle/
+gradle.properties
+
+# Idea
+.idea/workspace.xml
+*.iml
+
+# OS X
+.DS_Store
diff --git a/libs/networking/WordPressNetworking/build.gradle b/libs/networking/WordPressNetworking/build.gradle
new file mode 100644
index 000000000..c0e937773
--- /dev/null
+++ b/libs/networking/WordPressNetworking/build.gradle
@@ -0,0 +1,49 @@
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:2.2.0'
+ }
+}
+
+repositories {
+ jcenter()
+ maven { url 'http://wordpress-mobile.github.io/WordPress-Android' }
+}
+
+apply plugin: 'com.android.library'
+apply plugin: 'maven'
+
+android {
+ publishNonDefault true
+
+ compileSdkVersion 24
+ buildToolsVersion "24.0.2"
+
+ defaultConfig {
+ minSdkVersion 14
+ targetSdkVersion 24
+ versionName "1.0.0"
+ }
+}
+
+dependencies {
+ compile 'org.wordpress:utils:1.11.0'
+ compile 'com.automattic:rest:1.0.7'
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ def repo_url = ""
+ if (project.hasProperty("repository")) {
+ repo_url = project.repository
+ }
+ repository(url: repo_url)
+ pom.version = android.defaultConfig.versionName
+ pom.groupId = "org.wordpress"
+ pom.artifactId = "wordpress-networking"
+ }
+ }
+}
diff --git a/libs/networking/WordPressNetworking/gradle.properties-example b/libs/networking/WordPressNetworking/gradle.properties-example
new file mode 100644
index 000000000..5a17295c3
--- /dev/null
+++ b/libs/networking/WordPressNetworking/gradle.properties-example
@@ -0,0 +1,2 @@
+wp.db_secret = wordpress
+repository = file:///Users/max/work/automattic/WordPress-Android-gh-pages/
diff --git a/libs/networking/WordPressNetworking/src/main/AndroidManifest.xml b/libs/networking/WordPressNetworking/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..f19a8bd89
--- /dev/null
+++ b/libs/networking/WordPressNetworking/src/main/AndroidManifest.xml
@@ -0,0 +1,3 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.wordpress.android.networking">
+</manifest>
diff --git a/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/Authenticator.java b/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/Authenticator.java
new file mode 100644
index 000000000..cf7bd78bb
--- /dev/null
+++ b/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/Authenticator.java
@@ -0,0 +1,13 @@
+package org.wordpress.android.networking;
+
+/**
+ * Interface that provides a method that should perform the necessary task to make sure
+ * the provided AuthenticatorRequest will be authenticated.
+ *
+ * The Authenticator must call AuthenticatorRequest.send() when it has completed its operations. For
+ * convenience the AuthenticatorRequest class provides AuthenticatorRequest.setAccessToken so the Authenticator can
+ * easily update the access token.
+ */
+public interface Authenticator {
+ void authenticate(final AuthenticatorRequest authenticatorRequest);
+}
diff --git a/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/AuthenticatorRequest.java b/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/AuthenticatorRequest.java
new file mode 100644
index 000000000..40d2af7f3
--- /dev/null
+++ b/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/AuthenticatorRequest.java
@@ -0,0 +1,96 @@
+package org.wordpress.android.networking;
+
+import com.android.volley.VolleyError;
+import com.wordpress.rest.Oauth;
+import com.wordpress.rest.RestClient;
+import com.wordpress.rest.RestRequest;
+import com.wordpress.rest.RestRequest.ErrorListener;
+
+/**
+ * Encapsulates the behaviour for asking the Authenticator for an access token. This
+ * allows the request maker to disregard the authentication state when making requests.
+ */
+public class AuthenticatorRequest {
+ private RestRequest mRequest;
+ private RestRequest.ErrorListener mListener;
+ private RestClient mRestClient;
+ private Authenticator mAuthenticator;
+
+ protected AuthenticatorRequest(RestRequest request, ErrorListener listener, RestClient restClient,
+ Authenticator authenticator) {
+ mRequest = request;
+ mListener = listener;
+ mRestClient = restClient;
+ mAuthenticator = authenticator;
+ }
+
+ public String getSiteId() {
+ return extractSiteIdFromUrl(mRestClient.getEndpointURL(), mRequest.getUrl());
+ }
+
+ /**
+ * Parse out the site ID from an URL.
+ * Note: For batch REST API calls, only the first siteID is returned
+ *
+ * @return The site ID
+ */
+ public static String extractSiteIdFromUrl(String restEndpointUrl, String url) {
+ if (url == null) {
+ return null;
+ }
+
+ final String sitePrefix = restEndpointUrl.endsWith("/") ? restEndpointUrl + "sites/" : restEndpointUrl + "/sites/";
+ final String batchCallPrefix = restEndpointUrl.endsWith("/") ? restEndpointUrl + "batch/?urls%5B%5D=%2Fsites%2F"
+ : restEndpointUrl + "/batch/?urls%5B%5D=%2Fsites%2F";
+
+ if (url.startsWith(sitePrefix) && !sitePrefix.equals(url)) {
+ int marker = sitePrefix.length();
+ if (url.indexOf("/", marker) < marker) {
+ return null;
+ }
+ return url.substring(marker, url.indexOf("/", marker));
+ } else if (url.startsWith(batchCallPrefix) && !batchCallPrefix.equals(url)) {
+ int marker = batchCallPrefix.length();
+ if (url.indexOf("%2F", marker) < marker) {
+ return null;
+ }
+ return url.substring(marker, url.indexOf("%2F", marker));
+ }
+
+ // not a sites/$siteId request or a batch request
+ return null;
+ }
+
+ /**
+ * Attempt to send the request, checks to see if we have an access token and if not
+ * asks the Authenticator to authenticate the request.
+ *
+ * If no Authenticator is provided the request is always sent.
+ */
+ protected void send(){
+ if (mAuthenticator == null) {
+ mRestClient.send(mRequest);
+ } else {
+ mAuthenticator.authenticate(this);
+ }
+ }
+
+ public void sendWithAccessToken(String token){
+ mRequest.setAccessToken(token);
+ mRestClient.send(mRequest);
+ }
+
+ public void sendWithAccessToken(Oauth.Token token){
+ sendWithAccessToken(token.toString());
+ }
+
+ /**
+ * If an access token cannot be obtained the request can be aborted and the
+ * handler's onFailure method is called
+ */
+ public void abort(VolleyError error){
+ if (mListener != null) {
+ mListener.onErrorResponse(error);
+ }
+ }
+}
diff --git a/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/RestClientFactory.java b/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/RestClientFactory.java
new file mode 100644
index 000000000..492b2b99f
--- /dev/null
+++ b/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/RestClientFactory.java
@@ -0,0 +1,19 @@
+package org.wordpress.android.networking;
+
+import com.android.volley.RequestQueue;
+import com.wordpress.rest.RestClient;
+
+public class RestClientFactory {
+ private static RestClientFactoryAbstract sFactory;
+
+ public static RestClient instantiate(RequestQueue queue) {
+ return instantiate(queue, RestClient.REST_CLIENT_VERSIONS.V1);
+ }
+
+ public static RestClient instantiate(RequestQueue queue, RestClient.REST_CLIENT_VERSIONS version) {
+ if (sFactory == null) {
+ sFactory = new RestClientFactoryDefault();
+ }
+ return sFactory.make(queue, version);
+ }
+}
diff --git a/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/RestClientFactoryAbstract.java b/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/RestClientFactoryAbstract.java
new file mode 100644
index 000000000..799a5a8e8
--- /dev/null
+++ b/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/RestClientFactoryAbstract.java
@@ -0,0 +1,9 @@
+package org.wordpress.android.networking;
+
+import com.android.volley.RequestQueue;
+import com.wordpress.rest.RestClient;
+
+public interface RestClientFactoryAbstract {
+ public RestClient make(RequestQueue queue);
+ public RestClient make(RequestQueue queue, RestClient.REST_CLIENT_VERSIONS version);
+}
diff --git a/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/RestClientFactoryDefault.java b/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/RestClientFactoryDefault.java
new file mode 100644
index 000000000..b87d4b40f
--- /dev/null
+++ b/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/RestClientFactoryDefault.java
@@ -0,0 +1,14 @@
+package org.wordpress.android.networking;
+
+import com.android.volley.RequestQueue;
+import com.wordpress.rest.RestClient;
+
+public class RestClientFactoryDefault implements RestClientFactoryAbstract {
+ public RestClient make(RequestQueue queue) {
+ return new RestClient(queue);
+ }
+
+ public RestClient make(RequestQueue queue, RestClient.REST_CLIENT_VERSIONS version) {
+ return new RestClient(queue, version);
+ }
+}
diff --git a/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/RestClientUtils.java b/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/RestClientUtils.java
new file mode 100644
index 000000000..6e06cfeee
--- /dev/null
+++ b/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/RestClientUtils.java
@@ -0,0 +1,475 @@
+/**
+ * Interface to the WordPress.com REST API.
+ */
+package org.wordpress.android.networking;
+
+import android.content.Context;
+import android.net.Uri;
+import android.text.TextUtils;
+
+import com.android.volley.DefaultRetryPolicy;
+import com.android.volley.Request;
+import com.android.volley.Request.Method;
+import com.android.volley.RequestQueue;
+import com.android.volley.RetryPolicy;
+import com.android.volley.toolbox.RequestFuture;
+import com.wordpress.rest.JsonRestRequest;
+import com.wordpress.rest.RestClient;
+import com.wordpress.rest.RestRequest;
+import com.wordpress.rest.RestRequest.ErrorListener;
+import com.wordpress.rest.RestRequest.Listener;
+
+import org.json.JSONObject;
+import org.wordpress.android.util.LanguageUtils;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+public class RestClientUtils {
+ private static final String NOTIFICATION_FIELDS = "id,type,unread,body,subject,timestamp,meta";
+ private static final String COMMENT_REPLY_CONTENT_FIELD = "content";
+ private static String sUserAgent = "WordPress Networking Android";
+
+ private RestClient mRestClient;
+ private Authenticator mAuthenticator;
+ private Context mContext;
+
+ /**
+ * Socket timeout in milliseconds for rest requests
+ */
+ public static final int REST_TIMEOUT_MS = 30000;
+
+ /**
+ * Default number of retries for POST rest requests
+ */
+ public static final int REST_MAX_RETRIES_POST = 0;
+
+ /**
+ * Default number of retries for GET rest requests
+ */
+ public static final int REST_MAX_RETRIES_GET = 3;
+
+ /**
+ * Default backoff multiplier for rest requests
+ */
+ public static final float REST_BACKOFF_MULT = 2f;
+
+ public static void setUserAgent(String userAgent) {
+ sUserAgent = userAgent;
+ }
+
+ public RestClientUtils(Context context, RequestQueue queue, Authenticator authenticator, RestRequest.OnAuthFailedListener onAuthFailedListener) {
+ this(context, queue, authenticator, onAuthFailedListener, RestClient.REST_CLIENT_VERSIONS.V1);
+ }
+
+ public RestClientUtils(Context context, RequestQueue queue, Authenticator authenticator, RestRequest.OnAuthFailedListener onAuthFailedListener, RestClient.REST_CLIENT_VERSIONS version) {
+ // load an existing access token from prefs if we have one
+ mContext = context;
+ mAuthenticator = authenticator;
+ mRestClient = RestClientFactory.instantiate(queue, version);
+ if (onAuthFailedListener != null) {
+ mRestClient.setOnAuthFailedListener(onAuthFailedListener);
+ }
+ mRestClient.setUserAgent(sUserAgent);
+ }
+
+ public Authenticator getAuthenticator() {
+ return mAuthenticator;
+ }
+
+ public RestClient getRestClient() {
+ return mRestClient;
+ }
+
+ public void getCategories(String siteId, Listener listener, ErrorListener errorListener) {
+ String path = String.format("sites/%s/categories", siteId);
+ get(path, null, null, listener, errorListener);
+ }
+
+ /**
+ * get a list of recent comments
+ * <p/>
+ * https://developer.wordpress.com/docs/api/1.1/get/sites/%24site/comments/
+ */
+ public void getComments(String siteId, Map<String, String> params, final Listener listener, ErrorListener errorListener) {
+ String path = String.format("sites/%s/comments", siteId);
+ get(path, params, null, listener, errorListener);
+ }
+
+ /**
+ * Reply to a comment
+ * <p/>
+ * https://developer.wordpress.com/docs/api/1/post/sites/%24site/posts/%24post_ID/replies/new/
+ */
+ public void replyToComment(String reply, String path, Listener listener, ErrorListener errorListener) {
+ Map<String, String> params = new HashMap<String, String>();
+ params.put(COMMENT_REPLY_CONTENT_FIELD, reply);
+ post(path, params, null, listener, errorListener);
+ }
+
+ /**
+ * Reply to a comment.
+ * <p/>
+ * https://developer.wordpress.com/docs/api/1/post/sites/%24site/posts/%24post_ID/replies/new/
+ */
+ public void replyToComment(long siteId, long commentId, String content, Listener listener,
+ ErrorListener errorListener) {
+ Map<String, String> params = new HashMap<String, String>();
+ params.put(COMMENT_REPLY_CONTENT_FIELD, content);
+ String path = String.format("sites/%d/comments/%d/replies/new", siteId, commentId);
+ post(path, params, null, listener, errorListener);
+ }
+
+ /**
+ * Follow a site given an ID or domain
+ * <p/>
+ * https://developer.wordpress.com/docs/api/1/post/sites/%24site/follows/new/
+ */
+ public void followSite(String siteId, Listener listener, ErrorListener errorListener) {
+ String path = String.format("sites/%s/follows/new", siteId);
+ post(path, listener, errorListener);
+ }
+
+ /**
+ * Unfollow a site given an ID or domain
+ * <p/>
+ * https://developer.wordpress.com/docs/api/1/post/sites/%24site/follows/mine/delete/
+ */
+ public void unfollowSite(String siteId, Listener listener, ErrorListener errorListener) {
+ String path = String.format("sites/%s/follows/mine/delete", siteId);
+ post(path, listener, errorListener);
+ }
+
+ /**
+ * Get notifications with the provided params.
+ * <p/>
+ * https://developer.wordpress.com/docs/api/1/get/notifications/
+ */
+ public void getNotifications(Map<String, String> params, Listener listener, ErrorListener errorListener) {
+ params.put("number", "40");
+ params.put("num_note_items", "20");
+ params.put("fields", NOTIFICATION_FIELDS);
+ get("notifications", params, null, listener, errorListener);
+ }
+
+ /**
+ * Get notifications with default params.
+ * <p/>
+ * https://developer.wordpress.com/docs/api/1/get/notifications/
+ */
+ public void getNotifications(Listener listener, ErrorListener errorListener) {
+ getNotifications(new HashMap<String, String>(), listener, errorListener);
+ }
+
+ /**
+ * Update the seen timestamp.
+ * <p/>
+ * https://developer.wordpress.com/docs/api/1/post/notifications/seen
+ */
+ public void markNotificationsSeen(String timestamp, Listener listener, ErrorListener errorListener) {
+ Map<String, String> params = new HashMap<String, String>();
+ params.put("time", timestamp);
+ post("notifications/seen", params, null, listener, errorListener);
+ }
+
+ /**
+ * Moderate a comment.
+ * <p/>
+ * http://developer.wordpress.com/docs/api/1/sites/%24site/comments/%24comment_ID/
+ */
+ public void moderateComment(String siteId, String commentId, String status, Listener listener,
+ ErrorListener errorListener) {
+ Map<String, String> params = new HashMap<String, String>();
+ params.put("status", status);
+ String path = String.format("sites/%s/comments/%s/", siteId, commentId);
+ post(path, params, null, listener, errorListener);
+ }
+
+ /**
+ * Edit the content of a comment
+ */
+ public void editCommentContent(long siteId, long commentId, String content, Listener listener,
+ ErrorListener errorListener) {
+ Map<String, String> params = new HashMap<String, String>();
+ params.put("content", content);
+ String path = String.format("sites/%d/comments/%d/", siteId, commentId);
+ post(path, params, null, listener, errorListener);
+ }
+
+ /**
+ * Like or unlike a comment.
+ */
+ public void likeComment(String siteId, String commentId, boolean isLiked, Listener listener,
+ ErrorListener errorListener) {
+ Map<String, String> params = new HashMap<String, String>();
+ String path = String.format("sites/%s/comments/%s/likes/", siteId, commentId);
+
+ if (!isLiked) {
+ path += "mine/delete";
+ } else {
+ path += "new";
+ }
+
+ post(path, params, null, listener, errorListener);
+ }
+
+ public void getFreeSearchThemes(String siteId, int limit, int offset, String searchTerm, Listener listener, ErrorListener errorListener) {
+ getSearchThemes("free", siteId, limit, offset, searchTerm, listener, errorListener);
+ }
+
+ public void getSearchThemes(String tier, String siteId, int limit, int offset, String searchTerm, Listener listener, ErrorListener errorListener) {
+ String path = String.format("sites/%s/themes?tier=" + tier + "&number=%d&offset=%d&search=%s", siteId, limit, offset, searchTerm);
+ get(path, listener, errorListener);
+ }
+
+ public void getFreeThemes(String siteId, int limit, int offset, Listener listener, ErrorListener errorListener) {
+ getThemes("free", siteId, limit, offset, listener, errorListener);
+ }
+
+ public void getPurchasedThemes(String siteId, Listener listener, ErrorListener errorListener) {
+ String path = String.format("sites/%s/themes/purchased", siteId);
+ get(path, listener, errorListener);
+ }
+
+ /**
+ * Get all a site's themes
+ */
+ public void getThemes(String tier, String siteId, int limit, int offset, Listener listener, ErrorListener errorListener) {
+ String path = String.format("sites/%s/themes/?tier=" + tier + "&number=%d&offset=%d", siteId, limit, offset);
+ get(path, listener, errorListener);
+ }
+
+ /**
+ * Set a site's theme
+ */
+ public void setTheme(String siteId, String themeId, Listener listener, ErrorListener errorListener) {
+ Map<String, String> params = new HashMap<>();
+ params.put("theme", themeId);
+ String path = String.format("sites/%s/themes/mine", siteId);
+ post(path, params, null, listener, errorListener);
+ }
+
+ /**
+ * Get a site's current theme
+ */
+ public void getCurrentTheme(String siteId, Listener listener, ErrorListener errorListener) {
+ String path = String.format("sites/%s/themes/mine", siteId);
+ get(path, listener, errorListener);
+ }
+
+ public void getGeneralSettings(String siteId, Listener listener, ErrorListener errorListener) {
+ String path = String.format("sites/%s/settings", siteId);
+ Map<String, String> params = new HashMap<String, String>();
+ get(path, params, null, listener, errorListener);
+ }
+
+ public void setGeneralSiteSettings(String siteId, Listener listener, ErrorListener errorListener,
+ Map<String, String> params) {
+ String path = String.format("sites/%s/settings", siteId);
+ post(path, params, null, listener, errorListener);
+ }
+
+ /**
+ * Delete a site
+ */
+ public void deleteSite(String siteId, Listener listener, ErrorListener errorListener) {
+ String path = String.format("sites/%s/delete", siteId);
+ post(path, listener, errorListener);
+ }
+
+ public void getSitePurchases(String siteId, Listener listener, ErrorListener errorListener) {
+ String path = String.format("sites/%s/purchases", siteId);
+ get(path, listener, errorListener);
+ }
+
+ public void exportContentAll(String siteId, Listener listener, ErrorListener errorListener) {
+ String path = String.format("sites/%s/exports/start", siteId);
+ post(path, listener, errorListener);
+ }
+
+ public void sendLoginEmail(Map<String, String> params, Listener listener, ErrorListener errorListener) {
+ post("auth/send-login-email", params, null, listener, errorListener);
+ }
+
+ public void isAvailable(String email, Listener listener, ErrorListener errorListener) {
+ String path = String.format("is-available/email?q=%s", email);
+ get(path, listener, errorListener);
+ }
+
+ /**
+ * Make GET request
+ */
+ public Request<JSONObject> get(String path, Listener listener, ErrorListener errorListener) {
+ return get(path, null, null, listener, errorListener);
+ }
+
+ /**
+ * Make GET request with params
+ */
+ public Request<JSONObject> get(String path, Map<String, String> params, RetryPolicy retryPolicy, Listener listener,
+ ErrorListener errorListener) {
+ // turn params into querystring
+ HashMap<String, String> paramsWithLocale = getRestLocaleParams(mContext);
+ if (params != null) {
+ paramsWithLocale.putAll(params);
+ }
+
+ String realPath = getSanitizedPath(path);
+ if (TextUtils.isEmpty(realPath)) {
+ realPath = path;
+ }
+ paramsWithLocale.putAll(getSanitizedParameters(path));
+
+ RestRequest request = mRestClient.makeRequest(Method.GET, mRestClient.getAbsoluteURL(realPath, paramsWithLocale), null,
+ listener, errorListener);
+
+ if (retryPolicy == null) {
+ retryPolicy = new DefaultRetryPolicy(REST_TIMEOUT_MS, REST_MAX_RETRIES_GET, REST_BACKOFF_MULT);
+ }
+ request.setRetryPolicy(retryPolicy);
+ AuthenticatorRequest authCheck = new AuthenticatorRequest(request, errorListener, mRestClient, mAuthenticator);
+ authCheck.send();
+ return request;
+ }
+
+ /**
+ * Make Synchronous GET request
+ *
+ * @throws TimeoutException
+ * @throws ExecutionException
+ * @throws InterruptedException
+ */
+ public JSONObject getSynchronous(String path) throws InterruptedException, ExecutionException, TimeoutException {
+ return getSynchronous(path, null, null);
+ }
+
+ /**
+ * Make Synchronous GET request with params
+ *
+ * @throws TimeoutException
+ * @throws ExecutionException
+ * @throws InterruptedException
+ */
+ public JSONObject getSynchronous(String path, Map<String, String> params, RetryPolicy retryPolicy)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ RequestFuture<JSONObject> future = RequestFuture.newFuture();
+
+ HashMap<String, String> paramsWithLocale = getRestLocaleParams(mContext);
+ if (params != null) {
+ paramsWithLocale.putAll(params);
+ }
+
+ String realPath = getSanitizedPath(path);
+ if (TextUtils.isEmpty(realPath)) {
+ realPath = path;
+ }
+ paramsWithLocale.putAll(getSanitizedParameters(path));
+
+ RestRequest request = mRestClient.makeRequest(Method.GET, mRestClient.getAbsoluteURL(realPath, paramsWithLocale), null, future, future);
+
+ if (retryPolicy == null) {
+ retryPolicy = new DefaultRetryPolicy(REST_TIMEOUT_MS, REST_MAX_RETRIES_GET, REST_BACKOFF_MULT);
+ }
+ request.setRetryPolicy(retryPolicy);
+
+ AuthenticatorRequest authCheck = new AuthenticatorRequest(request, null, mRestClient, mAuthenticator);
+ authCheck.send(); //this insert the request into the queue. //TODO: Verify that everything is OK on REST calls without a valid token
+ JSONObject response = future.get();
+ return response;
+ }
+
+ /**
+ * Make POST request
+ */
+ public void post(String path, Listener listener, ErrorListener errorListener) {
+ Map<String, String> params = null;
+ post(path, params, null, listener, errorListener);
+ }
+
+ /**
+ * Make POST request with params
+ */
+ public void post(final String path, Map<String, String> params, RetryPolicy retryPolicy, Listener listener,
+ ErrorListener errorListener) {
+ final RestRequest request = mRestClient.makeRequest(Method.POST, mRestClient.getAbsoluteURL(path, getRestLocaleParams(mContext)), params,
+ listener, errorListener);
+ if (retryPolicy == null) {
+ retryPolicy = new DefaultRetryPolicy(REST_TIMEOUT_MS, REST_MAX_RETRIES_POST,
+ REST_BACKOFF_MULT); //Do not retry on failure
+ }
+ request.setRetryPolicy(retryPolicy);
+ AuthenticatorRequest authCheck = new AuthenticatorRequest(request, errorListener, mRestClient, mAuthenticator);
+ authCheck.send();
+ }
+
+
+ /**
+ * Make a JSON POST request
+ */
+ public void post(final String path, JSONObject params, RetryPolicy retryPolicy, Listener listener,
+ ErrorListener errorListener) {
+ final JsonRestRequest request = mRestClient.makeRequest(mRestClient.getAbsoluteURL(path, getRestLocaleParams(mContext)), params,
+ listener, errorListener);
+ if (retryPolicy == null) {
+ retryPolicy = new DefaultRetryPolicy(REST_TIMEOUT_MS, REST_MAX_RETRIES_POST,
+ REST_BACKOFF_MULT); //Do not retry on failure
+ }
+ request.setRetryPolicy(retryPolicy);
+ AuthenticatorRequest authCheck = new AuthenticatorRequest(request, errorListener, mRestClient, mAuthenticator);
+ authCheck.send();
+ }
+
+ /**
+ * Takes a URL and returns the path within, or an empty string (not null)
+ */
+ public static String getSanitizedPath(String unsanitizedPath){
+ if (unsanitizedPath != null) {
+ int qmarkPos = unsanitizedPath.indexOf('?');
+ if (qmarkPos > -1) { //strip any querystring params off this to obtain the path
+ return unsanitizedPath.substring(0, qmarkPos+1);
+ } else {
+ // return the string as is, consider the whole string as the path
+ return unsanitizedPath;
+ }
+ }
+ return "";
+ }
+
+ /**
+ * Takes a URL with query strings and returns a Map of query string values.
+ */
+ public static HashMap<String, String> getSanitizedParameters(String unsanitizedPath){
+ HashMap<String, String> queryParams = new HashMap<>();
+
+ Uri uri = Uri.parse(unsanitizedPath);
+
+ if (uri.getQueryParameterNames() != null ) {
+ Iterator iter = uri.getQueryParameterNames().iterator();
+ while (iter.hasNext()) {
+ String name = (String)iter.next();
+ String value = uri.getQueryParameter(name);
+ queryParams.put(name, value);
+ }
+ }
+
+ return queryParams;
+ }
+
+ /**
+ * Returns locale parameter used in REST calls which require the response to be localized
+ */
+ public static HashMap<String, String> getRestLocaleParams(Context context) {
+ HashMap<String, String> params = new HashMap<>();
+ String deviceLanguageCode = LanguageUtils.getCurrentDeviceLanguageCode(context);
+ if (!TextUtils.isEmpty(deviceLanguageCode)) {
+ //patch locale if it's any of the deprecated codes as can be read in Locale.java source code:
+ deviceLanguageCode = LanguageUtils.patchDeviceLanguageCode(deviceLanguageCode);
+ params.put("locale", deviceLanguageCode);
+ }
+ return params;
+ }
+
+}
diff --git a/libs/networking/build.gradle b/libs/networking/build.gradle
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/libs/networking/build.gradle
diff --git a/libs/networking/gradle/wrapper/gradle-wrapper.jar b/libs/networking/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..8c0fb64a8
--- /dev/null
+++ b/libs/networking/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/libs/networking/gradle/wrapper/gradle-wrapper.properties b/libs/networking/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..4c74aab81
--- /dev/null
+++ b/libs/networking/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Apr 10 15:27:10 PDT 2013
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-all.zip
diff --git a/libs/networking/gradlew b/libs/networking/gradlew
new file mode 100755
index 000000000..91a7e269e
--- /dev/null
+++ b/libs/networking/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/libs/networking/gradlew.bat b/libs/networking/gradlew.bat
new file mode 100644
index 000000000..8a0b282aa
--- /dev/null
+++ b/libs/networking/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/libs/networking/settings.gradle b/libs/networking/settings.gradle
new file mode 100644
index 000000000..62b0b6897
--- /dev/null
+++ b/libs/networking/settings.gradle
@@ -0,0 +1 @@
+include ':WordPressNetworking'