Android Open Source - scoreflex-android-sdk Scoreflex View






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
 *//from   w  w  w . j a va  2  s. com
 *    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.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.scoreflex.Scoreflex.Response;
import com.scoreflex.facebook.ScoreflexFacebookWrapper;
import com.scoreflex.facebook.ScoreflexFacebookWrapper.FacebookException;
import com.scoreflex.google.ScoreflexGoogleWrapper;
import com.scoreflex.model.JSONParcelable;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Handler;
import android.os.Parcelable;
import android.provider.MediaStore;
import android.support.v4.content.LocalBroadcastManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.webkit.ValueCallback;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import android.webkit.WebChromeClient;
import android.webkit.ConsoleMessage;

/**
 * An Android view that displays Scoreflex content. A ScoreflexView
 * will hold a WebView pointing to Scoreflex web content.
 *
 *
 */
@SuppressLint("SetJavaScriptEnabled")
public class ScoreflexView extends FrameLayout {
  WebView mWebView;
  Activity mParentActivity;
  ViewGroup mErrorLayout;
  TextView mMessageView;
  ProgressBar mProgressBar;
  ScoreflexWebCallbackHandler mWebCallbackHandler = new ScoreflexWebCallbackHandler();
  ImageButton mCloseButton;
  ScoreflexView mSubview;
  Uri mOutputFileUri;
  UserInterfaceState mUserInterfaceState;
  ValueCallback<Uri> mUploadMessage;
  String mInitialResource;
  ScoreflexViewListener mScoreflexViewHandler;
  Scoreflex.RequestParams mInitialRequestParams;
  boolean mIsPreloading;
  protected boolean isLoginSource;

  /**
   * The constructor of the view.
   * @param activity The activity holding the view.
   * @param attrs
   * @param defStyle
   */
  @SuppressWarnings("deprecation")
  public ScoreflexView(Activity activity, AttributeSet attrs, int defStyle) {
    super(activity, attrs, defStyle);

    // Keep a reference on the activity
    mParentActivity = activity;

    // Default layout params
    if (null == getLayoutParams()) {
      setLayoutParams(new ViewGroup.LayoutParams(
          ViewGroup.LayoutParams.MATCH_PARENT,
          Scoreflex.getDensityIndependantPixel(R.dimen.scoreflex_panel_height)));
    }

    // Set our background color
    setBackgroundColor(getContext().getResources().getColor(
        R.color.scoreflex_background_color));

    // Create the top bar
    View topBar = new View(getContext());
    topBar.setLayoutParams(new FrameLayout.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT, getResources()
            .getDimensionPixelSize(R.dimen.scoreflex_topbar_height),
        Gravity.TOP));
    topBar.setBackgroundDrawable(getResources().getDrawable(
        R.drawable.scoreflex_gradient_background));
    addView(topBar);

    // Create the retry button
    LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
        Context.LAYOUT_INFLATER_SERVICE);

    mErrorLayout = (ViewGroup) inflater.inflate(
        R.layout.scoreflex_error_layout, null);
    if (mErrorLayout != null) {

      // Configure refresh button
      Button refreshButton = (Button) mErrorLayout
          .findViewById(R.id.scoreflex_retry_button);
      if (null != refreshButton) {
        refreshButton.setOnClickListener(new View.OnClickListener() {

          @Override
          public void onClick(View arg0) {
            if (null == Scoreflex.getPlayerId()) {
              setUserInterfaceState(new LoadingState());
              loadUrlAfterLoggedIn(mInitialResource, mInitialRequestParams);
            } else if (null == mWebView.getUrl()) {
              setResource(mInitialResource);
            } else {
              mWebView.reload();
            }
          }
        });
      }

      // Configure cancel button
      Button cancelButton = (Button) mErrorLayout
          .findViewById(R.id.scoreflex_cancel_button);
      if (null != cancelButton) {
        cancelButton.setOnClickListener(new View.OnClickListener() {

          @Override
          public void onClick(View arg0) {
            close();
          }
        });
      }

      // Get hold of the message view
      mMessageView = (TextView) mErrorLayout
          .findViewById(R.id.scoreflex_error_message_view);
      addView(mErrorLayout);

    }

    // Create the close button
    mCloseButton = new ImageButton(getContext());
    Drawable closeButtonDrawable = getResources().getDrawable(
        R.drawable.scoreflex_close_button);
    int closeButtonMargin = (int) ((getResources().getDimensionPixelSize(
        R.dimen.scoreflex_topbar_height) - closeButtonDrawable
        .getIntrinsicHeight()) / 2.0f);
    FrameLayout.LayoutParams closeButtonLayoutParams = new FrameLayout.LayoutParams(
        ViewGroup.LayoutParams.WRAP_CONTENT,
        ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.TOP | Gravity.RIGHT);
    closeButtonLayoutParams.setMargins(0, closeButtonMargin, closeButtonMargin,
        0);
    mCloseButton.setLayoutParams(closeButtonLayoutParams);
    mCloseButton.setImageDrawable(closeButtonDrawable);
    mCloseButton.setBackgroundDrawable(null);
    mCloseButton.setPadding(0, 0, 0, 0);
    mCloseButton.setOnClickListener(new View.OnClickListener() {

      @Override
      public void onClick(View arg0) {
        close();
      }
    });
    addView(mCloseButton);

    // Create the web view
    mWebView = new WebView(mParentActivity);
    mWebView.setLayoutParams(new ViewGroup.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT,
        ViewGroup.LayoutParams.MATCH_PARENT));
    // mWebView.setBackgroundColor(Color.RED);
    mWebView.setWebViewClient(new ScoreflexWebViewClient());
    mWebView.setWebChromeClient(new WebChromeClient() {

      @Override
      public boolean onConsoleMessage(ConsoleMessage cm) {
         Log.d(
                         "Scoreflex",
                         "javascript Error: "
                             + String.format("%s @ %d: %s", cm.message(), cm.lineNumber(),
                                 cm.sourceId()));
        return true;
      }

      public void openFileChooser(ValueCallback<Uri> uploadMsg) {
        // mtbActivity.mUploadMessage = uploadMsg;
        mUploadMessage = uploadMsg;

        String fileName = "picture.jpg";
        ContentValues values = new ContentValues();
        values.put(MediaStore.Images.Media.TITLE, fileName);
        // mOutputFileUri = mParentActivity.getContentResolver().insert(
        // MediaStore.Images.Media.DATA, values);
        final List<Intent> cameraIntents = new ArrayList<Intent>();
        final Intent captureIntent = new Intent(
            android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
        final PackageManager packageManager = mParentActivity
            .getPackageManager();
        final List<ResolveInfo> listCam = packageManager.queryIntentActivities(
            captureIntent, 0);
        for (ResolveInfo res : listCam) {
          final String packageName = res.activityInfo.packageName;
          final Intent intent = new Intent(captureIntent);
          intent.setComponent(new ComponentName(res.activityInfo.packageName,
              res.activityInfo.name));
          intent.setPackage(packageName);
          cameraIntents.add(intent);
        }

        // Filesystem.
        final Intent galleryIntent = new Intent();
        galleryIntent.setType("image/*");
        galleryIntent.setAction(Intent.ACTION_GET_CONTENT);

        // Chooser of filesystem options.
        final Intent chooserIntent = Intent.createChooser(galleryIntent,
            "Select Source please");

        // Add the camera options.
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS,
            cameraIntents.toArray(new Parcelable[] {}));

        mParentActivity.startActivityForResult(chooserIntent,
            Scoreflex.FILECHOOSER_RESULTCODE);
      }

      public void openFileChooser(ValueCallback<Uri> uploadMsg,
          String acceptType) {
        openFileChooser(uploadMsg);
      }

      public void openFileChooser(ValueCallback<Uri> uploadMsg,
          String acceptType, String capture) {
        openFileChooser(uploadMsg);
      }
    });
    mWebView.getSettings().setJavaScriptEnabled(true);
    mWebView.getSettings().setDomStorageEnabled(true);
    mWebView.getSettings().setDatabasePath(
        getContext().getFilesDir().getPath() + "/data/"
            + getContext().getPackageName() + "/databases/");
    addView(mWebView);

    TypedArray a = mParentActivity.obtainStyledAttributes(attrs,
        R.styleable.ScoreflexView, defStyle, 0);
    String resource = a.getString(R.styleable.ScoreflexView_resource);
    if (null != resource)
      setResource(resource);

    a.recycle();

    // Create the animated spinner

    mProgressBar = (ProgressBar) ((LayoutInflater) getContext()
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(
        R.layout.scoreflex_progress_bar, null);
    mProgressBar.setLayoutParams(new FrameLayout.LayoutParams(
        ViewGroup.LayoutParams.WRAP_CONTENT,
        ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER));
    addView(mProgressBar);
    LocalBroadcastManager.getInstance(activity).registerReceiver(mLoginReceiver,
        new IntentFilter(Scoreflex.INTENT_USER_LOGED_IN));
    setUserInterfaceState(new InitialState());
  }

  /**
   * The constructor of the view.
   * @param activity The activity hodling the view.
   * @param attrs
   */
  public ScoreflexView(Activity activity, AttributeSet attrs) {
    this(activity, attrs, 0);
  }

  /**
   * The constructor of the view.
   * @param activity The activity hodling the view.
   */
  public ScoreflexView(Activity activity) {
    this(activity, null);
  }

  private void setUserInterfaceState(UserInterfaceState state) {
    if (null != mUserInterfaceState)
      mUserInterfaceState.onLeaveState();
    mUserInterfaceState = state;
    state.onEnterState();
    requestLayout();
  }

  /**
   * Can the webview go back (is its history stack non-empty) ?
   *
   * @return Wether the view can go back or not.
   */
  public boolean canGoBack() {
    return mWebView.canGoBack();
  }

  /**
   * Makes the webview go back.
   */
  public void goBack() {
    mWebView.goBack();
  }


  private void loadUrlAfterLoggedIn(final String resource, final Scoreflex.RequestParams params)
  {

    ScoreflexRestClient.fetchAnonymousAccessToken(new Scoreflex.ResponseHandler() {

      @Override
      public void onFailure(Throwable e, Response errorResponse) {
        mMessageView.setText(R.string.scoreflex_network_error);
        setUserInterfaceState(new ErrorState());
      }

      @Override
      public void onSuccess(Response response) {
        ScoreflexRequestParamsDecorator.decorate(resource, params);
        String url = String.format(Locale.getDefault(), "%s?%s",
          ScoreflexUriHelper.getNonSecureAbsoluteUrl(resource),
          params.getURLEncodedString());
        mWebView.loadUrl(url);
      }
    }, 0);
  }

  /**
   * Preloads all the static resources of the selected url.
   *
   * @param resource The url to preload..
   */
  public void preloadResource(String resource) {

    setLayoutParams(new ViewGroup.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
    mIsPreloading = true;
    mInitialResource = resource;
    Scoreflex.RequestParams params = new Scoreflex.RequestParams();
    if (Scoreflex.getPlayerId() != null) {
      ScoreflexRequestParamsDecorator.decorate(resource, params);
      String url = String.format(Locale.getDefault(), "%s?%s",
          ScoreflexUriHelper.getNonSecureAbsoluteUrl(resource),
          params.getURLEncodedString());

      mWebView.loadUrl(url);
    } else {
      loadUrlAfterLoggedIn(resource,  new Scoreflex.RequestParams());
    }
  }

  public void startOpeningAnimation() {
    int gravity = getLayoutGravity();
    int anim = (Gravity.TOP == (gravity & Gravity.VERTICAL_GRAVITY_MASK)) ? R.anim.scoreflex_enter_slide_down
        : R.anim.scoreflex_enter_slide_up;
    Animation animation = AnimationUtils.loadAnimation(mParentActivity, anim);
    this.startAnimation(animation);
  }


  /**
   * Sets the listener that will be called during the lifecycle of the view
   * @param listener the listener
   */
  public void setScoreflexViewListener(ScoreflexViewListener listener) {
    mScoreflexViewHandler = listener;
  }

  /**
   * Closes this ScoreflexView. If the view is attached to the developer
   * hierarchy it will be detached. If the view is attached to a
   * ScoreflexActivity, this activity will be terminated.
   */
  public void close() {
    // If we're displayed in the developer view hierarchy,
    // remove ourselves.
    final ViewParent parent = this.getParent();
    ViewGroup.LayoutParams currentLayoutParams = getLayoutParams();
    boolean isFullscreen = currentLayoutParams.height == LayoutParams.MATCH_PARENT;

    LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(mLoginReceiver);

    if (isFullscreen && null != parent && parent instanceof ViewGroup) {
      int gravity = getLayoutGravity();
      int anim = (Gravity.TOP == (gravity & Gravity.VERTICAL_GRAVITY_MASK)) ? R.anim.scoreflex_exit_slide_up
          : R.anim.scoreflex_exit_slide_down;
      Animation animation = AnimationUtils.loadAnimation(mParentActivity, anim);
      animation.setAnimationListener(new AnimationListener() {

        @Override
        public void onAnimationEnd(Animation arg0) {
          ViewGroup parentGroup = (ViewGroup) parent;
          parentGroup.removeView(ScoreflexView.this);
          if (mScoreflexViewHandler != null) {
            mScoreflexViewHandler.onViewClosed();
            mScoreflexViewHandler = null;
          }
        }

        @Override
        public void onAnimationRepeat(Animation arg0) {

        }

        @Override
        public void onAnimationStart(Animation arg0) {

        }

      });
      startAnimation(animation);
    } else if (null != parent && parent instanceof ViewGroup) {
      ViewGroup parentGroup = (ViewGroup) parent;
      parentGroup.removeView(this);
      if (mScoreflexViewHandler != null) {
        mScoreflexViewHandler.onViewClosed();
        mScoreflexViewHandler = null;
      }
    }
  }

  /**
   * Sets the resource for the web content displayed in this ScoreflexView's
   * webview.
   *
   * @param resource
   */
  public void setResource(String resource) {
    setResource(resource, null, false);
  }

  protected int getLayoutGravity() {
    ViewGroup.LayoutParams currentLayoutParams = getLayoutParams();
    int gravity = Scoreflex.getDefaultGravity() & Gravity.VERTICAL_GRAVITY_MASK;
    if (currentLayoutParams instanceof FrameLayout.LayoutParams) {
      FrameLayout.LayoutParams frameLayoutParams = (FrameLayout.LayoutParams) currentLayoutParams;
      gravity = (Gravity.TOP == (frameLayoutParams.gravity & Gravity.VERTICAL_GRAVITY_MASK)) ? Gravity.TOP
          : Gravity.BOTTOM;
    }
    return gravity;
  }

  protected View openNewView(String resource, Scoreflex.RequestParams params,
      boolean forceFullScreen) {
    int gravity = getLayoutGravity();
    int anim = (Gravity.TOP == (gravity & Gravity.VERTICAL_GRAVITY_MASK)) ? R.anim.scoreflex_enter_slide_down
        : R.anim.scoreflex_enter_slide_up;
    Animation animation = AnimationUtils.loadAnimation(mParentActivity, anim);

    ScoreflexView webview = new ScoreflexView(mParentActivity);
    webview.setResource(resource, params, forceFullScreen);
    ViewGroup contentView = (ViewGroup) mParentActivity.getWindow()
        .getDecorView().findViewById(android.R.id.content);
    FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT,
        ViewGroup.LayoutParams.MATCH_PARENT, gravity);
    webview.setLayoutParams(layoutParams);
    contentView.addView(webview);
    webview.startAnimation(animation);
    Scoreflex.setCurrentScoreflexView(this);
    return webview;
  }

  /**
   * Sets the resource for the web content displayed in this ScoreflexView's
   * webview.
   *
   * @param resource
   * @param params
   * @param forceFullScreen
   */
  public void setResource(String resource, Scoreflex.RequestParams params,
      boolean forceFullScreen) {
    if (null == resource) {
      Log.e("Scoreflex", "null resource provided to ScoreflexView");
      return;
    }
    mInitialResource = resource;
    mInitialRequestParams = params;
    mIsPreloading = false;
    if (null == params)
      params = new Scoreflex.RequestParams();

    ScoreflexRequestParamsDecorator.decorate(resource, params);

    ViewGroup.LayoutParams currentLayoutParams = getLayoutParams();
    boolean isFullscreen = currentLayoutParams.height == LayoutParams.MATCH_PARENT;

    if (isFullscreen && forceFullScreen) {
      Scoreflex.setCurrentScoreflexView(this);
    }

    if (isFullscreen || forceFullScreen == false) {
      if (Scoreflex.getPlayerId() != null) {
        String url = String.format(Locale.getDefault(), "%s?%s",
            ScoreflexUriHelper.getNonSecureAbsoluteUrl(resource),
            params.getURLEncodedString());
        mWebView.loadUrl(url);
      } else {
        loadUrlAfterLoggedIn(resource, params);
      }


      return;
    }


    if (Scoreflex.getPlayerId() != null) {
      String url = String.format(Locale.getDefault(), "%s?%s#start",
          ScoreflexUriHelper.getNonSecureAbsoluteUrl(resource),
          params.getURLEncodedString());
      mWebView.loadUrl(url);
    } else {
      loadUrlAfterLoggedIn(resource, params);
    }
    Scoreflex.setCurrentScoreflexView(this);
    // String fullUrl = String.format("%s?%s",
    // ScoreflexUriHelper.getNonSecureAbsoluteUrl(resource),
    // params != null ? params.getURLEncodedString(): "");
    int gravity = getLayoutGravity();
    FrameLayout.LayoutParams newLayoutParams = new FrameLayout.LayoutParams(
        LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, gravity);
    this.setLayoutParams(newLayoutParams);

    this.startOpeningAnimation();
    return;

  }

  /**
   * Sets the resource for the web content displayed in this ScoreflexView's
   * webview.
   *
   * @param resource
   * @param params
   */
  public void setResource(String resource, Scoreflex.RequestParams params) {
    setResource(resource, params, false);
  }

  /**
   * Sets the full URL for the web content displayed in this ScoreflexView's
   * webview.
   *
   * @param fullUrl
   *          A full Scoreflex URL.
   * @throws IllegalArgumentException
   *           When the provided URL is not a Scoreflex URL.
   */
  public void setFullUrl(String fullUrl) throws IllegalArgumentException {
    if (fullUrl == null)
        return;

    Uri parsedUri = Uri.parse(fullUrl);

    if (!ScoreflexUriHelper.isAPIUri(parsedUri))
      throw new IllegalArgumentException(String.format(
          "Not a Scoreflex URL: %s", fullUrl));



    setResource(ScoreflexUriHelper.getResource(parsedUri),
        ScoreflexUriHelper.getParams(parsedUri));
  }

  /**
   * Sets the full URL for the web content displayed in this ScoreflexView's
   * webview.
   *
   * @param fullUrl
   *          A full Scoreflex URL
   * @throws IllegalArgumentException
   *           When the provided URL is not a Scoreflex URL
   */
  public void setFullUrl(String fullUrl, boolean forceFullScreen,
      boolean newView) throws IllegalArgumentException {
    Uri parsedUri = Uri.parse(fullUrl);

    if (!ScoreflexUriHelper.isAPIUri(parsedUri))
      throw new IllegalArgumentException(String.format(
          "Not a Scoreflex URL: %s", fullUrl));
    if (!newView) {
      setResource(ScoreflexUriHelper.getResource(parsedUri),
          ScoreflexUriHelper.getParams(parsedUri), forceFullScreen);
      return;
    }
    openNewView(ScoreflexUriHelper.getResource(parsedUri),
        ScoreflexUriHelper.getParams(parsedUri), forceFullScreen);
  }

  /**
   * Removes the drop shadow.
   *
   */
  @SuppressWarnings("deprecation")
  public void removeDropShadow() {
    setBackgroundDrawable(null);
    setPadding(0, 0, 0, 0);
  }

  /**
   * Adds a drop shadow to this view.
   *
   * @param gravity
   *          The gravity of the Scoreflex view (not the drop shadow's).
   */
  @SuppressWarnings("deprecation")
  public void addDropShadow(int gravity) {
    boolean top = Gravity.TOP != (gravity & Gravity.VERTICAL_GRAVITY_MASK);
    setBackgroundDrawable(getContext().getResources().getDrawable(
        top ? R.drawable.scoreflex_top_shadow
            : R.drawable.scoreflex_bottom_shadow));
    int height = getResources().getDimensionPixelSize(
        R.dimen.scoreflex_shadow_height);
    setPadding(0, top ? height : 0, 0, top ? 0 : height);
  }

  /**
   * An implementation of {@link android.webkit.WebViewClient} that queries the
   * {@link ScoreflexWebCallbackHandler} before loading any URL.
   *
   *
   *
   */
  private class ScoreflexWebViewClient extends WebViewClient {

    private boolean mError;
    private boolean mIsLoading;
    private Timer mWebviewTimer;
    private Handler mMainThreadHandler;
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
      Uri uri = Uri.parse(url);

      // Handle market urls
      // https://play.google.com/store/apps/details?id=com.yakaz.mtb
      if ("market".equals(uri.getScheme())
          || "play.google.com".equals(uri.getHost())) {

        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url.replace(
            "https://play.google.com/store/apps", "market:/")));
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        Scoreflex.getApplicationContext().startActivity(intent);
        return true;
      }
      // Handle web callback
      if (mWebCallbackHandler.handleWebCallback(uri)) {
        return true;
      }

      return false;
    }

    @Override
    public void onPageStarted(final WebView view, String url, Bitmap favicon) {
      super.onPageStarted(view, url, favicon);
      // OnPageStarted is called twice on error
      if (!mIsLoading) {
        mError = false;
        setUserInterfaceState(new LoadingState());
      }
      if (null != mWebviewTimer) {
        mWebviewTimer.cancel();
        mWebviewTimer = null;
      }
      mMainThreadHandler = new Handler();
      mWebviewTimer = new Timer("webviewTimeout", true);
      mWebviewTimer.schedule(new TimerTask() {

        @Override
        public void run() {
          mMainThreadHandler.post(new Runnable(){

            @Override
            public void run() {
              view.stopLoading();
              mMessageView.setText(R.string.scoreflex_network_error);
              setUserInterfaceState(new ErrorState());
              // if we are preloading we must remove the preloaded view from the preloaded view pool
              if (ScoreflexView.this.mIsPreloading) {
                Scoreflex.freePreloadedResources(ScoreflexView.this.mInitialResource);
              }
            }});
        }}, Scoreflex.WEBVIEW_REQUEST_TOTAL_TIMEOUT);

      mIsLoading = true;
    }

    @Override
    public void onReceivedError(WebView view, int errorCode,
        String description, String failingUrl) {
      super.onReceivedError(view, errorCode, description, failingUrl);

      if (null != failingUrl && failingUrl.equals(view.getUrl())) {
        mError = true;
        if (null != mMessageView)
          mMessageView.setText(description);
        setUserInterfaceState(new ErrorState());
      }
    }

    @Override
    public void onPageFinished(WebView view, String url) {
      super.onPageFinished(view, url);
      if (mWebviewTimer != null) {
        mWebviewTimer.cancel();
      }
      mMainThreadHandler = null;
      mWebviewTimer = null;
      mIsLoading = false;
      if (mIsPreloading) {
        Uri parsedUri = Uri.parse(url);
        String resource = ScoreflexUriHelper.getResource(parsedUri);
        Intent intent = new Intent(Scoreflex.INTENT_RESOURCE_PRELOADED);
        intent.putExtra(Scoreflex.INTENT_RESOURCE_PRELOADED_EXTRA_PATH,
            resource);

        LocalBroadcastManager.getInstance(Scoreflex.getApplicationContext())
            .sendBroadcast(intent);
      }
      if (null != url && url.equals(view.getUrl())) {
        if (!mError) {
          setUserInterfaceState(new WebContentState());
        }
      }
    }

  }

  /**
   * A class that optionally handles a web callback uri. The callback uri should
   * be "/web/callback" and provide a code and a status. Depending on these 2
   * parameters, this object will trigger various behaviors.
   *
   *
   *
   */
  private class ScoreflexWebCallbackHandler {
    private static final String sCallbackResource = "/web/callback";

    private String mAuthGrantedNextUrlString;
    private String mAuthState;

    protected boolean handleWebCallback(Uri uri) {
      // Only handle when uri is the callback resource
      if (!sCallbackResource.equals(ScoreflexUriHelper.getResource(uri)))
        return false;

      // Parse status and code
      String statusString = uri.getQueryParameter("status");
      String codeString = uri.getQueryParameter("code");
      int status, code;
      try {
        status = Integer.parseInt(statusString);
        code = Integer.parseInt(codeString);
      } catch (NumberFormatException e) {
        Log.e("Scoreflex", String.format(
            "Invalid status or code (should be an int): %s %s", statusString,
            codeString), e);
        return false;
      }

      // Successes
      if (300 > status) {

        if (handleMoveToNewUrl(uri, status, code))
          return true;

        if (handleCloseWebView(uri, status, code))
          return true;

        if (handleNeedsAuth(uri, status, code))
          return true;

        if (handleAuthGranted(uri, status, code))
          return true;

        if (handleLogout(uri, status, code))
          return true;

        if (handleNeedsClientAuth(uri, status, code))
          return true;

        if (handleStartChallenge(uri, status, code))
          return true;

        if (handlePlayLevel(uri, status, code))
          return true;

        if (handleLinkService(uri, status, code))
          return true;

        if (handleSocialInvite(uri, status, code))
          return true;

        if (handleSocialShare(uri, status, code))
          return true;

      } else {

        // 404 errors: let the user see them
        if (404 == status)
          return false;

        // Generic errors
        if (handleGenericError(uri, status, code)) {
          return true;
        }

        // Invalid SID
        if (handleInvalidSIDError(uri, status, code))
          return true;

        // HTTPS required
        if (handleSecureConnectionRequiredError(uri, status, code))
          return true;

        // Inactive game
        if (handleInactiveGameError(uri, status, code))
          return true;
      }

      return false;
    }

    /*
     * case Scoreflex.ERROR_SECURE_CONNECTION_REQUIRED: res =
     * R.string.SCOREFLEX_ERROR_MISSING_MANDATORY_PARAMETER; break;
     *
     * case Scoreflex.ERROR_INACTIVE_GAME: res =
     * R.string.SCOREFLEX_ERROR_INACTIVE_GAME; break;
     */


    private boolean handlePlayLevel(Uri uri, int status, int code) {
      if (Scoreflex.SUCCESS_PLAY_LEVEL != code)
        return false;

      try {
        JSONObject data = new JSONObject(uri.getQueryParameter("data"));
        Intent intent = new Intent(Scoreflex.INTENT_PLAY_LEVEL);
        intent.putExtra(Scoreflex.INTENT_PLAY_LEVEL_EXTRA_LEADERBOARD_ID,
            data.getString("leaderboardId"));
        LocalBroadcastManager.getInstance(Scoreflex.getApplicationContext())
            .sendBroadcast(intent);
        close();
      } catch (Exception e) {

      }
      return false;
    }

    private boolean handleStartChallenge(Uri uri, int status, int code) {
      if (Scoreflex.SUCCESS_START_CHALLENGE != code)
        return false;

      try {
        JSONObject data = new JSONObject(uri.getQueryParameter("data"));
        Scoreflex.RequestParams params = new Scoreflex.RequestParams();
        params.put("fields","core,turn,outcome,config");
        Scoreflex.get(
            "/challenges/instances/" + data.getString("challengeInstanceId"),
            params, new Scoreflex.ResponseHandler() {
              public void onFailure(Throwable e, Response errorResponse) {

              }

              public void onSuccess(Response response) {
                JSONParcelable challengeInstance = new JSONParcelable(response.getJSONObject());
                Intent intent = new Intent(Scoreflex.INTENT_START_CHALLENGE);
                intent.putExtra(Scoreflex.INTENT_START_CHALLENGE_EXTRA_INSTANCE, challengeInstance);
                LocalBroadcastManager.getInstance(
                    Scoreflex.getApplicationContext()).sendBroadcast(intent);
                Scoreflex.startPlayingSession();
                close();
              }
            });
        return true;
      } catch (JSONException e) {
        e.printStackTrace();
      }
      return false;
    }

    private boolean handleInactiveGameError(Uri uri, int status, int code) {
      if (Scoreflex.ERROR_INACTIVE_GAME != code)
        return false;

      close();

      return true;

    }

    private boolean handleSecureConnectionRequiredError(Uri uri, int status,
        int code) {
      if (Scoreflex.ERROR_SECURE_CONNECTION_REQUIRED != code)
        return false;

      mWebView.loadUrl(uri.toString().replace("http:", "https:"));
      return true;
    }

    private boolean handleInvalidSIDError(Uri uri, int status, int code) {

      if (Scoreflex.ERROR_INVALID_SID != code)
        return false;

      // Invalidate access token
      ScoreflexRestClient.setAccessToken(null, true);

      // Invalidate SID
      ScoreflexRestClient.setSID(null);

      // Request a new anonymous access token
      ScoreflexRestClient.fetchAnonymousAccessTokenIfNeeded();

      return true;
    }

    private boolean handleGenericError(Uri uri, int status, int code) {
      int res;
      switch (code) {
      case Scoreflex.ERROR_INVALID_PARAMETER:
        res = R.string.SCOREFLEX_ERROR_INVALID_PARAMETER;
        break;
      case Scoreflex.ERROR_MISSING_MANDATORY_PARAMETER:
        res = R.string.SCOREFLEX_ERROR_INVALID_PARAMETER;
        break;
      case Scoreflex.ERROR_INVALID_PREV_NEXT_PARAMETER:
        res = R.string.SCOREFLEX_ERROR_INVALID_PREV_NEXT_PARAMETER;
        break;
      case Scoreflex.ERROR_SANDBOX_URL_REQUIRED:
        res = R.string.SCOREFLEX_ERROR_INVALID_PREV_NEXT_PARAMETER;
        break;
      case Scoreflex.ERROR_MISSING_PERMISSIONS:
        res = R.string.SCOREFLEX_ERROR_MISSING_PERMISSIONS;
        break;
      case Scoreflex.ERROR_PLAYER_DOES_NOT_EXIST:
        res = R.string.SCOREFLEX_ERROR_PLAYER_DOES_NOT_EXIST;
        break;
      case Scoreflex.ERROR_DEVELOPER_DOES_NOT_EXIST:
        res = R.string.SCOREFLEX_ERROR_DEVELOPER_DOES_NOT_EXIST;
        break;
      case Scoreflex.ERROR_GAME_DOES_NOT_EXIST:
        res = R.string.SCOREFLEX_ERROR_GAME_DOES_NOT_EXIST;
        break;
      case Scoreflex.ERROR_LEADERBOARD_CONFIG_DOES_NOT_EXIST:
        res = R.string.SCOREFLEX_ERROR_LEADERBOARD_CONFIG_DOES_NOT_EXIST;
        break;
      case Scoreflex.ERROR_SERVICE_EXCEPTION:
        res = R.string.SCOREFLEX_ERROR_SERVICE_EXCEPTION;
        break;
      default:
        return false;
      }

      Log.e("Scoreflex", getContext().getString(res));

      // In sandbox mode, we let the developer see the error page.
      if (Scoreflex.usesSandbox())
        return false;

      // In production, the error is handled by doing nothing
      return true;
    }

    private boolean handleLogout(Uri uri, int status, int code) {

      if (code != Scoreflex.SUCCESS_LOGOUT)
        return false;

      // Invalidate access token
      ScoreflexRestClient.setAccessToken(null, true);

      // Invalidate SID
      ScoreflexRestClient.setSID(null);

      // if (null != mParentActivity)
      // ScoreflexGoogleWrapper.logout(mParentActivity);

      if (null != mParentActivity)
        try {
          ScoreflexFacebookWrapper.logout(mParentActivity);
        } catch (FacebookException e) {
          Log.e("Scoreflex", "Error signing out of Facebook SDK", e);
        }

      // Remove all cookies
      CookieSyncManager cookieSyncManager = CookieSyncManager
          .createInstance(getContext());
      CookieManager cookieManager = CookieManager.getInstance();
      cookieManager.removeAllCookie();
      cookieManager.removeSessionCookie();
      cookieSyncManager.sync();

      // Request a new anonymous access token
      ScoreflexRestClient.fetchAnonymousAccessTokenIfNeeded();

      close();

      return true;

    }
    private void handleLoggedInResponse(JSONObject json)
    {
      if (null == json) {
        Log.e("Scoreflex",
            "Error authenticating, server didn't return a JSON response");
        return;
      }

      JSONObject accessToken = json.optJSONObject("accessToken");
      if (null == accessToken || !accessToken.has("token")) {
        Log.e("Scoreflex",
            "Error authenticating, server didn't return an access token");
        return;
      }

      if (!json.has("sid")) {
        Log.e("Scoreflex",
            "Error authenticating, server didn't return an sid");
        return;
      }

      String token = accessToken.optString("token");
      String sid = json.optString("sid");
      JSONObject meObject = json.optJSONObject("me");
      String playerId = meObject.optString("id");
      ScoreflexRestClient.setAccessToken(token, false);
      ScoreflexRestClient.setSID(sid);
      ScoreflexRestClient.setPlayerId(playerId);

      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);
      isLoginSource = true;
      LocalBroadcastManager.getInstance(
          Scoreflex.getApplicationContext()).sendBroadcast(intent);

      if (null != mAuthGrantedNextUrlString) {
        openFullUrl(mAuthGrantedNextUrlString, false, false);
        mWebView.clearHistory();
      }
    }

    private boolean handleAuthGranted(Uri uri, int status, int code) {

      if (code != Scoreflex.SUCCESS_AUTH_GRANTED)
        return false;

      String dataString = uri.getQueryParameter("data");

      JSONObject dataJson;
      try {
        dataJson = new JSONObject(dataString);
      } catch (JSONException e) {
        Log.e("Scoreflex", "Invalid json received in the data parameter", e);
        // Handle by doing nothing
        return true;
      }

      // Check returned state against our recorded state
      String state = dataJson.optString("state");
      if (null == mAuthState) {
        Log.e("Scoreflex",
            "Error authenticating as we have no recorded state to check against");
        return true;
      }

      if (!mAuthState.equals(state)) {
        Log.e(
            "Scoreflex",
            String
                .format(
                    "Error authenticating as the returned state doesn't match the one we recorded: %s != %s",
                    mAuthState, state));
        return true;
      }

      // Get the oauth code
      String codeString = dataJson.optString("code");

      if (null == codeString) {
        Log.e("Scoreflex", "Error authenticating, no oauth code returned");
        return true;
      }

      // Transform that code into a token
      Scoreflex.RequestParams params = new Scoreflex.RequestParams();
      params.put("code", codeString);
      params.put("clientId", Scoreflex.getClientId());
      params.put("devicePlatform", "Android");
      params.put("deviceModel", Scoreflex.getDeviceModel());
      String udid = Scoreflex.getUDID();
      if (null != udid)
        params.put("deviceId", udid);

      ScoreflexRestClient.post("/oauth/accessToken", params,
          new Scoreflex.ResponseHandler() {
            public void onFailure(Throwable e, Response errorResponse) {
              Log.e(
                  "Scoreflex",
                  String
                      .format(
                          "Error authenticating, could not transform code into accessToken: %s",
                          errorResponse.getErrorMessage()), e);
            }

            public void onSuccess(Response response) {
              handleLoggedInResponse(response.getJSONObject());
            }
          });

      return true;

    }

    private boolean handleNeedsClientAuth(Uri uri, int status, int code) {
      if (code != Scoreflex.SUCCESS_NEEDS_CLIENT_AUTH)
        return false;

      Scoreflex.RequestParams params = new Scoreflex.RequestParams();
      // Pass the anonymous access token
      String accessToken = ScoreflexRestClient.getAccessToken();
      if (ScoreflexRestClient.getAccessTokenIsAnonymous()
          && null != accessToken)
        params.put("anonymousAccessToken", accessToken);

      return nativeLogin(uri, false,
          params);
    }

    private boolean handleLinkService(Uri uri, int status, int code) {
      if (code != Scoreflex.SUCCESS_LINK_SERVICE)
        return false;

      JSONObject dataJson;
      String dataString = uri.getQueryParameter("data");
      try {
        dataJson = new JSONObject(dataString);
      } catch (JSONException e) {
        Log.e("Scoreflex", "Invalid json received in the data parameter", e);
        // Handle by doing nothing
        return true;
      }
      String service = dataJson.optString("service");
      if (null == service) {
        Log.w("Scoreflex", "handleLinkService: No service specified");
        return false;
      }

      return nativeLogin(uri, true,
          new Scoreflex.RequestParams());
    }

    private boolean nativeLogin(Uri uri, final boolean isLink,
        final Scoreflex.RequestParams params) {

      String dataString = uri.getQueryParameter("data");

      JSONObject dataJson;
      try {
        dataJson = new JSONObject(dataString);
      } catch (JSONException e) {
        Log.e("Scoreflex", "Invalid json received in the data parameter", e);
        // Handle by doing nothing
        return true;
      }

      // Manage next url
      final String nextUrlString = dataJson.optString("nextUrl");

      if (null != nextUrlString && 0 < nextUrlString.length()) {
        Uri nextUri = Uri.parse(nextUrlString);
        mAuthGrantedNextUrlString = String.format("%s?%s",
            ScoreflexUriHelper.getNonSecureAbsoluteUrl(nextUri.getPath()),
            nextUri.getQuery());
      }

      final String service = dataJson.optString("service");

      if (!"Facebook".equals(service) && !"Google".equals(service)) {
        Log.d("Scoreflex", "Unknown service: "
            + (service != null ? service : "null"));
        return false;
      }

      if ("Facebook".equals(service)
          && !ScoreflexFacebookWrapper.isFacebookAvailable(getContext()))
        return false;

      if ("Google".equals(service)
          && !ScoreflexGoogleWrapper.isGoogleAvailable(getContext()))
        return false;

      // Handle facebook when we live in a scoreflex activity only
      if (null == mParentActivity) {
        return false;
      }

      try {
        SocialCallback callback = new SocialCallback() {

          @Override
          public void call(String accessToken, Exception exception) {

            if (exception != null) {
              Log.e("Scoreflex", "Error with native login", exception);
            }

            if (null != accessToken && 0 < accessToken.length()) {

              params.put("clientId", Scoreflex.getClientId());
              params.put("service", service);
              params.put("serviceAccessToken", accessToken);
              params.put("state", mAuthState);
              params.put("devicePlatform", "Android");
              params.put("deviceModel", Scoreflex.getDeviceModel());
              params.put("deviceId", Scoreflex.getUDID());
              if (nextUrlString != null) {
                 params.put("next", nextUrlString);
              }

              if (isLink) {
                  setResource("/web/linkExternallyAuthenticated/" + service, params);
                  return;
              }

              // Generate a new auth state
              mAuthState = UUID.randomUUID().toString();
              ScoreflexRestClient.post("/oauth/accessTokenExternallyAuthenticated", params,
                  new Scoreflex.ResponseHandler() {
                    public void onFailure(Throwable e, Response errorResponse) {
                      Log.e(
                          "Scoreflex",
                          String
                              .format(
                                  "Error authenticating, could not transform code into accessToken: %s",
                                  errorResponse.getErrorMessage()), e);
                    }

                    public void onSuccess(Response response) {
                        handleLoggedInResponse(response.getJSONObject());
                    }
                  });
            }
          }
        };
        if ("Facebook".equals(service))
          ScoreflexFacebookWrapper.login(mParentActivity, callback);

        if ("Google".equals(service))
          ScoreflexGoogleWrapper.login(mParentActivity, callback);
      } catch (Exception e) {
        Log.e("Scoreflex", "Native login exception", e);
        webLogin(true, true, service);
      }
      return true;
    }

    private List<String> JSONArrayToList(JSONArray array) throws JSONException {
      ArrayList<String> targetsList = new ArrayList<String>();
      if (array != null) {
         for (int i=0;i<array.length();i++){
           targetsList.add(array.get(i).toString());
         }
      }
      return targetsList;
    }

    private boolean handleSocialInvite(Uri uri, int status, int code) {
      if (code != Scoreflex.SUCCESS_INVITE_WITH_SERVICE)
        return false;

      JSONObject dataJson;
      String dataString = uri.getQueryParameter("data");
      try {
        dataJson = new JSONObject(dataString);
        String service = dataJson.optString("service");
        if ("Facebook".equals(service)) {
          List<String> suggestedList = JSONArrayToList(dataJson.optJSONArray("targetIds"));
          String data = dataJson.optString("data");
          Scoreflex.sendFacebookInvitation(mParentActivity, dataJson.getString("text"), null, suggestedList, data);
//          ScoreflexFacebookWrapper.sendInvitation(
        }
        if ("Google".equals(service)) {
          List<String> friendIds = JSONArrayToList(dataJson.optJSONArray("targetIds"));
          Scoreflex.sendGoogleInvitation(mParentActivity, dataJson.getString("text"),friendIds, dataJson.optString("url"), "/invite");
        }
      } catch (JSONException e) {
        Log.e("Scoreflex", "Invalid json received in the data parameter", e);

        return true;
      }

      return true;
    }

    private boolean handleSocialShare(Uri uri, int status, int code) {
      if (code != Scoreflex.SUCCESS_SHARE_WITH_SERVICE)
        return false;

      JSONObject dataJson;
      String dataString = uri.getQueryParameter("data");
      try {
        dataJson = new JSONObject(dataString);
        String text = dataJson.optString("text");
        String url = dataJson.optString("url");
        if ("Facebook".equals(dataJson.optString("service"))) {
          String title = dataJson.optString("title");
          Scoreflex.shareOnFacebook(mParentActivity, title, text, url);
        }
        if ("Google".equals(dataJson.optString("service"))) {
          Scoreflex.shareOnGoogle(mParentActivity, text, url);
        }
      } catch (JSONException e) {
        Log.e("Scoreflex", "Invalid json received in the data parameter", e);
        // Handle by doing nothing
        return true;
      }


      return true;
    }

    private boolean handleNeedsAuth(Uri uri, int status, int code) {
      if (code != Scoreflex.SUCCESS_NEEDS_AUTH)
        return false;

      String dataString = uri.getQueryParameter("data");

      JSONObject dataJson;
      try {
        dataJson = new JSONObject(dataString);
      } catch (JSONException e) {
        Log.e("Scoreflex", "Invalid json received in the data parameter", e);
        // Handle by doing nothing
        return true;
      }

      // Remember where we ought to go once auth is successful
      // Note that we can't use the "redirectUri" parameter of the
      // authorize call
      // as it is intended to be registered on the server side (see oauth
      // spec).
      String nextUrlString = dataJson.optString("nextUrl");
      if (null != nextUrlString) {
        Uri nextUri = Uri.parse(nextUrlString);
        mAuthGrantedNextUrlString = String.format("%s?%s",
            ScoreflexUriHelper.getNonSecureAbsoluteUrl(nextUri.getPath()),
            nextUri.getQuery());
      } else {
        mAuthGrantedNextUrlString = null;
      }

      // full mode ?
      String modeString = dataJson.optString("mode");

      String service = dataJson.optString("service");
      webLogin("full".equals(modeString), false, service);

      return true;

    }

    private void webLogin(boolean fullScreen, boolean disableNativeLogin,
        String service) {
      // Build the uri
      Scoreflex.RequestParams params = new Scoreflex.RequestParams();
      params.put("clientId", Scoreflex.getClientId());
      params.put("devicePlatform", "Android");
      params.put("deviceModel", Scoreflex.getDeviceModel());

      // If native login disabled, override the default handledServices
      // parameter
      if (disableNativeLogin)
        params.put("handledServices", "");

      // Pass the anonymous access token
      String accessToken = ScoreflexRestClient.getAccessToken();
      if (ScoreflexRestClient.getAccessTokenIsAnonymous()
          && null != accessToken)
        params.put("anonymousAccessToken", accessToken);

      if (null != service)
        params.put("service", service);

      // A random state
      mAuthState = UUID.randomUUID().toString();
      params.put("state", mAuthState);

      // Open authorize resource in the web view
      openResource("/oauth/web/authorize", params, fullScreen, false);
    }

    private boolean handleCloseWebView(Uri uri, int status, int code) {
      if (code != Scoreflex.SUCCESS_CLOSE_WEBVIEW)
        return false;

      close();

      return true;

    }

    private boolean handleMoveToNewUrl(Uri uri, int status, int code) {

      if (code != Scoreflex.SUCCESS_MOVE_TO_NEW_URL)
        return false;

      String dataString = uri.getQueryParameter("data");

      JSONObject dataJson;
      try {
        dataJson = new JSONObject(dataString);
      } catch (JSONException e) {
        Log.e("Scoreflex", "Invalid json received in the data parameter", e);
        // Handle by doing nothing
        return true;
      }

      String urlString = dataJson.optString("url");

      // No URL provided, handle by doing nothing
      if (null == urlString) {
        Log.e("Scoreflex", "Move to new URL requested but no url provided");
        return true;
      }

      String modeString = dataJson.optString("mode");
      boolean isFullscreen = "full".equals(modeString);
      if (isFullscreen && mScoreflexViewHandler != null && mScoreflexViewHandler.handleOpenNewFullscreenView(urlString)) {
        return true;
      }

      openFullUrl(urlString, "full".equals(modeString), true);

      return true;
    }

    private boolean openResource(String resource,
        Scoreflex.RequestParams params, boolean forceFullScreen, boolean newView) {

      return openFullUrl(String.format("%s%s?%s", Scoreflex.getBaseURL(),
          resource, params != null ? params.getURLEncodedString() : ""),
          forceFullScreen, newView);
    }

    private boolean openFullUrl(String fullUrl, boolean forceFullScreen,
        boolean newView) {
      // If we don't absolutely need full screen, open the url in the
      // current screen configuration
      setFullUrl(fullUrl, forceFullScreen, newView);
      return true;
    }
  }

  private abstract class UserInterfaceState {
    public abstract void onEnterState();

    public void onLeaveState() {
    }
  }

  private class InitialState extends UserInterfaceState {
    @Override
    public void onEnterState() {
      mProgressBar.setVisibility(View.VISIBLE);
      mWebView.setVisibility(View.GONE);
      mErrorLayout.setVisibility(View.GONE);
      mCloseButton.setVisibility(View.VISIBLE);
    }

    @Override
    public void onLeaveState() {
      mProgressBar.setVisibility(View.GONE);
    }
  }

  private class LoadingState extends UserInterfaceState {
    @Override
    public void onEnterState() {
      mProgressBar.setVisibility(View.VISIBLE);
    }

    @Override
    public void onLeaveState() {
      mProgressBar.setVisibility(View.GONE);
    }
  }

  /**
   * A simple interface to get notified when a scoreflex view is closed
   */
  public interface ScoreflexViewListener {
    /**
     * this method is called when the ScoreflexView is closed.
     */
    public void onViewClosed();

    /**
     * If you want to overload the opening of a new view
     * @param fullUrlString the full string of the url to open
     * @return true if you want to overload the opening of a new view false otherwise
     */

    public boolean handleOpenNewFullscreenView(String fullUrlString);
  }

  private class WebContentState extends UserInterfaceState {
    @Override
    public void onEnterState() {
      mWebView.setVisibility(View.VISIBLE);
      mProgressBar.setVisibility(View.GONE);

      FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
          ViewGroup.LayoutParams.MATCH_PARENT,
          ViewGroup.LayoutParams.MATCH_PARENT, Gravity.TOP);
      if (ScoreflexUriHelper.isAPIUri(Uri.parse(mWebView.getUrl()))) {
        layoutParams.setMargins(0, 0, 0, 0);
      } else {
        layoutParams.setMargins(
            0,
            getResources().getDimensionPixelSize(
                R.dimen.scoreflex_topbar_height), 0, 0);
      }
      mWebView.setLayoutParams(layoutParams);

      // If the scoreflex view is gone, fade it in
      if (View.GONE == getVisibility()) {
        setVisibility(View.VISIBLE);

        AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
        alphaAnimation.setFillBefore(true);
        alphaAnimation.setFillAfter(true);
        alphaAnimation.setDuration(1000);
        startAnimation(alphaAnimation);
      }
    }
  }

  private class ErrorState extends UserInterfaceState {
    @Override
    public void onEnterState() {
      mWebView.setVisibility(View.GONE);
      mErrorLayout.setVisibility(View.VISIBLE);
      if (!ScoreflexView.this.mIsPreloading) {
        Toast.makeText(getContext(), R.string.scoreflex_network_error,
            Toast.LENGTH_LONG).show();
      }
    }

    @Override
    public void onLeaveState() {
      mErrorLayout.setVisibility(View.GONE);
    }

  }
  /**
   * Method called when a picture has been chosen for a input type file / image.
   *
   * @param activity
   * @param requestCode
   * @param resultCode
   * @param intent
   */
  public void onActivityResult(Activity activity, int requestCode,
      int resultCode, Intent intent) {
    Uri result = intent == null || resultCode != activity.RESULT_OK ? null
        : intent.getData();
    if (result == null) {
      return;
    }
    mUploadMessage.onReceiveValue(result);
    mUploadMessage = null;
    mOutputFileUri = null;

  }
  private BroadcastReceiver mLoginReceiver = new BroadcastReceiver() {
     @Override
     public void onReceive(final Context context,final Intent intent) {
       if (ScoreflexView.this.isLoginSource) {
         ScoreflexView.this.isLoginSource = false;
         return;
       }
       setFullUrl(mWebView.getUrl());
     }
  };
}




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