Android Open Source - scoreflex-android-sdk Scoreflex Rest Client






From Project

Back to project page scoreflex-android-sdk.

License

The source code is released under:

Apache License

If you think the Android project scoreflex-android-sdk listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Licensed to Scoreflex (www.scoreflex.com) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. Scoreflex licenses this
 * file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *// w  w w  .  j a  va  2s .  c om
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package com.scoreflex;

import java.io.UnsupportedEncodingException;
import java.net.SocketException;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.apache.http.Header;
import org.apache.http.NoHttpResponseException;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.message.BasicHeader;
import org.json.JSONException;
import org.json.JSONObject;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Handler;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Base64;
import android.util.Log;

import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.JsonHttpResponseHandler;
import com.scoreflex.Scoreflex.Response;

/**
 * A REST client that lets you hit the Scoreflex REST server.
 *
 */
class ScoreflexRestClient {

  private enum HttpMethod {
    GET, PUT, POST, DELETE
  }

  private static final int RETRY_INTERVAL = 1000; //60000;
  private static final String ACCESS_TOKEN_PREF_NAME = "__scoreflex_access_token";
  private static final String ACCESS_TOKEN_IS_ANONYMOUS_PREF_NAME = "__scoreflex_access_token_is_anonymous";
  private static final String SID_PREF_NAME = "__scoreflex_sid";
  private static final String PLAYER_ID_PREF_NAME = "__player_id";
  private static boolean sIsFetchingAnonymousAccessToken = false;
  private static List<Scoreflex.ResponseHandler> sPendingHandlers = new ArrayList<Scoreflex.ResponseHandler>();

  private static AsyncHttpClient sClient = new AsyncHttpClient();

  /**
   * A GET request
   *
   * @param resource
   *          The resource path, starting with /
   * @param params
   *          AsyncHttpClient request parameters
   * @param responseHandler
   *          An AsyncHttpClient response handler
   */
  protected static void get(String resource, Scoreflex.RequestParams params,
      Scoreflex.ResponseHandler responseHandler) {
    requestAuthenticated(new Request(HttpMethod.GET, resource, params,
        responseHandler));
  }

  /**
   * A POST request
   *
   * @param resource
   *          The resource path, starting with /
   * @param params
   *          AsyncHttpClient request parameters
   * @param responseHandler
   *          An AsyncHttpClient response handler
   */
  protected static void post(String resource, Scoreflex.RequestParams params,
      Scoreflex.ResponseHandler responseHandler) {
    requestAuthenticated(new Request(HttpMethod.POST, resource, params,
        responseHandler));
  }

  /**
   * A POST request that is guaranteed to be executed when a network connection
   * is present, surviving application reboot. The responseHandler will be
   * called only if the network is present when the request is first run.
   *
   * @param resource
   * @param params
   * @param responseHandler
   */
  protected static void postEventually(String resource,
      Scoreflex.RequestParams params,
      final Scoreflex.ResponseHandler responseHandler) {

    // Create a request
    final Request request = new Request(HttpMethod.POST, resource, params, null);

    // Wrap the provided handler with ours
    request.setHandler(new Scoreflex.ResponseHandler() {

      @Override
      public void onFailure(Throwable e, Response errorResponse) {

        // Post to vault on network error
        if (e instanceof NoHttpResponseException
            || e instanceof UnknownHostException
            || e instanceof SocketException) {
          try {
            ScoreflexRequestVault.getDefaultVault().put(request);
          } catch (JSONException e1) {
            Log.e("Scoreflex", "Could not save request to vault", e1);
          }
          return;
        }

        // Forward to original handler otherwise
        if (null != responseHandler)
          responseHandler.onFailure(e, errorResponse);
      }

      @Override
      public void onSuccess(Response response) {
        if (null != responseHandler)
          responseHandler.onSuccess(response);
      }

      @Override
      public void onSuccess(int statusCode, Response response) {
        if (null != responseHandler)
          responseHandler.onSuccess(statusCode, response);
      }

    });
    requestAuthenticated(request);

  }

  /**
   * A PUT request
   *
   * @param resource
   *          The resource path, starting with /
   * @param params
   *          AsyncHttpClient request parameters
   * @param responseHandler
   *          An AsyncHttpClient response handler
   */
  protected static void put(String resource, Scoreflex.RequestParams params,
      Scoreflex.ResponseHandler responseHandler) {
    requestAuthenticated(new Request(HttpMethod.PUT, resource, params,
        responseHandler));
  }

  /**
   * A DELETE request
   *
   * @param resource
   *          The resource path, starting with /
   * @param params
   *          AsyncHttpClient request parameters
   * @param responseHandler
   *          An AsyncHttpClient response handler
   */
  protected static void delete(String resource,
      Scoreflex.ResponseHandler responseHandler) {
    requestAuthenticated(new Request(HttpMethod.DELETE, resource, null,
        responseHandler));
  }

  /**
   * If no access token is found in the user's preferences, fetch an anonymous
   * access token
   *
   * @param onFetchedHandler
   *          a handler called if a request to fetch an access token has been
   *          executed successfully, never called if retreived from cache
   * @return whether or not a request has been executed to fetch an anonymous
   *         access token (true fetching, false retrived from local cache)
   */
  protected static boolean fetchAnonymousAccessTokenIfNeeded(
      Scoreflex.ResponseHandler onFetchedHandler) {
    if (null == getAccessToken()) {
      fetchAnonymousAccessToken(onFetchedHandler);
      return true;
    }
    return false;
  }

  /**
   * If no access token is found in the user's preferences, fetch an anonymous
   * access token
   */
  protected static void fetchAnonymousAccessTokenIfNeeded() {
    fetchAnonymousAccessTokenIfNeeded(null);
  }

  /**
   * Runs the specified request and ensure a valid access token is fetched if
   * neccessary beforehand or afterwards (and re-run the request) if the request
   * fails for auth reasons
   *
   * @param request
   */
  protected static void requestAuthenticated(final Request request) {
    if (null == request)
      return;

    String accessToken = getAccessToken();

    // User is authenticated
    if (null != accessToken) {

      // Add the access token to the params
      Scoreflex.RequestParams params = request.getParams();
      if (null == params) {
        params = new Scoreflex.RequestParams();
        request.setParams(params);
      }

      params.remove("accessToken");
      params.put("accessToken", accessToken);

      // Wrap the request handler with our own
      Scoreflex.ResponseHandler wrapperHandler = new Scoreflex.ResponseHandler() {

        @Override
        public void onSuccess(int status, Scoreflex.Response response) {
          if (null != request.getHandler())
            request.getHandler().onSuccess(status, response);
        }

        @Override
        public void onFailure(Throwable e, Scoreflex.Response errorResponse) {
          Log.e("Scoreflex", "Request failed", e);
          if (null != errorResponse
              && Scoreflex.ERROR_INVALID_ACCESS_TOKEN == errorResponse
                  .getErrorCode()) {

            // null out the access token
            setAccessToken(null, true);
            setSID(null);
            setPlayerId(null);

            // retry in 60 secs
            new Handler().postDelayed(new Runnable() {

              @Override
              public void run() {
                requestAuthenticated(request);

              }
            }, RETRY_INTERVAL);

          } else {
            if (null == request.getHandler())
              return;
            // if (e instanceof ConnectTimeoutException)
            request.getHandler().onFailure(e, errorResponse);
          }
        }

        @Override
        public void onSuccess(Response response) {

        }
      };
      Request wrapperRequest = (Request) request.clone();
      wrapperRequest.setHandler(wrapperHandler);

      // Perform request
      request(wrapperRequest);
      return;
    }

    // User is not authenticated
    // request a token
    fetchAnonymousAccessTokenAndRunRequest(request);
  }

  /**
   * Thin wrapper to the {@link AsyncHttpClient} library
   *
   * @param request
   */
  private static void request(final Request request) {

    if (null == request) {
      Log.e("Scoreflex", "Request with null request.");
      return;
    }

    // Decorate parameters
    ScoreflexRequestParamsDecorator.decorate(request.getResource(),
        request.getParams());

    // Generate signature
    Header authorizationHeader = request.getAuthorizationHeader();

    // Headers
    Header[] headers = null;
    if (null != authorizationHeader) {
      headers = new Header[1];
      headers[0] = authorizationHeader;
    }

    // Handler
    JsonHttpResponseHandler jsonHandler = null;
    if (null != request.getHandler()) {
      jsonHandler = new JsonHttpResponseHandler() {

        @Override
        public void onFailure(Throwable arg0, JSONObject arg1) {
          if (arg1 != null) {
            if (Scoreflex.showDebug) {
              Log.d("Scoreflex", "Requesting Error: " + arg1);
            }
            Scoreflex.setNetworkAvailable(true);
            request.getHandler().onFailure(arg0, new Scoreflex.Response(arg1));
          } else {
            Scoreflex.setNetworkAvailable(false);
            request.getHandler().onFailure(arg0, null);
          }
        }

        @Override
        public void onFailure(Throwable arg0, String arg1) {
          Scoreflex.setNetworkAvailable(false);
          request.getHandler().onFailure(arg0, null);
        }

        @Override
        public void onSuccess(int arg0, JSONObject arg1) {
          Scoreflex.setNetworkAvailable(true);
          request.getHandler().onSuccess(arg0, new Scoreflex.Response(arg1));
        }
      };
    }

    String url = ScoreflexUriHelper.getAbsoluteUrl(request.getResource());
    if (Scoreflex.showDebug) {
      Log.d("Scoreflex", "requesting url["+request.getMethod()+"]: "+ url + "?" + request.getParams().getURLEncodedString());
    }
    // TODO: support other contentTypes such as "application/json"
    String contentType = "application/x-www-form-urlencoded";
    switch (request.getMethod()) {
    case GET:
      sClient.get(null, url, headers, request.getParams(), jsonHandler);
      break;
    case PUT:
      sClient.put(null, url, headers, request.getParams() != null ? request
          .getParams().getEntity() : null, contentType, jsonHandler);
      break;
    case POST:
      sClient.post(null, url, headers, request.getParams(), contentType,
          jsonHandler);
      break;
    case DELETE:
      sClient.delete(null, url, headers, jsonHandler);
      break;
    }
  }

  protected static void fetchAnonymousAccessToken(
      final Scoreflex.ResponseHandler handler) {
    fetchAnonymousAccessToken(handler, 0);
  }

  protected static void fetchAnonymousAccessToken(
      final Scoreflex.ResponseHandler handler, final int nbRetries) {
    if (sIsFetchingAnonymousAccessToken) {
      queueHandler(handler);
      return;
    }
    sIsFetchingAnonymousAccessToken = true;
    Scoreflex.RequestParams authParams = new Scoreflex.RequestParams();
    authParams.put("clientId", Scoreflex.getClientId());
    authParams.put("devicePlatform", "Android");
    authParams.put("deviceModel", Scoreflex.getDeviceModel());
    String udid = Scoreflex.getUDID();
    if (null != udid)
      authParams.put("deviceId", udid);

    String resource = "/oauth/anonymousAccessToken";

    request(new Request(HttpMethod.POST, resource, authParams,
        new Scoreflex.ResponseHandler() {

          @Override
          public void onFailure(Throwable e, Response errorResponse) {

            if (nbRetries <= 0) {
              Log.e("Scoreflex", "Error request anonymous access token (aborting):"
                  + (errorResponse != null ? errorResponse.getJSONObject()
                      .toString() : " null error response, aborting"), e);

              sIsFetchingAnonymousAccessToken = false;
              if (null != handler) {
                handler.onFailure(e, errorResponse);
              }
              Scoreflex.ResponseHandler chainedHandler = null;
              while ((chainedHandler = dequeueHandler()) != null) {
                chainedHandler.onFailure(e, errorResponse);
              }
              return;
            }
            Log.e("Scoreflex", "Error request anonymous access token (retrying : "+nbRetries+"):"
                + (errorResponse != null ? errorResponse.getJSONObject()
                    .toString() : " null error response, retrying"), e);

            new Handler().postDelayed(new Runnable() {

              @Override
              public void run() {
                sIsFetchingAnonymousAccessToken = false;
                fetchAnonymousAccessToken(handler, nbRetries -1);
              }
            }, RETRY_INTERVAL);
          }

          @Override
          public void onSuccess(int statusCode, Response response) {
            // Parse response
            JSONObject json = response.getJSONObject();
            if (json.has("accessToken") && json.has("sid")) {
              JSONObject accessToken = json.optJSONObject("accessToken");
              String sid = json.optString("sid");
              JSONObject meObject = json.optJSONObject("me");
              String playerId = meObject.optString("id");
              if (null != accessToken && accessToken.has("token")) {
                String token = accessToken.optString("token");

                // Store access token
                setAccessToken(token, true);
                setSID(sid);
                setPlayerId(playerId);
                sIsFetchingAnonymousAccessToken = false;

                Intent intent = new Intent(Scoreflex.INTENT_USER_LOGED_IN);
                intent.putExtra(Scoreflex.INTENT_USER_LOGED_IN_EXTRA_SID, sid);
                intent.putExtra(
                    Scoreflex.INTENT_USER_LOGED_IN_EXTRA_ACCESS_TOKEN, token);
                LocalBroadcastManager.getInstance(
                    Scoreflex.getApplicationContext()).sendBroadcast(intent);

                // call handlers
                if (null != handler) {
                  handler.onSuccess(statusCode, response);
                }
                Scoreflex.ResponseHandler chainedHandler = null;
                while ((chainedHandler = dequeueHandler()) != null) {
                  chainedHandler.onSuccess(statusCode, response);
                }
                return;
              }
            }
            Log.e("Scoreflex",
                "Could not obtain anonymous access token from server");

          }

          @Override
          public void onSuccess(Response response) {

          }

        }));

  }

  /**
   * Fetches an anonymous access token and run the given request with that
   * token. Retries when access token cannot be fetched.
   *
   * @param request
   *          The request to be run
   */
  public static void fetchAnonymousAccessTokenAndRunRequest(
      final Request request) {
    fetchAnonymousAccessToken(new Scoreflex.ResponseHandler() {

      @Override
      public void onSuccess(Response response) {
        requestAuthenticated(request);
      }

      @Override
      public void onFailure(Throwable e, Response errorResponse) {

      }
    });
  }

  private static void queueHandler(Scoreflex.ResponseHandler handler) {
    if (null == handler) {
      return;
    }

    synchronized (sPendingHandlers) {
      sPendingHandlers.add(handler);
    }
  }

  private static Scoreflex.ResponseHandler dequeueHandler() {
    Scoreflex.ResponseHandler handler = null;
    synchronized (sPendingHandlers) {
      if (sPendingHandlers.size() > 0) {
        handler = sPendingHandlers.get(0);
        if (null != handler) {
          sPendingHandlers.remove(0);
        }
      }
    }
    return handler;
  }

  /**
   * Get the access token stored in the user's shared preferences.
   *
   * @return
   */

  protected static String getAccessToken() {
    SharedPreferences prefs = Scoreflex.getSharedPreferences();
    if (null == prefs) {
      return null;
    }
    String token = prefs.getString(ACCESS_TOKEN_PREF_NAME, null);
    return token;
  }

  /**
   * Is the access token stored in the user's shared preferences anonymous ?
   *
   * @return
   */

  protected static boolean getAccessTokenIsAnonymous() {
    SharedPreferences prefs = Scoreflex.getSharedPreferences();
    if (null == prefs) {
      return true;
    }
    return prefs.getBoolean(ACCESS_TOKEN_IS_ANONYMOUS_PREF_NAME, true);
  }

  /**
   * Set the SID stored in the user's shared preferences.
   *
   * @param accessToken
   *          The access token to be stored
   */
  protected static void setSID(String sid) {

    SharedPreferences preferences = Scoreflex.getSharedPreferences();
    SharedPreferences.Editor editor = preferences.edit();
    if (null == sid)
      editor.remove(SID_PREF_NAME);
    else
      editor.putString(SID_PREF_NAME, sid);
    editor.commit();

  }

  protected static void setPlayerId(String playerId) {
    SharedPreferences preferences = Scoreflex.getSharedPreferences();
    SharedPreferences.Editor editor = preferences.edit();
    if (null == playerId)
      editor.remove(PLAYER_ID_PREF_NAME);
    editor.putString(PLAYER_ID_PREF_NAME, playerId);
    editor.commit();

  }

  protected static String getPlayerId(Context applicationContext) {
    SharedPreferences prefs = Scoreflex
        .getSharedPreferences(applicationContext);
    if (null == prefs) {
      return null;
    }
    String playerId = prefs.getString(PLAYER_ID_PREF_NAME, null);
    return playerId;

  }

  protected static String getPlayerId() {
    SharedPreferences prefs = Scoreflex.getSharedPreferences();
    if (null == prefs) {
      return null;
    }
    String playerId = prefs.getString(PLAYER_ID_PREF_NAME, null);
    return playerId;

  }

  /**
   * Get the access token stored in the user's shared preferences.
   *
   * @return
   */

  protected static String getSID() {
    SharedPreferences prefs = Scoreflex.getSharedPreferences();
    if (null == prefs) {
      return null;
    }
    String sid = prefs.getString(SID_PREF_NAME, null);
    return sid;
  }

  /**
   * Set the access token stored in the user's shared preferences.
   *
   * @param accessToken
   *          The access token to be stored
   * @param isAnonymous
   *          Is this access token anonymous
   */
  protected static void setAccessToken(String accessToken, boolean isAnonymous) {
    SharedPreferences preferences = Scoreflex.getSharedPreferences();
    SharedPreferences.Editor editor = preferences.edit();
    if (null == accessToken) {
      editor.remove(ACCESS_TOKEN_PREF_NAME);
      editor.remove(ACCESS_TOKEN_IS_ANONYMOUS_PREF_NAME);
    } else {
      editor.putString(ACCESS_TOKEN_PREF_NAME, accessToken);
      editor.putBoolean(ACCESS_TOKEN_IS_ANONYMOUS_PREF_NAME, isAnonymous);
    }
    editor.commit();

  }

  /**
   * A serializable object that represents a request to the Scoreflex API.
   *
   *
   */

  protected static class Request implements Cloneable {
    HttpMethod mMethod;
    Scoreflex.RequestParams mParams;
    Scoreflex.ResponseHandler mHandler;
    String mResource;

    public Request(HttpMethod method, String resource,
        Scoreflex.RequestParams params, Scoreflex.ResponseHandler handler) {
      mMethod = method;
      mParams = params;
      mHandler = handler;
      mResource = resource;
    }

    public Request(JSONObject data) throws JSONException {
      mMethod = HttpMethod.values()[data.getInt("method")];
      mResource = data.getString("resource");
      JSONObject paramsJson = data.getJSONObject("params");
      mParams = new Scoreflex.RequestParams();
      @SuppressWarnings("unchecked")
      Iterator<String> keys = paramsJson.keys();
      while (keys.hasNext()) {
        String key = keys.next();
        mParams.put(key, paramsJson.getString(key));
      }
    }

    public JSONObject toJSON() throws JSONException {
      JSONObject result = new JSONObject();
      result.put("method", mMethod.ordinal());
      result.put("resource", mResource);
      JSONObject params = new JSONObject();
      if (null != mParams)
        for (String key : mParams.getParamNames())
          params.put(key, mParams.getParamValue(key));
      result.put("params", params);
      return result;
    }

    public HttpMethod getMethod() {
      return mMethod;
    }

    public Scoreflex.RequestParams getParams() {
      return mParams;
    }

    public Scoreflex.ResponseHandler getHandler() {
      return mHandler;
    }

    public String getResource() {
      return mResource;
    }

    public void setMethod(HttpMethod mMethod) {
      this.mMethod = mMethod;
    }

    public void setParams(Scoreflex.RequestParams mParams) {
      this.mParams = mParams;
    }

    public void setHandler(Scoreflex.ResponseHandler mHandler) {
      this.mHandler = mHandler;
    }

    public void setResource(String resource) {
      this.mResource = resource;
    }

    @Override
    protected Object clone() {
      return new Request(mMethod, mResource, mParams, mHandler);
    }

    /**
     * Generates X-Scoreflex-Authorization header with request signature
     *
     * @return The authorization header or null for GET requests
     */
    @SuppressLint("DefaultLocale")
    protected BasicHeader getAuthorizationHeader() {
      try {
        StringBuilder sb = new StringBuilder();

        // Step 1: add HTTP method uppercase
        switch (mMethod) {
        case POST:
          sb.append("POST");
          break;
        case PUT:
          sb.append("PUT");
          break;
        case GET:
          // No authorization header for GET requests
          return null;
        case DELETE:
          sb.append("DELETE");
          break;
        }

        sb.append('&');

        // Step 2: add the URI
        Uri uri = Uri.parse(mResource);

        // Query string is stripped from resource
        sb.append(encode(String.format("%s%s", Scoreflex.getBaseURL(),
            uri.getEncodedPath())));

        // Step 3: add URL encoded parameters
        sb.append('&');
        TreeSet<String> paramNames = new TreeSet<String>();

        // Params from the URL
        Scoreflex.RequestParams queryStringParams = QueryStringParser
            .getRequestParams(uri.getQuery());
        if (null != queryStringParams)
          paramNames.addAll(queryStringParams.getParamNames());

        // Params from the request
        if (null != mParams)
          paramNames.addAll(mParams.getParamNames());

        if (paramNames.size() > 0) {

          String last = paramNames.last();
          for (String paramName : paramNames) {
            String paramValue = null;

            if (null != mParams)
              paramValue = mParams.getParamValue(paramName);

            if (null == paramValue && null != queryStringParams)
              paramValue = queryStringParams.getParamValue(paramName);

            sb.append(encode(String.format("%s=%s", encode(paramName),
                encode(paramValue))));
            if (!last.equals(paramName))
              sb.append("%26");

          }
        }

        // Step 4: add body
        sb.append('&');
        // TODO: add the body here when we support other content types
        // than application/x-www-form-urlencoded
        Mac mac = Mac.getInstance("HmacSHA1");
        SecretKeySpec secret = new SecretKeySpec(Scoreflex.getClientSecret()
            .getBytes("UTF-8"), mac.getAlgorithm());
        mac.init(secret);
        byte[] digest = mac.doFinal(sb.toString().getBytes());
        String sig = Base64.encodeToString(digest, Base64.DEFAULT).trim();
        String encodedSig = encode(sig.trim());
        BasicHeader result = new BasicHeader("X-Scoreflex-Authorization",
            String.format("Scoreflex sig=\"%s\", meth=\"0\"", encodedSig));
        return result;
      } catch (Exception e) {
        Log.e("Scoreflex", "Could not generate signature", e);
        return null;
      }
    }

    private static String encode(String s) throws UnsupportedEncodingException {
      return URLEncoder.encode(s, "UTF-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~");
    }

    @Override
    public String toString() {
      String method = null;
      switch (mMethod) {
      case POST:
        method = "POST";
        break;
      case PUT:
        method = "PUT";
        break;
      case GET:
        method = "GET";
        break;
      case DELETE:
        method = "DELETE";
      }
      return String.format("%s %s", method, mResource);
    }

  }

}




Java Source Code List

com.scoreflex.ConnectivityReceiver.java
com.scoreflex.QueryStringParser.java
com.scoreflex.ScoreflexActivity.java
com.scoreflex.ScoreflexBroadcastReceiver.java
com.scoreflex.ScoreflexGcmClient.java
com.scoreflex.ScoreflexJobQueue.java
com.scoreflex.ScoreflexRequestParamsDecorator.java
com.scoreflex.ScoreflexRequestVault.java
com.scoreflex.ScoreflexRestClient.java
com.scoreflex.ScoreflexUriHelper.java
com.scoreflex.ScoreflexView.java
com.scoreflex.Scoreflex.java
com.scoreflex.SocialCallback.java
com.scoreflex.SocialShareCallback.java
com.scoreflex.facebook.ScoreflexFacebookWrapper.java
com.scoreflex.google.ScoreflexGcmWrapper.java
com.scoreflex.google.ScoreflexGoogleWrapper.java
com.scoreflex.model.JSONParcelable.java