Android Open Source - vk-android-sdk V K Request






From Project

Back to project page vk-android-sdk.

License

The source code is released under:

MIT License

If you think the Android project vk-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

//
//  Copyright (c) 2014 VK.com
///*from   w  w w.  ja v a2 s  .c  om*/
//  Permission is hereby granted, free of charge, to any person obtaining a copy of
//  this software and associated documentation files (the "Software"), to deal in
//  the Software without restriction, including without limitation the rights to
//  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
//  the Software, and to permit persons to whom the Software is furnished to do so,
//  subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in all
//  copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
//  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
//  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
//  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

package com.vk.sdk.api;

import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import com.vk.sdk.VKAccessToken;
import com.vk.sdk.VKObject;
import com.vk.sdk.VKOpenAuthActivity;
import com.vk.sdk.VKSdk;
import com.vk.sdk.VKSdkVersion;
import com.vk.sdk.VKUIHelper;
import com.vk.sdk.api.httpClient.VKAbstractOperation;
import com.vk.sdk.api.httpClient.VKHttpClient;
import com.vk.sdk.api.httpClient.VKHttpOperation;
import com.vk.sdk.api.httpClient.VKJsonOperation;
import com.vk.sdk.api.httpClient.VKJsonOperation.VKJSONOperationCompleteListener;
import com.vk.sdk.api.httpClient.VKModelOperation;
import com.vk.sdk.api.model.VKApiModel;
import com.vk.sdk.util.VKStringJoiner;
import com.vk.sdk.util.VKUtil;

import org.apache.http.client.methods.HttpUriRequest;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;

/**
 * Class for execution API-requests.
 */
public class VKRequest extends VKObject {


    public enum VKProgressType {
        Download,
        Upload
    }

    public enum HttpMethod {
        GET,
        POST
    }

  /**
   * Selected method name
   */
  public final  String              methodName;
  /**
   * HTTP method for loading
   */
  public final  HttpMethod          httpMethod;
  /**
   * Passed parameters for method
   */
  private final VKParameters        mMethodParameters;
  /**
   * Method parametes with common parameters
   */
  private       VKParameters        mPreparedParameters;
  /**
   * HTTP loading operation
   */
  private       VKAbstractOperation mLoadingOperation;
  /**
   * How much times request was loaded
   */
  private       int                 mAttemptsUsed;

  /**
   * Requests that should be called after current request.
   */
  private ArrayList<VKRequest>        mPostRequestsQueue;
  /**
   * Class for model parsing
   */
  private Class<? extends VKApiModel> mModelClass;

  /**
   * Response parser
   */
  private VKParser mModelParser;

  /**
   * Specify language for API request
   */
  private String mPreferredLang;

  /**
   * Looper which starts request
   */
  private Looper mLooper;

  /**
   * Specify listener for current request
   */
  public VKRequestListener         requestListener;
  /**
   * Specify attempts for request loading if caused HTTP-error. 0 for infinite
   */
  public int                       attempts;
  /**
   * Use HTTPS requests (by default is YES). If http-request is impossible (user denied no https access), SDK will load https version
   */
  public boolean                   secure;
  /**
   * Sets current system language as default for API data
   */
  public boolean                   useSystemLanguage;
  /**
   * Set to false if you don't need automatic model parsing
   */
  public boolean                   parseModel;
  /**
   * Response for this request
   */
  public WeakReference<VKResponse> response;

  /**
   * @return Returns HTTP-method for current request
   */
  public HttpMethod getHttpMethod()
  {
    return httpMethod;
  }

  /**
   * @return Returns list of method parameters (without common parameters)
   */
  public VKParameters getMethodParameters()
  {
    return mMethodParameters;
  }

  /**
   * Creates new request with parameters. See documentation for methods here https://vk.com/dev/methods
   *
   * @param method API-method name, e.g. audio.get
   */
  public VKRequest(String method)
  {
    this(method, null);
  }

  /**
   * Creates new request with parameters. See documentation for methods here https://vk.com/dev/methods
   *
   * @param method     API-method name, e.g. audio.get
   * @param parameters method parameters
   */
  public VKRequest(String method, VKParameters parameters)
  {
    this(method, parameters, HttpMethod.GET);
  }

  /**
   * Creates new request with parameters. See documentation for methods here https://vk.com/dev/methods
   *
   * @param method     API-method name, e.g. audio.get
   * @param parameters method parameters
   * @param httpMethod HTTP method for execution, e.g. GET, POST
   */
  public VKRequest(String method, VKParameters parameters, HttpMethod httpMethod)
  {
    this.methodName = method;
    if (parameters == null)
    {
      parameters = new VKParameters();
    }
    this.mMethodParameters = new VKParameters(parameters);
    if (httpMethod == null)
      httpMethod = HttpMethod.GET;
    this.httpMethod = httpMethod;
    this.mAttemptsUsed = 0;

    this.secure = true;
    //By default there is 1 attempt for loading.
    this.attempts = 1;

    //If system language is not supported, we use english
    this.mPreferredLang = "en";
    //By default we use system language.
    this.useSystemLanguage = true;
  }

  /**
   * Creates new request with parameters. See documentation for methods here https://vk.com/dev/methods
   *
   * @param method     API-method name, e.g. audio.get
   * @param parameters method parameters
   * @param httpMethod HTTP method for execution, e.g. GET, POST
   * @param modelClass class for automatic parse
   */
  public VKRequest(String method, VKParameters parameters, HttpMethod httpMethod,
                   Class<? extends VKApiModel> modelClass)
  {
    this(method, parameters, httpMethod);
    setModelClass(modelClass);
  }

  /**
   * Executes that request, and returns result to blocks
   *
   * @param listener listener for request events
     */
    public void executeWithListener(VKRequestListener listener) {
        this.requestListener = listener;
        start();
    }

    public void setRequestListener(VKRequestListener listener) {
        this.requestListener = listener;
    }

    /**
     * Register current request for execute after passed request, if passed request is successful. If it's not, errorBlock will be called.
     *
     * @param request  after which request must be called that request
     * @param listener listener for request events
     */
    public void executeAfterRequest(VKRequest request, VKRequestListener listener) {
        this.requestListener = listener;
        request.addPostRequest(this);
    }

    private void addPostRequest(VKRequest postRequest) {
        if (mPostRequestsQueue == null) {
            mPostRequestsQueue = new ArrayList<VKRequest>();
        }
        mPostRequestsQueue.add(postRequest);
    }

    public VKParameters getPreparedParameters() {
        if (mPreparedParameters == null) {
            mPreparedParameters = new VKParameters(mMethodParameters);

            //Set current access token from SDK object
            VKAccessToken token = VKSdk.getAccessToken();
          if (token != null)
                mPreparedParameters.put(VKApiConst.ACCESS_TOKEN, token.accessToken);
            if (!this.secure)
              if (token != null && (token.secret != null || token.httpsRequired)) {
                    this.secure = true;
                }
            //Set actual version of API
            mPreparedParameters.put(VKApiConst.VERSION, VKSdkVersion.API_VERSION);
            //Set preferred language for request
            mPreparedParameters.put(VKApiConst.LANG, getLang());

            if (this.secure) {
                //If request is secure, we need all urls as https
                mPreparedParameters.put(VKApiConst.HTTPS, "1");
            }
            if (token != null && token.secret != null) {
                //If it not, generate signature of request
                String sig = generateSig(token);
                mPreparedParameters.put(VKApiConst.SIG, sig);
            }
            //From that moment you cannot modify parameters.
            //Specially for http loading
        }
        return mPreparedParameters;
    }

    /**
     * Prepares request for loading
     *
     * @return Prepared HttpUriRequest for that VKRequest
     */
    public HttpUriRequest getPreparedRequest() {
        HttpUriRequest request = VKHttpClient.requestWithVkRequest(this);
        if (request == null) {
            VKError error = new VKError(VKError.VK_REQUEST_NOT_PREPARED);
            provideError(error);
            return null;
        }
        return request;
    }

    public VKAbstractOperation getOperation() {
        if (this.parseModel) {
            if (this.mModelClass != null) {
                mLoadingOperation = new VKModelOperation(getPreparedRequest(), this.mModelClass);
            } else if (this.mModelParser != null){
                mLoadingOperation = new VKModelOperation(getPreparedRequest(), this.mModelParser);
            }
        }
        if (mLoadingOperation == null)
            mLoadingOperation = new VKJsonOperation(getPreparedRequest());
        ((VKJsonOperation) mLoadingOperation).setJsonOperationListener(
                new VKJSONOperationCompleteListener() {
                    @Override
                    public void onComplete(VKJsonOperation operation, JSONObject response) {
                        if (response.has("error")) {
                            try {
                                VKError error = new VKError(response.getJSONObject("error"));
                              if (VKSdk.DEBUG && VKSdk.DEBUG_API_ERRORS) {
                                Log.w(VKSdk.SDK_TAG, operation.getResponseString());
                              }
                                if (processCommonError(error)) return;
                                provideError(error);
                            } catch (JSONException e) {
                                if (VKSdk.DEBUG)
                                    e.printStackTrace();
                            }

                            return;
                        }
                        provideResponse(response,
                                mLoadingOperation instanceof VKModelOperation ?
                                        ((VKModelOperation) mLoadingOperation).parsedModel :
                                        null);
                    }

                    @Override
                    public void onError(VKJsonOperation operation, VKError error) {
                        //??? ???? ???????? ????, ??? ????????? ??????????????? ????? ??? ??????? ????????
                        if (    error.errorCode != VKError.VK_CANCELED  &&
                                error.errorCode != VKError.VK_API_ERROR &&
                                operation != null && operation.response != null &&
                                operation.response.getStatusLine().getStatusCode() == 200) {
                            provideResponse(operation.getResponseJson(), null);
                            return;
                        }
                      if (VKSdk.DEBUG && VKSdk.DEBUG_API_ERRORS &&
                            operation != null && operation.getResponseString() != null) {
                        Log.w(VKSdk.SDK_TAG, operation.getResponseString());
                      }
                        if (attempts == 0 || ++mAttemptsUsed < attempts) {
                            if (requestListener != null)
                                requestListener.attemptFailed(VKRequest.this, mAttemptsUsed, attempts);
                            runOnLooper(new Runnable() {
                                @Override
                                public void run() {
                                    start();
                                }
                            }, 300);
                            return;
                        }
                        provideError(error);
                    }
                });
        return mLoadingOperation;
    }

    /**
     * Starts loading of prepared request. You can use it instead of executeWithResultBlock
     */
    public void start() {
        if ((mLoadingOperation = getOperation()) == null) {
            return;
        }
      mLooper = Looper.myLooper();
        VKHttpClient.enqueueOperation(mLoadingOperation);
    }

    /**
     * Repeats this request with initial parameters and blocks.
     * Used attempts will be set to 0.
     */
    public void repeat() {
        this.mAttemptsUsed = 0;
        this.mPreparedParameters = null;
        this.mLoadingOperation   = null;
        start();
    }

    /**
     * Cancel current request. Result will be not passed. errorBlock will be called with error code
     */
    public void cancel() {
        if (mLoadingOperation != null)
            mLoadingOperation.cancel();
        else
            provideError(new VKError(VKError.VK_CANCELED));
    }

    /**
     * Method used for errors processing
     *
     * @param error error caused by this request
     */
    private void provideError(final VKError error) {
        error.request = this;

      runOnLooper(new Runnable()
      {
        @Override public void run()
        {
          if (requestListener != null) {
            requestListener.onError(error);
          }
          if (mPostRequestsQueue != null && mPostRequestsQueue.size() > 0) {
            for (VKRequest postRequest : mPostRequestsQueue)
              if (postRequest.requestListener != null) postRequest.requestListener.onError(error);
          }
        }
      });

    }

    /**
     * Method used for response processing
     *
     * @param jsonResponse response from API
     * @param parsedModel  model parsed from json
     */
    private void provideResponse(final JSONObject jsonResponse, Object parsedModel) {
        final VKResponse response = new VKResponse();
        response.request = this;
        response.json = jsonResponse;
        response.parsedModel = parsedModel;

      this.response = new WeakReference<VKResponse>(response);
      if (mLoadingOperation instanceof VKHttpOperation) {
        response.responseString = ((VKHttpOperation)mLoadingOperation).getResponseString();
      }

      runOnLooper(new Runnable()
      {
        @Override public void run()
        {
          if (mPostRequestsQueue != null && mPostRequestsQueue.size() > 0)
          {
            for (final VKRequest request : mPostRequestsQueue)
            {
              request.start();
            }
          }

          if (requestListener != null)
          {
            requestListener.onComplete(response);
          }
        }
      });
    }

    /**
     * Adds additional parameter to that request
     *
     * @param key   parameter name
     * @param value parameter value
     */
    public void addExtraParameter(String key, Object value) {
        mMethodParameters.put(key, value);
    }

    /**
     * Adds additional parameters to that request
     *
     * @param extraParameters parameters supposed to be added
     */
    public void addExtraParameters(VKParameters extraParameters) {
        mMethodParameters.putAll(extraParameters);
    }

    private String generateSig(VKAccessToken token) {
        //Read description here https://vk.com/dev/api_nohttps
        //At first, we need key-value pairs in order of request
        String queryString = VKStringJoiner.joinParams(mPreparedParameters);
        //Then we generate "request string" /method/{METHOD_NAME}?{GET_PARAMS}{POST_PARAMS}
        queryString = String.format(Locale.US, "/method/%s?%s", methodName, queryString);
        return VKUtil.md5(queryString + token.secret);

    }

    private boolean processCommonError(final VKError error) {
        if (error.errorCode == VKError.VK_API_ERROR) {
            if (error.apiError.errorCode == 14) {
                error.apiError.request = this;
                this.mLoadingOperation = null;
              runOnLooper(new Runnable()
              {
                @Override public void run()
                {
                  VKSdk.instance().sdkListener().onCaptchaError(error.apiError);
                }
              });

                return true;
            } else if (error.apiError.errorCode == 16) {
                VKAccessToken token = VKSdk.getAccessToken();
                token.httpsRequired = true;
              runOnLooper(new Runnable()
              {
                @Override public void run()
                {
                  repeat();
                }
              });

                return true;
            } else if (error.apiError.errorCode == 17) {
              if (VKUIHelper.getTopActivity() != null)
              {
                runOnMainLooper(new Runnable()
                {
                  @Override public void run()
                  {
                    Intent i = new Intent(VKUIHelper.getTopActivity(), VKOpenAuthActivity.class);
                    i.putExtra(VKOpenAuthActivity.VK_EXTRA_VALIDATION_URL,
                               error.apiError.redirectUri);
                    i.putExtra(VKOpenAuthActivity.VK_EXTRA_VALIDATION_REQUEST,
                               VKRequest.this.registerObject());
                    VKUIHelper.getTopActivity()
                              .startActivityForResult(i, VKSdk.VK_SDK_REQUEST_CODE);
                  }
                });

                return true;
              }
            }
        }

        return false;
    }

    private String getLang() {
        String result = mPreferredLang;
        if (useSystemLanguage) {
            result = VKUIHelper.getApplicationContext().getResources().getConfiguration().locale.getLanguage();
            if (result.equals("uk")) {
                result = "ua";
            }

            if (!Arrays.asList(new String[]{"ru", "en", "ua", "es", "fi", "de", "it"})
                    .contains(result)) {
                result = mPreferredLang;
            }
        }
        return result;
    }

    /**
     * Sets preferred language for api results.
     * @param lang Two letter language code. May be "ru", "en", "ua", "es", "fi", "de", "it"
     */
    public void setPreferredLang(String lang) {
        useSystemLanguage = false;
        mPreferredLang = lang;
    }

    /**
     * Sets class for parse object model
     * @param modelClass Class extends VKApiModel
     */
    public void setModelClass(Class<? extends VKApiModel> modelClass) {
        mModelClass = modelClass;
        if (mModelClass != null)
            parseModel = true;
    }

    public void setResponseParser(VKParser parser) {
        mModelParser = parser;
        if (mModelParser != null)
            parseModel = true;
    }

    private void runOnLooper(Runnable block) {
        runOnLooper(block, 0);
    }
  private void runOnLooper(Runnable block, int delay) {
    if (mLooper == null) {
      mLooper = Looper.getMainLooper();
    }
        if (delay > 0) {
            new Handler(mLooper).postDelayed(block, delay);
        } else {
            new Handler(mLooper).post(block);
        }
  }
  private void runOnMainLooper(Runnable block) {

    new Handler(Looper.getMainLooper()).post(block);
  }

    /**
     * Extend listeners for requests from that class
     * Created by Roman Truba on 02.12.13.
     * Copyright (c) 2013 VK. All rights reserved.
     */
    public static abstract class VKRequestListener {
        /**
         * Called if there were no HTTP or API errors, returns execution result.
         *
         * @param response response from VKRequest
         */
        public void onComplete(VKResponse response) {
        }

        /**
         * Called when request has failed attempt, and ready to do next attempt
         *
         * @param request       Failed request
         * @param attemptNumber Number of failed attempt, started from 1
         * @param totalAttempts Total request attempts defined for request
         */
        public void attemptFailed(VKRequest request, int attemptNumber, int totalAttempts) {
        }

        /**
         * Called immediately if there was API error, or after <b>attempts</b> tries if there was an HTTP error
         *
         * @param error error for VKRequest
         */
        public void onError(VKError error) {
        }

        /**
         * Specify progress for uploading or downloading. Useless for text requests (because gzip encoding bytesTotal will always return -1)
         *
         * @param progressType type of progress (upload or download)
         * @param bytesLoaded  total bytes loaded
         * @param bytesTotal   total bytes suppose to be loaded
         */
        public void onProgress(VKRequest.VKProgressType progressType, long bytesLoaded, long bytesTotal) {
        }
    }
    public static VKRequest getRegisteredRequest(long requestId) {
        return (VKRequest) getRegisteredObject(requestId);
    }
}




Java Source Code List

com.vk.sdk.VKAccessToken.java
com.vk.sdk.VKObject.java
com.vk.sdk.VKOpenAuthActivity.java
com.vk.sdk.VKScope.java
com.vk.sdk.VKSdkListener.java
com.vk.sdk.VKSdkVersion.java
com.vk.sdk.VKSdk.java
com.vk.sdk.VKUIHelper.java
com.vk.sdk.api.VKApiConst.java
com.vk.sdk.api.VKApi.java
com.vk.sdk.api.VKBatchRequest.java
com.vk.sdk.api.VKDefaultParser.java
com.vk.sdk.api.VKError.java
com.vk.sdk.api.VKParameters.java
com.vk.sdk.api.VKParser.java
com.vk.sdk.api.VKRequest.java
com.vk.sdk.api.VKResponse.java
com.vk.sdk.api.httpClient.VKAbstractOperation.java
com.vk.sdk.api.httpClient.VKHttpClient.java
com.vk.sdk.api.httpClient.VKHttpOperation.java
com.vk.sdk.api.httpClient.VKImageOperation.java
com.vk.sdk.api.httpClient.VKJsonOperation.java
com.vk.sdk.api.httpClient.VKModelOperation.java
com.vk.sdk.api.httpClient.VKMultipartEntity.java
com.vk.sdk.api.methods.VKApiBase.java
com.vk.sdk.api.methods.VKApiCaptcha.java
com.vk.sdk.api.methods.VKApiFriends.java
com.vk.sdk.api.methods.VKApiGroups.java
com.vk.sdk.api.methods.VKApiPhotos.java
com.vk.sdk.api.methods.VKApiUsers.java
com.vk.sdk.api.methods.VKApiWall.java
com.vk.sdk.api.model.Identifiable.java
com.vk.sdk.api.model.ParseUtils.java
com.vk.sdk.api.model.VKApiApplicationContent.java
com.vk.sdk.api.model.VKApiAudio.java
com.vk.sdk.api.model.VKApiChat.java
com.vk.sdk.api.model.VKApiCity.java
com.vk.sdk.api.model.VKApiComment.java
com.vk.sdk.api.model.VKApiCommunityArray.java
com.vk.sdk.api.model.VKApiCommunityFull.java
com.vk.sdk.api.model.VKApiCommunity.java
com.vk.sdk.api.model.VKApiCountry.java
com.vk.sdk.api.model.VKApiDocument.java
com.vk.sdk.api.model.VKApiLink.java
com.vk.sdk.api.model.VKApiMessage.java
com.vk.sdk.api.model.VKApiModel.java
com.vk.sdk.api.model.VKApiNote.java
com.vk.sdk.api.model.VKApiOwner.java
com.vk.sdk.api.model.VKApiPhotoAlbum.java
com.vk.sdk.api.model.VKApiPhotoSize.java
com.vk.sdk.api.model.VKApiPhoto.java
com.vk.sdk.api.model.VKApiPlace.java
com.vk.sdk.api.model.VKApiPoll.java
com.vk.sdk.api.model.VKApiPost.java
com.vk.sdk.api.model.VKApiPostedPhoto.java
com.vk.sdk.api.model.VKApiSchool.java
com.vk.sdk.api.model.VKApiUniversity.java
com.vk.sdk.api.model.VKApiUserFull.java
com.vk.sdk.api.model.VKApiUser.java
com.vk.sdk.api.model.VKApiVideo.java
com.vk.sdk.api.model.VKApiWikiPage.java
com.vk.sdk.api.model.VKAttachments.java
com.vk.sdk.api.model.VKCommentArray.java
com.vk.sdk.api.model.VKList.java
com.vk.sdk.api.model.VKPhotoArray.java
com.vk.sdk.api.model.VKPhotoSizes.java
com.vk.sdk.api.model.VKPostArray.java
com.vk.sdk.api.model.VKPrivacy.java
com.vk.sdk.api.model.VKScopes.java
com.vk.sdk.api.model.VKUsersArray.java
com.vk.sdk.api.model.VKWallPostResult.java
com.vk.sdk.api.model.package-info.java
com.vk.sdk.api.photo.VKImageParameters.java
com.vk.sdk.api.photo.VKUploadAlbumPhotoRequest.java
com.vk.sdk.api.photo.VKUploadImage.java
com.vk.sdk.api.photo.VKUploadPhotoBase.java
com.vk.sdk.api.photo.VKUploadWallPhotoRequest.java
com.vk.sdk.dialogs.VKCaptchaDialog.java
com.vk.sdk.dialogs.VKShareDialog.java
com.vk.sdk.util.VKJsonHelper.java
com.vk.sdk.util.VKStringJoiner.java
com.vk.sdk.util.VKUtil.java
com.vk.vktestapp.ApiCallActivity.java
com.vk.vktestapp.LoginActivity.java
com.vk.vktestapp.TestActivity.java