Skip to content

Commit d489e88

Browse files
author
Oleg Smirnov
committed
version 2.1.0
version 2.1.0 * compile sdk - 28 * add phone/phoneAccesKey params (require permissions, see https://vk.com/dev/permissions) * fix NPE, minor issues.
1 parent 14dcdd0 commit d489e88

16 files changed

+265
-24
lines changed

dependencies.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
ext.sdkVersions = [
22
code : '11',
3-
name : '2.0.2',
3+
name : '2.1.0',
44

55
minSdk : 16,
66
targetSdk : 26,
7-
compileSdk : '27',
7+
compileSdk : '28',
88
buildTools : '27.0.3',
99

1010
kotlin : '1.3.10',

samples/app/src/main/AndroidManifest.xml

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
android:icon="@mipmap/ic_launcher_round"
3434
android:roundIcon="@mipmap/ic_launcher_round"
3535
android:supportsRtl="true"
36+
android:networkSecurityConfig="@xml/network_security_config"
3637
android:theme="@style/AppTheme" >
3738
<activity
3839
android:name=".WelcomeActivity"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<network-security-config>
3+
<debug-overrides>
4+
<trust-anchors>
5+
<certificates src="system" />
6+
<certificates src="user" />
7+
</trust-anchors>
8+
</debug-overrides>
9+
</network-security-config>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package com.vk.api.sdk
2+
3+
class OauthHttpUrlPostCall(val url: String, val timeoutMs: Long = 0L, val retryCountOnBackendError: Int = 0)

vk-sdk-core/src/main/java/com/vk/api/sdk/VK.kt

+14-2
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ import android.annotation.SuppressLint
2828
import android.app.Activity
2929
import android.content.Context
3030
import android.content.Intent
31-
import com.vk.api.sdk.internal.ApiCommand
31+
import com.vk.api.sdk.auth.VKAccessToken
3232
import com.vk.api.sdk.auth.VKAuthCallback
3333
import com.vk.api.sdk.auth.VKAuthManager
34-
import com.vk.api.sdk.auth.VKAuthParams
3534
import com.vk.api.sdk.auth.VKScope
3635
import com.vk.api.sdk.exceptions.VKApiException
3736
import com.vk.api.sdk.exceptions.VKApiExecutionException
37+
import com.vk.api.sdk.internal.ApiCommand
3838
import com.vk.api.sdk.requests.VKBooleanRequest
3939
import com.vk.api.sdk.utils.VKUtils
4040
import java.io.IOException
@@ -76,6 +76,18 @@ object VK {
7676
authManager.login(activity, scopes)
7777
}
7878

79+
/**
80+
* This method is used to set new credentials for future requests. E.g. if you login via your own lib
81+
* @param userId userId of saving user
82+
* @param accessToken accessToken for future requests
83+
* @param secret secret for future requests
84+
*/
85+
@JvmStatic
86+
fun setCredentials(context: Context, userId: Int, accessToken: String, secret: String?) {
87+
VKAccessToken(userId, accessToken, secret).save(authManager.getPreferences(context))
88+
apiManager.setCredentials(accessToken, secret)
89+
}
90+
7991
/**
8092
* This method clears information about access token and cookies
8193
*/

vk-sdk-core/src/main/java/com/vk/api/sdk/VKApiManager.kt

+11
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,17 @@ open class VKApiManager(val config: VKApiConfig) {
6565
return executeWithExceptionAdjust(cc)
6666
}
6767

68+
fun <T> execute(call: OauthHttpUrlPostCall, parser: VKApiResponseParser<T>? = null): T {
69+
var cc: ChainCall<T> = OAuthHttpUrlChainCall(this, executor, call, parser)
70+
if (call.retryCountOnBackendError != 0) {
71+
cc = InternalErrorRetryChainCall(this, call.retryCountOnBackendError, cc)
72+
}
73+
if (call.retryCountOnBackendError != 0) {
74+
cc = ValidationHandlerChainCall(this, call.retryCountOnBackendError, cc)
75+
}
76+
return executeWithExceptionAdjust(cc)
77+
}
78+
6879
protected open fun <T> wrapCall(call: VKMethodCall, chainCall: ChainCall<T>): ChainCall<T> {
6980
var cc: ChainCall<T> = if (call.skipValidation) {
7081
chainCall

vk-sdk-core/src/main/java/com/vk/api/sdk/auth/VKAccessToken.kt

+13-1
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,21 @@ package com.vk.api.sdk.auth
2626

2727
import android.content.SharedPreferences
2828
import android.os.Bundle
29-
import java.util.HashMap
29+
import java.util.*
3030

3131
class VKAccessToken(params: Map<String, String?>) {
32+
internal constructor(userId: Int, accessToken: String, secret: String?) : this(mapOf(Pair(USER_ID, userId.toString()),
33+
Pair(ACCESS_TOKEN, accessToken),
34+
Pair(SECRET, secret),
35+
Pair(HTTPS_REQUIRED, "1")))
3236

3337
val userId: Int?
3438
val accessToken: String
3539
val secret: String?
3640
val created: Long
3741
val email: String?
42+
val phone: String?
43+
val phoneAccessKey: String?
3844
private val httpsRequired: Boolean
3945
private val expirationDate: Long
4046

@@ -49,6 +55,8 @@ class VKAccessToken(params: Map<String, String?>) {
4955
this.created = if (params.containsKey(CREATED)) params[CREATED]!!.toLong() else System.currentTimeMillis()
5056
this.expirationDate = if (params.containsKey(EXPIRES_IN)) params[EXPIRES_IN]!!.toLong() else -1
5157
this.email = if (params.containsKey(EMAIL)) params[EMAIL] else null
58+
this.phone = if (params.containsKey(PHONE)) params[PHONE] else null
59+
this.phoneAccessKey = if (params.containsKey(PHONE_ACCESS_KEY)) params[PHONE_ACCESS_KEY] else null
5260
}
5361

5462
fun save(bundle: Bundle) {
@@ -78,6 +86,8 @@ class VKAccessToken(params: Map<String, String?>) {
7886
result[EXPIRES_IN] = expirationDate.toString()
7987
result[USER_ID] = userId?.toString()
8088
result[EMAIL] = email
89+
result[PHONE] = phone
90+
result[PHONE_ACCESS_KEY] = phoneAccessKey
8191
return result
8292
}
8393

@@ -90,6 +100,8 @@ class VKAccessToken(params: Map<String, String?>) {
90100
private const val CREATED = "created"
91101
private const val VK_ACCESS_TOKEN_KEY = "vk_access_token"
92102
private const val EMAIL = "email"
103+
private const val PHONE = "phone"
104+
private const val PHONE_ACCESS_KEY = "phone_access_key"
93105

94106
fun restore(bundle: Bundle?): VKAccessToken? {
95107
if (bundle == null) {

vk-sdk-core/src/main/java/com/vk/api/sdk/auth/VKAuthManager.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,11 @@ package com.vk.api.sdk.auth
2727
import android.app.Activity
2828
import android.content.Context
2929
import android.content.Intent
30+
import android.content.SharedPreferences
3031
import com.vk.api.sdk.VK
3132
import com.vk.api.sdk.ui.VKWebViewAuthActivity
3233
import com.vk.api.sdk.utils.VKUtils
33-
import java.util.HashMap
34+
import java.util.*
3435

3536
internal class VKAuthManager {
3637
fun login(activity: Activity, scopes: Collection<VKScope>) {
@@ -116,8 +117,7 @@ internal class VKAuthManager {
116117
getPreferences(context).edit().clear().apply()
117118
}
118119

119-
private fun getPreferences(context: Context)
120-
= context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE)
120+
fun getPreferences(context: Context): SharedPreferences = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE)
121121

122122
companion object {
123123
private const val VK_APP_PACKAGE_ID = "com.vkontakte.android"

vk-sdk-core/src/main/java/com/vk/api/sdk/auth/VKScope.kt

+3-1
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,7 @@ enum class VKScope {
4343
NOTIFICATIONS,
4444
STATS,
4545
EMAIL,
46-
MARKET
46+
MARKET,
47+
// Need to pass moderation for this scope. Check this: https://vk.com/dev/permissions
48+
PHONE
4749
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package com.vk.api.sdk.chain
2+
3+
import android.os.Bundle
4+
import android.os.SystemClock
5+
import com.vk.api.sdk.OauthHttpUrlPostCall
6+
import com.vk.api.sdk.VKApiManager
7+
import com.vk.api.sdk.VKApiResponseParser
8+
import com.vk.api.sdk.exceptions.VKApiCodes
9+
import com.vk.api.sdk.exceptions.VKApiException
10+
import com.vk.api.sdk.exceptions.VKApiExecutionException
11+
import com.vk.api.sdk.okhttp.OkHttpExecutor
12+
import org.json.JSONObject
13+
import java.io.IOException
14+
import java.util.concurrent.TimeUnit
15+
import kotlin.math.max
16+
import kotlin.math.min
17+
18+
class OAuthHttpUrlChainCall<T>(manager: VKApiManager,
19+
private val okHttpExecutor: OkHttpExecutor,
20+
private val call: OauthHttpUrlPostCall,
21+
private val parser: VKApiResponseParser<T>?)
22+
: ChainCall<T>(manager) {
23+
24+
@Throws(Exception::class)
25+
override fun call(args: ChainArgs): T? {
26+
return call(args, System.currentTimeMillis())
27+
}
28+
29+
@Throws(Exception::class)
30+
private fun call(args: ChainArgs, firstRequestTime: Long): T? {
31+
val currentTime = System.currentTimeMillis()
32+
if (firstRequestTime + getTimeout() < currentTime) {
33+
throw IOException()
34+
}
35+
36+
val response = okHttpExecutor.execute(call, args)
37+
return when (response) {
38+
null -> throw VKApiException("Response returned null instead of valid string response")
39+
else -> {
40+
val jo = JSONObject(response)
41+
val error = jo.optString("error")
42+
val processing = jo.has("processing")
43+
when {
44+
error == "need_captcha" -> {
45+
// Hack conversion to VKApiExecutionException, because ApiManager is able to handle a captcha properly
46+
val extras = Bundle().apply {
47+
putString(VKApiCodes.EXTRA_CAPTCHA_SID, jo.getString(VKApiCodes.EXTRA_CAPTCHA_SID))
48+
putString(VKApiCodes.EXTRA_CAPTCHA_IMG, jo.getString(VKApiCodes.EXTRA_CAPTCHA_IMG))
49+
}
50+
throw VKApiExecutionException(
51+
code = VKApiCodes.CODE_CAPTCHA_REQUIRED,
52+
apiMethod = call.url,
53+
hasLocalizedMessage = false,
54+
detailMessage = error,
55+
extra = extras)
56+
}
57+
processing -> {
58+
val timeout = jo.optLong("timeout", 200)
59+
val realTimeout = max(200, min(timeout, getTimeout()))
60+
SystemClock.sleep(realTimeout)
61+
call(args, firstRequestTime)
62+
}
63+
else -> parser?.parse(response)
64+
}
65+
}
66+
}
67+
}
68+
69+
private fun getTimeout(): Long {
70+
return if (call.timeoutMs > 0) {
71+
call.timeoutMs
72+
} else {
73+
DEFAULT_TIMEOUT
74+
}
75+
}
76+
77+
companion object {
78+
private val DEFAULT_TIMEOUT = TimeUnit.SECONDS.toMillis(10)
79+
}
80+
}

vk-sdk-core/src/main/java/com/vk/api/sdk/exceptions/VKApiExecutionException.kt

+17-10
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ import org.json.JSONObject
3131
* See [http://vk.com/dev/errors](http://vk.com/dev/errors)
3232
*/
3333
open class VKApiExecutionException
34-
@JvmOverloads constructor(
35-
val code: Int,
36-
val apiMethod: String,
37-
val hasLocalizedMessage: Boolean,
38-
detailMessage: String,
39-
val extra: Bundle? = Bundle.EMPTY,
40-
val executeErrors: List<VKApiExecutionException>? = null,
41-
val errorMsg: String? = null) : VKApiException(detailMessage) {
34+
@JvmOverloads constructor(
35+
val code: Int,
36+
val apiMethod: String,
37+
val hasLocalizedMessage: Boolean,
38+
detailMessage: String,
39+
val extra: Bundle? = Bundle.EMPTY,
40+
val executeErrors: List<VKApiExecutionException>? = null,
41+
val errorMsg: String? = null) : VKApiException(detailMessage) {
4242

4343
val isCompositeError: Boolean
4444
get() = code == VKApiCodes.CODE_COMPOSITE_EXECUTE_ERROR
@@ -95,7 +95,7 @@ open class VKApiExecutionException
9595
get() = code == VKApiCodes.CODE_CAPTCHA_REQUIRED
9696

9797
val captchaSid: String
98-
get() = extra?.getString(VKApiCodes.EXTRA_CAPTCHA_SID, "") ?: ""
98+
get() = extra?.getString(VKApiCodes.EXTRA_CAPTCHA_SID, "") ?: ""
9999

100100
val captchaImg: String
101101
get() = extra?.getString(VKApiCodes.EXTRA_CAPTCHA_IMG, "") ?: ""
@@ -136,6 +136,12 @@ open class VKApiExecutionException
136136
'}'.toString()
137137
}
138138

139+
fun hasError(errorCode: Int): Boolean {
140+
if (code == errorCode) return true
141+
if (executeErrors?.find { it.code == errorCode } != null) return true
142+
return false
143+
}
144+
139145
companion object {
140146
internal const val serialVersionUID = 7524047853274172872L
141147

@@ -145,7 +151,8 @@ open class VKApiExecutionException
145151
val code = json.getInt("error_code")
146152
val errorMsg = json.optString("error_msg") ?: ""
147153
return if (json.has("error_text")) {
148-
VKApiExecutionException(code, method, true, json.optString("error_text") ?: "", extra, errorMsg = errorMsg)
154+
VKApiExecutionException(code, method, true, json.optString("error_text")
155+
?: "", extra, errorMsg = errorMsg)
149156
} else {
150157
val errorMsg = json.optString("error_msg") ?: ""
151158
VKApiExecutionException(code, method, false, "$errorMsg | by [$method]", extra, errorMsg = errorMsg)

vk-sdk-core/src/main/java/com/vk/api/sdk/internal/QueryStringGenerator.kt

+3-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ object QueryStringGenerator {
6363
strBuilder.clear()
6464
var sb = strBuilder + "v=" + version + "&https=1&"
6565
for ((key, value) in args) {
66-
sb = sb.plus(key) + "=" + value.encodeUrlAsUtf8(isApplyUrlEncode) + "&"
66+
if (key != "v" && key != "access_token" && key != "api_id") {
67+
sb = sb.plus(key) + "=" + value.encodeUrlAsUtf8(isApplyUrlEncode) + "&"
68+
}
6769
}
6870
sb = if (!accessToken.isNullOrEmpty()) {
6971
sb + "access_token=" + accessToken + "&"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*******************************************************************************
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2019 vk.com
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
******************************************************************************/
24+
package com.vk.api.sdk.okhttp
25+
26+
import android.support.v4.util.ArrayMap
27+
import com.vk.api.sdk.utils.log.Logger
28+
import com.vk.api.sdk.utils.getValue
29+
import com.vk.api.sdk.utils.threadLocal
30+
import okhttp3.Interceptor
31+
import okhttp3.Response
32+
import okhttp3.logging.HttpLoggingInterceptor
33+
34+
class LoggingInterceptor(private val filterCredentials: Boolean, private val logger: Logger) : Interceptor {
35+
private val delegate by threadLocal {
36+
HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
37+
override fun log(message: String) {
38+
val finalMessage = if (filterCredentials) filterCredentials(message) else message
39+
logger.log(logger.logLevel, finalMessage)
40+
}
41+
42+
private fun filterCredentials(msg: String): String {
43+
return msg
44+
.replace("access_token=[a-z0-9]+".toRegex(), "access_token=<HIDE>")
45+
.replace("key=[a-z0-9]+".toRegex(), "key=<HIDE>")
46+
}
47+
})
48+
}
49+
50+
override fun intercept(chain: Interceptor.Chain): Response {
51+
// Do not log big bodies because of probability of OutOfMemoryError
52+
val bodyLength = chain.request().body()?.contentLength() ?: 0
53+
delegate.level =
54+
if (bodyLength > 1024L) HttpLoggingInterceptor.Level.BASIC
55+
else LogLevelMap.levelsMap[logger.logLevel]
56+
return delegate.intercept(chain)
57+
}
58+
59+
object LogLevelMap {
60+
val levelsMap = ArrayMap<Logger.LogLevel, HttpLoggingInterceptor.Level>()
61+
init {
62+
levelsMap[Logger.LogLevel.NONE] = HttpLoggingInterceptor.Level.NONE
63+
levelsMap[Logger.LogLevel.ERROR] = HttpLoggingInterceptor.Level.NONE
64+
levelsMap[Logger.LogLevel.WARNING] = HttpLoggingInterceptor.Level.BASIC
65+
levelsMap[Logger.LogLevel.DEBUG] = HttpLoggingInterceptor.Level.HEADERS
66+
levelsMap[Logger.LogLevel.VERBOSE] = HttpLoggingInterceptor.Level.BODY
67+
}
68+
}
69+
}

0 commit comments

Comments
 (0)