diff --git a/README.md b/README.md index 6fca94ab43..c1cf22e0e5 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ You can add next maven dependency in your project: You may also need to add the following to your `project/build.gradle` file. -`implementation 'com.vk:androidsdk:2.1.1` +`implementation 'com.vk:androidsdk:2.2.0` For example, your `app/build.gradle` script will contains such dependencies: ``` diff --git a/dependencies.gradle b/dependencies.gradle index 851ddefbeb..8f24d38a03 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -1,19 +1,19 @@ ext.sdkVersions = [ - code : '12', - name : '2.1.1', + code : '14', + name : '2.2.0', minSdk : 16, - targetSdk : 26, + targetSdk : 28, compileSdk : '28', - buildTools : '27.0.3', + buildTools : '28.0.3', - kotlin : '1.3.10', - supportLibs : '27.1.1', - okHttp : '3.11.0', + kotlin : '1.3.41', + androidX : '1.0.0', + okHttp : '3.12.1', picasso : '2.71828', - androidGradlePlugin : '3.2.1', + androidGradlePlugin : '3.5.0', ] ext.sdkLibraries = [ @@ -25,10 +25,10 @@ ext.sdkLibraries = [ ] ext.sdkLibrariesSupport = [ - supportV4 : "com.android.support:support-v4:$sdkVersions.supportLibs", - support : "com.android.support:support-v13:$sdkVersions.supportLibs", - appCompat : "com.android.support:appcompat-v7:$sdkVersions.supportLibs", - recyclerView : "com.android.support:recyclerview-v7:$sdkVersions.supportLibs", + appCompat : "androidx.appcompat:appcompat:$sdkVersions.androidX", + recyclerView : "androidx.recyclerview:recyclerview:$sdkVersions.androidX", + supportV4 : "androidx.legacy:legacy-support-v4:$sdkVersions.androidX", + support : "androidx.legacy:legacy-support-v13:$sdkVersions.androidX", ] ext.sdkGradlePlugins = [ diff --git a/samples/app/src/main/java/com/vk/sdk/sample/UserActivity.kt b/samples/app/src/main/java/com/vk/sdk/sample/UserActivity.kt index fae651a743..5b6307787b 100644 --- a/samples/app/src/main/java/com/vk/sdk/sample/UserActivity.kt +++ b/samples/app/src/main/java/com/vk/sdk/sample/UserActivity.kt @@ -29,13 +29,12 @@ import android.content.Context import android.content.Intent import android.net.Uri import android.os.Bundle -import android.support.v7.widget.LinearLayoutManager -import android.support.v7.widget.RecyclerView import android.text.TextUtils import android.util.Log import android.view.LayoutInflater import android.view.ViewGroup import android.widget.* +import androidx.recyclerview.widget.RecyclerView import com.squareup.picasso.Picasso import com.vk.api.sdk.VK import com.vk.api.sdk.VKApiCallback @@ -85,7 +84,7 @@ class UserActivity: Activity() { } } } - override fun fail(error: VKApiExecutionException) { + override fun fail(error: Exception) { Log.e(TAG, error.toString()) } }) @@ -98,7 +97,7 @@ class UserActivity: Activity() { showFriends(result) } } - override fun fail(error: VKApiExecutionException) { + override fun fail(error: Exception) { Log.e(TAG, error.toString()) } }) @@ -106,7 +105,7 @@ class UserActivity: Activity() { private fun showFriends(friends: List) { val recyclerView = findViewById(R.id.friendsRV) - recyclerView.layoutManager = LinearLayoutManager(this, RecyclerView.HORIZONTAL, false) + recyclerView.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this, RecyclerView.HORIZONTAL, false) val adapter = FriendsAdapter() adapter.setData(friends) @@ -143,13 +142,13 @@ class UserActivity: Activity() { Toast.makeText(this@UserActivity, R.string.wall_ok, Toast.LENGTH_SHORT).show() } - override fun fail(error: VKApiExecutionException) { + override fun fail(error: Exception) { Log.e(TAG, error.toString()) } }) } - inner class FriendsAdapter: RecyclerView.Adapter() { + inner class FriendsAdapter: RecyclerView.Adapter() { private val friends: MutableList = arrayListOf() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) diff --git a/samples/app/src/main/res/layout/activity_user.xml b/samples/app/src/main/res/layout/activity_user.xml index 3f97df96e5..ae0d74d81c 100644 --- a/samples/app/src/main/res/layout/activity_user.xml +++ b/samples/app/src/main/res/layout/activity_user.xml @@ -31,7 +31,7 @@ android:layout_gravity="center" android:background="@android:color/white" android:textColor="@color/colorPrimary" /> - { fun success(result: T) - fun fail(error: VKApiExecutionException) + fun fail(error: Exception) } diff --git a/vk-sdk-core/src/main/java/com/vk/api/sdk/VKApiManager.kt b/vk-sdk-core/src/main/java/com/vk/api/sdk/VKApiManager.kt index f1640e43b0..d4b320cb71 100644 --- a/vk-sdk-core/src/main/java/com/vk/api/sdk/VKApiManager.kt +++ b/vk-sdk-core/src/main/java/com/vk/api/sdk/VKApiManager.kt @@ -65,17 +65,6 @@ open class VKApiManager(val config: VKApiConfig) { return executeWithExceptionAdjust(cc) } - fun execute(call: OauthHttpUrlPostCall, parser: VKApiResponseParser? = null): T { - var cc: ChainCall = OAuthHttpUrlChainCall(this, executor, call, parser) - if (call.retryCountOnBackendError != 0) { - cc = InternalErrorRetryChainCall(this, call.retryCountOnBackendError, cc) - } - if (call.retryCountOnBackendError != 0) { - cc = ValidationHandlerChainCall(this, call.retryCountOnBackendError, cc) - } - return executeWithExceptionAdjust(cc) - } - protected open fun wrapCall(call: VKMethodCall, chainCall: ChainCall): ChainCall { var cc: ChainCall = if (call.skipValidation) { chainCall diff --git a/vk-sdk-core/src/main/java/com/vk/api/sdk/VKMethodCall.kt b/vk-sdk-core/src/main/java/com/vk/api/sdk/VKMethodCall.kt index 348a36571c..303f285acb 100644 --- a/vk-sdk-core/src/main/java/com/vk/api/sdk/VKMethodCall.kt +++ b/vk-sdk-core/src/main/java/com/vk/api/sdk/VKMethodCall.kt @@ -35,7 +35,7 @@ open class VKMethodCall { private set var args: MutableMap = LinkedHashMap() private set - var retryCount: Int = Int.MAX_VALUE + var retryCount: Int = DEFAULT_RETRY_COUNT private set var skipValidation: Boolean = false private set @@ -48,6 +48,7 @@ open class VKMethodCall { open fun version(version: String) = apply { this.version = version } open fun args(args: Map) = apply { this.args.putAll(args) } open fun args(key: String, value: String) = apply { this.args[key] = value } + open fun args(key: String, value: Boolean) = apply { this.args[key] = if (value) "1" else "0" } open fun args(key: String, value: Any) = apply { this.args[key] = value.toString() } open fun retryCount(count: Int) = apply { this.retryCount = count } open fun skipValidation(skip: Boolean) = apply { this.skipValidation = skip } @@ -70,4 +71,8 @@ open class VKMethodCall { this.retryCount = b.retryCount this.skipValidation = b.skipValidation } + + companion object { + private const val DEFAULT_RETRY_COUNT = 4 + } } \ No newline at end of file diff --git a/vk-sdk-core/src/main/java/com/vk/api/sdk/VKScheduler.kt b/vk-sdk-core/src/main/java/com/vk/api/sdk/VKScheduler.kt index cbd749673a..d8a0045ba8 100644 --- a/vk-sdk-core/src/main/java/com/vk/api/sdk/VKScheduler.kt +++ b/vk-sdk-core/src/main/java/com/vk/api/sdk/VKScheduler.kt @@ -2,6 +2,7 @@ package com.vk.api.sdk import android.os.Handler import android.os.Looper +import java.util.concurrent.ExecutorService import java.util.concurrent.Executors import java.util.concurrent.atomic.AtomicInteger @@ -19,10 +20,11 @@ internal object VKScheduler { * Intended to perform network requests: makes new thread every time if cached threads are busy * or reuse idle thread. */ - @JvmField - val networkExecutor = Executors.newFixedThreadPool(NETWORK_THREADS_COUNT) { runnable -> - Thread(runnable, "vk-network-thread-${counter.getAndIncrement()}") - }!! + val networkExecutor: ExecutorService by lazy { + Executors.newFixedThreadPool(NETWORK_THREADS_COUNT) { runnable -> + Thread(runnable, "vk-api-network-thread-${counter.getAndIncrement()}") + } + } @JvmOverloads @JvmStatic diff --git a/vk-sdk-core/src/main/java/com/vk/api/sdk/auth/VKAccessToken.kt b/vk-sdk-core/src/main/java/com/vk/api/sdk/auth/VKAccessToken.kt index 2f01b2e263..d33236e47a 100644 --- a/vk-sdk-core/src/main/java/com/vk/api/sdk/auth/VKAccessToken.kt +++ b/vk-sdk-core/src/main/java/com/vk/api/sdk/auth/VKAccessToken.kt @@ -108,7 +108,7 @@ class VKAccessToken(params: Map) { return null } val vkTokenBundle = bundle.getBundle(VK_ACCESS_TOKEN_KEY) ?: return null - val tokenParams = HashMap() + val tokenParams = HashMap() for (key in vkTokenBundle.keySet()) { tokenParams[key] = vkTokenBundle.getString(key) } @@ -119,7 +119,7 @@ class VKAccessToken(params: Map) { if (preferences == null) { return null } - val tokenParams = HashMap() + val tokenParams = HashMap() for (key in preferences.all.keys) { tokenParams[key] = preferences.getString(key, "") } diff --git a/vk-sdk-core/src/main/java/com/vk/api/sdk/auth/VKAuthManager.kt b/vk-sdk-core/src/main/java/com/vk/api/sdk/auth/VKAuthManager.kt index 0042f77e77..fe1a5450d2 100644 --- a/vk-sdk-core/src/main/java/com/vk/api/sdk/auth/VKAuthManager.kt +++ b/vk-sdk-core/src/main/java/com/vk/api/sdk/auth/VKAuthManager.kt @@ -35,7 +35,7 @@ import java.util.* internal class VKAuthManager { fun login(activity: Activity, scopes: Collection) { - val params = VKAuthParams(getAppId(activity), scopes) + val params = VKAuthParams(getAppId(activity), scope = scopes) if (VKUtils.isAppInstalled(activity, VK_APP_PACKAGE_ID) && VKUtils.isIntentAvailable(activity, VK_APP_AUTH_ACTION)) { startAuthActivity(activity, params) } else { @@ -57,10 +57,15 @@ internal class VKAuthManager { } fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?, callback: VKAuthCallback, context: Context): Boolean { - if (requestCode != VK_APP_AUTH_CODE || data == null) { + if (requestCode != VK_APP_AUTH_CODE) { return false } + if (data == null) { + callback.onLoginFailed(VKAuthCallback.AUTH_CANCELED) + return true + } + val result = processResult(data) if (resultCode != Activity.RESULT_OK || result == null || result.isError) { callback.onLoginFailed(VKAuthCallback.AUTH_CANCELED) diff --git a/vk-sdk-core/src/main/java/com/vk/api/sdk/auth/VKAuthParams.kt b/vk-sdk-core/src/main/java/com/vk/api/sdk/auth/VKAuthParams.kt index c1e6d042f9..7cd6eed584 100644 --- a/vk-sdk-core/src/main/java/com/vk/api/sdk/auth/VKAuthParams.kt +++ b/vk-sdk-core/src/main/java/com/vk/api/sdk/auth/VKAuthParams.kt @@ -27,7 +27,7 @@ package com.vk.api.sdk.auth import android.os.Bundle import java.util.HashSet -class VKAuthParams @JvmOverloads constructor(val appId: Int, scope: Collection = emptySet()) { +class VKAuthParams @JvmOverloads constructor(val appId: Int, val redirectUrl: String = DEFAULT_REDIRECT_URL, scope: Collection = emptySet()) { private val scope: Set init { @@ -41,6 +41,7 @@ class VKAuthParams @JvmOverloads constructor(val appId: Int, scope: Collection = bundle.getStringArrayList(VK_APP_SCOPE_KEY)?.map { VKScope.valueOf(it) } ?: emptySet() + val redirectUrl = bundle.getString(VK_APP_REDIRECT_URL_KEY, DEFAULT_REDIRECT_URL) - return VKAuthParams(appId, scope) + return VKAuthParams(appId, redirectUrl, scope) } } } \ No newline at end of file diff --git a/vk-sdk-core/src/main/java/com/vk/api/sdk/exceptions/VKApiCodes.kt b/vk-sdk-core/src/main/java/com/vk/api/sdk/exceptions/VKApiCodes.kt index 08c2738bd9..e90b516f18 100644 --- a/vk-sdk-core/src/main/java/com/vk/api/sdk/exceptions/VKApiCodes.kt +++ b/vk-sdk-core/src/main/java/com/vk/api/sdk/exceptions/VKApiCodes.kt @@ -26,6 +26,7 @@ package com.vk.api.sdk.exceptions object VKApiCodes { const val CODE_COMPOSITE_EXECUTE_ERROR = Int.MIN_VALUE + const val CODE_IO_ERROR = -1 const val CODE_UNKNOWN_ERROR = 1 const val CODE_APP_DISABLED = 2 const val CODE_UNKNOWN_METHOD = 3 @@ -83,6 +84,7 @@ object VKApiCodes { const val CODE_CHAT_INVITE_MAKE_LINK_DENIED = 919 const val CODE_MSG_DELETE_FOR_ALL_FAILED = 924 const val CODE_CHAT_NOT_ADMIN = 925 + const val CODE_CHAT_MR_ALREADY_SEND = 939 const val CODE_TOO_MANY_CONTACTS_TO_SYNC = 937 diff --git a/vk-sdk-core/src/main/java/com/vk/api/sdk/exceptions/VKApiExecutionException.kt b/vk-sdk-core/src/main/java/com/vk/api/sdk/exceptions/VKApiExecutionException.kt index 97bfc86943..e50c962728 100644 --- a/vk-sdk-core/src/main/java/com/vk/api/sdk/exceptions/VKApiExecutionException.kt +++ b/vk-sdk-core/src/main/java/com/vk/api/sdk/exceptions/VKApiExecutionException.kt @@ -28,7 +28,7 @@ import android.os.Bundle import org.json.JSONObject /** - * See [http://vk.com/dev/errors](http://vk.com/dev/errors) + * See [https://vk.com/dev/errors](https://vk.com/dev/errors) */ open class VKApiExecutionException @JvmOverloads constructor( diff --git a/vk-sdk-core/src/main/java/com/vk/api/sdk/internal/JsonUtils.kt b/vk-sdk-core/src/main/java/com/vk/api/sdk/internal/JsonUtils.kt index e57b1d7e39..14274322b0 100644 --- a/vk-sdk-core/src/main/java/com/vk/api/sdk/internal/JsonUtils.kt +++ b/vk-sdk-core/src/main/java/com/vk/api/sdk/internal/JsonUtils.kt @@ -2,12 +2,21 @@ package com.vk.api.sdk.internal import android.util.JsonReader import android.util.JsonToken +import android.util.MalformedJsonException import java.io.Reader import java.io.StringReader object JsonUtils { fun containsElement(jsonString: String, name: String): Boolean { + try { + return containsElementImpl(jsonString, name) + } catch (ex: MalformedJsonException) { + throw MalformedJsonException("${ex.message}. Json: '$jsonString'") + } + } + + private fun containsElementImpl(jsonString: String, name: String): Boolean { if (jsonString.isEmpty()) { return false } @@ -29,4 +38,5 @@ object JsonUtils { } return false } + } \ No newline at end of file diff --git a/vk-sdk-core/src/main/java/com/vk/api/sdk/okhttp/LoggingInterceptor.kt b/vk-sdk-core/src/main/java/com/vk/api/sdk/okhttp/LoggingInterceptor.kt index 1ee1fca850..7310211fa4 100644 --- a/vk-sdk-core/src/main/java/com/vk/api/sdk/okhttp/LoggingInterceptor.kt +++ b/vk-sdk-core/src/main/java/com/vk/api/sdk/okhttp/LoggingInterceptor.kt @@ -23,9 +23,9 @@ ******************************************************************************/ package com.vk.api.sdk.okhttp -import android.support.v4.util.ArrayMap -import com.vk.api.sdk.utils.log.Logger +import androidx.collection.ArrayMap import com.vk.api.sdk.utils.getValue +import com.vk.api.sdk.utils.log.Logger import com.vk.api.sdk.utils.threadLocal import okhttp3.Interceptor import okhttp3.Response diff --git a/vk-sdk-core/src/main/java/com/vk/api/sdk/okhttp/OkHttpExecutor.kt b/vk-sdk-core/src/main/java/com/vk/api/sdk/okhttp/OkHttpExecutor.kt index 3a07f2f126..8e9b1f6396 100644 --- a/vk-sdk-core/src/main/java/com/vk/api/sdk/okhttp/OkHttpExecutor.kt +++ b/vk-sdk-core/src/main/java/com/vk/api/sdk/okhttp/OkHttpExecutor.kt @@ -25,11 +25,9 @@ package com.vk.api.sdk.okhttp import android.net.Uri import android.os.Looper -import android.support.v4.util.LongSparseArray -import com.vk.api.sdk.OauthHttpUrlPostCall +import androidx.collection.LongSparseArray import com.vk.api.sdk.VKApiProgressListener import com.vk.api.sdk.VKOkHttpProvider -import com.vk.api.sdk.chain.ChainArgs import com.vk.api.sdk.exceptions.* import com.vk.api.sdk.internal.HttpMultipartEntry import com.vk.api.sdk.internal.QueryStringGenerator @@ -81,27 +79,6 @@ open class OkHttpExecutor(protected val config: OkHttpExecutorConfig) { return readResponse(executeRequest(request)) } - open fun execute(call: OauthHttpUrlPostCall, chainArgs: ChainArgs?): String? { - val url = if (chainArgs != null && chainArgs.hasCaptcha()) { - Uri.parse(call.url) - .buildUpon() - .appendQueryParameter(VKApiCodes.EXTRA_CAPTCHA_KEY, chainArgs.captchaKey) - .appendQueryParameter(VKApiCodes.EXTRA_CAPTCHA_SID, chainArgs.captchaSid) - .build() - .toString() - - } else { - call.url - } - val request = Request.Builder() - .post(RequestBody.create(null, "")) - .cacheControl(CacheControl.FORCE_NETWORK) - .url(url) - .build() - - return readResponse(executeRequest(request, call.timeoutMs + timeoutDelay)) - } - @Throws(InterruptedException::class, IOException::class, VKApiException::class) fun execute(call: OkHttpPostCall, progressListener: VKApiProgressListener?): String? { val body = MultipartBody.Builder() diff --git a/vk-sdk-core/src/main/java/com/vk/api/sdk/ui/VKWebViewAuthActivity.kt b/vk-sdk-core/src/main/java/com/vk/api/sdk/ui/VKWebViewAuthActivity.kt index e378d2bfae..edcce5602b 100644 --- a/vk-sdk-core/src/main/java/com/vk/api/sdk/ui/VKWebViewAuthActivity.kt +++ b/vk-sdk-core/src/main/java/com/vk/api/sdk/ui/VKWebViewAuthActivity.kt @@ -33,13 +33,13 @@ import android.graphics.Bitmap import android.net.Uri import android.os.Build import android.os.Bundle -import android.support.annotation.RequiresApi import android.view.View import android.webkit.WebResourceError import android.webkit.WebResourceRequest import android.webkit.WebView import android.webkit.WebViewClient import android.widget.ProgressBar +import androidx.annotation.RequiresApi import com.vk.api.sdk.R import com.vk.api.sdk.VK import com.vk.api.sdk.VKApiValidationHandler @@ -51,7 +51,7 @@ import com.vk.api.sdk.utils.VKValidationLocker /** * Activity for showing authorization or validation WebView */ -class VKWebViewAuthActivity: Activity() { +open class VKWebViewAuthActivity: Activity() { private lateinit var webView: WebView private lateinit var progress: ProgressBar @@ -87,15 +87,28 @@ class VKWebViewAuthActivity: Activity() { } } + protected open fun getUrlParams(): Map = mapOf( + "client_id" to params.appId.toString(), + "scope" to params.getScopeString(), + "redirect_uri" to params.redirectUrl, + "response_type" to "token", + "display" to "mobile", + "v" to VK.getApiVersion(), + "revoke" to "1" + ) + private fun loadUrl() { try { val urlToLoad = if (needValidationResult()) intent.getStringExtra(VK_EXTRA_VALIDATION_URL) - else "https://oauth.vk.com/authorize?client_id=${params.appId}" + - "&scope=${params.getScopeString()}" + - "&redirect_uri=$REDIRECT_URL" + - "&display=mobile" + - "&v=${VK.getApiVersion()}" + - "&response_type=token&revoke=1" + else { + val uri = Uri.parse("https://oauth.vk.com/authorize").buildUpon() + val params = getUrlParams() + for ((key, value) in params) { + uri.appendQueryParameter(key, value) + } + uri.build().toString() + } + webView.loadUrl(urlToLoad) } catch (e: Exception) { setResult(Activity.RESULT_CANCELED) @@ -129,7 +142,7 @@ class VKWebViewAuthActivity: Activity() { } private fun handleUrl(url: String?): Boolean { - if (url == null || !url.startsWith(REDIRECT_URL)) return false + if (url == null || !url.startsWith(params.redirectUrl)) return false val intent = Intent(VK_RESULT_INTENT_NAME) val extraData = url.substring(url.indexOf("#") + 1) @@ -208,7 +221,6 @@ class VKWebViewAuthActivity: Activity() { companion object { const val VK_EXTRA_AUTH_PARAMS = "vk_auth_params" const val VK_RESULT_INTENT_NAME = "com.vk.auth-token" - const val REDIRECT_URL = "https://oauth.vk.com/blank.html" private const val VK_EXTRA_VALIDATION_URL = "vk_validation_url" diff --git a/vk-sdk-core/src/main/java/com/vk/api/sdk/utils/ApiExt.kt b/vk-sdk-core/src/main/java/com/vk/api/sdk/utils/ApiExt.kt index b600585c96..1060e4e277 100644 --- a/vk-sdk-core/src/main/java/com/vk/api/sdk/utils/ApiExt.kt +++ b/vk-sdk-core/src/main/java/com/vk/api/sdk/utils/ApiExt.kt @@ -28,7 +28,7 @@ import android.util.MalformedJsonException import com.vk.api.sdk.internal.VKErrorUtils import java.io.IOException import java.io.InterruptedIOException -import java.net.SocketTimeoutException +import java.net.* internal inline fun T.applyPos(value: N, block: T.(N) -> Unit): T { return if (value.toDouble() > 0) { @@ -53,4 +53,12 @@ internal fun String.hasSimpleError() = VKErrorUtils.hasSimpleError(this) internal fun String.toSimpleError(method: String? = null) = VKErrorUtils.parseSimpleError(this, method) internal fun String.toExecuteError(method: String, ignoredErrors: IntArray?) = VKErrorUtils.parseExecuteError(this, method, ignoredErrors) -operator fun android.support.v4.util.LongSparseArray.set(key: Long, value: E) = put(key, value) +operator fun androidx.collection.LongSparseArray.set(key: Long, value: E) = put(key, value) + +fun Throwable.isNetworkException() = this::class in listOf( + ConnectException::class, + SocketException::class, + SocketTimeoutException::class, + UnknownHostException::class, + ProtocolException::class +) \ No newline at end of file diff --git a/vk-sdk-core/src/main/java/com/vk/api/sdk/utils/VKUtils.kt b/vk-sdk-core/src/main/java/com/vk/api/sdk/utils/VKUtils.kt index 26b607b556..3f270a0c09 100644 --- a/vk-sdk-core/src/main/java/com/vk/api/sdk/utils/VKUtils.kt +++ b/vk-sdk-core/src/main/java/com/vk/api/sdk/utils/VKUtils.kt @@ -22,7 +22,7 @@ * SOFTWARE. ******************************************************************************/ -@file:Suppress("DEPRECATION") +@file:Suppress("DEPRECATION", "unused") package com.vk.api.sdk.utils